ClickHouse/src/Interpreters/ReplaceQueryParameterVisitor.cpp

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

160 lines
5.5 KiB
C++
Raw Normal View History

2019-05-18 23:57:26 +00:00
#include <Columns/IColumn.h>
2019-05-18 21:07:23 +00:00
#include <DataTypes/DataTypeFactory.h>
2022-09-04 14:26:31 +00:00
#include <DataTypes/IDataType.h>
2023-04-10 01:48:58 +00:00
#include <DataTypes/DataTypeString.h>
2019-05-18 21:07:23 +00:00
#include <Formats/FormatSettings.h>
#include <IO/ReadBufferFromString.h>
2020-11-02 10:03:52 +00:00
#include <Interpreters/IdentifierSemantic.h>
2019-05-18 21:07:23 +00:00
#include <Interpreters/ReplaceQueryParameterVisitor.h>
2019-06-14 17:15:30 +00:00
#include <Interpreters/addTypeConversionToAST.h>
2022-09-04 14:26:31 +00:00
#include <Parsers/ASTIdentifier.h>
#include <Parsers/ASTLiteral.h>
#include <Parsers/ASTQueryParameter.h>
#include <Parsers/TablePropertiesQueriesASTs.h>
#include <Common/quoteString.h>
#include <Common/typeid_cast.h>
2022-10-01 15:47:58 +00:00
#include <Common/checkStackSize.h>
2019-06-14 17:15:30 +00:00
2019-05-18 21:07:23 +00:00
namespace DB
{
2019-06-16 17:32:37 +00:00
namespace ErrorCodes
{
extern const int UNKNOWN_QUERY_PARAMETER;
extern const int BAD_QUERY_PARAMETER;
}
/// It is important to keep in mind that in the case of ASTIdentifier, we are changing the shared object itself,
/// and all shared_ptr's that pointed to the original object will now point to the new replaced value.
/// However, with ASTQueryParameter, we are only assigning a new value to the passed shared_ptr, while
/// all other shared_ptr's still point to the old ASTQueryParameter.
2019-06-16 17:32:37 +00:00
2019-05-18 21:07:23 +00:00
void ReplaceQueryParameterVisitor::visit(ASTPtr & ast)
2020-06-24 21:36:18 +00:00
{
2022-10-01 15:47:58 +00:00
checkStackSize();
2020-06-24 21:36:18 +00:00
if (ast->as<ASTQueryParameter>())
visitQueryParameter(ast);
2021-04-15 07:33:15 +00:00
else if (ast->as<ASTIdentifier>() || ast->as<ASTTableIdentifier>())
2020-11-02 10:03:52 +00:00
visitIdentifier(ast);
2020-06-24 21:36:18 +00:00
else
2022-09-04 14:26:31 +00:00
{
if (auto * describe_query = dynamic_cast<ASTDescribeQuery *>(ast.get()); describe_query && describe_query->table_expression)
visitChildren(describe_query->table_expression);
else
visitChildren(ast);
}
2020-06-24 21:36:18 +00:00
}
void ReplaceQueryParameterVisitor::visitChildren(ASTPtr & ast)
2019-05-18 21:07:23 +00:00
{
for (auto & child : ast->children)
2023-03-11 19:16:06 +00:00
{
void * old_ptr = child.get();
2020-06-24 21:36:18 +00:00
visit(child);
2023-03-11 19:16:06 +00:00
void * new_ptr = child.get();
/// Some AST classes have naked pointers to children elements as members.
/// We have to replace them if the child was replaced.
if (new_ptr != old_ptr)
ast->updatePointerToChild(old_ptr, new_ptr);
}
2019-05-18 21:07:23 +00:00
}
const String & ReplaceQueryParameterVisitor::getParamValue(const String & name)
2019-05-18 21:07:23 +00:00
{
2019-06-15 17:52:53 +00:00
auto search = query_parameters.find(name);
2023-08-16 20:35:45 +00:00
if (search == query_parameters.end())
throw Exception(ErrorCodes::UNKNOWN_QUERY_PARAMETER, "Substitution {} is not set", backQuote(name));
2023-08-16 20:35:45 +00:00
++num_replaced_parameters;
return search->second;
2019-05-18 21:07:23 +00:00
}
void ReplaceQueryParameterVisitor::visitQueryParameter(ASTPtr & ast)
2019-05-18 21:07:23 +00:00
{
const auto & ast_param = ast->as<ASTQueryParameter &>();
const String & value = getParamValue(ast_param.name);
2019-06-14 17:15:30 +00:00
const String & type_name = ast_param.type;
String alias = ast_param.alias;
2019-06-04 18:15:32 +00:00
2019-06-14 17:15:30 +00:00
const auto data_type = DataTypeFactory::instance().get(type_name);
2019-05-18 21:07:23 +00:00
auto temp_column_ptr = data_type->createColumn();
2019-05-18 23:57:26 +00:00
IColumn & temp_column = *temp_column_ptr;
2019-05-18 21:07:23 +00:00
ReadBufferFromString read_buffer{value};
FormatSettings format_settings;
const SerializationPtr & serialization = data_type->getDefaultSerialization();
try
{
if (ast_param.name == "_request_body")
serialization->deserializeWholeText(temp_column, read_buffer, format_settings);
else
serialization->deserializeTextEscaped(temp_column, read_buffer, format_settings);
}
catch (Exception & e)
{
e.addMessage("value {} cannot be parsed as {} for query parameter '{}'", value, type_name, ast_param.name);
throw;
}
2019-05-18 21:07:23 +00:00
2019-06-05 21:04:17 +00:00
if (!read_buffer.eof())
2020-09-19 15:13:51 +00:00
throw Exception(ErrorCodes::BAD_QUERY_PARAMETER,
"Value {} cannot be parsed as {} for query parameter '{}'"
" because it isn't parsed completely: only {} of {} bytes was parsed: {}",
value, type_name, ast_param.name, read_buffer.count(), value.size(), value.substr(0, read_buffer.count()));
2019-06-05 21:04:17 +00:00
Field literal;
2022-01-25 07:10:04 +00:00
/// If data type has custom serialization, we should use CAST from String,
/// because CAST from field may not work correctly (for example for type IPv6).
if (data_type->getCustomSerialization())
literal = value;
else
literal = temp_column[0];
2023-03-11 19:16:06 +00:00
/// If it's a String, substitute it in the form of a string literal without CAST
/// to enable substitutions in simple queries that don't support expressions
/// (such as CREATE USER).
2023-04-10 01:48:58 +00:00
if (typeid_cast<const DataTypeString *>(data_type.get()))
ast = std::make_shared<ASTLiteral>(literal);
else
ast = addTypeConversionToAST(std::make_shared<ASTLiteral>(literal), type_name);
2020-09-19 15:13:51 +00:00
/// Keep the original alias.
ast->setAlias(alias);
2019-05-18 21:07:23 +00:00
}
2020-11-02 10:03:52 +00:00
void ReplaceQueryParameterVisitor::visitIdentifier(ASTPtr & ast)
{
2021-04-15 07:33:15 +00:00
auto ast_identifier = dynamic_pointer_cast<ASTIdentifier>(ast);
if (ast_identifier->children.empty())
2020-11-02 10:03:52 +00:00
return;
2023-08-15 18:37:39 +00:00
bool replaced_parameter = false;
2021-04-15 07:33:15 +00:00
auto & name_parts = ast_identifier->name_parts;
2020-11-02 10:03:52 +00:00
for (size_t i = 0, j = 0, size = name_parts.size(); i < size; ++i)
{
if (name_parts[i].empty())
{
2021-04-15 07:33:15 +00:00
const auto & ast_param = ast_identifier->children[j++]->as<ASTQueryParameter &>();
2020-11-02 10:03:52 +00:00
name_parts[i] = getParamValue(ast_param.name);
2023-08-15 18:37:39 +00:00
replaced_parameter = true;
2020-11-02 10:03:52 +00:00
}
}
2023-08-15 18:37:39 +00:00
/// Do not touch AST if there are no parameters
if (!replaced_parameter)
return;
2021-04-15 07:33:15 +00:00
/// FIXME: what should this mean?
if (!ast_identifier->semantic->special && name_parts.size() >= 2)
ast_identifier->semantic->table = ast_identifier->name_parts.end()[-2];
2020-11-02 10:03:52 +00:00
2021-04-15 07:33:15 +00:00
ast_identifier->resetFullName();
ast_identifier->children.clear();
2020-11-02 10:03:52 +00:00
}
2019-05-18 21:07:23 +00:00
}