Пример #1
0
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
}
Пример #2
0
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());
        }
    }
}