//===----------------------------------------------------------------------===// // DuckDB // // duckdb/planner/binder.hpp // // //===----------------------------------------------------------------------===// #pragma once #include "duckdb/common/case_insensitive_map.hpp" #include "duckdb/common/enums/join_type.hpp" #include "duckdb/common/enums/statement_type.hpp" #include "duckdb/common/unordered_map.hpp" #include "duckdb/parser/column_definition.hpp" #include "duckdb/parser/query_node.hpp" #include "duckdb/parser/result_modifier.hpp" #include "duckdb/parser/tokens.hpp" #include "duckdb/planner/bind_context.hpp" #include "duckdb/planner/bound_statement.hpp" #include "duckdb/planner/bound_tokens.hpp" #include "duckdb/planner/expression/bound_columnref_expression.hpp" #include "duckdb/planner/logical_operator.hpp" #include "duckdb/common/reference_map.hpp" namespace duckdb { class BoundResultModifier; class BoundSelectNode; class ClientContext; class ExpressionBinder; class LimitModifier; class OrderBinder; class TableCatalogEntry; class ViewCatalogEntry; class TableMacroCatalogEntry; class UpdateSetInfo; class LogicalProjection; class ColumnList; class ExternalDependency; class TableFunction; class TableStorageInfo; struct CreateInfo; struct BoundCreateTableInfo; struct BoundCreateFunctionInfo; struct CommonTableExpressionInfo; struct BoundParameterMap; enum class BindingMode : uint8_t { STANDARD_BINDING, EXTRACT_NAMES }; struct CorrelatedColumnInfo { ColumnBinding binding; LogicalType type; string name; idx_t depth; CorrelatedColumnInfo(ColumnBinding binding, LogicalType type_p, string name_p, idx_t depth) : binding(binding), type(std::move(type_p)), name(std::move(name_p)), depth(depth) { } explicit CorrelatedColumnInfo(BoundColumnRefExpression &expr) : CorrelatedColumnInfo(expr.binding, expr.return_type, expr.GetName(), expr.depth) { } bool operator==(const CorrelatedColumnInfo &rhs) const { return binding == rhs.binding; } }; //! Bind the parsed query tree to the actual columns present in the catalog. /*! The binder is responsible for binding tables and columns to actual physical tables and columns in the catalog. In the process, it also resolves types of all expressions. */ class Binder : public std::enable_shared_from_this { friend class ExpressionBinder; friend class RecursiveSubqueryPlanner; public: DUCKDB_API static shared_ptr CreateBinder(ClientContext &context, optional_ptr parent = nullptr, bool inherit_ctes = true); //! The client context ClientContext &context; //! A mapping of names to common table expressions case_insensitive_map_t> CTE_bindings; // NOLINT //! The CTEs that have already been bound reference_set_t bound_ctes; //! The bind context BindContext bind_context; //! The set of correlated columns bound by this binder (FIXME: this should probably be an unordered_set and not a //! vector) vector correlated_columns; //! The set of parameter expressions bound by this binder optional_ptr parameters; //! Statement properties StatementProperties properties; //! The alias for the currently processing subquery, if it exists string alias; //! Macro parameter bindings (if any) optional_ptr macro_binding; //! The intermediate lambda bindings to bind nested lambdas (if any) optional_ptr> lambda_bindings; public: DUCKDB_API BoundStatement Bind(SQLStatement &statement); DUCKDB_API BoundStatement Bind(QueryNode &node); unique_ptr BindCreateTableInfo(unique_ptr info); unique_ptr BindCreateTableInfo(unique_ptr info, SchemaCatalogEntry &schema); vector> BindCreateIndexExpressions(TableCatalogEntry &table, CreateIndexInfo &info); void BindCreateViewInfo(CreateViewInfo &base); SchemaCatalogEntry &BindSchema(CreateInfo &info); SchemaCatalogEntry &BindCreateFunctionInfo(CreateInfo &info); //! Check usage, and cast named parameters to their types static void BindNamedParameters(named_parameter_type_map_t &types, named_parameter_map_t &values, QueryErrorContext &error_context, string &func_name); unique_ptr Bind(TableRef &ref); unique_ptr CreatePlan(BoundTableRef &ref); //! Generates an unused index for a table idx_t GenerateTableIndex(); //! Add a common table expression to the binder void AddCTE(const string &name, CommonTableExpressionInfo &cte); //! Find a common table expression by name; returns nullptr if none exists optional_ptr FindCTE(const string &name, bool skip = false); bool CTEIsAlreadyBound(CommonTableExpressionInfo &cte); //! Add the view to the set of currently bound views - used for detecting recursive view definitions void AddBoundView(ViewCatalogEntry &view); void PushExpressionBinder(ExpressionBinder &binder); void PopExpressionBinder(); void SetActiveBinder(ExpressionBinder &binder); ExpressionBinder &GetActiveBinder(); bool HasActiveBinder(); vector> &GetActiveBinders(); void MergeCorrelatedColumns(vector &other); //! Add a correlated column to this binder (if it does not exist) void AddCorrelatedColumn(const CorrelatedColumnInfo &info); string FormatError(ParsedExpression &expr_context, const string &message); string FormatError(TableRef &ref_context, const string &message); string FormatErrorRecursive(idx_t query_location, const string &message, vector &values); template string FormatErrorRecursive(idx_t query_location, const string &msg, vector &values, T param, ARGS... params) { values.push_back(ExceptionFormatValue::CreateFormatValue(param)); return FormatErrorRecursive(query_location, msg, values, params...); } template string FormatError(idx_t query_location, const string &msg, ARGS... params) { vector values; return FormatErrorRecursive(query_location, msg, values, params...); } unique_ptr BindUpdateSet(LogicalOperator &op, unique_ptr root, UpdateSetInfo &set_info, TableCatalogEntry &table, vector &columns); void BindDoUpdateSetExpressions(const string &table_alias, LogicalInsert &insert, UpdateSetInfo &set_info, TableCatalogEntry &table, TableStorageInfo &storage_info); void BindOnConflictClause(LogicalInsert &insert, TableCatalogEntry &table, InsertStatement &stmt); static void BindSchemaOrCatalog(ClientContext &context, string &catalog, string &schema); static void BindLogicalType(ClientContext &context, LogicalType &type, optional_ptr catalog = nullptr, const string &schema = INVALID_SCHEMA); bool HasMatchingBinding(const string &table_name, const string &column_name, string &error_message); bool HasMatchingBinding(const string &schema_name, const string &table_name, const string &column_name, string &error_message); bool HasMatchingBinding(const string &catalog_name, const string &schema_name, const string &table_name, const string &column_name, string &error_message); void SetBindingMode(BindingMode mode); BindingMode GetBindingMode(); void AddTableName(string table_name); const unordered_set &GetTableNames(); optional_ptr GetRootStatement() { return root_statement; } void SetCanContainNulls(bool can_contain_nulls); private: //! The parent binder (if any) shared_ptr parent; //! The vector of active binders vector> active_binders; //! The count of bound_tables idx_t bound_tables; //! Whether or not the binder has any unplanned subqueries that still need to be planned bool has_unplanned_subqueries = false; //! Whether or not subqueries should be planned already bool plan_subquery = true; //! Whether CTEs should reference the parent binder (if it exists) bool inherit_ctes = true; //! Whether or not the binder can contain NULLs as the root of expressions bool can_contain_nulls = false; //! The root statement of the query that is currently being parsed optional_ptr root_statement; //! Binding mode BindingMode mode = BindingMode::STANDARD_BINDING; //! Table names extracted for BindingMode::EXTRACT_NAMES unordered_set table_names; //! The set of bound views reference_set_t bound_views; private: //! Bind the expressions of generated columns to check for errors void BindGeneratedColumns(BoundCreateTableInfo &info); //! Bind the default values of the columns of a table void BindDefaultValues(const ColumnList &columns, vector> &bound_defaults); //! Bind a limit value (LIMIT or OFFSET) unique_ptr BindDelimiter(ClientContext &context, OrderBinder &order_binder, unique_ptr delimiter, const LogicalType &type, Value &delimiter_value); //! Move correlated expressions from the child binder to this binder void MoveCorrelatedExpressions(Binder &other); BoundStatement Bind(SelectStatement &stmt); BoundStatement Bind(InsertStatement &stmt); BoundStatement Bind(CopyStatement &stmt); BoundStatement Bind(DeleteStatement &stmt); BoundStatement Bind(UpdateStatement &stmt); BoundStatement Bind(CreateStatement &stmt); BoundStatement Bind(DropStatement &stmt); BoundStatement Bind(AlterStatement &stmt); BoundStatement Bind(PrepareStatement &stmt); BoundStatement Bind(ExecuteStatement &stmt); BoundStatement Bind(TransactionStatement &stmt); BoundStatement Bind(PragmaStatement &stmt); BoundStatement Bind(ExplainStatement &stmt); BoundStatement Bind(VacuumStatement &stmt); BoundStatement Bind(RelationStatement &stmt); BoundStatement Bind(ShowStatement &stmt); BoundStatement Bind(CallStatement &stmt); BoundStatement Bind(ExportStatement &stmt); BoundStatement Bind(ExtensionStatement &stmt); BoundStatement Bind(SetStatement &stmt); BoundStatement Bind(SetVariableStatement &stmt); BoundStatement Bind(ResetVariableStatement &stmt); BoundStatement Bind(LoadStatement &stmt); BoundStatement Bind(LogicalPlanStatement &stmt); BoundStatement Bind(AttachStatement &stmt); BoundStatement Bind(DetachStatement &stmt); BoundStatement BindReturning(vector> returning_list, TableCatalogEntry &table, const string &alias, idx_t update_table_index, unique_ptr child_operator, BoundStatement result); unique_ptr BindTableMacro(FunctionExpression &function, TableMacroCatalogEntry ¯o_func, idx_t depth); unique_ptr BindNode(SelectNode &node); unique_ptr BindNode(SetOperationNode &node); unique_ptr BindNode(RecursiveCTENode &node); unique_ptr BindNode(QueryNode &node); unique_ptr VisitQueryNode(BoundQueryNode &node, unique_ptr root); unique_ptr CreatePlan(BoundRecursiveCTENode &node); unique_ptr CreatePlan(BoundSelectNode &statement); unique_ptr CreatePlan(BoundSetOperationNode &node); unique_ptr CreatePlan(BoundQueryNode &node); unique_ptr Bind(BaseTableRef &ref); unique_ptr Bind(JoinRef &ref); unique_ptr Bind(SubqueryRef &ref, optional_ptr cte = nullptr); unique_ptr Bind(TableFunctionRef &ref); unique_ptr Bind(EmptyTableRef &ref); unique_ptr Bind(ExpressionListRef &ref); unique_ptr Bind(PivotRef &expr); unique_ptr BindPivot(PivotRef &expr, vector> all_columns); unique_ptr BindUnpivot(Binder &child_binder, PivotRef &expr, vector> all_columns, unique_ptr &where_clause); unique_ptr BindBoundPivot(PivotRef &expr); bool BindTableFunctionParameters(TableFunctionCatalogEntry &table_function, vector> &expressions, vector &arguments, vector ¶meters, named_parameter_map_t &named_parameters, unique_ptr &subquery, string &error); bool BindTableInTableOutFunction(vector> &expressions, unique_ptr &subquery, string &error); unique_ptr BindTableFunction(TableFunction &function, vector parameters); unique_ptr BindTableFunctionInternal(TableFunction &table_function, const string &function_name, vector parameters, named_parameter_map_t named_parameters, vector input_table_types, vector input_table_names, const vector &column_name_alias, unique_ptr external_dependency); unique_ptr CreatePlan(BoundBaseTableRef &ref); unique_ptr CreatePlan(BoundJoinRef &ref); unique_ptr CreatePlan(BoundSubqueryRef &ref); unique_ptr CreatePlan(BoundTableFunction &ref); unique_ptr CreatePlan(BoundEmptyTableRef &ref); unique_ptr CreatePlan(BoundExpressionListRef &ref); unique_ptr CreatePlan(BoundCTERef &ref); unique_ptr CreatePlan(BoundPivotRef &ref); BoundStatement BindCopyTo(CopyStatement &stmt); BoundStatement BindCopyFrom(CopyStatement &stmt); void BindModifiers(OrderBinder &order_binder, QueryNode &statement, BoundQueryNode &result); void BindModifierTypes(BoundQueryNode &result, const vector &sql_types, idx_t projection_index); BoundStatement BindSummarize(ShowStatement &stmt); unique_ptr BindLimit(OrderBinder &order_binder, LimitModifier &limit_mod); unique_ptr BindLimitPercent(OrderBinder &order_binder, LimitPercentModifier &limit_mod); unique_ptr BindOrderExpression(OrderBinder &order_binder, unique_ptr expr); unique_ptr PlanFilter(unique_ptr condition, unique_ptr root); void PlanSubqueries(unique_ptr &expr, unique_ptr &root); unique_ptr PlanSubquery(BoundSubqueryExpression &expr, unique_ptr &root); unique_ptr PlanLateralJoin(unique_ptr left, unique_ptr right, vector &correlated_columns, JoinType join_type = JoinType::INNER, unique_ptr condition = nullptr); unique_ptr CastLogicalOperatorToTypes(vector &source_types, vector &target_types, unique_ptr op); string FindBinding(const string &using_column, const string &join_side); bool TryFindBinding(const string &using_column, const string &join_side, string &result); void AddUsingBindingSet(unique_ptr set); string RetrieveUsingBinding(Binder ¤t_binder, optional_ptr current_set, const string &column_name, const string &join_side); void AddCTEMap(CommonTableExpressionMap &cte_map); void ExpandStarExpressions(vector> &select_list, vector> &new_select_list); void ExpandStarExpression(unique_ptr expr, vector> &new_select_list); bool FindStarExpression(unique_ptr &expr, StarExpression **star, bool is_root, bool in_columns); void ReplaceStarExpression(unique_ptr &expr, unique_ptr &replacement); void BindWhereStarExpression(unique_ptr &expr); //! If only a schema name is provided (e.g. "a.b") then figure out if "a" is a schema or a catalog name void BindSchemaOrCatalog(string &catalog_name, string &schema_name); SchemaCatalogEntry &BindCreateSchema(CreateInfo &info); unique_ptr BindSelectNode(SelectNode &statement, unique_ptr from_table); public: // This should really be a private constructor, but make_shared does not allow it... // If you are thinking about calling this, you should probably call Binder::CreateBinder Binder(bool i_know_what_i_am_doing, ClientContext &context, shared_ptr parent, bool inherit_ctes); }; } // namespace duckdb