mirror of
https://github.com/hanzoai/datastore.git
synced 2026-09-26 13:55:07 +00:00
Forbid subqueries in key expressions (ORDER BY, PRIMARY KEY, PARTITION BY, INDEX, TTL)
Subqueries in key expressions (e.g., `ORDER BY (1 = ANY(SELECT 1))`) caused a LOGICAL_ERROR exception "Not-ready Set" during INSERT because the `ExpressionAnalyzer` creates `FutureSetFromSubquery` objects that nobody builds. Rather than fixing the complex interaction between expression analysis, set building, and column naming across multiple code paths, forbid subqueries in key expressions entirely — they have no practical use case. The check is added in `KeyDescription::getSortingKeyFromAST` (covers ORDER BY, PRIMARY KEY, PARTITION BY), `IndexDescription::getIndexFromAST` (covers skip indices), and `TTLDescription::getTTLFromAST` (covers TTL), via a shared `checkExpressionDoesntContainSubqueries` function. Closes https://github.com/ClickHouse/ClickHouse/issues/96657 Co-Authored-By: Claude Opus 4.6 <[email protected]>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
2e525b608b
commit
7896defecb
@@ -108,6 +108,7 @@ IndexDescription IndexDescription::getIndexFromAST(
|
||||
result.is_implicitly_created = is_implicitly_created;
|
||||
result.escape_filenames = escape_filenames;
|
||||
|
||||
checkExpressionDoesntContainSubqueries(*index_definition->getExpression());
|
||||
result.initExpressionInfo(index_definition->getExpression(), columns, context);
|
||||
|
||||
for (auto & elem : result.sample_block)
|
||||
|
||||
@@ -3,13 +3,11 @@
|
||||
#include <Functions/IFunction.h>
|
||||
#include <Parsers/ASTIdentifier.h>
|
||||
#include <Parsers/ASTFunction.h>
|
||||
#include <Parsers/ASTSubquery.h>
|
||||
#include <Interpreters/ExpressionActions.h>
|
||||
#include <Interpreters/ExpressionAnalyzer.h>
|
||||
#include <Interpreters/TreeRewriter.h>
|
||||
#include <Storages/ColumnsDescription.h>
|
||||
#include <Storages/extractKeyExpressionList.h>
|
||||
#include <Common/checkStackSize.h>
|
||||
#include <Common/quoteString.h>
|
||||
#include <Interpreters/FunctionNameNormalizer.h>
|
||||
#include <Parsers/ASTOrderByElement.h>
|
||||
@@ -22,7 +20,6 @@ namespace DB
|
||||
|
||||
namespace ErrorCodes
|
||||
{
|
||||
extern const int BAD_ARGUMENTS;
|
||||
extern const int LOGICAL_ERROR;
|
||||
extern const int DATA_TYPE_CANNOT_BE_USED_IN_KEY;
|
||||
}
|
||||
@@ -122,17 +119,6 @@ bool KeyDescription::moduloToModuloLegacyRecursive(ASTPtr node_expr)
|
||||
return modulo_in_ast;
|
||||
}
|
||||
|
||||
static void checkExpressionDoesntContainSubqueries(const IAST & ast)
|
||||
{
|
||||
checkStackSize();
|
||||
|
||||
if (ast.as<ASTSubquery>())
|
||||
throw Exception(ErrorCodes::BAD_ARGUMENTS, "Key expressions cannot contain subqueries");
|
||||
|
||||
for (const auto & child : ast.children)
|
||||
checkExpressionDoesntContainSubqueries(*child);
|
||||
}
|
||||
|
||||
KeyDescription KeyDescription::getSortingKeyFromAST(
|
||||
const ASTPtr & definition_ast,
|
||||
const ColumnsDescription & columns,
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <Interpreters/addTypeConversionToAST.h>
|
||||
#include <Parsers/ASTFunction.h>
|
||||
#include <Parsers/ASTTTLElement.h>
|
||||
#include <Storages/extractKeyExpressionList.h>
|
||||
#include <Parsers/ASTIdentifier.h>
|
||||
#include <Parsers/ASTAssignment.h>
|
||||
#include <Storages/ColumnsDescription.h>
|
||||
@@ -228,6 +229,8 @@ TTLDescription TTLDescription::getTTLFromAST(
|
||||
else /// It's columns TTL without any additions, just copy it
|
||||
result.expression_ast = definition_ast->clone();
|
||||
|
||||
checkExpressionDoesntContainSubqueries(*result.expression_ast);
|
||||
|
||||
auto ttl_ast = result.expression_ast->clone();
|
||||
auto expression = buildExpressionAndSets(ttl_ast, columns.getAllPhysical(), context).expression;
|
||||
result.expression_columns = expression->getRequiredColumnsWithTypes();
|
||||
|
||||
@@ -1,9 +1,28 @@
|
||||
#include <Storages/extractKeyExpressionList.h>
|
||||
#include <Parsers/ASTFunction.h>
|
||||
#include <Parsers/ASTExpressionList.h>
|
||||
#include <Parsers/ASTSubquery.h>
|
||||
#include <Common/checkStackSize.h>
|
||||
#include <Common/Exception.h>
|
||||
|
||||
namespace DB
|
||||
{
|
||||
namespace ErrorCodes
|
||||
{
|
||||
extern const int BAD_ARGUMENTS;
|
||||
}
|
||||
|
||||
void checkExpressionDoesntContainSubqueries(const IAST & ast)
|
||||
{
|
||||
checkStackSize();
|
||||
|
||||
if (ast.as<ASTSubquery>())
|
||||
throw Exception(ErrorCodes::BAD_ARGUMENTS, "Key expressions cannot contain subqueries");
|
||||
|
||||
for (const auto & child : ast.children)
|
||||
checkExpressionDoesntContainSubqueries(*child);
|
||||
}
|
||||
|
||||
ASTPtr extractKeyExpressionList(const ASTPtr & node)
|
||||
{
|
||||
if (!node)
|
||||
|
||||
@@ -5,4 +5,7 @@
|
||||
namespace DB
|
||||
{
|
||||
ASTPtr extractKeyExpressionList(const ASTPtr & node);
|
||||
|
||||
/// Throws BAD_ARGUMENTS if the AST contains any subqueries.
|
||||
void checkExpressionDoesntContainSubqueries(const IAST & ast);
|
||||
}
|
||||
|
||||
@@ -5,3 +5,5 @@ CREATE TABLE t0 (c0 Int) ENGINE = MergeTree() ORDER BY (1 = ANY(SELECT 1)); -- {
|
||||
CREATE TABLE t0 (c0 Int) ENGINE = MergeTree() ORDER BY (c0 IN (SELECT 1)); -- { serverError BAD_ARGUMENTS }
|
||||
CREATE TABLE t0 (c0 Int) ENGINE = MergeTree() PARTITION BY (1 IN (SELECT 1)) ORDER BY c0; -- { serverError BAD_ARGUMENTS }
|
||||
CREATE TABLE t0 (c0 Int) ENGINE = MergeTree() ORDER BY c0 PRIMARY KEY (c0 IN (SELECT 1)); -- { serverError BAD_ARGUMENTS }
|
||||
CREATE TABLE t0 (c0 Int, INDEX idx (c0 IN (SELECT 1)) TYPE minmax GRANULARITY 1) ENGINE = MergeTree() ORDER BY c0; -- { serverError BAD_ARGUMENTS }
|
||||
CREATE TABLE t0 (c0 Int, d DateTime) ENGINE = MergeTree() ORDER BY c0 TTL d + INTERVAL (1 IN (SELECT 1)) DAY; -- { serverError BAD_ARGUMENTS }
|
||||
|
||||
Reference in New Issue
Block a user