//===----------------------------------------------------------------------===// // DuckDB // // duckdb/parser/transformer.hpp // // //===----------------------------------------------------------------------===// #pragma once #include "duckdb/common/constants.hpp" #include "duckdb/common/enums/expression_type.hpp" #include "duckdb/common/types.hpp" #include "duckdb/common/unordered_map.hpp" #include "duckdb/parser/qualified_name.hpp" #include "duckdb/parser/tokens.hpp" #include "duckdb/parser/parsed_data/create_info.hpp" #include "duckdb/parser/group_by_node.hpp" #include "duckdb/parser/query_node.hpp" #include "duckdb/common/case_insensitive_map.hpp" #include "pg_definitions.hpp" #include "nodes/parsenodes.hpp" #include "nodes/primnodes.hpp" namespace duckdb { class ColumnDefinition; class StackChecker; struct OrderByNode; struct CopyInfo; struct CommonTableExpressionInfo; struct GroupingExpressionMap; class OnConflictInfo; class UpdateSetInfo; struct ParserOptions; struct PivotColumn; //! The transformer class is responsible for transforming the internal Postgres //! parser representation into the DuckDB representation class Transformer { friend class StackChecker; struct CreatePivotEntry { string enum_name; unique_ptr base; unique_ptr column; unique_ptr subquery; }; public: explicit Transformer(ParserOptions &options); explicit Transformer(Transformer &parent); ~Transformer(); //! Transforms a Postgres parse tree into a set of SQL Statements bool TransformParseTree(duckdb_libpgquery::PGList *tree, vector> &statements); string NodetypeToString(duckdb_libpgquery::PGNodeTag type); idx_t ParamCount() const; private: optional_ptr parent; //! Parser options ParserOptions &options; //! The current prepared statement parameter index idx_t prepared_statement_parameter_index = 0; //! Map from named parameter to parameter index; case_insensitive_map_t named_param_map; //! Holds window expressions defined by name. We need those when transforming the expressions referring to them. unordered_map window_clauses; //! The set of pivot entries to create vector> pivot_entries; //! Sets of stored CTEs, if any vector stored_cte_map; //! Whether or not we are currently binding a window definition bool in_window_definition = false; void Clear(); bool InWindowDefinition(); Transformer &RootTransformer(); const Transformer &RootTransformer() const; void SetParamCount(idx_t new_count); void SetNamedParam(const string &name, int32_t index); bool GetNamedParam(const string &name, int32_t &index); bool HasNamedParameters() const; void AddPivotEntry(string enum_name, unique_ptr source, unique_ptr column, unique_ptr subquery); unique_ptr GenerateCreateEnumStmt(unique_ptr entry); bool HasPivotEntries(); idx_t PivotEntryCount(); vector> &GetPivotEntries(); void PivotEntryCheck(const string &type); void ExtractCTEsRecursive(CommonTableExpressionMap &cte_map); private: //! Transforms a Postgres statement into a single SQL statement unique_ptr TransformStatement(duckdb_libpgquery::PGNode &stmt); //! Transforms a Postgres statement into a single SQL statement unique_ptr TransformStatementInternal(duckdb_libpgquery::PGNode &stmt); //===--------------------------------------------------------------------===// // Statement transformation //===--------------------------------------------------------------------===// //! Transform a Postgres duckdb_libpgquery::T_PGSelectStmt node into a SelectStatement unique_ptr TransformSelect(optional_ptr node, bool is_select = true); //! Transform a Postgres duckdb_libpgquery::T_PGSelectStmt node into a SelectStatement unique_ptr TransformSelect(duckdb_libpgquery::PGSelectStmt &select, bool is_select = true); //! Transform a Postgres T_AlterStmt node into a AlterStatement unique_ptr TransformAlter(duckdb_libpgquery::PGAlterTableStmt &stmt); //! Transform a Postgres duckdb_libpgquery::T_PGRenameStmt node into a RenameStatement unique_ptr TransformRename(duckdb_libpgquery::PGRenameStmt &stmt); //! Transform a Postgres duckdb_libpgquery::T_PGCreateStmt node into a CreateStatement unique_ptr TransformCreateTable(duckdb_libpgquery::PGCreateStmt &node); //! Transform a Postgres duckdb_libpgquery::T_PGCreateStmt node into a CreateStatement unique_ptr TransformCreateTableAs(duckdb_libpgquery::PGCreateTableAsStmt &stmt); //! Transform a Postgres node into a CreateStatement unique_ptr TransformCreateSchema(duckdb_libpgquery::PGCreateSchemaStmt &stmt); //! Transform a Postgres duckdb_libpgquery::T_PGCreateSeqStmt node into a CreateStatement unique_ptr TransformCreateSequence(duckdb_libpgquery::PGCreateSeqStmt &node); //! Transform a Postgres duckdb_libpgquery::T_PGViewStmt node into a CreateStatement unique_ptr TransformCreateView(duckdb_libpgquery::PGViewStmt &node); //! Transform a Postgres duckdb_libpgquery::T_PGIndexStmt node into CreateStatement unique_ptr TransformCreateIndex(duckdb_libpgquery::PGIndexStmt &stmt); //! Transform a Postgres duckdb_libpgquery::T_PGCreateFunctionStmt node into CreateStatement unique_ptr TransformCreateFunction(duckdb_libpgquery::PGCreateFunctionStmt &stmt); //! Transform a Postgres duckdb_libpgquery::T_PGCreateTypeStmt node into CreateStatement unique_ptr TransformCreateType(duckdb_libpgquery::PGCreateTypeStmt &stmt); //! Transform a Postgres duckdb_libpgquery::T_PGAlterSeqStmt node into CreateStatement unique_ptr TransformAlterSequence(duckdb_libpgquery::PGAlterSeqStmt &stmt); //! Transform a Postgres duckdb_libpgquery::T_PGDropStmt node into a Drop[Table,Schema]Statement unique_ptr TransformDrop(duckdb_libpgquery::PGDropStmt &stmt); //! Transform a Postgres duckdb_libpgquery::T_PGInsertStmt node into a InsertStatement unique_ptr TransformInsert(duckdb_libpgquery::PGInsertStmt &stmt); //! Transform a Postgres duckdb_libpgquery::T_PGOnConflictClause node into a OnConflictInfo unique_ptr TransformOnConflictClause(duckdb_libpgquery::PGOnConflictClause *node, const string &relname); //! Transform a ON CONFLICT shorthand into a OnConflictInfo unique_ptr DummyOnConflictClause(duckdb_libpgquery::PGOnConflictActionAlias type, const string &relname); //! Transform a Postgres duckdb_libpgquery::T_PGCopyStmt node into a CopyStatement unique_ptr TransformCopy(duckdb_libpgquery::PGCopyStmt &stmt); void TransformCopyOptions(CopyInfo &info, optional_ptr options); //! Transform a Postgres duckdb_libpgquery::T_PGTransactionStmt node into a TransactionStatement unique_ptr TransformTransaction(duckdb_libpgquery::PGTransactionStmt &stmt); //! Transform a Postgres T_DeleteStatement node into a DeleteStatement unique_ptr TransformDelete(duckdb_libpgquery::PGDeleteStmt &stmt); //! Transform a Postgres duckdb_libpgquery::T_PGUpdateStmt node into a UpdateStatement unique_ptr TransformUpdate(duckdb_libpgquery::PGUpdateStmt &stmt); //! Transform a Postgres duckdb_libpgquery::T_PGPragmaStmt node into a PragmaStatement unique_ptr TransformPragma(duckdb_libpgquery::PGPragmaStmt &stmt); //! Transform a Postgres duckdb_libpgquery::T_PGExportStmt node into a ExportStatement unique_ptr TransformExport(duckdb_libpgquery::PGExportStmt &stmt); //! Transform a Postgres duckdb_libpgquery::T_PGImportStmt node into a PragmaStatement unique_ptr TransformImport(duckdb_libpgquery::PGImportStmt &stmt); unique_ptr TransformExplain(duckdb_libpgquery::PGExplainStmt &stmt); unique_ptr TransformVacuum(duckdb_libpgquery::PGVacuumStmt &stmt); unique_ptr TransformShow(duckdb_libpgquery::PGVariableShowStmt &stmt); unique_ptr TransformShowSelect(duckdb_libpgquery::PGVariableShowSelectStmt &stmt); unique_ptr TransformAttach(duckdb_libpgquery::PGAttachStmt &stmt); unique_ptr TransformDetach(duckdb_libpgquery::PGDetachStmt &stmt); unique_ptr TransformUse(duckdb_libpgquery::PGUseStmt &stmt); unique_ptr TransformPrepare(duckdb_libpgquery::PGPrepareStmt &stmt); unique_ptr TransformExecute(duckdb_libpgquery::PGExecuteStmt &stmt); unique_ptr TransformCall(duckdb_libpgquery::PGCallStmt &stmt); unique_ptr TransformDeallocate(duckdb_libpgquery::PGDeallocateStmt &stmt); unique_ptr TransformPivotStatement(duckdb_libpgquery::PGSelectStmt &select); unique_ptr CreatePivotStatement(unique_ptr statement); PivotColumn TransformPivotColumn(duckdb_libpgquery::PGPivot &pivot); vector TransformPivotList(duckdb_libpgquery::PGList &list); //===--------------------------------------------------------------------===// // SetStatement Transform //===--------------------------------------------------------------------===// unique_ptr TransformSet(duckdb_libpgquery::PGVariableSetStmt &set); unique_ptr TransformSetVariable(duckdb_libpgquery::PGVariableSetStmt &stmt); unique_ptr TransformResetVariable(duckdb_libpgquery::PGVariableSetStmt &stmt); unique_ptr TransformCheckpoint(duckdb_libpgquery::PGCheckPointStmt &stmt); unique_ptr TransformLoad(duckdb_libpgquery::PGLoadStmt &stmt); //===--------------------------------------------------------------------===// // Query Node Transform //===--------------------------------------------------------------------===// //! Transform a Postgres duckdb_libpgquery::T_PGSelectStmt node into a QueryNode unique_ptr TransformSelectNode(duckdb_libpgquery::PGSelectStmt &select); unique_ptr TransformSelectInternal(duckdb_libpgquery::PGSelectStmt &select); void TransformModifiers(duckdb_libpgquery::PGSelectStmt &stmt, QueryNode &node); //===--------------------------------------------------------------------===// // Expression Transform //===--------------------------------------------------------------------===// //! Transform a Postgres boolean expression into an Expression unique_ptr TransformBoolExpr(duckdb_libpgquery::PGBoolExpr &root); //! Transform a Postgres case expression into an Expression unique_ptr TransformCase(duckdb_libpgquery::PGCaseExpr &root); //! Transform a Postgres type cast into an Expression unique_ptr TransformTypeCast(duckdb_libpgquery::PGTypeCast &root); //! Transform a Postgres coalesce into an Expression unique_ptr TransformCoalesce(duckdb_libpgquery::PGAExpr &root); //! Transform a Postgres column reference into an Expression unique_ptr TransformColumnRef(duckdb_libpgquery::PGColumnRef &root); //! Transform a Postgres constant value into an Expression unique_ptr TransformValue(duckdb_libpgquery::PGValue val); //! Transform a Postgres operator into an Expression unique_ptr TransformAExpr(duckdb_libpgquery::PGAExpr &root); unique_ptr TransformAExprInternal(duckdb_libpgquery::PGAExpr &root); //! Transform a Postgres abstract expression into an Expression unique_ptr TransformExpression(optional_ptr node); unique_ptr TransformExpression(duckdb_libpgquery::PGNode &node); //! Transform a Postgres function call into an Expression unique_ptr TransformFuncCall(duckdb_libpgquery::PGFuncCall &root); //! Transform a Postgres boolean expression into an Expression unique_ptr TransformInterval(duckdb_libpgquery::PGIntervalConstant &root); //! Transform a Postgres lambda node [e.g. (x, y) -> x + y] into a lambda expression unique_ptr TransformLambda(duckdb_libpgquery::PGLambdaFunction &node); //! Transform a Postgres array access node (e.g. x[1] or x[1:3]) unique_ptr TransformArrayAccess(duckdb_libpgquery::PGAIndirection &node); //! Transform a positional reference (e.g. #1) unique_ptr TransformPositionalReference(duckdb_libpgquery::PGPositionalReference &node); unique_ptr TransformStarExpression(duckdb_libpgquery::PGAStar &node); unique_ptr TransformBooleanTest(duckdb_libpgquery::PGBooleanTest &node); //! Transform a Postgres constant value into an Expression unique_ptr TransformConstant(duckdb_libpgquery::PGAConst &c); unique_ptr TransformGroupingFunction(duckdb_libpgquery::PGGroupingFunc &n); unique_ptr TransformResTarget(duckdb_libpgquery::PGResTarget &root); unique_ptr TransformNullTest(duckdb_libpgquery::PGNullTest &root); unique_ptr TransformParamRef(duckdb_libpgquery::PGParamRef &node); unique_ptr TransformNamedArg(duckdb_libpgquery::PGNamedArgExpr &root); unique_ptr TransformSQLValueFunction(duckdb_libpgquery::PGSQLValueFunction &node); unique_ptr TransformSubquery(duckdb_libpgquery::PGSubLink &root); //===--------------------------------------------------------------------===// // Constraints transform //===--------------------------------------------------------------------===// unique_ptr TransformConstraint(duckdb_libpgquery::PGListCell *cell); unique_ptr TransformConstraint(duckdb_libpgquery::PGListCell *cell, ColumnDefinition &column, idx_t index); //===--------------------------------------------------------------------===// // Update transform //===--------------------------------------------------------------------===// unique_ptr TransformUpdateSetInfo(duckdb_libpgquery::PGList *target_list, duckdb_libpgquery::PGNode *where_clause); //===--------------------------------------------------------------------===// // Index transform //===--------------------------------------------------------------------===// vector> TransformIndexParameters(duckdb_libpgquery::PGList &list, const string &relation_name); //===--------------------------------------------------------------------===// // Collation transform //===--------------------------------------------------------------------===// unique_ptr TransformCollateExpr(duckdb_libpgquery::PGCollateClause &collate); string TransformCollation(optional_ptr collate); ColumnDefinition TransformColumnDefinition(duckdb_libpgquery::PGColumnDef &cdef); //===--------------------------------------------------------------------===// // Helpers //===--------------------------------------------------------------------===// OnCreateConflict TransformOnConflict(duckdb_libpgquery::PGOnCreateConflict conflict); string TransformAlias(duckdb_libpgquery::PGAlias *root, vector &column_name_alias); vector TransformStringList(duckdb_libpgquery::PGList *list); void TransformCTE(duckdb_libpgquery::PGWithClause &de_with_clause, CommonTableExpressionMap &cte_map); unique_ptr TransformRecursiveCTE(duckdb_libpgquery::PGCommonTableExpr &cte, CommonTableExpressionInfo &info); unique_ptr TransformUnaryOperator(const string &op, unique_ptr child); unique_ptr TransformBinaryOperator(string op, unique_ptr left, unique_ptr right); //===--------------------------------------------------------------------===// // TableRef transform //===--------------------------------------------------------------------===// //! Transform a Postgres node into a TableRef unique_ptr TransformTableRefNode(duckdb_libpgquery::PGNode &n); //! Transform a Postgres FROM clause into a TableRef unique_ptr TransformFrom(optional_ptr root); //! Transform a Postgres table reference into a TableRef unique_ptr TransformRangeVar(duckdb_libpgquery::PGRangeVar &root); //! Transform a Postgres table-producing function into a TableRef unique_ptr TransformRangeFunction(duckdb_libpgquery::PGRangeFunction &root); //! Transform a Postgres join node into a TableRef unique_ptr TransformJoin(duckdb_libpgquery::PGJoinExpr &root); //! Transform a Postgres pivot node into a TableRef unique_ptr TransformPivot(duckdb_libpgquery::PGPivotExpr &root); //! Transform a table producing subquery into a TableRef unique_ptr TransformRangeSubselect(duckdb_libpgquery::PGRangeSubselect &root); //! Transform a VALUES list into a set of expressions unique_ptr TransformValuesList(duckdb_libpgquery::PGList *list); //! Transform a range var into a (schema) qualified name QualifiedName TransformQualifiedName(duckdb_libpgquery::PGRangeVar &root); //! Transform a Postgres TypeName string into a LogicalType LogicalType TransformTypeName(duckdb_libpgquery::PGTypeName &name); //! Transform a Postgres GROUP BY expression into a list of Expression bool TransformGroupBy(optional_ptr group, SelectNode &result); void TransformGroupByNode(duckdb_libpgquery::PGNode &n, GroupingExpressionMap &map, SelectNode &result, vector &result_sets); void AddGroupByExpression(unique_ptr expression, GroupingExpressionMap &map, GroupByNode &result, vector &result_set); void TransformGroupByExpression(duckdb_libpgquery::PGNode &n, GroupingExpressionMap &map, GroupByNode &result, vector &result_set); //! Transform a Postgres ORDER BY expression into an OrderByDescription bool TransformOrderBy(duckdb_libpgquery::PGList *order, vector &result); //! Transform a Postgres SELECT clause into a list of Expressions void TransformExpressionList(duckdb_libpgquery::PGList &list, vector> &result); //! Transform a Postgres PARTITION BY/ORDER BY specification into lists of expressions void TransformWindowDef(duckdb_libpgquery::PGWindowDef &window_spec, WindowExpression &expr, const char *window_name = nullptr); //! Transform a Postgres window frame specification into frame expressions void TransformWindowFrame(duckdb_libpgquery::PGWindowDef &window_spec, WindowExpression &expr); unique_ptr TransformSampleOptions(optional_ptr options); //! Returns true if an expression is only a star (i.e. "*", without any other decorators) bool ExpressionIsEmptyStar(ParsedExpression &expr); OnEntryNotFound TransformOnEntryNotFound(bool missing_ok); Vector PGListToVector(optional_ptr column_list, idx_t &size); vector TransformConflictTarget(duckdb_libpgquery::PGList &list); private: //! Current stack depth idx_t stack_depth; void InitializeStackCheck(); StackChecker StackCheck(idx_t extra_stack = 1); public: template static T &PGCast(duckdb_libpgquery::PGNode &node) { return reinterpret_cast(node); } template static optional_ptr PGPointerCast(void *ptr) { return optional_ptr(reinterpret_cast(ptr)); } }; class StackChecker { public: StackChecker(Transformer &transformer, idx_t stack_usage); ~StackChecker(); StackChecker(StackChecker &&) noexcept; StackChecker(const StackChecker &) = delete; private: Transformer &transformer; idx_t stack_usage; }; vector ReadPgListToString(duckdb_libpgquery::PGList *column_list); } // namespace duckdb