Fixing query parameters

This commit is contained in:
Alexey Milovidov 2019-06-15 20:52:53 +03:00
parent 54ece5f968
commit fad6013270
11 changed files with 46 additions and 43 deletions

View File

@ -204,7 +204,7 @@ private:
std::list<ExternalTable> external_tables;
/// Dictionary with query parameters for prepared statements.
NameToNameMap parameters_substitution;
NameToNameMap query_parameters;
ConnectionParameters connection_parameters;
@ -807,15 +807,12 @@ private:
if (!parsed_query)
return true;
if (!parameters_substitution.empty())
{
/// Replace ASTQueryParameter with ASTLiteral for prepared statements.
ReplaceQueryParameterVisitor visitor(parameters_substitution);
visitor.visit(parsed_query);
/// Replace ASTQueryParameter with ASTLiteral for prepared statements.
ReplaceQueryParameterVisitor visitor(query_parameters);
visitor.visit(parsed_query);
/// Get new query after substitutions.
query = serializeAST(*parsed_query);
}
/// Get new query after substitutions.
query = serializeAST(*parsed_query);
processed_rows = 0;
progress.reset();
@ -1719,7 +1716,7 @@ public:
if (pos != String::npos && pos + 1 != parameter.size())
{
const String name = parameter.substr(0, pos);
if (!parameters_substitution.insert({name, parameter.substr(pos + 1)}).second)
if (!query_parameters.insert({name, parameter.substr(pos + 1)}).second)
throw Exception("Duplicate name " + name + " of query parameter", ErrorCodes::BAD_ARGUMENTS);
}
else

View File

