From 77e11da4f052bfbb8674a1e2eab1b84cc7deb207 Mon Sep 17 00:00:00 2001 From: RJ Atwal Date: Sun, 30 Oct 2022 22:19:38 -0700 Subject: [PATCH 1/8] Initial version of extension to allow creating operators outside of duckdb core lib --- src/common/enums/logical_operator_type.cpp | 2 + src/execution/physical_plan_generator.cpp | 20 ++- .../common/enums/logical_operator_type.hpp | 4 +- src/include/duckdb/main/config.hpp | 21 +-- .../operator/logical_extension_operator.hpp | 26 ++++ .../duckdb/planner/operator_extension.hpp | 45 +++++++ src/planner/binder.cpp | 120 +++++++++++------- src/planner/logical_operator.cpp | 2 + 8 files changed, 179 insertions(+), 61 deletions(-) create mode 100644 src/include/duckdb/planner/operator/logical_extension_operator.hpp create mode 100644 src/include/duckdb/planner/operator_extension.hpp diff --git a/src/common/enums/logical_operator_type.cpp b/src/common/enums/logical_operator_type.cpp index ebdd68b75a01..eb02790885b8 100644 --- a/src/common/enums/logical_operator_type.cpp +++ b/src/common/enums/logical_operator_type.cpp @@ -110,6 +110,8 @@ string LogicalOperatorToString(LogicalOperatorType type) { return "LOAD"; case LogicalOperatorType::LOGICAL_INVALID: break; + case LogicalOperatorType::LOGICAL_EXTENSION_OPERATOR: + return "CUSTOM_OP"; } return "INVALID"; } diff --git a/src/execution/physical_plan_generator.cpp b/src/execution/physical_plan_generator.cpp index 4a69ed41556f..413998a2e277 100644 --- a/src/execution/physical_plan_generator.cpp +++ b/src/execution/physical_plan_generator.cpp @@ -1,10 +1,14 @@ #include "duckdb/execution/physical_plan_generator.hpp" -#include "duckdb/main/query_profiler.hpp" + #include "duckdb/catalog/catalog_entry/scalar_function_catalog_entry.hpp" +#include "duckdb/common/types/column_data_collection.hpp" #include "duckdb/execution/column_binding_resolver.hpp" #include "duckdb/main/client_context.hpp" +#include "duckdb/main/config.hpp" +#include "duckdb/main/query_profiler.hpp" #include "duckdb/planner/expression/bound_function_expression.hpp" -#include "duckdb/common/types/column_data_collection.hpp" +#include "duckdb/planner/operator/logical_extension_operator.hpp" +#include "duckdb/planner/operator/opaque_remote_logic_get.hpp" namespace duckdb { @@ -191,6 +195,18 @@ unique_ptr PhysicalPlanGenerator::CreatePlan(LogicalOperator & case LogicalOperatorType::LOGICAL_SET: plan = CreatePlan((LogicalSet &)op); break; + case LogicalOperatorType::LOGICAL_EXTENSION_OPERATOR: + auto &extension_op = (LogicalExtensionOperator &)op; + for (auto &extension : DBConfig::GetConfig(context).operator_extensions) { + if (extension.operator_info.get() == extension_op.operator_info) { + plan = extension.CreatePlan(context, *this, extension_op); + if (plan) + break; + } + } + if (!plan) + throw InternalException("Missing PhysicalOperator for Extension Operator"); + break; default: { throw NotImplementedException("Unimplemented logical operator type!"); } diff --git a/src/include/duckdb/common/enums/logical_operator_type.hpp b/src/include/duckdb/common/enums/logical_operator_type.hpp index a81f2b3ca389..5ea001d07b53 100644 --- a/src/include/duckdb/common/enums/logical_operator_type.hpp +++ b/src/include/duckdb/common/enums/logical_operator_type.hpp @@ -96,7 +96,9 @@ enum class LogicalOperatorType : uint8_t { LOGICAL_EXPORT = 177, LOGICAL_VACUUM = 178, LOGICAL_SET = 179, - LOGICAL_LOAD = 180 + LOGICAL_LOAD = 180, + + LOGICAL_EXTENSION_OPERATOR = 255 }; DUCKDB_API string LogicalOperatorToString(LogicalOperatorType type); diff --git a/src/include/duckdb/main/config.hpp b/src/include/duckdb/main/config.hpp index da185d2dca7a..682b101885aa 100644 --- a/src/include/duckdb/main/config.hpp +++ b/src/include/duckdb/main/config.hpp @@ -11,21 +11,22 @@ #include "duckdb/common/allocator.hpp" #include "duckdb/common/case_insensitive_map.hpp" #include "duckdb/common/common.hpp" +#include "duckdb/common/enums/compression_type.hpp" +#include "duckdb/common/enums/optimizer_type.hpp" #include "duckdb/common/enums/order_type.hpp" +#include "duckdb/common/enums/set_scope.hpp" +#include "duckdb/common/enums/window_aggregation_mode.hpp" #include "duckdb/common/file_system.hpp" -#include "duckdb/common/winapi.hpp" +#include "duckdb/common/set.hpp" #include "duckdb/common/types/value.hpp" #include "duckdb/common/vector.hpp" -#include "duckdb/function/replacement_scan.hpp" -#include "duckdb/function/replacement_open.hpp" -#include "duckdb/common/set.hpp" -#include "duckdb/common/enums/compression_type.hpp" -#include "duckdb/common/enums/optimizer_type.hpp" -#include "duckdb/common/enums/window_aggregation_mode.hpp" -#include "duckdb/common/enums/set_scope.hpp" -#include "duckdb/parser/parser_extension.hpp" +#include "duckdb/common/winapi.hpp" #include "duckdb/function/cast/default_casts.hpp" +#include "duckdb/function/replacement_open.hpp" +#include "duckdb/function/replacement_scan.hpp" #include "duckdb/optimizer/optimizer_extension.hpp" +#include "duckdb/parser/parser_extension.hpp" +#include "duckdb/planner/operator_extension.hpp" namespace duckdb { class CastFunctionSet; @@ -164,6 +165,8 @@ struct DBConfig { unique_ptr error_manager; //! A reference to the (shared) default allocator (Allocator::DefaultAllocator) shared_ptr default_allocator; + //! Extensions made to binder + vector operator_extensions; public: DUCKDB_API static DBConfig &GetConfig(ClientContext &context); diff --git a/src/include/duckdb/planner/operator/logical_extension_operator.hpp b/src/include/duckdb/planner/operator/logical_extension_operator.hpp new file mode 100644 index 000000000000..25428e4b0a42 --- /dev/null +++ b/src/include/duckdb/planner/operator/logical_extension_operator.hpp @@ -0,0 +1,26 @@ +//===----------------------------------------------------------------------===// +// DuckDB +// +// duckdb/planner/operator/logical_extension.operator.hpp +// +// +//===----------------------------------------------------------------------===// + +#pragma once + +#include "duckdb/planner/logical_operator.hpp" +#include "duckdb/planner/operator_extension.hpp" + +namespace duckdb { + +struct LogicalExtensionOperator : LogicalOperator { + OperatorExtensionInfo *operator_info; + + LogicalExtensionOperator(OperatorExtensionInfo *info) + : LogicalOperator(LogicalOperatorType::LOGICAL_EXTENSION_OPERATOR), operator_info(info) { + } + LogicalExtensionOperator(OperatorExtensionInfo *info, vector> expressions) + : LogicalOperator(LogicalOperatorType::LOGICAL_EXTENSION_OPERATOR, move(expressions)), operator_info(info) { + } +}; +} // namespace duckdb diff --git a/src/include/duckdb/planner/operator_extension.hpp b/src/include/duckdb/planner/operator_extension.hpp new file mode 100644 index 000000000000..8ed8f6bd8b13 --- /dev/null +++ b/src/include/duckdb/planner/operator_extension.hpp @@ -0,0 +1,45 @@ +//===----------------------------------------------------------------------===// +// DuckDB +// +// duckdb/planner/operator_extension.hpp +// +// +//===----------------------------------------------------------------------===// + +#pragma once + +#include "duckdb/common/common.hpp" +#include "duckdb/execution/physical_plan_generator.hpp" +#include "duckdb/planner/binder.hpp" + +namespace duckdb { + +// forward declaration to break circular inclusion +class LogicalExtensionOperator; + +//! The OperatorExtensionInfo holds static information relevant to the operator extension +struct OperatorExtensionInfo { + DUCKDB_API virtual ~OperatorExtensionInfo() { + } +}; + +typedef unique_ptr (*create_plan_function_t)(ClientContext &context, PhysicalPlanGenerator &generator, + LogicalExtensionOperator &plan); +typedef BoundStatement (*bind_function_t)(ClientContext &context, Binder &binder, OperatorExtensionInfo *info, + SQLStatement &statement); + +class OperatorExtension { +public: + //! Creates a plan for a new logical operator injected into duckdb via the OperatorExtension's bind function or + // the optimizer extension + create_plan_function_t CreatePlan; + bind_function_t Bind; + + //! Additional info passed to the CreatePlan & Bind functions + shared_ptr operator_info; + + DUCKDB_API virtual ~OperatorExtension() { + } +}; + +} // namespace duckdb diff --git a/src/planner/binder.cpp b/src/planner/binder.cpp index fc0f0f957805..c97de0255f28 100644 --- a/src/planner/binder.cpp +++ b/src/planner/binder.cpp @@ -2,6 +2,7 @@ #include "duckdb/catalog/catalog_entry/table_catalog_entry.hpp" #include "duckdb/catalog/catalog_entry/view_catalog_entry.hpp" +#include "duckdb/main/config.hpp" #include "duckdb/parser/query_node/select_node.hpp" #include "duckdb/parser/statement/list.hpp" #include "duckdb/parser/tableref/table_function_ref.hpp" @@ -41,55 +42,76 @@ Binder::Binder(bool, ClientContext &context, shared_ptr parent_p, bool i BoundStatement Binder::Bind(SQLStatement &statement) { root_statement = &statement; - switch (statement.type) { - case StatementType::SELECT_STATEMENT: - return Bind((SelectStatement &)statement); - case StatementType::INSERT_STATEMENT: - return Bind((InsertStatement &)statement); - case StatementType::COPY_STATEMENT: - return Bind((CopyStatement &)statement); - case StatementType::DELETE_STATEMENT: - return Bind((DeleteStatement &)statement); - case StatementType::UPDATE_STATEMENT: - return Bind((UpdateStatement &)statement); - case StatementType::RELATION_STATEMENT: - return Bind((RelationStatement &)statement); - case StatementType::CREATE_STATEMENT: - return Bind((CreateStatement &)statement); - case StatementType::DROP_STATEMENT: - return Bind((DropStatement &)statement); - case StatementType::ALTER_STATEMENT: - return Bind((AlterStatement &)statement); - case StatementType::TRANSACTION_STATEMENT: - return Bind((TransactionStatement &)statement); - case StatementType::PRAGMA_STATEMENT: - return Bind((PragmaStatement &)statement); - case StatementType::EXPLAIN_STATEMENT: - return Bind((ExplainStatement &)statement); - case StatementType::VACUUM_STATEMENT: - return Bind((VacuumStatement &)statement); - case StatementType::SHOW_STATEMENT: - return Bind((ShowStatement &)statement); - case StatementType::CALL_STATEMENT: - return Bind((CallStatement &)statement); - case StatementType::EXPORT_STATEMENT: - return Bind((ExportStatement &)statement); - case StatementType::SET_STATEMENT: - return Bind((SetStatement &)statement); - case StatementType::LOAD_STATEMENT: - return Bind((LoadStatement &)statement); - case StatementType::EXTENSION_STATEMENT: - return Bind((ExtensionStatement &)statement); - case StatementType::PREPARE_STATEMENT: - return Bind((PrepareStatement &)statement); - case StatementType::EXECUTE_STATEMENT: - return Bind((ExecuteStatement &)statement); - case StatementType::LOGICAL_PLAN_STATEMENT: - return Bind((LogicalPlanStatement &)statement); - default: // LCOV_EXCL_START - throw NotImplementedException("Unimplemented statement type \"%s\" for Bind", - StatementTypeToString(statement.type)); - } // LCOV_EXCL_STOP + try { + switch (statement.type) { + case StatementType::SELECT_STATEMENT: + return Bind((SelectStatement &)statement); + case StatementType::INSERT_STATEMENT: + return Bind((InsertStatement &)statement); + case StatementType::COPY_STATEMENT: + return Bind((CopyStatement &)statement); + case StatementType::DELETE_STATEMENT: + return Bind((DeleteStatement &)statement); + case StatementType::UPDATE_STATEMENT: + return Bind((UpdateStatement &)statement); + case StatementType::RELATION_STATEMENT: + return Bind((RelationStatement &)statement); + case StatementType::CREATE_STATEMENT: + return Bind((CreateStatement &)statement); + case StatementType::DROP_STATEMENT: + return Bind((DropStatement &)statement); + case StatementType::ALTER_STATEMENT: + return Bind((AlterStatement &)statement); + case StatementType::TRANSACTION_STATEMENT: + return Bind((TransactionStatement &)statement); + case StatementType::PRAGMA_STATEMENT: + return Bind((PragmaStatement &)statement); + case StatementType::EXPLAIN_STATEMENT: + return Bind((ExplainStatement &)statement); + case StatementType::VACUUM_STATEMENT: + return Bind((VacuumStatement &)statement); + case StatementType::SHOW_STATEMENT: + return Bind((ShowStatement &)statement); + case StatementType::CALL_STATEMENT: + return Bind((CallStatement &)statement); + case StatementType::EXPORT_STATEMENT: + return Bind((ExportStatement &)statement); + case StatementType::SET_STATEMENT: + return Bind((SetStatement &)statement); + case StatementType::LOAD_STATEMENT: + return Bind((LoadStatement &)statement); + case StatementType::EXTENSION_STATEMENT: + return Bind((ExtensionStatement &)statement); + case StatementType::PREPARE_STATEMENT: + return Bind((PrepareStatement &)statement); + case StatementType::EXECUTE_STATEMENT: + return Bind((ExecuteStatement &)statement); + case StatementType::LOGICAL_PLAN_STATEMENT: + return Bind((LogicalPlanStatement &)statement); + default: // LCOV_EXCL_START + auto &config = DBConfig::GetConfig(context); + + for (auto &extension_op : config.operator_extensions) { + auto bound_statement = extension_op.Bind(context, *this, extension_op.operator_info.get(), statement); + if (bound_statement.plan != nullptr) + return bound_statement; + } + + throw NotImplementedException("Unimplemented statement type \"%s\" for Bind", + StatementTypeToString(statement.type)); + } // LCOV_EXCL_STOP + } catch (const StandardException &e) { + auto &config = DBConfig::GetConfig(context); + + for (auto &extension_op : config.operator_extensions) { + auto bound_statement = extension_op.Bind(context, *this, extension_op.operator_info.get(), statement); + if (bound_statement.plan != nullptr) + return bound_statement; + } + + // rethrow since no extension could bind the query either + throw e; + } } void Binder::AddCTEMap(CommonTableExpressionMap &cte_map) { diff --git a/src/planner/logical_operator.cpp b/src/planner/logical_operator.cpp index ccbef3ee0ae9..5619c2c40cde 100644 --- a/src/planner/logical_operator.cpp +++ b/src/planner/logical_operator.cpp @@ -338,6 +338,8 @@ unique_ptr LogicalOperator::Deserialize(Deserializer &deseriali case LogicalOperatorType::LOGICAL_LOAD: result = LogicalSimple::Deserialize(state, reader); break; + case LogicalOperatorType::LOGICAL_EXTENSION_OPERATOR: + throw SerializationException("Invalid type for operator deserialization"); case LogicalOperatorType::LOGICAL_INVALID: /* no default here to trigger a warning if we forget to implement deserialize for a new operator */ throw SerializationException("Invalid type for operator deserialization"); From bcd613d93a2dc75afcf0c3c8356f2c85349aeb7d Mon Sep 17 00:00:00 2001 From: RJ Atwal Date: Mon, 7 Nov 2022 03:24:01 -0800 Subject: [PATCH 2/8] Changing extension operators planning to use a virtual method on the logical operator itself --- src/execution/physical_plan_generator.cpp | 9 ++------- .../duckdb/parser/parsed_data/create_info.hpp | 2 ++ .../planner/operator/logical_extension_operator.hpp | 12 ++++++------ src/include/duckdb/planner/operator_extension.hpp | 5 ----- src/parser/parsed_data/create_info.cpp | 4 ++++ 5 files changed, 14 insertions(+), 18 deletions(-) diff --git a/src/execution/physical_plan_generator.cpp b/src/execution/physical_plan_generator.cpp index 413998a2e277..8bdf8698bc0d 100644 --- a/src/execution/physical_plan_generator.cpp +++ b/src/execution/physical_plan_generator.cpp @@ -197,13 +197,8 @@ unique_ptr PhysicalPlanGenerator::CreatePlan(LogicalOperator & break; case LogicalOperatorType::LOGICAL_EXTENSION_OPERATOR: auto &extension_op = (LogicalExtensionOperator &)op; - for (auto &extension : DBConfig::GetConfig(context).operator_extensions) { - if (extension.operator_info.get() == extension_op.operator_info) { - plan = extension.CreatePlan(context, *this, extension_op); - if (plan) - break; - } - } + plan = extension_op.CreatePlan(context, *this); + if (!plan) throw InternalException("Missing PhysicalOperator for Extension Operator"); break; diff --git a/src/include/duckdb/parser/parsed_data/create_info.hpp b/src/include/duckdb/parser/parsed_data/create_info.hpp index 2ae31cbfaa6d..306238e79f9f 100644 --- a/src/include/duckdb/parser/parsed_data/create_info.hpp +++ b/src/include/duckdb/parser/parsed_data/create_info.hpp @@ -11,6 +11,7 @@ #include "duckdb/common/enums/catalog_type.hpp" #include "duckdb/common/field_writer.hpp" #include "duckdb/parser/parsed_data/parse_info.hpp" +#include "duckdb/planner/plan_serialization.hpp" namespace duckdb { struct AlterInfo; @@ -56,6 +57,7 @@ struct CreateInfo : public ParseInfo { void Serialize(Serializer &serializer) const; static unique_ptr Deserialize(Deserializer &deserializer); + static unique_ptr Deserialize(Deserializer &deserializer, PlanDeserializationState &state); virtual unique_ptr Copy() const = 0; diff --git a/src/include/duckdb/planner/operator/logical_extension_operator.hpp b/src/include/duckdb/planner/operator/logical_extension_operator.hpp index 25428e4b0a42..f717327689dc 100644 --- a/src/include/duckdb/planner/operator/logical_extension_operator.hpp +++ b/src/include/duckdb/planner/operator/logical_extension_operator.hpp @@ -13,14 +13,14 @@ namespace duckdb { -struct LogicalExtensionOperator : LogicalOperator { - OperatorExtensionInfo *operator_info; +struct LogicalExtensionOperator : public LogicalOperator { - LogicalExtensionOperator(OperatorExtensionInfo *info) - : LogicalOperator(LogicalOperatorType::LOGICAL_EXTENSION_OPERATOR), operator_info(info) { + LogicalExtensionOperator() : LogicalOperator(LogicalOperatorType::LOGICAL_EXTENSION_OPERATOR) { } - LogicalExtensionOperator(OperatorExtensionInfo *info, vector> expressions) - : LogicalOperator(LogicalOperatorType::LOGICAL_EXTENSION_OPERATOR, move(expressions)), operator_info(info) { + LogicalExtensionOperator(vector> expressions) + : LogicalOperator(LogicalOperatorType::LOGICAL_EXTENSION_OPERATOR, move(expressions)) { } + + virtual unique_ptr CreatePlan(ClientContext &context, PhysicalPlanGenerator &generator) const = 0; }; } // namespace duckdb diff --git a/src/include/duckdb/planner/operator_extension.hpp b/src/include/duckdb/planner/operator_extension.hpp index 8ed8f6bd8b13..f2ff2f368cf6 100644 --- a/src/include/duckdb/planner/operator_extension.hpp +++ b/src/include/duckdb/planner/operator_extension.hpp @@ -23,16 +23,11 @@ struct OperatorExtensionInfo { } }; -typedef unique_ptr (*create_plan_function_t)(ClientContext &context, PhysicalPlanGenerator &generator, - LogicalExtensionOperator &plan); typedef BoundStatement (*bind_function_t)(ClientContext &context, Binder &binder, OperatorExtensionInfo *info, SQLStatement &statement); class OperatorExtension { public: - //! Creates a plan for a new logical operator injected into duckdb via the OperatorExtension's bind function or - // the optimizer extension - create_plan_function_t CreatePlan; bind_function_t Bind; //! Additional info passed to the CreatePlan & Bind functions diff --git a/src/parser/parsed_data/create_info.cpp b/src/parser/parsed_data/create_info.cpp index d6597ce3bf5d..857263dccfdc 100644 --- a/src/parser/parsed_data/create_info.cpp +++ b/src/parser/parsed_data/create_info.cpp @@ -41,6 +41,10 @@ unique_ptr CreateInfo::Deserialize(Deserializer &deserializer) { } } +unique_ptr CreateInfo::Deserialize(Deserializer &source, PlanDeserializationState &state) { + return Deserialize(source); +} + void CreateInfo::CopyProperties(CreateInfo &other) const { other.type = type; other.schema = schema; From 3ab2d97a29eda2fe54c6c1bf693ff9d94085e266 Mon Sep 17 00:00:00 2001 From: RJ Atwal Date: Mon, 7 Nov 2022 03:48:11 -0800 Subject: [PATCH 3/8] Moved extension bind hook up the call stack from binder.cpp into planner.cpp --- src/execution/physical_plan_generator.cpp | 4 +- src/planner/binder.cpp | 119 +++++++++------------- src/planner/planner.cpp | 13 +++ 3 files changed, 63 insertions(+), 73 deletions(-) diff --git a/src/execution/physical_plan_generator.cpp b/src/execution/physical_plan_generator.cpp index 8bdf8698bc0d..4aadd9320504 100644 --- a/src/execution/physical_plan_generator.cpp +++ b/src/execution/physical_plan_generator.cpp @@ -8,7 +8,6 @@ #include "duckdb/main/query_profiler.hpp" #include "duckdb/planner/expression/bound_function_expression.hpp" #include "duckdb/planner/operator/logical_extension_operator.hpp" -#include "duckdb/planner/operator/opaque_remote_logic_get.hpp" namespace duckdb { @@ -196,8 +195,7 @@ unique_ptr PhysicalPlanGenerator::CreatePlan(LogicalOperator & plan = CreatePlan((LogicalSet &)op); break; case LogicalOperatorType::LOGICAL_EXTENSION_OPERATOR: - auto &extension_op = (LogicalExtensionOperator &)op; - plan = extension_op.CreatePlan(context, *this); + plan = ((LogicalExtensionOperator &)op).CreatePlan(context, *this); if (!plan) throw InternalException("Missing PhysicalOperator for Extension Operator"); diff --git a/src/planner/binder.cpp b/src/planner/binder.cpp index c97de0255f28..9f368d91f6ca 100644 --- a/src/planner/binder.cpp +++ b/src/planner/binder.cpp @@ -42,76 +42,55 @@ Binder::Binder(bool, ClientContext &context, shared_ptr parent_p, bool i BoundStatement Binder::Bind(SQLStatement &statement) { root_statement = &statement; - try { - switch (statement.type) { - case StatementType::SELECT_STATEMENT: - return Bind((SelectStatement &)statement); - case StatementType::INSERT_STATEMENT: - return Bind((InsertStatement &)statement); - case StatementType::COPY_STATEMENT: - return Bind((CopyStatement &)statement); - case StatementType::DELETE_STATEMENT: - return Bind((DeleteStatement &)statement); - case StatementType::UPDATE_STATEMENT: - return Bind((UpdateStatement &)statement); - case StatementType::RELATION_STATEMENT: - return Bind((RelationStatement &)statement); - case StatementType::CREATE_STATEMENT: - return Bind((CreateStatement &)statement); - case StatementType::DROP_STATEMENT: - return Bind((DropStatement &)statement); - case StatementType::ALTER_STATEMENT: - return Bind((AlterStatement &)statement); - case StatementType::TRANSACTION_STATEMENT: - return Bind((TransactionStatement &)statement); - case StatementType::PRAGMA_STATEMENT: - return Bind((PragmaStatement &)statement); - case StatementType::EXPLAIN_STATEMENT: - return Bind((ExplainStatement &)statement); - case StatementType::VACUUM_STATEMENT: - return Bind((VacuumStatement &)statement); - case StatementType::SHOW_STATEMENT: - return Bind((ShowStatement &)statement); - case StatementType::CALL_STATEMENT: - return Bind((CallStatement &)statement); - case StatementType::EXPORT_STATEMENT: - return Bind((ExportStatement &)statement); - case StatementType::SET_STATEMENT: - return Bind((SetStatement &)statement); - case StatementType::LOAD_STATEMENT: - return Bind((LoadStatement &)statement); - case StatementType::EXTENSION_STATEMENT: - return Bind((ExtensionStatement &)statement); - case StatementType::PREPARE_STATEMENT: - return Bind((PrepareStatement &)statement); - case StatementType::EXECUTE_STATEMENT: - return Bind((ExecuteStatement &)statement); - case StatementType::LOGICAL_PLAN_STATEMENT: - return Bind((LogicalPlanStatement &)statement); - default: // LCOV_EXCL_START - auto &config = DBConfig::GetConfig(context); - - for (auto &extension_op : config.operator_extensions) { - auto bound_statement = extension_op.Bind(context, *this, extension_op.operator_info.get(), statement); - if (bound_statement.plan != nullptr) - return bound_statement; - } - - throw NotImplementedException("Unimplemented statement type \"%s\" for Bind", - StatementTypeToString(statement.type)); - } // LCOV_EXCL_STOP - } catch (const StandardException &e) { - auto &config = DBConfig::GetConfig(context); - - for (auto &extension_op : config.operator_extensions) { - auto bound_statement = extension_op.Bind(context, *this, extension_op.operator_info.get(), statement); - if (bound_statement.plan != nullptr) - return bound_statement; - } - - // rethrow since no extension could bind the query either - throw e; - } + switch (statement.type) { + case StatementType::SELECT_STATEMENT: + return Bind((SelectStatement &)statement); + case StatementType::INSERT_STATEMENT: + return Bind((InsertStatement &)statement); + case StatementType::COPY_STATEMENT: + return Bind((CopyStatement &)statement); + case StatementType::DELETE_STATEMENT: + return Bind((DeleteStatement &)statement); + case StatementType::UPDATE_STATEMENT: + return Bind((UpdateStatement &)statement); + case StatementType::RELATION_STATEMENT: + return Bind((RelationStatement &)statement); + case StatementType::CREATE_STATEMENT: + return Bind((CreateStatement &)statement); + case StatementType::DROP_STATEMENT: + return Bind((DropStatement &)statement); + case StatementType::ALTER_STATEMENT: + return Bind((AlterStatement &)statement); + case StatementType::TRANSACTION_STATEMENT: + return Bind((TransactionStatement &)statement); + case StatementType::PRAGMA_STATEMENT: + return Bind((PragmaStatement &)statement); + case StatementType::EXPLAIN_STATEMENT: + return Bind((ExplainStatement &)statement); + case StatementType::VACUUM_STATEMENT: + return Bind((VacuumStatement &)statement); + case StatementType::SHOW_STATEMENT: + return Bind((ShowStatement &)statement); + case StatementType::CALL_STATEMENT: + return Bind((CallStatement &)statement); + case StatementType::EXPORT_STATEMENT: + return Bind((ExportStatement &)statement); + case StatementType::SET_STATEMENT: + return Bind((SetStatement &)statement); + case StatementType::LOAD_STATEMENT: + return Bind((LoadStatement &)statement); + case StatementType::EXTENSION_STATEMENT: + return Bind((ExtensionStatement &)statement); + case StatementType::PREPARE_STATEMENT: + return Bind((PrepareStatement &)statement); + case StatementType::EXECUTE_STATEMENT: + return Bind((ExecuteStatement &)statement); + case StatementType::LOGICAL_PLAN_STATEMENT: + return Bind((LogicalPlanStatement &)statement); + default: // LCOV_EXCL_START + throw NotImplementedException("Unimplemented statement type \"%s\" for Bind", + StatementTypeToString(statement.type)); + } // LCOV_EXCL_STOP } void Binder::AddCTEMap(CommonTableExpressionMap &cte_map) { diff --git a/src/planner/planner.cpp b/src/planner/planner.cpp index e08858e7d59e..747fb21bfa20 100644 --- a/src/planner/planner.cpp +++ b/src/planner/planner.cpp @@ -52,6 +52,19 @@ void Planner::CreatePlan(SQLStatement &statement) { this->plan = nullptr; parameters_resolved = false; } catch (const Exception &ex) { + auto &config = DBConfig::GetConfig(context); + + for (auto &extension_op : config.operator_extensions) { + auto bound_statement = + extension_op.Bind(context, *this->binder, extension_op.operator_info.get(), statement); + if (bound_statement.plan != nullptr) { + this->names = bound_statement.names; + this->types = bound_statement.types; + this->plan = move(bound_statement.plan); + break; + } + } + throw; } catch (std::exception &ex) { throw; From e612716f009d497561a4ff67a0f89de3d3a54dca Mon Sep 17 00:00:00 2001 From: RJ Atwal Date: Mon, 7 Nov 2022 04:05:47 -0800 Subject: [PATCH 4/8] Removing forward-declaration made redundant by refactoring --- src/include/duckdb/planner/operator_extension.hpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/include/duckdb/planner/operator_extension.hpp b/src/include/duckdb/planner/operator_extension.hpp index f2ff2f368cf6..77dce6bb0cf3 100644 --- a/src/include/duckdb/planner/operator_extension.hpp +++ b/src/include/duckdb/planner/operator_extension.hpp @@ -14,9 +14,6 @@ namespace duckdb { -// forward declaration to break circular inclusion -class LogicalExtensionOperator; - //! The OperatorExtensionInfo holds static information relevant to the operator extension struct OperatorExtensionInfo { DUCKDB_API virtual ~OperatorExtensionInfo() { From 42ba867555a4370cbcdebf83112ca8050cfc8a21 Mon Sep 17 00:00:00 2001 From: RJ Atwal Date: Thu, 10 Nov 2022 03:38:44 -0800 Subject: [PATCH 5/8] Formatting --- .../duckdb/planner/operator/logical_extension_operator.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/include/duckdb/planner/operator/logical_extension_operator.hpp b/src/include/duckdb/planner/operator/logical_extension_operator.hpp index f717327689dc..c2abbf55becf 100644 --- a/src/include/duckdb/planner/operator/logical_extension_operator.hpp +++ b/src/include/duckdb/planner/operator/logical_extension_operator.hpp @@ -21,6 +21,6 @@ struct LogicalExtensionOperator : public LogicalOperator { : LogicalOperator(LogicalOperatorType::LOGICAL_EXTENSION_OPERATOR, move(expressions)) { } - virtual unique_ptr CreatePlan(ClientContext &context, PhysicalPlanGenerator &generator) const = 0; + virtual unique_ptr CreatePlan(ClientContext &context, PhysicalPlanGenerator &generator) = 0; }; } // namespace duckdb From b2c92e8b44804671d9cdef08d9cc7bdf88903bb7 Mon Sep 17 00:00:00 2001 From: RJ Atwal Date: Thu, 10 Nov 2022 05:05:26 -0800 Subject: [PATCH 6/8] Fixing ctidy check --- src/execution/physical_plan_generator.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/execution/physical_plan_generator.cpp b/src/execution/physical_plan_generator.cpp index 4aadd9320504..f02f88fe1d07 100644 --- a/src/execution/physical_plan_generator.cpp +++ b/src/execution/physical_plan_generator.cpp @@ -197,8 +197,9 @@ unique_ptr PhysicalPlanGenerator::CreatePlan(LogicalOperator & case LogicalOperatorType::LOGICAL_EXTENSION_OPERATOR: plan = ((LogicalExtensionOperator &)op).CreatePlan(context, *this); - if (!plan) + if (!plan) { throw InternalException("Missing PhysicalOperator for Extension Operator"); + } break; default: { throw NotImplementedException("Unimplemented logical operator type!"); From cc2eff07278e9054fcebb9dee6f1f4c384f3a75f Mon Sep 17 00:00:00 2001 From: RJ Atwal Date: Fri, 11 Nov 2022 09:50:04 -0800 Subject: [PATCH 7/8] Adding if clause that I staged incorrectly --- src/planner/planner.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/planner/planner.cpp b/src/planner/planner.cpp index 747fb21bfa20..42a24af2daf2 100644 --- a/src/planner/planner.cpp +++ b/src/planner/planner.cpp @@ -65,7 +65,9 @@ void Planner::CreatePlan(SQLStatement &statement) { } } - throw; + if (!this->plan) { + throw; + } } catch (std::exception &ex) { throw; } From 0bbd8b3f6405917ba4f3f5bd121a570517deea8c Mon Sep 17 00:00:00 2001 From: RJ Atwal Date: Fri, 11 Nov 2022 19:57:47 -0800 Subject: [PATCH 8/8] Fixing edge case brought up by fuzzer --- src/planner/planner.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/planner/planner.cpp b/src/planner/planner.cpp index 42a24af2daf2..e6a5dac72b1c 100644 --- a/src/planner/planner.cpp +++ b/src/planner/planner.cpp @@ -54,6 +54,7 @@ void Planner::CreatePlan(SQLStatement &statement) { } catch (const Exception &ex) { auto &config = DBConfig::GetConfig(context); + this->plan = nullptr; for (auto &extension_op : config.operator_extensions) { auto bound_statement = extension_op.Bind(context, *this->binder, extension_op.operator_info.get(), statement);