diff --git a/src/graph/util/ExpressionUtils.cpp b/src/graph/util/ExpressionUtils.cpp index 22e7d80c247..77cb5de29a3 100644 --- a/src/graph/util/ExpressionUtils.cpp +++ b/src/graph/util/ExpressionUtils.cpp @@ -6,8 +6,10 @@ #include "graph/util/ExpressionUtils.h" #include +#include #include "common/base/ObjectPool.h" +#include "common/expression/Expression.h" #include "common/expression/PropertyExpression.h" #include "common/function/AggFunctionManager.h" #include "graph/context/QueryContext.h" @@ -984,5 +986,183 @@ bool ExpressionUtils::isGeoIndexAcceleratedPredicate(const Expression *expr) { return false; } +bool ExpressionUtils::checkExprDepth(const Expression *expr) { + std::queue exprQueue; + exprQueue.emplace(expr); + int depth = 0; + while (!exprQueue.empty()) { + int size = exprQueue.size(); + while (size > 0) { + const Expression *cur = exprQueue.front(); + exprQueue.pop(); + switch (cur->kind()) { + case Expression::Kind::kConstant: + case Expression::Kind::kVar: { + break; + } + case Expression::Kind::kAdd: + case Expression::Kind::kMinus: + case Expression::Kind::kMultiply: + case Expression::Kind::kDivision: + case Expression::Kind::kMod: { + auto *ariExpr = static_cast(cur); + exprQueue.emplace(ariExpr->left()); + exprQueue.emplace(ariExpr->right()); + break; + } + case Expression::Kind::kIsNull: + case Expression::Kind::kIsNotNull: + case Expression::Kind::kIsEmpty: + case Expression::Kind::kIsNotEmpty: + case Expression::Kind::kUnaryPlus: + case Expression::Kind::kUnaryNegate: + case Expression::Kind::kUnaryNot: + case Expression::Kind::kUnaryIncr: + case Expression::Kind::kUnaryDecr: { + auto *unaExpr = static_cast(cur); + exprQueue.emplace(unaExpr->operand()); + break; + } + case Expression::Kind::kRelEQ: + case Expression::Kind::kRelNE: + case Expression::Kind::kRelLT: + case Expression::Kind::kRelLE: + case Expression::Kind::kRelGT: + case Expression::Kind::kRelGE: + case Expression::Kind::kRelREG: + case Expression::Kind::kContains: + case Expression::Kind::kNotContains: + case Expression::Kind::kStartsWith: + case Expression::Kind::kNotStartsWith: + case Expression::Kind::kEndsWith: + case Expression::Kind::kNotEndsWith: + case Expression::Kind::kRelNotIn: + case Expression::Kind::kRelIn: { + auto *relExpr = static_cast(cur); + exprQueue.emplace(relExpr->left()); + exprQueue.emplace(relExpr->right()); + break; + } + case Expression::Kind::kList: { + auto *listExpr = static_cast(cur); + for (auto &item : listExpr->items()) { + exprQueue.emplace(item); + } + break; + } + case Expression::Kind::kSet: { + auto *setExpr = static_cast(cur); + for (auto &item : setExpr->items()) { + exprQueue.emplace(item); + } + break; + } + case Expression::Kind::kMap: { + auto *mapExpr = static_cast(cur); + for (auto &item : mapExpr->items()) { + exprQueue.emplace(item.second); + } + break; + } + case Expression::Kind::kCase: { + auto *caseExpr = static_cast(cur); + if (caseExpr->hasCondition()) { + exprQueue.emplace(caseExpr->condition()); + } + if (caseExpr->hasDefault()) { + exprQueue.emplace(caseExpr->defaultResult()); + } + for (auto &whenThen : caseExpr->cases()) { + exprQueue.emplace(whenThen.when); + exprQueue.emplace(whenThen.then); + } + break; + } + case Expression::Kind::kListComprehension: { + auto *lcExpr = static_cast(cur); + exprQueue.emplace(lcExpr->collection()); + if (lcExpr->hasFilter()) { + exprQueue.emplace(lcExpr->filter()); + } + if (lcExpr->hasMapping()) { + exprQueue.emplace(lcExpr->mapping()); + } + break; + } + case Expression::Kind::kPredicate: { + auto *predExpr = static_cast(cur); + exprQueue.emplace(predExpr->collection()); + if (predExpr->hasFilter()) { + exprQueue.emplace(predExpr->filter()); + } + break; + } + case Expression::Kind::kReduce: { + auto *reduceExpr = static_cast(cur); + exprQueue.emplace(reduceExpr->collection()); + exprQueue.emplace(reduceExpr->mapping()); + break; + } + case Expression::Kind::kLogicalAnd: + case Expression::Kind::kLogicalOr: + case Expression::Kind::kLogicalXor: { + auto *logExpr = static_cast(cur); + for (auto &op : logExpr->operands()) { + exprQueue.emplace(op); + } + break; + } + case Expression::Kind::kTypeCasting: { + auto *typExpr = static_cast(cur); + exprQueue.emplace(typExpr->operand()); + break; + } + case Expression::Kind::kFunctionCall: { + auto *funExpr = static_cast(cur); + auto &args = funExpr->args()->args(); + for (auto iter = args.begin(); iter < args.end(); ++iter) { + exprQueue.emplace(*iter); + } + break; + } + case Expression::Kind::kTagProperty: + case Expression::Kind::kSrcProperty: + case Expression::Kind::kEdgeRank: + case Expression::Kind::kEdgeDst: + case Expression::Kind::kEdgeSrc: + case Expression::Kind::kEdgeType: + case Expression::Kind::kEdgeProperty: + case Expression::Kind::kInputProperty: + case Expression::Kind::kSubscript: + case Expression::Kind::kAttribute: + case Expression::Kind::kLabelAttribute: + case Expression::Kind::kVertex: + case Expression::Kind::kEdge: + case Expression::Kind::kLabel: + case Expression::Kind::kVarProperty: + case Expression::Kind::kDstProperty: + case Expression::Kind::kUUID: + case Expression::Kind::kPathBuild: + case Expression::Kind::kColumn: + case Expression::Kind::kTSPrefix: + case Expression::Kind::kTSWildcard: + case Expression::Kind::kTSRegexp: + case Expression::Kind::kTSFuzzy: + case Expression::Kind::kAggregate: + case Expression::Kind::kSubscriptRange: + case Expression::Kind::kVersionedVar: + default: + break; + } + size -= 1; + } + depth += 1; + if (depth > ExpressionUtils::kMaxDepth) { + return false; + } + } + return true; +} // namespace graph + } // namespace graph } // namespace nebula diff --git a/src/graph/util/ExpressionUtils.h b/src/graph/util/ExpressionUtils.h index 19193cb7a86..f42241f348b 100644 --- a/src/graph/util/ExpressionUtils.h +++ b/src/graph/util/ExpressionUtils.h @@ -164,6 +164,10 @@ class ExpressionUtils { // TODO(jie) Move it to a better place static bool isGeoIndexAcceleratedPredicate(const Expression* expr); + + static bool checkExprDepth(const Expression* expr); + + static constexpr int32_t kMaxDepth = 512; }; } // namespace graph diff --git a/src/parser/parser.yy b/src/parser/parser.yy index 8c61c1f0e27..c023d520d39 100644 --- a/src/parser/parser.yy +++ b/src/parser/parser.yy @@ -223,7 +223,7 @@ static constexpr size_t kCommentLengthLimit = 256; %token STRING VARIABLE LABEL IPV4 %type name_label unreserved_keyword predicate_name -%type expression +%type expression expression_internal %type property_expression %type vertex_prop_expression %type edge_prop_expression @@ -556,6 +556,18 @@ unreserved_keyword ; expression + : expression_internal { + if(!graph::ExpressionUtils::checkExprDepth($1)){ + // delete $1; + std::ostringstream errStr; + errStr << "The above expression's depth exceeds the maximum depth:" << graph::ExpressionUtils::kMaxDepth; + throw nebula::GraphParser::syntax_error(@1, errStr.str()); + } + $$ = $1; + } + ; + +expression_internal : constant_expression { $$ = $1; } @@ -572,7 +584,7 @@ expression } | MINUS { scanner.setUnaryMinus(true); - } expression %prec UNARY_MINUS { + } expression_internal %prec UNARY_MINUS { if (scanner.isIntMin()) { $$ = $3; scanner.setIsIntMin(false); @@ -581,98 +593,98 @@ expression } scanner.setUnaryMinus(false); } - | PLUS expression %prec UNARY_PLUS { + | PLUS expression_internal %prec UNARY_PLUS { $$ = UnaryExpression::makePlus(qctx->objPool(), $2); } - | NOT expression { + | NOT expression_internal { $$ = UnaryExpression::makeNot(qctx->objPool(), $2); } - | KW_NOT expression { + | KW_NOT expression_internal { $$ = UnaryExpression::makeNot(qctx->objPool(), $2); } - | L_PAREN type_spec R_PAREN expression %prec CASTING { + | L_PAREN type_spec R_PAREN expression_internal %prec CASTING { $$ = TypeCastingExpression::make(qctx->objPool(), graph::SchemaUtil::propTypeToValueType($2->type), $4); delete $2; } - | expression STAR expression { + | expression_internal STAR expression_internal { $$ = ArithmeticExpression::makeMultiply(qctx->objPool(), $1, $3); } - | expression DIV expression { + | expression_internal DIV expression_internal { $$ = ArithmeticExpression::makeDivision(qctx->objPool(), $1, $3); } - | expression MOD expression { + | expression_internal MOD expression_internal { $$ = ArithmeticExpression::makeMod(qctx->objPool(), $1, $3); } - | expression PLUS expression { + | expression_internal PLUS expression_internal { $$ = ArithmeticExpression::makeAdd(qctx->objPool(), $1, $3); } - | expression MINUS expression { + | expression_internal MINUS expression_internal { $$ = ArithmeticExpression::makeMinus(qctx->objPool(), $1, $3); } - | expression LT expression { + | expression_internal LT expression_internal { $$ = RelationalExpression::makeLT(qctx->objPool(), $1, $3); } - | expression GT expression { + | expression_internal GT expression_internal { $$ = RelationalExpression::makeGT(qctx->objPool(), $1, $3); } - | expression LE expression { + | expression_internal LE expression_internal { $$ = RelationalExpression::makeLE(qctx->objPool(), $1, $3); } - | expression GE expression { + | expression_internal GE expression_internal { $$ = RelationalExpression::makeGE(qctx->objPool(), $1, $3); } - | expression REG expression { + | expression_internal REG expression_internal { $$ = RelationalExpression::makeREG(qctx->objPool(), $1, $3); } - | expression KW_IN expression { + | expression_internal KW_IN expression_internal { $$ = RelationalExpression::makeIn(qctx->objPool(), $1, $3); } - | expression KW_NOT_IN expression { + | expression_internal KW_NOT_IN expression_internal { $$ = RelationalExpression::makeNotIn(qctx->objPool(), $1, $3); } - | expression KW_CONTAINS expression { + | expression_internal KW_CONTAINS expression_internal { $$ = RelationalExpression::makeContains(qctx->objPool(), $1, $3); } - | expression KW_NOT_CONTAINS expression { + | expression_internal KW_NOT_CONTAINS expression_internal { $$ = RelationalExpression::makeNotContains(qctx->objPool(), $1, $3); } - | expression KW_STARTS_WITH expression { + | expression_internal KW_STARTS_WITH expression_internal { $$ = RelationalExpression::makeStartsWith(qctx->objPool(), $1, $3); } - | expression KW_NOT_STARTS_WITH expression { + | expression_internal KW_NOT_STARTS_WITH expression_internal { $$ = RelationalExpression::makeNotStartsWith(qctx->objPool(), $1, $3); } - | expression KW_ENDS_WITH expression { + | expression_internal KW_ENDS_WITH expression_internal { $$ = RelationalExpression::makeEndsWith(qctx->objPool(), $1, $3); } - | expression KW_NOT_ENDS_WITH expression { + | expression_internal KW_NOT_ENDS_WITH expression_internal { $$ = RelationalExpression::makeNotEndsWith(qctx->objPool(), $1, $3); } - | expression KW_IS_NULL { + | expression_internal KW_IS_NULL { $$ = UnaryExpression::makeIsNull(qctx->objPool(), $1); } - | expression KW_IS_NOT_NULL { + | expression_internal KW_IS_NOT_NULL { $$ = UnaryExpression::makeIsNotNull(qctx->objPool(), $1); } - | expression KW_IS_EMPTY { + | expression_internal KW_IS_EMPTY { $$ = UnaryExpression::makeIsEmpty(qctx->objPool(), $1); } - | expression KW_IS_NOT_EMPTY { + | expression_internal KW_IS_NOT_EMPTY { $$ = UnaryExpression::makeIsNotEmpty(qctx->objPool(), $1); } - | expression EQ expression { + | expression_internal EQ expression_internal { $$ = RelationalExpression::makeEQ(qctx->objPool(), $1, $3); } - | expression NE expression { + | expression_internal NE expression_internal { $$ = RelationalExpression::makeNE(qctx->objPool(), $1, $3); } - | expression KW_AND expression { + | expression_internal KW_AND expression_internal { $$ = LogicalExpression::makeAnd(qctx->objPool(), $1, $3); } - | expression KW_OR expression { + | expression_internal KW_OR expression_internal { $$ = LogicalExpression::makeOr(qctx->objPool(), $1, $3); } - | expression KW_XOR expression { + | expression_internal KW_XOR expression_internal { $$ = LogicalExpression::makeXor(qctx->objPool(), $1, $3); } | case_expression { @@ -712,7 +724,7 @@ constant_expression ; compound_expression - : L_PAREN expression R_PAREN { + : L_PAREN expression_internal R_PAREN { $$ = $2; } | property_expression { @@ -751,51 +763,51 @@ property_expression ; subscript_expression - : name_label L_BRACKET expression R_BRACKET { + : name_label L_BRACKET expression_internal R_BRACKET { $$ = SubscriptExpression::make(qctx->objPool(), LabelExpression::make(qctx->objPool(), *$1), $3); delete $1; } - | VARIABLE L_BRACKET expression R_BRACKET { + | VARIABLE L_BRACKET expression_internal R_BRACKET { $$ = SubscriptExpression::make(qctx->objPool(), VariableExpression::make(qctx->objPool(), *$1), $3); delete $1; } - | compound_expression L_BRACKET expression R_BRACKET { + | compound_expression L_BRACKET expression_internal R_BRACKET { $$ = SubscriptExpression::make(qctx->objPool(), $1, $3); } ; subscript_range_expression - : name_label L_BRACKET expression DOT_DOT expression R_BRACKET { + : name_label L_BRACKET expression_internal DOT_DOT expression_internal R_BRACKET { $$ = SubscriptRangeExpression::make(qctx->objPool(), LabelExpression::make(qctx->objPool(), *$1), $3, $5); delete($1); } - | name_label L_BRACKET DOT_DOT expression R_BRACKET { + | name_label L_BRACKET DOT_DOT expression_internal R_BRACKET { $$ = SubscriptRangeExpression::make(qctx->objPool(), LabelExpression::make(qctx->objPool(), *$1), nullptr, $4); delete($1); } - | name_label L_BRACKET expression DOT_DOT R_BRACKET { + | name_label L_BRACKET expression_internal DOT_DOT R_BRACKET { $$ = SubscriptRangeExpression::make(qctx->objPool(), LabelExpression::make(qctx->objPool(), *$1), $3, nullptr); delete($1); } - | VARIABLE L_BRACKET expression DOT_DOT expression R_BRACKET { + | VARIABLE L_BRACKET expression_internal DOT_DOT expression_internal R_BRACKET { $$ = SubscriptRangeExpression::make(qctx->objPool(), VariableExpression::make(qctx->objPool(), *$1), $3, $5); delete($1); } - | VARIABLE L_BRACKET DOT_DOT expression R_BRACKET { + | VARIABLE L_BRACKET DOT_DOT expression_internal R_BRACKET { $$ = SubscriptRangeExpression::make(qctx->objPool(), VariableExpression::make(qctx->objPool(), *$1), nullptr, $4); delete($1); } - | VARIABLE L_BRACKET expression DOT_DOT R_BRACKET { + | VARIABLE L_BRACKET expression_internal DOT_DOT R_BRACKET { $$ = SubscriptRangeExpression::make(qctx->objPool(), VariableExpression::make(qctx->objPool(), *$1), $3, nullptr); delete($1); } - | compound_expression L_BRACKET expression DOT_DOT expression R_BRACKET { + | compound_expression L_BRACKET expression_internal DOT_DOT expression_internal R_BRACKET { $$ = SubscriptRangeExpression::make(qctx->objPool(), $1, $3, $5); } - | compound_expression L_BRACKET DOT_DOT expression R_BRACKET { + | compound_expression L_BRACKET DOT_DOT expression_internal R_BRACKET { $$ = SubscriptRangeExpression::make(qctx->objPool(), $1, nullptr, $4); } - | compound_expression L_BRACKET expression DOT_DOT R_BRACKET { + | compound_expression L_BRACKET expression_internal DOT_DOT R_BRACKET { $$ = SubscriptRangeExpression::make(qctx->objPool(), $1, $3, nullptr); } ; @@ -832,7 +844,7 @@ generic_case_expression ; conditional_expression - : expression QM expression COLON expression { + : expression_internal QM expression_internal COLON expression_internal { auto cases = CaseList::make(qctx->objPool()); cases->add($1, $3); auto expr = CaseExpression::make(qctx->objPool(), cases, false); @@ -845,7 +857,7 @@ case_condition : %empty { $$ = nullptr; } - | expression { + | expression_internal { $$ = $1; } ; @@ -854,17 +866,17 @@ case_default : %empty { $$ = nullptr; } - | KW_ELSE expression { + | KW_ELSE expression_internal { $$ = $2; } ; when_then_list - : KW_WHEN expression KW_THEN expression { + : KW_WHEN expression_internal KW_THEN expression_internal { $$ = CaseList::make(qctx->objPool()); $$->add($2, $4); } - | when_then_list KW_WHEN expression KW_THEN expression { + | when_then_list KW_WHEN expression_internal KW_THEN expression_internal { $1->add($3, $5); $$ = $1; } @@ -878,7 +890,7 @@ predicate_name ; predicate_expression - : predicate_name L_PAREN expression KW_IN expression KW_WHERE expression R_PAREN { + : predicate_name L_PAREN expression_internal KW_IN expression_internal KW_WHERE expression_internal R_PAREN { if ($3->kind() != Expression::Kind::kLabel) { delete $1; throw nebula::GraphParser::syntax_error(@3, "The loop variable must be a label in predicate functions"); @@ -889,7 +901,7 @@ predicate_expression $$ = expr; delete $1; } - | KW_EXISTS L_PAREN expression R_PAREN { + | KW_EXISTS L_PAREN expression_internal R_PAREN { if ($3->kind() != Expression::Kind::kLabelAttribute && $3->kind() != Expression::Kind::kAttribute && $3->kind() != Expression::Kind::kSubscript) { throw nebula::GraphParser::syntax_error(@3, "The exists only accept LabelAttribute, Attribute and Subscript"); @@ -899,7 +911,7 @@ predicate_expression ; list_comprehension_expression - : L_BRACKET expression KW_IN expression KW_WHERE expression R_BRACKET { + : L_BRACKET expression_internal KW_IN expression_internal KW_WHERE expression_internal R_BRACKET { if ($2->kind() != Expression::Kind::kLabel) { throw nebula::GraphParser::syntax_error(@2, "The loop variable must be a label in list comprehension"); } @@ -908,7 +920,7 @@ list_comprehension_expression nebula::graph::ParserUtil::rewriteLC(qctx, expr, innerVar); $$ = expr; } - | L_BRACKET expression KW_IN expression PIPE expression R_BRACKET { + | L_BRACKET expression_internal KW_IN expression_internal PIPE expression_internal R_BRACKET { if ($2->kind() != Expression::Kind::kLabel) { throw nebula::GraphParser::syntax_error(@2, "The loop variable must be a label in list comprehension"); } @@ -917,7 +929,7 @@ list_comprehension_expression nebula::graph::ParserUtil::rewriteLC(qctx, expr, innerVar); $$ = expr; } - | L_BRACKET expression KW_IN expression KW_WHERE expression PIPE expression R_BRACKET { + | L_BRACKET expression_internal KW_IN expression_internal KW_WHERE expression_internal PIPE expression_internal R_BRACKET { if ($2->kind() != Expression::Kind::kLabel) { throw nebula::GraphParser::syntax_error(@2, "The loop variable must be a label in list comprehension"); } @@ -929,7 +941,7 @@ list_comprehension_expression ; reduce_expression - : KW_REDUCE L_PAREN name_label ASSIGN expression COMMA name_label KW_IN expression PIPE expression R_PAREN { + : KW_REDUCE L_PAREN name_label ASSIGN expression_internal COMMA name_label KW_IN expression_internal PIPE expression_internal R_PAREN { auto *expr = ReduceExpression::make(qctx->objPool(), *$3, $5, *$7, $9, $11); nebula::graph::ParserUtil::rewriteReduce(qctx, expr, *$3, *$7); $$ = expr; @@ -1016,7 +1028,7 @@ function_call_expression throw nebula::GraphParser::syntax_error(@1, "Unknown function "); } } - | LABEL L_PAREN KW_DISTINCT expression R_PAREN { + | LABEL L_PAREN KW_DISTINCT expression_internal R_PAREN { if (AggFunctionManager::find(*$1).ok()) { $$ = AggregateExpression::make(qctx->objPool(), *$1, $4, true); delete($1); @@ -1136,13 +1148,13 @@ argument_list Expression *arg = EdgeExpression::make(qctx->objPool()); $$->addArgument(arg); } - | expression { + | expression_internal { $$ = ArgumentList::make(qctx->objPool()); Expression* arg = nullptr; arg = $1; $$->addArgument(arg); } - | argument_list COMMA expression { + | argument_list COMMA expression_internal { $$ = $1; Expression* arg = nullptr; arg = $3; @@ -1280,11 +1292,11 @@ opt_expression_list ; expression_list - : expression { + : expression_internal { $$ = ExpressionList::make(qctx->objPool()); $$->add($1); } - | expression_list COMMA expression { + | expression_list COMMA expression_internal { $$ = $1; $$->add($3); } @@ -1309,12 +1321,12 @@ opt_map_item_list ; map_item_list - : name_label COLON expression { + : name_label COLON expression_internal { $$ = MapItemList::make(qctx->objPool()); $$->add(*$1, $3); delete $1; } - | map_item_list COMMA name_label COLON expression { + | map_item_list COMMA name_label COLON expression_internal { $$ = $1; $$->add(*$3, $5); delete $3; diff --git a/src/parser/test/ParserBenchmark.cpp b/src/parser/test/ParserBenchmark.cpp index b1af6f3dc42..d420f1547d9 100644 --- a/src/parser/test/ParserBenchmark.cpp +++ b/src/parser/test/ParserBenchmark.cpp @@ -14,9 +14,7 @@ auto simpleQuery = "USE myspace"; auto complexQuery = "GO 2 STEPS FROM 123456789 OVER myedge " "WHERE alias.prop1 + alias.prop2 * alias.prop3 > alias.prop4 AND " - "alias.prop5 == alias.prop6 YIELD 1 AS first, 2 AS second"; - -auto qctx = std::make_unique(); + "alias.prop5 == alias.prop6 YIELD 1+1+1+1+1+1+1+1 AS first, 2 AS second"; size_t SimpleQuery(size_t iters, size_t nrThreads) { constexpr size_t ops = 500000UL; @@ -24,6 +22,7 @@ size_t SimpleQuery(size_t iters, size_t nrThreads) { auto parse = [&]() { auto n = iters * ops; for (auto i = 0UL; i < n; i++) { + auto qctx = std::make_unique(); // static thread_local GQLParser parser; GQLParser parser(qctx.get()); auto result = parser.parse(simpleQuery); @@ -48,6 +47,7 @@ size_t ComplexQuery(size_t iters, size_t nrThreads) { auto parse = [&]() { auto n = iters * ops; for (auto i = 0UL; i < n; i++) { + auto qctx = std::make_unique(); // static thread_local GQLParser parser; GQLParser parser(qctx.get()); auto result = parser.parse(complexQuery); @@ -87,11 +87,13 @@ BENCHMARK_RELATIVE_NAMED_PARAM_MULTI(ComplexQuery, 48_thread, 48) int main(int argc, char **argv) { gflags::ParseCommandLineFlags(&argc, &argv, true); { + auto qctx = std::make_unique(); GQLParser parser(qctx.get()); auto result = parser.parse(simpleQuery); CHECK(result.ok()) << result.status(); } { + auto qctx = std::make_unique(); GQLParser parser(qctx.get()); auto result = parser.parse(complexQuery); CHECK(result.ok()) << result.status(); diff --git a/tests/tck/features/expression/Depth.feature b/tests/tck/features/expression/Depth.feature new file mode 100644 index 00000000000..71bf5e3498e --- /dev/null +++ b/tests/tck/features/expression/Depth.feature @@ -0,0 +1,159 @@ +# Copyright (c) 2021 vesoft inc. All rights reserved. +# +# This source code is licensed under Apache 2.0 License. +Feature: Check Expression Depth + + Background: + Given a graph with space named "nba" + + Scenario: yield exceeds expression + When executing query: + """ + YIELD 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + 1 + 1 + 1 + 1 + 1 + 1 + 1 AS result + """ + Then the result should be, in any order: + | result | + | 488 | + When executing query: + """ + YIELD 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 AS result + """ + Then a SyntaxError should be raised at runtime: The above expression's depth exceeds the maximum depth + When executing query: + """ + YIELD 1 IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS + NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS + NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS + NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS + NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS + NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS + NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS + NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS + NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS + NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS + NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS + NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS + NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS + NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS + NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS + NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS + NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS + NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS + NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS + NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS + NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS + NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS + NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS + NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS + NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS + NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS + NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS + NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS + NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS + NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS + NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS + NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS + NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS + NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS + NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS + NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS + NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS + NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS + NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS + NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS + NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS + NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS + NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS + NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS + NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS + NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS + NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS + NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS + NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS + NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS + NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS + NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS + NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS + NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS + NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS + NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS + NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS + NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS + NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS + NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS + NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS + NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS + NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS + NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS + NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS + NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS + NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS + NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS + NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS + NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS + NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS + NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS + NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS + NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS + NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS + NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS + NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL IS NULL AS result + """ + Then a SyntaxError should be raised at runtime: The above expression's depth exceeds the maximum depth