@ -505,7 +505,7 @@ void HTTPHandler::processQuery(
{
/// Save name and values of substitution in dictionary.
const String parameter_name = key.substr(strlen("param_"));
context.setParameterSubstitution(parameter_name, value);
context.setQueryParameter(parameter_name, value);
}
else
{

View File

@ -1868,22 +1868,20 @@ Context::SampleBlockCache & Context::getSampleBlockCache() const
bool Context::hasQueryParameters() const
{
return !parameters_substitution.empty();
return !query_parameters.empty();
}
NameToNameMap Context::getParameterSubstitution() const
const NameToNameMap & Context::getQueryParameters() const
{
if (hasQueryParameters())
return parameters_substitution;
throw Exception("Logical error: there are no parameters to substitute", ErrorCodes::LOGICAL_ERROR);
return query_parameters;
}
void Context::setParameterSubstitution(const String & name, const String & value)
void Context::setQueryParameter(const String & name, const String & value)
{
if (!parameters_substitution.insert({name, value}).second)
throw Exception("Duplicate name " + name + " of query parameter", ErrorCodes::BAD_ARGUMENTS);
if (!query_parameters.emplace(name, value).second)
throw Exception("Duplicate name " + backQuote(name) + " of query parameter", ErrorCodes::BAD_ARGUMENTS);
}

View File

@ -145,7 +145,7 @@ private:
using DatabasePtr = std::shared_ptr<IDatabase>;
using Databases = std::map<String, std::shared_ptr<IDatabase>>;
NameToNameMap parameters_substitution; /// Dictionary with query parameters for prepared statements.
NameToNameMap query_parameters; /// Dictionary with query parameters for prepared statements.
/// (key=name, value)
IHostContextPtr host_context; /// Arbitrary object that may used to attach some host specific information to query context,
@ -472,8 +472,8 @@ public:
/// Query parameters for prepared statements.
bool hasQueryParameters() const;
NameToNameMap getParameterSubstitution() const;
void setParameterSubstitution(const String & name, const String & value);
const NameToNameMap & getQueryParameters() const;
void setQueryParameter(const String & name, const String & value);
#if USE_EMBEDDED_COMPILER
std::shared_ptr<CompiledExpressionCache> getCompiledExpressionCache() const;

View File

@ -28,11 +28,11 @@ void ReplaceQueryParameterVisitor::visit(ASTPtr & ast)
const String & ReplaceQueryParameterVisitor::getParamValue(const String & name)
{
auto search = parameters_substitution.find(name);
if (search != parameters_substitution.end())
auto search = query_parameters.find(name);
if (search != query_parameters.end())
return search->second;
else
throw Exception("Expected name '" + name + "' in argument --param_{name}", ErrorCodes::BAD_ARGUMENTS);
throw Exception("Substitution " + backQuote(name) + " is not set", ErrorCodes::BAD_ARGUMENTS);
}
void ReplaceQueryParameterVisitor::visitQueryParameter(ASTPtr & ast)

View File

@ -8,18 +8,18 @@ namespace DB
class ASTQueryParameter;
/// Get prepared statements in query, replace ASTQueryParameter with ASTLiteral.
/// Visit substitutions in a query, replace ASTQueryParameter with ASTLiteral.
class ReplaceQueryParameterVisitor
{
public:
ReplaceQueryParameterVisitor(const NameToNameMap & parameters)
: parameters_substitution(parameters)
: query_parameters(parameters)
{}
void visit(ASTPtr & ast);
private:
const NameToNameMap parameters_substitution;
const NameToNameMap & query_parameters;
const String & getParamValue(const String & name);
void visitQueryParameter(ASTPtr & ast);
};

View File

@ -170,12 +170,9 @@ static std::tuple<ASTPtr, BlockIO> executeQueryImpl(
/// TODO Parser should fail early when max_query_size limit is reached.
ast = parseQuery(parser, begin, end, "", max_query_size);
if (context.hasQueryParameters()) /// Avoid change from TCPHandler.
{
/// Replace ASTQueryParameter with ASTLiteral for prepared statements.
ReplaceQueryParameterVisitor visitor(context.getParameterSubstitution());
visitor.visit(ast);
}
/// Replace ASTQueryParameter with ASTLiteral for prepared statements.
ReplaceQueryParameterVisitor visitor(context.getQueryParameters());
visitor.visit(ast);
auto * insert_query = ast->as<ASTInsertQuery>();
@ -208,8 +205,8 @@ static std::tuple<ASTPtr, BlockIO> executeQueryImpl(
try
{
if (context.hasQueryParameters()) /// Avoid change from TCPHandler.
/// Get new query after substitutions.
/// Get new query after substitutions.
if (context.hasQueryParameters())
query = serializeAST(*ast);
logQuery(query.substr(0, settings.log_queries_cut_to_length), context, internal);

View File

@ -7,7 +7,13 @@ namespace DB
void ASTQueryParameter::formatImplWithoutAlias(const FormatSettings & settings, FormatState &, FormatStateStacked) const
{
settings.ostr << backQuoteIfNeed(name) + ':' + type;
settings.ostr
<< (settings.hilite ? hilite_substitution : "") << '{'
<< (settings.hilite ? hilite_identifier : "") << backQuoteIfNeed(name)
<< (settings.hilite ? hilite_substitution : "") << ':'
<< (settings.hilite ? hilite_identifier : "") << type
<< (settings.hilite ? hilite_substitution : "") << '}'
<< (settings.hilite ? hilite_none : "");
}
void ASTQueryParameter::appendColumnNameImpl(WriteBuffer & ostr) const

View File

@ -17,12 +17,13 @@ namespace ErrorCodes
}
const char * IAST::hilite_keyword = "\033[1m";
const char * IAST::hilite_identifier = "\033[0;36m";
const char * IAST::hilite_function = "\033[0;33m";
const char * IAST::hilite_operator = "\033[1;33m";
const char * IAST::hilite_alias = "\033[0;32m";
const char * IAST::hilite_none = "\033[0m";
const char * IAST::hilite_keyword = "\033[1m";
const char * IAST::hilite_identifier = "\033[0;36m";
const char * IAST::hilite_function = "\033[0;33m";
const char * IAST::hilite_operator = "\033[1;33m";
const char * IAST::hilite_alias = "\033[0;32m";
const char * IAST::hilite_substitution = "\033[1;36m";
const char * IAST::hilite_none = "\033[0m";
String backQuoteIfNeed(const String & x)

View File

@ -201,6 +201,7 @@ public:
static const char * hilite_function;
static const char * hilite_operator;
static const char * hilite_alias;
static const char * hilite_substitution;
static const char * hilite_none;
private:

View File

@ -18,4 +18,7 @@ $CLICKHOUSE_CLIENT --max_threads=1 --param_date='2005-05-25 15:00:00' \
$CLICKHOUSE_CLIENT --max_threads=1 --param_id=2 --param_phrase='test' \
-q "SELECT * FROM ps WHERE i = {id:UInt8} and s = {phrase:String}";
$CLICKHOUSE_CLIENT -q "SELECT {s:String}" 2>&1 | grep -P '^Code: 36\.'
$CLICKHOUSE_CLIENT -q "DROP TABLE ps";