AnalyzeLambdas::LambdaParameters AnalyzeLambdas::extractLambdaParameters(ASTPtr & ast) { /// Lambda parameters could be specified in AST in two forms: /// - just as single parameter: x -> x + 1 /// - parameters in tuple: (x, y) -> x + 1 #define LAMBDA_ERROR_MESSAGE " There are two valid forms of lambda expressions: x -> ... and (x, y...) -> ..." if (!ast->tryGetAlias().empty()) throw Exception("Lambda parameters cannot have aliases." LAMBDA_ERROR_MESSAGE, ErrorCodes::BAD_LAMBDA); if (const ASTIdentifier * identifier = typeid_cast<const ASTIdentifier *>(ast.get())) { return { identifier->name }; } else if (const ASTFunction * function = typeid_cast<const ASTFunction *>(ast.get())) { if (function->name != "tuple") throw Exception("Left hand side of '->' or first argument of 'lambda' is a function, but this function is not tuple." LAMBDA_ERROR_MESSAGE " Found function '" + function->name + "' instead.", ErrorCodes::BAD_LAMBDA); if (!function->arguments || function->arguments->children.empty()) throw Exception("Left hand side of '->' or first argument of 'lambda' is empty tuple." LAMBDA_ERROR_MESSAGE, ErrorCodes::BAD_LAMBDA); LambdaParameters res; res.reserve(function->arguments->children.size()); for (const ASTPtr & arg : function->arguments->children) { const ASTIdentifier * arg_identifier = typeid_cast<const ASTIdentifier *>(arg.get()); if (!arg_identifier) throw Exception("Left hand side of '->' or first argument of 'lambda' contains something that is not just identifier." LAMBDA_ERROR_MESSAGE, ErrorCodes::BAD_LAMBDA); if (!arg_identifier->children.empty()) throw Exception("Left hand side of '->' or first argument of 'lambda' contains compound identifier." LAMBDA_ERROR_MESSAGE, ErrorCodes::BAD_LAMBDA); if (!arg_identifier->alias.empty()) throw Exception("Lambda parameters cannot have aliases." LAMBDA_ERROR_MESSAGE, ErrorCodes::BAD_LAMBDA); res.emplace_back(arg_identifier->name); } return res; } else throw Exception("Unexpected left hand side of '->' or first argument of 'lambda'." LAMBDA_ERROR_MESSAGE, ErrorCodes::BAD_LAMBDA); #undef LAMBDA_ERROR_MESSAGE }
static void processImpl(const ASTPtr & ast, CollectAliases::Aliases & aliases, CollectAliases::Kind kind, size_t keep_kind_for_depth) { String alias = ast->tryGetAlias(); if (!alias.empty()) { auto it_inserted = aliases.emplace(alias, CollectAliases::AliasInfo(ast, kind)); if (!it_inserted.second && ast->getTreeHash() != it_inserted.first->second.node->getTreeHash()) { std::stringstream message; message << "Different expressions with the same alias " << backQuoteIfNeed(alias) << ":\n"; formatAST(*it_inserted.first->second.node, message, 0, false, true); message << "\nand\n"; formatAST(*ast, message, 0, false, true); message << "\n"; throw Exception(message.str(), ErrorCodes::MULTIPLE_EXPRESSIONS_FOR_ALIAS); } } for (auto & child : ast->children) { if (typeid_cast<const ASTSelectQuery *>(child.get())) { /// Don't go into subqueries. } else if (typeid_cast<const ASTTableExpression *>(child.get())) { processImpl(child, aliases, CollectAliases::Kind::Table, 1); } else if (typeid_cast<const ASTArrayJoin *>(child.get())) { /// ASTArrayJoin -> ASTExpressionList -> element of expression AS alias processImpl(child, aliases, CollectAliases::Kind::ArrayJoin, 3); } else if (keep_kind_for_depth > 0) { processImpl(child, aliases, kind, keep_kind_for_depth - 1); } else { processImpl(child, aliases, CollectAliases::Kind::Expression, 0); } } }
void ExecuteScalarSubqueriesMatcher::visit(const ASTSubquery & subquery, ASTPtr & ast, Data & data) { Context subquery_context = data.context; Settings subquery_settings = data.context.getSettings(); subquery_settings.max_result_rows = 1; subquery_settings.extremes = 0; subquery_context.setSettings(subquery_settings); ASTPtr subquery_select = subquery.children.at(0); BlockIO res = InterpreterSelectWithUnionQuery( subquery_select, subquery_context, {}, QueryProcessingStage::Complete, data.subquery_depth + 1).execute(); Block block; try { block = res.in->read(); if (!block) { /// Interpret subquery with empty result as Null literal auto ast_new = std::make_unique<ASTLiteral>(Null()); ast_new->setAlias(ast->tryGetAlias()); ast = std::move(ast_new); return; } if (block.rows() != 1 || res.in->read()) throw Exception("Scalar subquery returned more than one row", ErrorCodes::INCORRECT_RESULT_OF_SCALAR_SUBQUERY); } catch (const Exception & e) { if (e.code() == ErrorCodes::TOO_MANY_ROWS) throw Exception("Scalar subquery returned more than one row", ErrorCodes::INCORRECT_RESULT_OF_SCALAR_SUBQUERY); else throw; } size_t columns = block.columns(); if (columns == 1) { auto lit = std::make_unique<ASTLiteral>((*block.safeGetByPosition(0).column)[0]); lit->alias = subquery.alias; lit->prefer_alias_to_column_name = subquery.prefer_alias_to_column_name; ast = addTypeConversion(std::move(lit), block.safeGetByPosition(0).type->getName()); } else { auto tuple = std::make_shared<ASTFunction>(); tuple->alias = subquery.alias; ast = tuple; tuple->name = "tuple"; auto exp_list = std::make_shared<ASTExpressionList>(); tuple->arguments = exp_list; tuple->children.push_back(tuple->arguments); exp_list->children.resize(columns); for (size_t i = 0; i < columns; ++i) { exp_list->children[i] = addTypeConversion( std::make_unique<ASTLiteral>((*block.safeGetByPosition(i).column)[0]), block.safeGetByPosition(i).type->getName()); } } }