diff --git a/src/duckdb/extension/core_functions/aggregate/distributive/arg_min_max.cpp b/src/duckdb/extension/core_functions/aggregate/distributive/arg_min_max.cpp index 08781ebdb..e8a10f9d6 100644 --- a/src/duckdb/extension/core_functions/aggregate/distributive/arg_min_max.cpp +++ b/src/duckdb/extension/core_functions/aggregate/distributive/arg_min_max.cpp @@ -918,7 +918,7 @@ void AddArgMinMaxNFunction(AggregateFunctionSet &set) { .AddParameter("val", LogicalTypeId::ANY) .AddParameter("N", LogicalType::BIGINT); - return set.AddFunction(function); + set.AddFunction(function); } } // namespace diff --git a/src/duckdb/extension/core_functions/scalar/array/array_value.cpp b/src/duckdb/extension/core_functions/scalar/array/array_value.cpp index 83ac4073d..2fdec1d1c 100644 --- a/src/duckdb/extension/core_functions/scalar/array/array_value.cpp +++ b/src/duckdb/extension/core_functions/scalar/array/array_value.cpp @@ -92,7 +92,7 @@ unique_ptr ArrayValueStats(ClientContext &context, FunctionStati ScalarFunction ArrayValueFun::GetFunction() { // the arguments and return types are actually set in the binder function ScalarFunction fun("array_value", {}, LogicalTypeId::ARRAY, ArrayValueFunction, ArrayValueBind, ArrayValueStats); - fun.GetSignature().AddArgsParameter("args", LogicalType::ANY); + fun.GetSignature().AddArgs("args", LogicalType::ANY); fun.SetNullHandling(FunctionNullHandling::SPECIAL_HANDLING); return fun; } diff --git a/src/duckdb/extension/core_functions/scalar/debug/index_key.cpp b/src/duckdb/extension/core_functions/scalar/debug/index_key.cpp index 8345f7856..278f27119 100644 --- a/src/duckdb/extension/core_functions/scalar/debug/index_key.cpp +++ b/src/duckdb/extension/core_functions/scalar/debug/index_key.cpp @@ -218,7 +218,7 @@ static void IndexKeyFunction(DataChunk &args, ExpressionState &state, Vector &re ScalarFunction IndexKeyFun::GetFunction() { ScalarFunction fun("index_key", {}, LogicalType::BLOB, IndexKeyFunction, IndexKeyBind); fun.GetSignature().AddParameter("path", LogicalTypeId::STRUCT).AddParameter("name", LogicalType::VARCHAR); - fun.GetSignature().AddArgsParameter("args", LogicalTypeId::ANY); + fun.GetSignature().AddArgs("args", LogicalTypeId::ANY); return fun; } diff --git a/src/duckdb/extension/core_functions/scalar/generic/hash.cpp b/src/duckdb/extension/core_functions/scalar/generic/hash.cpp index 2e4e25465..31021ba40 100644 --- a/src/duckdb/extension/core_functions/scalar/generic/hash.cpp +++ b/src/duckdb/extension/core_functions/scalar/generic/hash.cpp @@ -9,7 +9,7 @@ static void HashFunction(DataChunk &args, ExpressionState &state, Vector &result ScalarFunction HashFun::GetFunction() { auto hash_fun = ScalarFunction({}, LogicalType::HASH, HashFunction); hash_fun.GetSignature().AddParameter("value", LogicalType::ANY); - hash_fun.GetSignature().AddArgsParameter("args", LogicalType::ANY); + hash_fun.GetSignature().AddArgs("args", LogicalType::ANY); hash_fun.SetNullHandling(FunctionNullHandling::SPECIAL_HANDLING); return hash_fun; } diff --git a/src/duckdb/extension/core_functions/scalar/generic/type_functions.cpp b/src/duckdb/extension/core_functions/scalar/generic/type_functions.cpp index 9e83bf820..685dd73b1 100644 --- a/src/duckdb/extension/core_functions/scalar/generic/type_functions.cpp +++ b/src/duckdb/extension/core_functions/scalar/generic/type_functions.cpp @@ -128,7 +128,7 @@ ScalarFunction MakeTypeFun::GetFunction() { fun.SetNullHandling(FunctionNullHandling::SPECIAL_HANDLING); fun.SetBindExpressionCallback(BindMakeTypeFunctionExpression); fun.GetProperties().SetRequiresExpressionNames(true); - fun.GetSignature().AddArgsParameter("args", LogicalType::ANY).AddKwargsParameter("kwargs", LogicalType::ANY); + fun.GetSignature().AddArgs("args", LogicalType::ANY).AddKwargs("kwargs", LogicalType::ANY); return fun; } diff --git a/src/duckdb/extension/core_functions/scalar/list/list_aggregates.cpp b/src/duckdb/extension/core_functions/scalar/list/list_aggregates.cpp index 1df5d823d..7a9d8b150 100644 --- a/src/duckdb/extension/core_functions/scalar/list/list_aggregates.cpp +++ b/src/duckdb/extension/core_functions/scalar/list/list_aggregates.cpp @@ -536,7 +536,7 @@ ScalarFunction ListAggregateFun::GetFunction() { .AddParameter("function_name", LogicalType::VARCHAR); result.SetFallible(); result.SetNullHandling(FunctionNullHandling::SPECIAL_HANDLING); - result.GetSignature().AddArgsParameter("args", LogicalType::ANY); + result.GetSignature().AddArgs("args", LogicalType::ANY); result.SetSerializeCallback(ListAggregatesBindData::SerializeFunction); result.SetDeserializeCallback(ListAggregatesBindData::DeserializeFunction); return result; diff --git a/src/duckdb/extension/core_functions/scalar/list/list_value.cpp b/src/duckdb/extension/core_functions/scalar/list/list_value.cpp index 4b1436d2f..918e4237f 100644 --- a/src/duckdb/extension/core_functions/scalar/list/list_value.cpp +++ b/src/duckdb/extension/core_functions/scalar/list/list_value.cpp @@ -317,7 +317,7 @@ ScalarFunctionSet ListValueFun::GetFunctions() { ScalarFunction value_fun({element_type}, LogicalType::LIST(element_type), ListValueFunction, ListValueBind, ListValueStats); value_fun.GetSignature().GetParameter(0).SetName("value"); - value_fun.GetSignature().AddArgsParameter("args", element_type); + value_fun.GetSignature().AddArgs("args", element_type); value_fun.SetNullHandling(FunctionNullHandling::SPECIAL_HANDLING); set.AddFunction(value_fun); @@ -326,7 +326,7 @@ ScalarFunctionSet ListValueFun::GetFunctions() { ScalarFunction UnpivotListFun::GetFunction() { ScalarFunction fun("unpivot_list", {}, LogicalTypeId::LIST, ListValueFunction, UnpivotBind, ListValueStats); - fun.GetSignature().AddArgsParameter("args", LogicalTypeId::ANY); + fun.GetSignature().AddArgs("args", LogicalTypeId::ANY); fun.SetNullHandling(FunctionNullHandling::SPECIAL_HANDLING); return fun; } diff --git a/src/duckdb/extension/core_functions/scalar/map/cardinality.cpp b/src/duckdb/extension/core_functions/scalar/map/cardinality.cpp index 598538653..25a69e580 100644 --- a/src/duckdb/extension/core_functions/scalar/map/cardinality.cpp +++ b/src/duckdb/extension/core_functions/scalar/map/cardinality.cpp @@ -39,7 +39,7 @@ static unique_ptr CardinalityBind(BindScalarFunctionInput &input) ScalarFunction CardinalityFun::GetFunction() { ScalarFunction fun({}, LogicalType::UBIGINT, CardinalityFunction, CardinalityBind); fun.GetSignature().AddParameter("map", LogicalType::ANY); - fun.GetSignature().AddArgsParameter("args", LogicalType::ANY); + fun.GetSignature().AddArgs("args", LogicalType::ANY); fun.SetNullHandling(FunctionNullHandling::DEFAULT_NULL_HANDLING); return fun; } diff --git a/src/duckdb/extension/core_functions/scalar/map/map_concat.cpp b/src/duckdb/extension/core_functions/scalar/map/map_concat.cpp index 1202bdf05..1e2a5b963 100644 --- a/src/duckdb/extension/core_functions/scalar/map/map_concat.cpp +++ b/src/duckdb/extension/core_functions/scalar/map/map_concat.cpp @@ -185,7 +185,7 @@ ScalarFunction MapConcatFun::GetFunction() { //! the arguments and return types are actually set in the binder function ScalarFunction fun("map_concat", {}, LogicalTypeId::LIST, MapConcatFunction, MapConcatBind); fun.SetNullHandling(FunctionNullHandling::SPECIAL_HANDLING); - fun.GetSignature().AddArgsParameter("args", LogicalType::ANY); + fun.GetSignature().AddArgs("args", LogicalType::ANY); return fun; } diff --git a/src/duckdb/extension/core_functions/scalar/string/printf.cpp b/src/duckdb/extension/core_functions/scalar/string/printf.cpp index 52d9a2339..4db8e449c 100644 --- a/src/duckdb/extension/core_functions/scalar/string/printf.cpp +++ b/src/duckdb/extension/core_functions/scalar/string/printf.cpp @@ -187,7 +187,7 @@ ScalarFunction PrintfFun::GetFunction() { ScalarFunction printf_fun({}, LogicalType::VARCHAR, PrintfFunction, BindPrintfFunction); printf_fun.GetSignature().AddParameter("format", LogicalType::VARCHAR); - printf_fun.GetSignature().AddArgsParameter("args", LogicalType::ANY); + printf_fun.GetSignature().AddArgs("args", LogicalType::ANY); printf_fun.SetFallible(); return printf_fun; } @@ -197,7 +197,7 @@ ScalarFunction FormatFun::GetFunction() { ScalarFunction format_fun({}, LogicalType::VARCHAR, PrintfFunction, BindPrintfFunction); format_fun.GetSignature().AddParameter("format", LogicalType::VARCHAR); - format_fun.GetSignature().AddArgsParameter("args", LogicalType::ANY); + format_fun.GetSignature().AddArgs("args", LogicalType::ANY); format_fun.SetFallible(); return format_fun; } diff --git a/src/duckdb/extension/core_functions/scalar/struct/struct_insert.cpp b/src/duckdb/extension/core_functions/scalar/struct/struct_insert.cpp index 28be6cfb5..86e5bd039 100644 --- a/src/duckdb/extension/core_functions/scalar/struct/struct_insert.cpp +++ b/src/duckdb/extension/core_functions/scalar/struct/struct_insert.cpp @@ -108,7 +108,7 @@ static unique_ptr StructInsertUnbind(FunctionUnbindInput &inpu ScalarFunction StructInsertFun::GetFunction() { ScalarFunction fun({}, LogicalTypeId::STRUCT, StructInsertFunction, StructInsertBind, StructInsertStats); fun.SetNullHandling(FunctionNullHandling::SPECIAL_HANDLING); - fun.GetSignature().AddParameter("struct", LogicalType::ANY).AddKwargsParameter("kwargs", LogicalType::ANY); + fun.GetSignature().AddParameter("struct", LogicalType::ANY).AddKwargs("kwargs", LogicalType::ANY); fun.GetProperties().SetRequiresExpressionNames(true); fun.SetSerializeCallback(VariableReturnBindData::Serialize); fun.SetDeserializeCallback(VariableReturnBindData::Deserialize); diff --git a/src/duckdb/extension/core_functions/scalar/struct/struct_update.cpp b/src/duckdb/extension/core_functions/scalar/struct/struct_update.cpp index 121c279d9..02e343d80 100644 --- a/src/duckdb/extension/core_functions/scalar/struct/struct_update.cpp +++ b/src/duckdb/extension/core_functions/scalar/struct/struct_update.cpp @@ -157,7 +157,7 @@ static unique_ptr StructUpdateUnbind(FunctionUnbindInput &inpu ScalarFunction StructUpdateFun::GetFunction() { ScalarFunction fun({}, LogicalTypeId::STRUCT, StructUpdateFunction, StructUpdateBind, StructUpdateStats); fun.SetNullHandling(FunctionNullHandling::SPECIAL_HANDLING); - fun.GetSignature().AddParameter("struct", LogicalType::ANY).AddKwargsParameter("kwargs", LogicalType::ANY); + fun.GetSignature().AddParameter("struct", LogicalType::ANY).AddKwargs("kwargs", LogicalType::ANY); fun.GetProperties().SetRequiresExpressionNames(true); fun.SetUnbindCallback(StructUpdateUnbind); fun.SetSerializeCallback(VariableReturnBindData::Serialize); diff --git a/src/duckdb/extension/core_functions/scalar/union/union_value.cpp b/src/duckdb/extension/core_functions/scalar/union/union_value.cpp index 473d095ca..041c3df0a 100644 --- a/src/duckdb/extension/core_functions/scalar/union/union_value.cpp +++ b/src/duckdb/extension/core_functions/scalar/union/union_value.cpp @@ -50,7 +50,7 @@ unique_ptr UnionValueBind(BindScalarFunctionInput &input) { ScalarFunction UnionValueFun::GetFunction() { ScalarFunction fun("union_value", {}, LogicalTypeId::UNION, UnionValueFunction, UnionValueBind, nullptr, nullptr); - fun.GetSignature().AddKwargsParameter("kwargs", LogicalType::ANY); + fun.GetSignature().AddKwargs("kwargs", LogicalType::ANY); fun.GetProperties().SetRequiresExpressionNames(true); fun.SetNullHandling(FunctionNullHandling::SPECIAL_HANDLING); fun.SetSerializeCallback(VariableReturnBindData::Serialize); diff --git a/src/duckdb/extension/icu/icu-table-range.cpp b/src/duckdb/extension/icu/icu-table-range.cpp index 3a494f92f..466b3dae2 100644 --- a/src/duckdb/extension/icu/icu-table-range.cpp +++ b/src/duckdb/extension/icu/icu-table-range.cpp @@ -265,9 +265,12 @@ struct ICUTableRange { } static void AddICUTableRangeFunction(ExtensionLoader &loader) { + const auto timestamps = FunctionSignature() + .AddPositionalOnly("start", LogicalType::TIMESTAMP_TZ) + .AddPositionalOnly("stop", LogicalType::TIMESTAMP_TZ) + .AddPositionalOnly("step", LogicalType::INTERVAL); TableFunctionSet range("range"); - TableFunction range_function({LogicalType::TIMESTAMP_TZ, LogicalType::TIMESTAMP_TZ, LogicalType::INTERVAL}, - nullptr, Bind, RangeDateTimeGlobalInit, RangeDateTimeLocalInit); + TableFunction range_function(timestamps, nullptr, Bind, RangeDateTimeGlobalInit, RangeDateTimeLocalInit); range_function.in_out_function = ICUTableRangeFunction; range_function.table_scan_progress = Progress; range_function.cardinality = Cardinality; @@ -278,9 +281,8 @@ struct ICUTableRange { // generate_series: similar to range, but inclusive instead of exclusive bounds on the RHS TableFunctionSet generate_series("generate_series"); - TableFunction generate_series_function( - {LogicalType::TIMESTAMP_TZ, LogicalType::TIMESTAMP_TZ, LogicalType::INTERVAL}, nullptr, Bind, - RangeDateTimeGlobalInit, RangeDateTimeLocalInit); + TableFunction generate_series_function(timestamps, nullptr, Bind, RangeDateTimeGlobalInit, + RangeDateTimeLocalInit); generate_series_function.in_out_function = ICUTableRangeFunction; generate_series_function.table_scan_progress = Progress; generate_series_function.cardinality = Cardinality; diff --git a/src/duckdb/extension/json/include/json_scan.hpp b/src/duckdb/extension/json/include/json_scan.hpp index f6b19ea49..7f3aafe80 100644 --- a/src/duckdb/extension/json/include/json_scan.hpp +++ b/src/duckdb/extension/json/include/json_scan.hpp @@ -186,8 +186,8 @@ struct JSONScan { vector &names); static void Serialize(Serializer &serializer, const optional_ptr bind_data, - const TableFunction &function); - static unique_ptr Deserialize(Deserializer &deserializer, TableFunction &function); + const BoundTableFunction &function); + static unique_ptr Deserialize(Deserializer &deserializer, BoundTableFunction &function); static void TableFunctionDefaults(TableFunction &table_function); //! The named parameters shared by all read_json variants diff --git a/src/duckdb/extension/json/json_functions/json_create.cpp b/src/duckdb/extension/json/json_functions/json_create.cpp index 6aeef4394..0ce05a8a0 100644 --- a/src/duckdb/extension/json/json_functions/json_create.cpp +++ b/src/duckdb/extension/json/json_functions/json_create.cpp @@ -1477,7 +1477,7 @@ unique_ptr JSONFunctions::CreateJSONCopyToJSONExpression(ClientConte ScalarFunctionSet JSONFunctions::GetObjectFunction() { ScalarFunction fun("json_object", {}, LogicalType::JSON(), ObjectFunction, JSONObjectBind, nullptr, JSONFunctionLocalState::Init); - fun.GetSignature().AddArgsParameter("args", LogicalType::ANY); + fun.GetSignature().AddArgs("args", LogicalType::ANY); fun.SetNullHandling(FunctionNullHandling::SPECIAL_HANDLING); // throws if a key is NULL fun.SetFallible(); @@ -1487,7 +1487,7 @@ ScalarFunctionSet JSONFunctions::GetObjectFunction() { ScalarFunctionSet JSONFunctions::GetArrayFunction() { ScalarFunction fun("json_array", {}, LogicalType::JSON(), ArrayFunction, JSONArrayBind, nullptr, JSONFunctionLocalState::Init); - fun.GetSignature().AddArgsParameter("args", LogicalType::ANY); + fun.GetSignature().AddArgs("args", LogicalType::ANY); fun.SetNullHandling(FunctionNullHandling::SPECIAL_HANDLING); return ScalarFunctionSet(fun); } @@ -1495,7 +1495,7 @@ ScalarFunctionSet JSONFunctions::GetArrayFunction() { ScalarFunctionSet JSONFunctions::GetToJSONFunction() { ScalarFunction fun("to_json", {}, LogicalType::JSON(), ToJSONFunction, ToJSONBind, nullptr, JSONFunctionLocalState::Init); - fun.GetSignature().AddArgsParameter("args", LogicalType::ANY); + fun.GetSignature().AddArgs("args", LogicalType::ANY); return ScalarFunctionSet(fun); } @@ -1531,14 +1531,14 @@ ScalarFunction JSONFunctions::GetJSONCopyToGeoJSONFunction() { ScalarFunctionSet JSONFunctions::GetArrayToJSONFunction() { ScalarFunction fun("array_to_json", {}, LogicalType::JSON(), ToJSONFunction, ArrayToJSONBind, nullptr, JSONFunctionLocalState::Init); - fun.GetSignature().AddArgsParameter("args", LogicalType::ANY); + fun.GetSignature().AddArgs("args", LogicalType::ANY); return ScalarFunctionSet(fun); } ScalarFunctionSet JSONFunctions::GetRowToJSONFunction() { ScalarFunction fun("row_to_json", {}, LogicalType::JSON(), ToJSONFunction, RowToJSONBind, nullptr, JSONFunctionLocalState::Init); - fun.GetSignature().AddArgsParameter("args", LogicalType::ANY); + fun.GetSignature().AddArgs("args", LogicalType::ANY); return ScalarFunctionSet(fun); } diff --git a/src/duckdb/extension/json/json_functions/json_deep_merge.cpp b/src/duckdb/extension/json/json_functions/json_deep_merge.cpp index 797114ff4..0e2187984 100644 --- a/src/duckdb/extension/json/json_functions/json_deep_merge.cpp +++ b/src/duckdb/extension/json/json_functions/json_deep_merge.cpp @@ -144,7 +144,7 @@ ScalarFunctionSet JSONFunctions::GetDeepMergeFunction() { ScalarFunction fun("json_deep_merge", {}, LogicalType::JSON(), DeepMergeFunction, nullptr, nullptr, JSONFunctionLocalState::Init); fun.GetSignature().AddParameter("json1", LogicalType::JSON()).AddParameter("json2", LogicalType::JSON()); - fun.GetSignature().AddArgsParameter("args", LogicalType::JSON()); + fun.GetSignature().AddArgs("args", LogicalType::JSON()); fun.SetNullHandling(FunctionNullHandling::SPECIAL_HANDLING); fun.SetFallible(); diff --git a/src/duckdb/extension/json/json_functions/json_merge_patch.cpp b/src/duckdb/extension/json/json_functions/json_merge_patch.cpp index 2dfa8f372..59f721445 100644 --- a/src/duckdb/extension/json/json_functions/json_merge_patch.cpp +++ b/src/duckdb/extension/json/json_functions/json_merge_patch.cpp @@ -75,7 +75,7 @@ ScalarFunctionSet JSONFunctions::GetMergePatchFunction() { ScalarFunction fun("json_merge_patch", {}, LogicalType::JSON(), MergePatchFunction, nullptr, nullptr, JSONFunctionLocalState::Init); fun.GetSignature().AddParameter("json1", LogicalType::JSON()).AddParameter("json2", LogicalType::JSON()); - fun.GetSignature().AddArgsParameter("args", LogicalType::JSON()); + fun.GetSignature().AddArgs("args", LogicalType::JSON()); fun.SetNullHandling(FunctionNullHandling::SPECIAL_HANDLING); return ScalarFunctionSet(fun); diff --git a/src/duckdb/extension/json/json_functions/json_serialize_sql.cpp b/src/duckdb/extension/json/json_functions/json_serialize_sql.cpp index 59790fbff..bdd157534 100644 --- a/src/duckdb/extension/json/json_functions/json_serialize_sql.cpp +++ b/src/duckdb/extension/json/json_functions/json_serialize_sql.cpp @@ -269,8 +269,9 @@ static string ExecuteJsonSerializedSqlPragmaFunction(ClientContext &context, con } PragmaFunctionSet JSONFunctions::GetExecuteJsonSerializedSqlPragmaFunction() { - return PragmaFunctionSet(PragmaFunction::PragmaCall( - "json_execute_serialized_sql", ExecuteJsonSerializedSqlPragmaFunction, {LogicalType::VARCHAR})); + return PragmaFunctionSet( + PragmaFunction::PragmaCall("json_execute_serialized_sql", ExecuteJsonSerializedSqlPragmaFunction, + FunctionSignature().AddPositionalOnly("serialized_sql", LogicalType::VARCHAR))); } //---------------------------------------------------------------------- @@ -322,8 +323,9 @@ struct ExecuteSqlTableFunction { }; TableFunctionSet JSONFunctions::GetExecuteJsonSerializedSqlFunction() { - TableFunction func("json_execute_serialized_sql", {LogicalType::VARCHAR}, ExecuteSqlTableFunction::Function, - ExecuteSqlTableFunction::Bind); + TableFunction func("json_execute_serialized_sql", + FunctionSignature().AddPositionalOnly("serialized_sql", LogicalType::VARCHAR), + ExecuteSqlTableFunction::Function, ExecuteSqlTableFunction::Bind); return TableFunctionSet(func); } diff --git a/src/duckdb/extension/json/json_functions/json_table_in_out.cpp b/src/duckdb/extension/json/json_functions/json_table_in_out.cpp index 046d97411..65232dea4 100644 --- a/src/duckdb/extension/json/json_functions/json_table_in_out.cpp +++ b/src/duckdb/extension/json/json_functions/json_table_in_out.cpp @@ -462,11 +462,13 @@ virtual_column_map_t GetJSONTableInOutVirtualColumns(ClientContext &, optional_p template TableFunction GetJSONTableInOutFunction(const LogicalType &input_type, const bool &has_path_param) { - vector arguments = {input_type}; + FunctionSignature signature; + signature.AddPositionalOnly("json", input_type); if (has_path_param) { - arguments.push_back(LogicalType::VARCHAR); + signature.AddPositionalOnly("path", LogicalType::VARCHAR); } - TableFunction function(arguments, nullptr, JSONTableInOutBind, JSONTableInOutInitGlobal, JSONTableInOutInitLocal); + TableFunction function(std::move(signature), nullptr, JSONTableInOutBind, JSONTableInOutInitGlobal, + JSONTableInOutInitLocal); function.in_out_function = JSONTableInOutFunction; function.table_scan_progress = JSONTableInOutProgress; function.get_virtual_columns = GetJSONTableInOutVirtualColumns; diff --git a/src/duckdb/extension/json/json_functions/read_single_json_file.cpp b/src/duckdb/extension/json/json_functions/read_single_json_file.cpp index 684004028..70efcc7af 100644 --- a/src/duckdb/extension/json/json_functions/read_single_json_file.cpp +++ b/src/duckdb/extension/json/json_functions/read_single_json_file.cpp @@ -307,8 +307,9 @@ static unique_ptr ReadSingleJSONFileCardinality(ClientContext &c TableFunction JSONFunctions::GetReadSingleJSONFileTableFunction(shared_ptr function_info) { const auto scan_type = function_info->type; - TableFunction table_function("read_single_json_file", {LogicalType::VARCHAR}, ReadSingleJSONFileFunction, - ReadSingleJSONFileBind, ReadSingleJSONFileInitGlobal, ReadSingleJSONFileInitLocal); + TableFunction table_function( + "read_single_json_file", FunctionSignature().AddPositionalOnly("path", LogicalType::VARCHAR), + ReadSingleJSONFileFunction, ReadSingleJSONFileBind, ReadSingleJSONFileInitGlobal, ReadSingleJSONFileInitLocal); JSONScan::TableFunctionDefaults(table_function); if (scan_type != JSONScanType::READ_JSON_OBJECTS) { // read_json_objects always emits a single JSON column - it has no schema options diff --git a/src/duckdb/extension/json/json_scan.cpp b/src/duckdb/extension/json/json_scan.cpp index 7effec241..edf854402 100644 --- a/src/duckdb/extension/json/json_scan.cpp +++ b/src/duckdb/extension/json/json_scan.cpp @@ -111,19 +111,22 @@ void JSONScanLocalState::AddTransformError(idx_t object_index, const string &err scan_state.current_reader->AddTransformError(scan_state, object_index, error_message); } -void JSONScan::Serialize(Serializer &serializer, const optional_ptr bind_data_p, const TableFunction &) { +void JSONScan::Serialize(Serializer &serializer, const optional_ptr bind_data_p, + const BoundTableFunction &) { throw NotImplementedException("JSONScan Serialize not implemented"); } -unique_ptr JSONScan::Deserialize(Deserializer &deserializer, TableFunction &) { +unique_ptr JSONScan::Deserialize(Deserializer &deserializer, BoundTableFunction &) { throw NotImplementedException("JSONScan Deserialize not implemented"); } void JSONScan::TableFunctionDefaults(TableFunction &table_function) { - table_function.named_parameters["maximum_object_size"] = LogicalType::UINTEGER; - table_function.named_parameters["ignore_errors"] = LogicalType::BOOLEAN; - table_function.named_parameters["format"] = LogicalType::VARCHAR; - table_function.named_parameters["compression"] = LogicalType::VARCHAR; + table_function.GetSignature().WithTypedKwargs("options", [](TypedKwargs &options) { + options.Add("maximum_object_size", LogicalType::UINTEGER) + .Add("ignore_errors", LogicalType::BOOLEAN) + .Add("format", LogicalType::VARCHAR) + .Add("compression", LogicalType::VARCHAR); + }); table_function.serialize = Serialize; table_function.deserialize = Deserialize; @@ -134,24 +137,29 @@ void JSONScan::TableFunctionDefaults(TableFunction &table_function) { } void JSONScan::AddReadJSONParameters(TableFunction &table_function) { - table_function.named_parameters["columns"] = LogicalType::ANY; - table_function.named_parameters["auto_detect"] = LogicalType::BOOLEAN; - table_function.named_parameters["geojson"] = LogicalType::BOOLEAN; - table_function.named_parameters["sample_size"] = LogicalType::BIGINT; - table_function.named_parameters["dateformat"] = LogicalType::VARCHAR; - table_function.named_parameters["date_format"] = LogicalType::VARCHAR; - table_function.named_parameters["timestampformat"] = LogicalType::VARCHAR; - table_function.named_parameters["timestamp_format"] = LogicalType::VARCHAR; - table_function.named_parameters["records"] = LogicalType::VARCHAR; - table_function.named_parameters["array"] = LogicalType::BOOLEAN; - table_function.named_parameters["maximum_sample_files"] = LogicalType::BIGINT; + // extends the options TableFunctionDefaults declares + table_function.GetSignature().ExtendTypedKwargs([](TypedKwargs &options) { + options.Add("columns", LogicalType::ANY) + .Add("auto_detect", LogicalType::BOOLEAN) + .Add("geojson", LogicalType::BOOLEAN) + .Add("sample_size", LogicalType::BIGINT) + .Add("dateformat", LogicalType::VARCHAR) + .Add("date_format", LogicalType::VARCHAR) + .Add("timestampformat", LogicalType::VARCHAR) + .Add("timestamp_format", LogicalType::VARCHAR) + .Add("records", LogicalType::ANY) + .Add("array", LogicalType::BOOLEAN) + .Add("maximum_sample_files", LogicalType::BIGINT); + }); } void JSONScan::AddAutoDetectParameters(TableFunction &table_function) { - table_function.named_parameters["maximum_depth"] = LogicalType::BIGINT; - table_function.named_parameters["field_appearance_threshold"] = LogicalType::DOUBLE; - table_function.named_parameters["convert_strings_to_integers"] = LogicalType::BOOLEAN; - table_function.named_parameters["map_inference_threshold"] = LogicalType::BIGINT; + table_function.GetSignature().ExtendTypedKwargs([](TypedKwargs &options) { + options.Add("maximum_depth", LogicalType::BIGINT) + .Add("field_appearance_threshold", LogicalType::DOUBLE) + .Add("convert_strings_to_integers", LogicalType::BOOLEAN) + .Add("map_inference_threshold", LogicalType::BIGINT); + }); } bool JSONScan::ParseOption(ClientContext &context, const Identifier &key, const Value &value, @@ -301,7 +309,10 @@ bool JSONScan::ParseOption(ClientContext &context, const Identifier &key, const return true; } if (key == "records") { - auto arg = StringValue::Get(value); + // records is tri-state: 'auto', 'true' or 'false'. Accept a boolean for the latter two, since + // records = false reads more naturally than records = 'false'. + auto arg = value.type().id() == LogicalTypeId::BOOLEAN ? string(BooleanValue::Get(value) ? "true" : "false") + : StringValue::Get(value); if (arg == "auto") { options.record_type = JSONRecordType::AUTO_DETECT; } else if (arg == "true") { diff --git a/src/duckdb/extension/parquet/parquet_extension.cpp b/src/duckdb/extension/parquet/parquet_extension.cpp index fcaa8010d..d2e9828ce 100644 --- a/src/duckdb/extension/parquet/parquet_extension.cpp +++ b/src/duckdb/extension/parquet/parquet_extension.cpp @@ -1072,7 +1072,9 @@ static void LoadInternal(ExtensionLoader &loader) { // parquet_key auto parquet_key_fun = PragmaFunction::PragmaCall("add_parquet_key", ParquetCrypto::AddKey, - {LogicalType::VARCHAR, LogicalType::VARCHAR}); + FunctionSignature() + .AddPositionalOnly("key_name", LogicalType::VARCHAR) + .AddPositionalOnly("key", LogicalType::VARCHAR)); loader.RegisterFunction(parquet_key_fun); auto &config = DBConfig::GetConfig(db_instance); diff --git a/src/duckdb/extension/parquet/parquet_metadata.cpp b/src/duckdb/extension/parquet/parquet_metadata.cpp index 85cef8c52..c2230bb02 100644 --- a/src/duckdb/extension/parquet/parquet_metadata.cpp +++ b/src/duckdb/extension/parquet/parquet_metadata.cpp @@ -1179,7 +1179,8 @@ double ParquetMetaDataOperator::Progress(ClientContext &context, const FunctionD } ParquetMetaDataFunction::ParquetMetaDataFunction() - : TableFunction("parquet_metadata", {LogicalType::VARCHAR}, ParquetMetaDataOperator::Function, + : TableFunction("parquet_metadata", FunctionSignature().AddPositionalOnly("path", LogicalType::VARCHAR), + ParquetMetaDataOperator::Function, ParquetMetaDataOperator::Bind, ParquetMetaDataOperator::InitGlobal, ParquetMetaDataOperator::InitLocal) { @@ -1188,7 +1189,8 @@ ParquetMetaDataFunction::ParquetMetaDataFunction() } ParquetSchemaFunction::ParquetSchemaFunction() - : TableFunction("parquet_schema", {LogicalType::VARCHAR}, ParquetMetaDataOperator::Function, + : TableFunction("parquet_schema", FunctionSignature().AddPositionalOnly("path", LogicalType::VARCHAR), + ParquetMetaDataOperator::Function, ParquetMetaDataOperator::Bind, ParquetMetaDataOperator::InitGlobal, ParquetMetaDataOperator::InitLocal) { @@ -1197,7 +1199,8 @@ ParquetSchemaFunction::ParquetSchemaFunction() } ParquetKeyValueMetadataFunction::ParquetKeyValueMetadataFunction() - : TableFunction("parquet_kv_metadata", {LogicalType::VARCHAR}, ParquetMetaDataOperator::Function, + : TableFunction("parquet_kv_metadata", FunctionSignature().AddPositionalOnly("path", LogicalType::VARCHAR), + ParquetMetaDataOperator::Function, ParquetMetaDataOperator::Bind, ParquetMetaDataOperator::InitGlobal, ParquetMetaDataOperator::InitLocal) { @@ -1206,7 +1209,8 @@ ParquetKeyValueMetadataFunction::ParquetKeyValueMetadataFunction() } ParquetFileMetadataFunction::ParquetFileMetadataFunction() - : TableFunction("parquet_file_metadata", {LogicalType::VARCHAR}, ParquetMetaDataOperator::Function, + : TableFunction("parquet_file_metadata", FunctionSignature().AddPositionalOnly("path", LogicalType::VARCHAR), + ParquetMetaDataOperator::Function, ParquetMetaDataOperator::Bind, ParquetMetaDataOperator::InitGlobal, ParquetMetaDataOperator::InitLocal) { @@ -1215,7 +1219,11 @@ ParquetFileMetadataFunction::ParquetFileMetadataFunction() } ParquetBloomProbeFunction::ParquetBloomProbeFunction() - : TableFunction("parquet_bloom_probe", {LogicalType::VARCHAR, LogicalType::VARCHAR, LogicalType::ANY}, + : TableFunction("parquet_bloom_probe", + FunctionSignature() + .AddPositionalOnly("path", LogicalType::VARCHAR) + .AddPositionalOnly("column_name", LogicalType::VARCHAR) + .AddPositionalOnly("value", LogicalType::ANY), ParquetMetaDataOperator::Function, ParquetMetaDataOperator::Bind, ParquetMetaDataOperator::InitGlobal, @@ -1225,7 +1233,8 @@ ParquetBloomProbeFunction::ParquetBloomProbeFunction() } ParquetFullMetadataFunction::ParquetFullMetadataFunction() - : TableFunction("parquet_full_metadata", {LogicalType::VARCHAR}, ParquetMetaDataOperator::Function, + : TableFunction("parquet_full_metadata", FunctionSignature().AddPositionalOnly("path", LogicalType::VARCHAR), + ParquetMetaDataOperator::Function, ParquetMetaDataOperator::Bind, ParquetMetaDataOperator::InitGlobal, ParquetMetaDataOperator::InitLocal) { diff --git a/src/duckdb/extension/parquet/parquet_multi_file_info.cpp b/src/duckdb/extension/parquet/parquet_multi_file_info.cpp index 447d1eb70..e35e56740 100644 --- a/src/duckdb/extension/parquet/parquet_multi_file_info.cpp +++ b/src/duckdb/extension/parquet/parquet_multi_file_info.cpp @@ -230,7 +230,7 @@ static bool ParquetScanSupportPushdownExtract(const FunctionData &bind_data_p, c } static void ParquetScanSerialize(Serializer &serializer, const optional_ptr bind_data_p, - const TableFunction &function) { + const BoundTableFunction &function) { auto &bind_data = bind_data_p->Cast(); auto &parquet_data = bind_data.bind_data->Cast(); @@ -253,7 +253,7 @@ static void ParquetScanSerialize(Serializer &serializer, const optional_ptr ParquetScanDeserialize(Deserializer &deserializer, TableFunction &function) { +static unique_ptr ParquetScanDeserialize(Deserializer &deserializer, BoundTableFunction &function) { auto &context = deserializer.Get(); auto files = deserializer.ReadProperty>(100, "files"); auto types = deserializer.ReadProperty>(101, "types"); @@ -514,17 +514,20 @@ static vector ParquetGetPartitionStats(ClientContext &conte TableFunctionSet ParquetScanFunction::GetFunctionSet() { MultiFileFunction table_function("parquet_scan"); - table_function.named_parameters["binary_as_string"] = LogicalType::BOOLEAN; - table_function.named_parameters["file_row_number"] = LogicalType::BOOLEAN; - table_function.named_parameters["debug_use_openssl"] = LogicalType::BOOLEAN; - table_function.named_parameters["compression"] = LogicalType::VARCHAR; - table_function.named_parameters["explicit_cardinality"] = LogicalType::UBIGINT; - table_function.named_parameters["schema"] = LogicalTypeId::ANY; - table_function.named_parameters["encryption_config"] = LogicalTypeId::ANY; - table_function.named_parameters["parquet_version"] = LogicalType::VARCHAR; - table_function.named_parameters["can_have_nan"] = LogicalType::BOOLEAN; - table_function.named_parameters["prefetch_strategy"] = LogicalType::VARCHAR; - table_function.named_parameters["utf8_validation"] = LogicalType::VARCHAR; + // extends the options MultiFileFunction declares + table_function.GetSignature().ExtendTypedKwargs([](TypedKwargs &options) { + options.Add("binary_as_string", LogicalType::BOOLEAN) + .Add("file_row_number", LogicalType::BOOLEAN) + .Add("debug_use_openssl", LogicalType::BOOLEAN) + .Add("compression", LogicalType::VARCHAR) + .Add("explicit_cardinality", LogicalType::UBIGINT) + .Add("schema", LogicalTypeId::ANY) + .Add("encryption_config", LogicalTypeId::ANY) + .Add("parquet_version", LogicalType::VARCHAR) + .Add("can_have_nan", LogicalType::BOOLEAN) + .Add("prefetch_strategy", LogicalType::VARCHAR) + .Add("utf8_validation", LogicalType::VARCHAR); + }); table_function.statistics_extended = MultiFileFunction::MultiFileScanStatsExtended; table_function.get_metrics = ParquetScanGetMetrics; table_function.projection_expression_pushdown = ParquetProjectionExpressionPushdown; diff --git a/src/duckdb/generated_extension_loader_package_build.cpp b/src/duckdb/generated_extension_loader_package_build.cpp index 0615ecaea..3105d5079 100644 --- a/src/duckdb/generated_extension_loader_package_build.cpp +++ b/src/duckdb/generated_extension_loader_package_build.cpp @@ -41,7 +41,7 @@ int32_t duckdb_extension_core_functions_describe(duckdb_extension_descriptor *de descriptor->version = 1; descriptor->name = "core_functions"; descriptor->extension_version = EXT_VERSION_CORE_FUNCTIONS; - descriptor->api_version = "v2.0.0-alpha43586"; + descriptor->api_version = "v2.0.0-alpha43678"; descriptor->entry_cpp = (void (*)(void))core_functions_duckdb_cpp_init; return 0; } @@ -74,7 +74,7 @@ int32_t duckdb_extension_parquet_describe(duckdb_extension_descriptor *descripto descriptor->version = 1; descriptor->name = "parquet"; descriptor->extension_version = EXT_VERSION_PARQUET; - descriptor->api_version = "v2.0.0-alpha43586"; + descriptor->api_version = "v2.0.0-alpha43678"; descriptor->entry_cpp = (void (*)(void))parquet_duckdb_cpp_init; return 0; } @@ -107,7 +107,7 @@ int32_t duckdb_extension_icu_describe(duckdb_extension_descriptor *descriptor) { descriptor->version = 1; descriptor->name = "icu"; descriptor->extension_version = EXT_VERSION_ICU; - descriptor->api_version = "v2.0.0-alpha43586"; + descriptor->api_version = "v2.0.0-alpha43678"; descriptor->entry_cpp = (void (*)(void))icu_duckdb_cpp_init; return 0; } @@ -140,7 +140,7 @@ int32_t duckdb_extension_json_describe(duckdb_extension_descriptor *descriptor) descriptor->version = 1; descriptor->name = "json"; descriptor->extension_version = EXT_VERSION_JSON; - descriptor->api_version = "v2.0.0-alpha43586"; + descriptor->api_version = "v2.0.0-alpha43678"; descriptor->entry_cpp = (void (*)(void))json_duckdb_cpp_init; return 0; } diff --git a/src/duckdb/src/catalog/default/default_types.cpp b/src/duckdb/src/catalog/default/default_types.cpp index 813644c09..91147ed53 100644 --- a/src/duckdb/src/catalog/default/default_types.cpp +++ b/src/duckdb/src/catalog/default/default_types.cpp @@ -190,7 +190,7 @@ LogicalType BindEnumType(BindLogicalTypeInput &input) { void RegisterEnumConstructors(TypeConstructorSet &set) { auto signature = TypeConstructor::Signature(); - signature.AddArgsParameter("args", LogicalType::VARCHAR); + signature.AddArgs("args", LogicalType::VARCHAR); set.AddFunction(TypeConstructor(std::move(signature), BindEnumType)); } @@ -249,7 +249,7 @@ LogicalType BindStructType(BindLogicalTypeInput &input) { void RegisterStructConstructors(TypeConstructorSet &set) { auto signature = TypeConstructor::Signature(); - signature.AddKwargsParameter("kwargs", LogicalType::TYPE()); + signature.AddKwargs("kwargs", LogicalType::TYPE()); set.AddFunction(TypeConstructor(std::move(signature), BindStructType)); } @@ -267,7 +267,7 @@ LogicalType BindTupleType(BindLogicalTypeInput &input) { void RegisterTupleConstructors(TypeConstructorSet &set) { auto signature = TypeConstructor::Signature(); - signature.AddArgsParameter("args", LogicalType::TYPE()); + signature.AddArgs("args", LogicalType::TYPE()); set.AddFunction(TypeConstructor(std::move(signature), BindTupleType)); } @@ -311,7 +311,7 @@ LogicalType BindUnionType(BindLogicalTypeInput &input) { void RegisterUnionConstructors(TypeConstructorSet &set) { auto signature = TypeConstructor::Signature(); - signature.AddKwargsParameter("kwargs", LogicalType::TYPE()); + signature.AddKwargs("kwargs", LogicalType::TYPE()); set.AddFunction(TypeConstructor(std::move(signature), BindUnionType)); } diff --git a/src/duckdb/src/common/enum_util.cpp b/src/duckdb/src/common/enum_util.cpp index 39fcb2755..9603bd297 100644 --- a/src/duckdb/src/common/enum_util.cpp +++ b/src/duckdb/src/common/enum_util.cpp @@ -2766,22 +2766,23 @@ FunctionNullHandling EnumUtil::FromString(const char *valu const StringUtil::EnumStringLiteral *GetFunctionParameterKindValues() { static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(FunctionParameterKind::POSITIONAL_ONLY), "POSITIONAL_ONLY" }, { static_cast(FunctionParameterKind::STANDARD), "STANDARD" }, { static_cast(FunctionParameterKind::VAR_POSITIONAL), "VAR_POSITIONAL" }, - { static_cast(FunctionParameterKind::VAR_KEYWORD), "VAR_KEYWORD" }, - { static_cast(FunctionParameterKind::KEYWORD_ONLY), "KEYWORD_ONLY" } + { static_cast(FunctionParameterKind::KEYWORD_ONLY), "KEYWORD_ONLY" }, + { static_cast(FunctionParameterKind::VAR_KEYWORD), "VAR_KEYWORD" } }; return values; } template<> const char* EnumUtil::ToChars(FunctionParameterKind value) { - return StringUtil::EnumToString(GetFunctionParameterKindValues(), 4, "FunctionParameterKind", static_cast(value)); + return StringUtil::EnumToString(GetFunctionParameterKindValues(), 5, "FunctionParameterKind", static_cast(value)); } template<> FunctionParameterKind EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetFunctionParameterKindValues(), 4, "FunctionParameterKind", value)); + return static_cast(StringUtil::StringToEnum(GetFunctionParameterKindValues(), 5, "FunctionParameterKind", value)); } const StringUtil::EnumStringLiteral *GetFunctionStabilityValues() { diff --git a/src/duckdb/src/common/multi_file/multi_file_reader.cpp b/src/duckdb/src/common/multi_file/multi_file_reader.cpp index 1a9ff99f2..b6d3704bc 100644 --- a/src/duckdb/src/common/multi_file/multi_file_reader.cpp +++ b/src/duckdb/src/common/multi_file/multi_file_reader.cpp @@ -34,14 +34,14 @@ MultiFileReaderGlobalState::~MultiFileReaderGlobalState() { MultiFileReader::~MultiFileReader() { } -unique_ptr MultiFileReader::Create(const TableFunction &table_function) { +unique_ptr MultiFileReader::Create(const BoundTableFunction &table_function) { unique_ptr res; if (table_function.get_multi_file_reader) { res = table_function.get_multi_file_reader(table_function); - res->function_name = table_function.name; + res->function_name = table_function.GetName(); } else { res = make_uniq(); - res->function_name = table_function.name; + res->function_name = table_function.GetName(); } return res; } @@ -85,13 +85,25 @@ Value MultiFileReader::CreateValueFromFileList(const vector &file_list) return Value::LIST(LogicalType::VARCHAR, std::move(files)); } -void MultiFileReader::AddParameters(TableFunction &table_function) { - table_function.named_parameters["filename"] = LogicalType::ANY; - table_function.named_parameters["hive_partitioning"] = LogicalType::BOOLEAN; - table_function.named_parameters["union_by_name"] = LogicalType::BOOLEAN; - table_function.named_parameters["hive_types"] = LogicalType::ANY; - table_function.named_parameters["hive_types_autocast"] = LogicalType::BOOLEAN; - table_function.named_parameters["allow_empty"] = LogicalType::BOOLEAN; +void MultiFileReader::AddParameters(TableFunction &table_function, MultiFileParameters which) { + auto add_options = [&](TypedKwargs &options) { + if (which == MultiFileParameters::ALL) { + // "filename" is a boolean, or the name of the column to hold the file name + options.Add("filename", LogicalType::ANY) + .Add("hive_partitioning", LogicalType::BOOLEAN) + .Add("union_by_name", LogicalType::BOOLEAN) + .Add("hive_types", LogicalType::ANY) + .Add("hive_types_autocast", LogicalType::BOOLEAN); + } + options.Add("allow_empty", LogicalType::BOOLEAN); + }; + // a reader can declare its own options before or after these + auto &signature = table_function.GetSignature(); + if (signature.GetTypedKwargs()) { + signature.ExtendTypedKwargs(add_options); + } else { + signature.WithTypedKwargs("options", add_options); + } } OpenFileInfo MultiFileReader::ParseFileEntry(const Value &input) { @@ -607,15 +619,20 @@ TablePartitionInfo MultiFileReader::GetPartitionInfo(ClientContext &context, con TableFunctionSet MultiFileReader::CreateFunctionSet(TableFunction table_function) { TableFunctionSet function_set {table_function.name}; function_set.AddFunction(table_function); - D_ASSERT(!table_function.GetArguments().empty() && table_function.GetArguments()[0] == LogicalType::VARCHAR); + D_ASSERT(table_function.GetSignature().GetPositionalParameterCount() > 0 && + table_function.GetSignature().GetParameter(0).GetType() == LogicalType::VARCHAR); // the list variant takes ANY as its child type: a file is either a path (VARCHAR) or a STRUCT/VARIANT // holding the path together with the options to open the file with auto list_function = table_function; - list_function.GetArguments()[0] = LogicalType::LIST(LogicalType::ANY); + auto &list_parameter = list_function.GetSignature().GetParameter(0); + list_parameter.SetType(LogicalType::LIST(LogicalType::ANY)); + if (list_parameter.GetName() == "path") { + list_parameter.SetName("paths"); + } function_set.AddFunction(std::move(list_function)); // a single file can also be passed as a VARIANT - without this overload it would implicitly cast to VARCHAR // and the stringified variant would be read as a path - table_function.GetArguments()[0] = LogicalType::VARIANT(); + table_function.GetSignature().GetParameter(0).SetType(LogicalType::VARIANT()); function_set.AddFunction(std::move(table_function)); return function_set; } diff --git a/src/duckdb/src/common/multi_file/table_function_multi_file.cpp b/src/duckdb/src/common/multi_file/table_function_multi_file.cpp index 1cdd99633..8913434fe 100644 --- a/src/duckdb/src/common/multi_file/table_function_multi_file.cpp +++ b/src/duckdb/src/common/multi_file/table_function_multi_file.cpp @@ -39,7 +39,7 @@ class TableFunctionMultiFileLocalState : public LocalTableFunctionState { // Reader //===--------------------------------------------------------------------===// TableFunctionFileReader::TableFunctionFileReader(TableFunction function_p, OpenFileInfo file_p, - named_parameter_map_t named_parameters_p, string reader_type_p) + named_argument_map_t named_parameters_p, string reader_type_p) : BaseFileReader(std::move(file_p)), function(std::move(function_p)), named_parameters(std::move(named_parameters_p)), reader_type(std::move(reader_type_p)), file_is_assigned(false), exhausted(false) { @@ -66,11 +66,13 @@ void TableFunctionFileReader::BindFunction(ClientContext &context, const TableFu vector inputs; inputs.emplace_back(file.path); auto parameters = named_parameters; + function.GetSignature().FillNamedDefaults(context, parameters); vector input_table_types; vector input_table_names; TableFunctionRef empty_ref; + BoundTableFunction bound_function(function); TableFunctionBindInput bind_input(inputs, parameters, input_table_types, input_table_names, - function.function_info.get(), nullptr, function, empty_ref); + function.function_info.get(), nullptr, bound_function, empty_ref); bind_input.multi_file_options = file_options; bind_input.multi_file_scan = options.multi_file_scan; if (!options.expected_names.empty()) { @@ -272,12 +274,32 @@ unique_ptr TableFunctionMultiFileWrapper::InitializeOptio return make_uniq(); } +optional> TableFunctionMultiFileWrapper::GetDeclaredOption(const Identifier &key) const { + auto &signature = function.GetSignature(); + auto index = signature.GetParameterIndexByName(key); + if (index.IsValid()) { + auto ¶m = signature.GetParameter(index.GetIndex()); + if (param.GetKind() != FunctionParameterKind::KEYWORD_ONLY) { + return {}; + } + return make_pair(param.GetName(), param.GetType()); + } + auto option_schema = signature.GetTypedKwargs(); + auto option = option_schema ? option_schema->Find(key) : nullptr; + if (!option) { + return {}; + } + return make_pair(option->name, option->type); +} + bool TableFunctionMultiFileWrapper::ParseNamedParameter(const Identifier &key, const Value &val, TableFunctionFileReaderOptions &options) const { - if (function.named_parameters.find(key) == function.named_parameters.end()) { + auto declared_option = GetDeclaredOption(key); + if (!declared_option) { return false; } - options.named_parameters[key] = val; + // under the name of the option, whichever alias was used + options.named_parameters[declared_option->first] = val; return true; } @@ -299,11 +321,11 @@ bool TableFunctionMultiFileWrapper::ParseCopyOption(ClientContext &context, cons vector &, vector &) { // COPY supports exactly the named parameters of the wrapped function - the only difference is that COPY passes // the values as a list, and that a bare option (e.g. "auto_detect") means "true" - auto entry = function.named_parameters.find(key); - if (entry == function.named_parameters.end()) { + auto declared_option = GetDeclaredOption(key); + if (!declared_option) { return false; } - auto &type = entry->second; + auto &type = declared_option->second; Value val; if (type.id() == LogicalTypeId::LIST || (type.id() == LogicalTypeId::ANY && values.size() != 1)) { // COPY passes the elements of a list-valued option as separate values - an option that takes any value is @@ -539,8 +561,9 @@ unique_ptr TableFunctionMultiFileWrapper::MultiFileBindCopy(Client TableFunction TableFunctionMultiFileWrapper::CreateFunction(TableFunction single_file_function, Identifier name, TableFunctionMultiFileSettings settings) { - if (single_file_function.GetArguments().size() != 1 || - single_file_function.GetArguments()[0] != LogicalType::VARCHAR) { + auto &wrapped_signature = single_file_function.GetSignature(); + if (wrapped_signature.GetPositionalParameterCount() != 1 || + wrapped_signature.GetParameter(0).GetType() != LogicalType::VARCHAR) { throw InternalException("Only table functions taking a single VARCHAR file path can be wrapped in a multi " "file function, %s does not", single_file_function.name); @@ -550,9 +573,11 @@ TableFunction TableFunctionMultiFileWrapper::CreateFunction(TableFunction single } TableFunctionMultiFileFunction result(std::move(name)); result.bind = TableFunctionMultiFileBind; - // forward the named parameters and the pushdown capabilities of the wrapped function - for (auto &named_parameter : single_file_function.named_parameters) { - result.named_parameters[named_parameter.first] = named_parameter.second; + // forward the options and the pushdown capabilities of the wrapped function + auto &signature = result.GetSignature(); + auto wrapped_options = single_file_function.GetSignature().GetTypedKwargs(); + if (wrapped_options) { + signature.ExtendTypedKwargs([&](TypedKwargs &options) { options = options.Merge(*wrapped_options); }); } result.projection_pushdown = single_file_function.projection_pushdown; result.filter_pushdown = single_file_function.filter_pushdown; diff --git a/src/duckdb/src/execution/operator/csv_scanner/table_function/read_single_csv_file.cpp b/src/duckdb/src/execution/operator/csv_scanner/table_function/read_single_csv_file.cpp index bf6f30e33..0469070f6 100644 --- a/src/duckdb/src/execution/operator/csv_scanner/table_function/read_single_csv_file.cpp +++ b/src/duckdb/src/execution/operator/csv_scanner/table_function/read_single_csv_file.cpp @@ -468,8 +468,9 @@ static unique_ptr ReadSingleCSVFileCardinality(ClientContext &co } TableFunction ReadCSVTableFunction::GetSingleFileFunction() { - TableFunction read_csv("read_single_csv_file", {LogicalType::VARCHAR}, ReadSingleCSVFileFunction, - ReadSingleCSVFileBind, ReadSingleCSVFileInitGlobal, ReadSingleCSVFileInitLocal); + TableFunction read_csv("read_single_csv_file", FunctionSignature().AddPositionalOnly("path", LogicalType::VARCHAR), + ReadSingleCSVFileFunction, ReadSingleCSVFileBind, ReadSingleCSVFileInitGlobal, + ReadSingleCSVFileInitLocal); read_csv.combine_schema = ReadSingleCSVFileCombineSchema; read_csv.claim_batch = ReadSingleCSVFileClaimBatch; read_csv.finish_batch = ReadSingleCSVFileFinishBatch; diff --git a/src/duckdb/src/execution/operator/csv_scanner/util/csv_reader_options.cpp b/src/duckdb/src/execution/operator/csv_scanner/util/csv_reader_options.cpp index 41ce7d6a1..2b0cbb4f4 100644 --- a/src/duckdb/src/execution/operator/csv_scanner/util/csv_reader_options.cpp +++ b/src/duckdb/src/execution/operator/csv_scanner/util/csv_reader_options.cpp @@ -650,7 +650,7 @@ string CSVReaderOptions::GetUserDefinedParameters() const { return result; } -void CSVReaderOptions::FromNamedParameters(const named_parameter_map_t &in, ClientContext &context, +void CSVReaderOptions::FromNamedParameters(const named_argument_map_t &in, ClientContext &context, MultiFileOptions &file_options) { for (auto &kv : in) { if (MultiFileReader().ParseOption(kv.first, kv.second, file_options, context)) { @@ -858,7 +858,7 @@ void CSVReaderOptions::ToNamedParameters(named_parameter_map_t &named_params) co } named_params["max_line_size"] = Value::BIGINT(NumericCast(maximum_line_size.GetValue())); if (dialect_options.skip_rows.IsSetByUser()) { - named_params["skip"] = Value::UBIGINT(GetSkipRows()); + named_params["skip"] = Value::BIGINT(NumericCast(GetSkipRows())); } named_params["null_padding"] = Value::BOOLEAN(null_padding); named_params["parallel"] = Value::BOOLEAN(parallel); diff --git a/src/duckdb/src/execution/operator/projection/physical_tableinout_function.cpp b/src/duckdb/src/execution/operator/projection/physical_tableinout_function.cpp index e838f252a..cb82d41ac 100644 --- a/src/duckdb/src/execution/operator/projection/physical_tableinout_function.cpp +++ b/src/duckdb/src/execution/operator/projection/physical_tableinout_function.cpp @@ -33,7 +33,8 @@ class TableInOutGlobalState : public GlobalOperatorState { }; PhysicalTableInOutFunction::PhysicalTableInOutFunction(PhysicalPlan &physical_plan, vector types, - TableFunction function_p, unique_ptr bind_data_p, + BoundTableFunction function_p, + unique_ptr bind_data_p, vector column_ids_p, vector projection_ids_p, unique_ptr table_filters_p, idx_t estimated_cardinality, vector project_input_p) @@ -154,7 +155,7 @@ InsertionOrderPreservingMap PhysicalTableInOutFunction::ParamsToString() result[it.first] = it.second; } } else { - result["Name"] = function.name.GetIdentifierName(); + result["Name"] = function.GetName().GetIdentifierName(); } SetEstimatedCardinality(result, estimated_cardinality); return result; diff --git a/src/duckdb/src/execution/operator/scan/physical_table_scan.cpp b/src/duckdb/src/execution/operator/scan/physical_table_scan.cpp index d656c33ad..083e947e4 100644 --- a/src/duckdb/src/execution/operator/scan/physical_table_scan.cpp +++ b/src/duckdb/src/execution/operator/scan/physical_table_scan.cpp @@ -15,12 +15,13 @@ namespace duckdb { -PhysicalTableScan::PhysicalTableScan(PhysicalPlan &physical_plan, vector types, TableFunction function_p, - unique_ptr bind_data_p, vector returned_types_p, - vector column_ids_p, vector projection_ids_p, - vector names_p, unique_ptr table_filters_p, - idx_t estimated_cardinality, ExtraOperatorInfo extra_info, - vector parameters_p, virtual_column_map_t virtual_columns_p) +PhysicalTableScan::PhysicalTableScan(PhysicalPlan &physical_plan, vector types, + BoundTableFunction function_p, unique_ptr bind_data_p, + vector returned_types_p, vector column_ids_p, + vector projection_ids_p, vector names_p, + unique_ptr table_filters_p, idx_t estimated_cardinality, + ExtraOperatorInfo extra_info, vector parameters_p, + virtual_column_map_t virtual_columns_p) : PhysicalOperator(physical_plan, PhysicalOperatorType::TABLE_SCAN, std::move(types), estimated_cardinality), function(std::move(function_p)), bind_data(std::move(bind_data_p)), returned_types(std::move(returned_types_p)), @@ -267,7 +268,8 @@ OperatorPartitionData PhysicalTableScan::GetPartitionData(ExecutionContext &cont } string PhysicalTableScan::GetName() const { - return StringUtil::Upper(function.name + (function.extra_info.empty() ? "" : " " + function.extra_info)); + auto &extra_info = function.GetExtraInfo(); + return StringUtil::Upper(function.GetName().GetIdentifierName() + (extra_info.empty() ? "" : " " + extra_info)); } void AddProjectionNames(const ColumnIndex &index, const string &name, const LogicalType &type, string &result) { @@ -340,7 +342,7 @@ InsertionOrderPreservingMap PhysicalTableScan::ParamsToString() const { result[it.first] = it.second; } } else { - result["Function"] = StringUtil::Upper(function.name.GetIdentifierName()); + result["Function"] = StringUtil::Upper(function.GetName().GetIdentifierName()); } if (function.projection_pushdown) { string projections; diff --git a/src/duckdb/src/function/function.cpp b/src/duckdb/src/function/function.cpp index c426af1ba..70d271897 100644 --- a/src/duckdb/src/function/function.cpp +++ b/src/duckdb/src/function/function.cpp @@ -4,11 +4,107 @@ #include "duckdb/common/types/hash.hpp" #include "duckdb/execution/expression_executor.hpp" #include "duckdb/function/built_in_functions.hpp" +#include "duckdb/function/function_binder.hpp" #include "duckdb/function/scalar/string_functions.hpp" #include "duckdb/function/scalar_function.hpp" namespace duckdb { +TypedKwarg::TypedKwarg(Identifier name_p, LogicalType type_p) : name(std::move(name_p)), type(std::move(type_p)) { +} + +bool TypedKwarg::operator==(const TypedKwarg &other) const { + return name == other.name && aliases == other.aliases && type == other.type; +} + +bool TypedKwarg::operator!=(const TypedKwarg &other) const { + return !(*this == other); +} + +string TypedKwarg::ToString() const { + return StringUtil::Format("%s %s", SQLIdentifier(name), type.ToString()); +} + +TypedKwargs &TypedKwargs::Add(Identifier name, LogicalType type) { + options.emplace_back(std::move(name), std::move(type)); + return *this; +} + +TypedKwargs &TypedKwargs::Alias(Identifier alias) { + if (options.empty()) { + throw InternalException("TypedKwargs::Alias called before any option was added"); + } + options.back().aliases.push_back(std::move(alias)); + return *this; +} + +TypedKwargs TypedKwargs::Merge(const TypedKwargs &other) const { + auto result = *this; + result.options.insert(result.options.end(), other.options.begin(), other.options.end()); + return result; +} + +optional_ptr TypedKwargs::Find(const Identifier &name) const { + // names are matched case-insensitively, like parameter names + for (auto &option : options) { + if (option.name == name) { + return option; + } + for (auto &alias : option.aliases) { + if (alias == name) { + return option; + } + } + } + return nullptr; +} + +const vector &TypedKwargs::GetOptions() const { + return options; +} + +void TypedKwargs::Verify() const { + identifier_set_t names; + for (auto &option : options) { + if (!names.insert(option.name).second) { + throw InvalidInputException("Duplicate option name: %s", option.name); + } + for (auto &alias : option.aliases) { + if (!names.insert(alias).second) { + throw InvalidInputException("Duplicate option name: %s", alias); + } + } + } +} + +vector TypedKwargs::GetNames() const { + vector result; + for (auto &option : options) { + result.push_back(option.name); + for (auto &alias : option.aliases) { + result.push_back(alias); + } + } + return result; +} + +bool TypedKwargs::operator==(const TypedKwargs &other) const { + return options == other.options; +} + +bool TypedKwargs::operator!=(const TypedKwargs &other) const { + return !(*this == other); +} + +hash_t TypedKwargs::Hash() const { + hash_t hash = duckdb::Hash(options.size()); + for (auto &option : options) { + hash = CombineHash(hash, IdentifierHashFunction()(option.name)); + hash = CombineHash(hash, option.type.Hash()); + } + return hash; +} + bool FunctionProperties::operator==(const FunctionProperties &rhs) const { return stability == rhs.stability && null_handling == rhs.null_handling && errors == rhs.errors && collation_handling == rhs.collation_handling && capture_argument_aliases == rhs.capture_argument_aliases && @@ -59,7 +155,10 @@ SimpleFunction::SimpleFunction(Identifier name_p, FunctionSignature signature_p) SimpleFunction::SimpleFunction(Identifier name_p, vector arguments_p, LogicalType return_type, LogicalType varargs_p) - : Function(std::move(name_p)), signature(std::move(arguments_p), std::move(varargs_p), std::move(return_type)) { + : Function(std::move(name_p)), signature(std::move(arguments_p), std::move(return_type)) { + if (varargs_p.id() != LogicalTypeId::INVALID) { + signature.AddArgs("args", varargs_p).AddKwargs("kwargs", std::move(varargs_p)); + } } SimpleFunction::~SimpleFunction() { @@ -83,12 +182,55 @@ string FunctionParameter::ToString() const { return StringUtil::Format("%s %s", SQLIdentifier(name), type.ToString()); } +// signatures are copied and moved freely - keep the move cheap +static_assert(std::is_nothrow_move_constructible::value, "FunctionSignature must stay movable"); +static_assert(std::is_nothrow_move_assignable::value, "FunctionSignature must stay movable"); + +auto FunctionSignature::AddTypedKwargs(Identifier name, TypedKwargs schema) -> FunctionSignature & { + typed_kwargs = make_shared_ptr(std::move(schema)); + return AddKwargs(std::move(name), LogicalType::ANY); +} + +auto FunctionSignature::WithTypedKwargs(Identifier name, const std::function &configure) + -> FunctionSignature & { + TypedKwargs schema; + configure(schema); + return AddTypedKwargs(std::move(name), std::move(schema)); +} + +auto FunctionSignature::ExtendTypedKwargs(const std::function &configure) -> FunctionSignature & { + if (!typed_kwargs) { + throw InternalException("ExtendTypedKwargs called on a signature without typed \"**kwargs\""); + } + if (typed_kwargs.use_count() > 1) { + // other signatures copied from this one share its schema - extend a copy of it + typed_kwargs = make_shared_ptr(*typed_kwargs); + } + configure(*typed_kwargs); + return *this; +} + string FunctionSignature::ToString() const { vector params; params.reserve(parameters.size()); - for (auto ¶m : parameters) { + // A keyword-only parameter that no "*args" precedes closes the positional parameters by itself, which Python + // spells as a bare "*" in that position; a "/" likewise closes the positional-only parameters + const auto positional_only_count = GetPositionalOnlyParameterCount(); + auto needs_separator = !GetArgs(); + for (idx_t i = 0; i < parameters.size(); i++) { + auto ¶m = parameters[i]; + if (i == positional_only_count && positional_only_count > 0) { + params.push_back("/"); + } + if (needs_separator && param.GetKind() == FunctionParameterKind::KEYWORD_ONLY) { + params.push_back("*"); + needs_separator = false; + } params.push_back(param.ToString()); } + if (positional_only_count > 0 && positional_only_count == parameters.size()) { + params.push_back("/"); + } auto head = StringUtil::Format("(%s)", StringUtil::Join(params, ", ")); if (return_type.IsValid()) { return head + " -> " + return_type.ToString(); @@ -104,22 +246,6 @@ string SimpleFunction::ToString() const { return SQLIdentifier::ToString(name.GetIdentifierName()) + signature.ToString(); } -SimpleNamedParameterFunction::SimpleNamedParameterFunction(Identifier name_p, vector arguments_p, - LogicalType varargs_p) - : Function(std::move(name_p)), arguments(std::move(arguments_p)), varargs(std::move(varargs_p)) { -} - -SimpleNamedParameterFunction::~SimpleNamedParameterFunction() { -} - -string SimpleNamedParameterFunction::ToString() const { - return Function::CallToString(GetCatalogName(), GetSchemaName(), name, arguments, named_parameters); -} - -bool SimpleNamedParameterFunction::HasNamedParameters() const { - return !named_parameters.empty(); -} - // add your initializer for new functions here void BuiltinFunctions::Initialize() { RegisterTableScanFunctions(); @@ -146,26 +272,37 @@ hash_t FunctionSignature::Hash() const { hash = duckdb::CombineHash(hash, param.GetType().Hash()); hash = duckdb::CombineHash(hash, duckdb::Hash(static_cast(param.GetKind()))); } + if (typed_kwargs) { + hash = duckdb::CombineHash(hash, typed_kwargs->Hash()); + } return hash; } -const LogicalType &FunctionSignature::GetVarArgs() const { - static const LogicalType INVALID_TYPE(LogicalTypeId::INVALID); - auto args = GetArgsParameter(); - return args ? args->GetType() : INVALID_TYPE; -} - -void FunctionSignature::SetVarArgs(LogicalType varargs_p) { - for (idx_t i = parameters.size(); i > 0; i--) { - if (parameters[i - 1].IsVariadic()) { - parameters.erase_at(i - 1); +void FunctionSignature::FillNamedDefaults(ClientContext &context, named_argument_map_t &named_parameters) const { + // keyword-only parameters are slots, bound in the order they are declared - the arguments "**kwargs" receives + // follow them in the order they were passed + named_argument_map_t result; + for (auto ¶m : parameters) { + if (param.GetKind() != FunctionParameterKind::KEYWORD_ONLY) { + continue; + } + auto entry = named_parameters.find(param.GetName()); + if (entry != named_parameters.end()) { + result.insert(param.GetName(), std::move(entry->second)); + } else if (param.HasDefaultValue()) { + result.insert(param.GetName(), + FunctionBinder::CastToParameterType(context, *param.GetDefaultValue(), param.GetType())); } } - if (varargs_p.id() == LogicalTypeId::INVALID) { + if (result.empty()) { return; } - AddArgsParameter("args", varargs_p); - AddKwargsParameter("kwargs", std::move(varargs_p)); + for (auto &entry : named_parameters) { + if (!result.contains(entry.first)) { + result.insert(entry.first, std::move(entry.second)); + } + } + named_parameters = std::move(result); } void FunctionSignature::Verify() const { @@ -194,10 +331,12 @@ void FunctionSignature::Verify() const { } } - // And that the parameter kinds are in order: standard parameters, "*args", keyword-only parameters, "**kwargs" + // And that the parameter kinds are in order: + // positional-only, "/", standard parameters, "*args", keyword-only parameters, "**kwargs" bool found_args = false; bool found_kwargs = false; bool found_keyword_only = false; + bool found_standard = false; for (const auto ¶m : parameters) { if (found_kwargs) { throw InvalidInputException("Parameter '%s' follows '**kwargs', which must be the last parameter", @@ -207,11 +346,19 @@ void FunctionSignature::Verify() const { throw InvalidInputException("Variadic parameter '%s' cannot have a default value", param.ToString()); } switch (param.GetKind()) { + case FunctionParameterKind::POSITIONAL_ONLY: + if (found_standard || found_args || found_keyword_only) { + throw InvalidInputException( + "Positional-only parameter '%s' must be declared before every parameter that can be passed by name", + param.ToString()); + } + break; case FunctionParameterKind::STANDARD: if (found_args || found_keyword_only) { throw InvalidInputException("Parameter '%s' follows '*args' and must therefore be keyword-only", param.ToString()); } + found_standard = true; break; case FunctionParameterKind::VAR_POSITIONAL: if (found_args) { @@ -230,6 +377,19 @@ void FunctionSignature::Verify() const { break; } } + + if (typed_kwargs) { + if (!found_kwargs) { + throw InvalidInputException("A function signature with options must have a '**kwargs' parameter"); + } + typed_kwargs->Verify(); + // a named argument binds to a parameter of its name first, so an option of the same name is never reached + for (auto ¶m : parameters) { + if (param.AcceptsName() && typed_kwargs->Find(param.GetName())) { + throw InvalidInputException("Option '%s' has the same name as a parameter", param.GetName()); + } + } + } } hash_t SimpleFunction::Hash() const { @@ -270,24 +430,6 @@ string Function::CallToString(const Identifier &catalog_name, const Identifier & return result; } -string Function::CallToString(const Identifier &catalog_name, const Identifier &schema_name, const Identifier &name, - const vector &arguments, - const named_parameter_type_map_t &named_parameters) { - vector input_arguments; - input_arguments.reserve(arguments.size() + named_parameters.size()); - for (auto &arg : arguments) { - input_arguments.push_back(arg.ToString()); - } - for (auto &kv : named_parameters) { - input_arguments.push_back(StringUtil::Format("%s : %s", SQLIdentifier(kv.first), kv.second.ToString())); - } - string prefix = ""; - if (RequiresCatalogAndSchemaNamePrefix(catalog_name, schema_name)) { - prefix = StringUtil::Format("%s.%s.", SQLIdentifier(catalog_name), SQLIdentifier(schema_name)); - } - return StringUtil::Format("%s%s(%s)", prefix, name, StringUtil::Join(input_arguments, ", ")); -} - hash_t BoundSimpleFunction::Hash() const { hash_t hash = return_type.Hash(); for (auto &arg : arguments) { @@ -317,7 +459,7 @@ FunctionParameterKind BoundSimpleFunction::GetArgumentParameterKind(const Functi throw InternalException("%s: Argument index %llu is out of range", GetName(), argument_index); } if (argument_index < signature.GetPositionalParameterCount()) { - return FunctionParameterKind::STANDARD; + return signature.GetParameter(argument_index).GetKind(); } if (argument_index < positional_arguments) { return FunctionParameterKind::VAR_POSITIONAL; @@ -340,14 +482,75 @@ bool FunctionParameter::operator!=(const FunctionParameter &other) const { return !(*this == other); } +//! Whether two signatures declare the same options - compared by content, as each registration builds its own +static bool OptionSchemasEqual(optional_ptr lhs, optional_ptr rhs) { + if (!lhs || !rhs) { + return !lhs && !rhs; + } + return *lhs == *rhs; +} + bool FunctionSignature::operator==(const FunctionSignature &other) const { - return parameters == other.parameters && return_type == other.return_type; + return parameters == other.parameters && return_type == other.return_type && + OptionSchemasEqual(GetTypedKwargs(), other.GetTypedKwargs()); } bool FunctionSignature::operator!=(const FunctionSignature &other) const { return !(*this == other); } +bool FunctionSignature::IsSameOverload(const FunctionSignature &other) const { + // the parameters a caller can pass by position, "*args" and "**kwargs", in declaration order + auto ordered = [](const FunctionSignature &signature) { + vector> result; + for (auto ¶m : signature.GetParameters()) { + if (param.GetKind() != FunctionParameterKind::KEYWORD_ONLY) { + result.push_back(param); + } + } + return result; + }; + auto lhs_ordered = ordered(*this); + auto rhs_ordered = ordered(other); + if (lhs_ordered.size() != rhs_ordered.size()) { + return false; + } + for (idx_t i = 0; i < lhs_ordered.size(); i++) { + auto &lhs = lhs_ordered[i].get(); + auto &rhs = rhs_ordered[i].get(); + // a positional-only and a standard parameter both take a position, which is all a call can tell apart + auto takes_position = lhs.AcceptsPosition(); + if (takes_position != rhs.AcceptsPosition() || (!takes_position && lhs.GetKind() != rhs.GetKind())) { + return false; + } + if (lhs.GetType() != rhs.GetType()) { + return false; + } + } + // the keyword-only parameters, by name + auto keywords = [](const FunctionSignature &signature) { + identifier_map_t result; + for (auto ¶m : signature.GetParameters()) { + if (param.GetKind() == FunctionParameterKind::KEYWORD_ONLY) { + result.emplace(param.GetName(), param.GetType()); + } + } + return result; + }; + auto lhs_keywords = keywords(*this); + auto rhs_keywords = keywords(other); + if (lhs_keywords.size() != rhs_keywords.size()) { + return false; + } + for (auto &entry : lhs_keywords) { + auto match = rhs_keywords.find(entry.first); + if (match == rhs_keywords.end() || match->second != entry.second) { + return false; + } + } + return true; +} + bool FunctionSignature::Equal(const FunctionSignature &other) const { if (parameters.size() != other.parameters.size()) { return false; @@ -361,7 +564,7 @@ bool FunctionSignature::Equal(const FunctionSignature &other) const { if (return_type != other.return_type) { return false; } - return true; + return OptionSchemasEqual(GetTypedKwargs(), other.GetTypedKwargs()); } //---------------------------------------------------------------------------------------------------------------------- diff --git a/src/duckdb/src/function/function_binder.cpp b/src/duckdb/src/function/function_binder.cpp index 407ad0677..94a3710fe 100644 --- a/src/duckdb/src/function/function_binder.cpp +++ b/src/duckdb/src/function/function_binder.cpp @@ -88,20 +88,40 @@ optional_idx FunctionOverloads::Cost(optional_ptr context, const // Compute total number of arguments passed const auto received_arg_count = static_cast(arguments.size() + named_arguments.size()); - // And the minimum and maximum number of arguments the function can accept - const auto minimum_arg_count = sig.GetRequiredParameterCount(); + // And the maximum number of arguments the function can accept const auto positional_count = sig.GetPositionalParameterCount(); - const auto args_param = sig.GetArgsParameter(); - const auto kwargs_param = sig.GetKwargsParameter(); + const auto args_param = sig.GetArgs(); + const auto kwargs_param = sig.GetKwargs(); idx_t maximum_arg_count = NumericLimits::Maximum(); if (!args_param && !kwargs_param) { maximum_arg_count = sig.GetParameterCount(); } - if (received_arg_count < minimum_arg_count) { - // We have fewer arguments than the function requires, so this function cannot be a match. - return optional_idx(); + // Every parameter without a default has to be filled by the call, either from its position or by its name. + // Counting the arguments instead would let a named argument stand in for a required positional parameter, so + // that f(a, *, opt := NULL) matched a call f(opt := 1) that cannot fill "a" just as well as f(*, opt := NULL). + for (idx_t i = 0; i < sig.GetParameterCount(); i++) { + auto ¶m = sig.GetParameter(i); + if (param.IsVariadic() || param.HasDefaultValue()) { + continue; + } + if (param.AcceptsPosition() && i < arguments.size()) { + continue; + } + bool filled = false; + if (param.AcceptsName()) { + for (auto &named_arg : named_arguments) { + if (named_arg.first == param.GetName()) { + filled = true; + break; + } + } + } + if (!filled) { + // This parameter cannot be filled by the call, so this function cannot be a match. + return optional_idx(); + } } if (received_arg_count > maximum_arg_count) { @@ -145,7 +165,7 @@ optional_idx FunctionOverloads::Cost(optional_ptr context, const // no parameter with this name, and no "**kwargs" to receive it return optional_idx(); } - + // the options of "**kwargs" do not select the overload - they are checked once it is chosen int64_t cast_cost = ImplicitCastCost(context, named_arg.second, kwargs_param->GetType()); if (cast_cost >= 0) { // we can implicitly cast, add the cost to the total cost @@ -171,6 +191,7 @@ optional_idx FunctionOverloads::Cost(optional_ptr context, const if (cast_cost >= 0) { cost += idx_t(cast_cost); } else { + // A named argument reaches its parameter only by an implicit cast, exactly like a positional one return optional_idx(); } } @@ -183,66 +204,6 @@ optional_idx FunctionOverloads::Cost(optional_ptr context, const return cost; } -static optional_idx BindVarArgsFunctionCost(optional_ptr context, - const SimpleNamedParameterFunction &func, - const vector &arguments) { - if (arguments.size() < func.GetArguments().size()) { - // not enough arguments to fulfill the non-vararg part of the function - return optional_idx(); - } - idx_t cost = 0; - for (idx_t i = 0; i < arguments.size(); i++) { - LogicalType arg_type = i < func.GetArguments().size() ? func.GetArguments()[i] : func.GetVarArgs(); - if (arguments[i] == arg_type) { - // arguments match: do nothing - continue; - } - int64_t cast_cost = ImplicitCastCost(context, arguments[i], arg_type); - if (cast_cost >= 0) { - // we can implicitly cast, add the cost to the total cost - cost += idx_t(cast_cost); - } else { - // we can't implicitly cast: throw an error - return optional_idx(); - } - } - return cost; -} - -optional_idx FunctionOverloads::Cost(optional_ptr context, const SimpleNamedParameterFunction &func, - const vector &arguments, - const vector> &) { - if (func.HasVarArgs()) { - // special case varargs function - return BindVarArgsFunctionCost(context, func, arguments); - } - if (func.GetArguments().size() != arguments.size()) { - // invalid argument count: check the next function - return optional_idx(); - } - idx_t cost = 0; - bool has_parameter = false; - for (idx_t i = 0; i < arguments.size(); i++) { - if (arguments[i].id() == LogicalTypeId::UNKNOWN) { - has_parameter = true; - continue; - } - int64_t cast_cost = ImplicitCastCost(context, arguments[i], func.GetArguments()[i]); - if (cast_cost >= 0) { - // we can implicitly cast, add the cost to the total cost - cost += idx_t(cast_cost); - } else { - // we can't implicitly cast: throw an error - return optional_idx(); - } - } - if (has_parameter) { - // all arguments are implicitly castable and there is a parameter - return 0 as cost - return 0; - } - return cost; -} - template vector FunctionOverloads::Candidates(optional_ptr context, const Identifier &name, const FunctionSet &functions, const vector &arguments, @@ -460,23 +421,240 @@ optional_idx FunctionBinder::BindFunction(const Identifier &name, const TableFun return BindFunctionFromArguments(name, functions, regular_args, keyword_args, error); } -optional_idx FunctionBinder::BindFunction(const Identifier &name, const PragmaFunctionSet &functions, - vector ¶meters, ErrorData &error) { - vector types; - for (auto &value : parameters) { - types.push_back(value.type()); +//! Reject a named argument that no overload of the set accepts, naming the options that were available. Overload +//! selection would otherwise report only that nothing matched the call, which hides which name was wrong +template +static void VerifyNamedArgumentsAccepted(const Identifier &name, const FunctionSet &functions, + const vector>> &named_arguments) { + for (auto &named_argument : named_arguments) { + bool accepted = false; + for (idx_t i = 0; i < functions.functions.size() && !accepted; i++) { + auto &signature = functions.functions[i]->GetSignature(); + // the options of a "**kwargs" are checked once the overload is chosen + accepted = + signature.GetParameterIndexByName(named_argument.first).IsValid() || signature.GetKwargs() != nullptr; + } + if (accepted) { + continue; + } + // list every option any overload accepts, in name order + map candidates; + for (idx_t i = 0; i < functions.functions.size(); i++) { + for (auto ¶m : functions.functions[i]->GetSignature().GetParameters()) { + if (!param.IsVariadic() && param.HasDefaultValue()) { + candidates[param.GetName().GetIdentifierName()] = param.GetType().ToString(); + } + } + } + string candidate_list; + for (auto &candidate : candidates) { + candidate_list += " " + candidate.first + " " + candidate.second + "\n"; + } + throw BinderException("Invalid named parameter %s for function %s\n%s", named_argument.first, + name.GetIdentifierName(), + candidate_list.empty() ? "Function does not accept any named parameters." + : "Candidates:\n" + candidate_list); + } +} + +enum class LogicalTypeComparisonResult : uint8_t { IDENTICAL_TYPE, TARGET_IS_ANY, DIFFERENT_TYPES }; + +static LogicalTypeComparisonResult RequiresCast(const LogicalType &source_type, const LogicalType &target_type) { + if (target_type.id() == LogicalTypeId::ANY) { + return LogicalTypeComparisonResult::TARGET_IS_ANY; + } + if (source_type == target_type) { + return LogicalTypeComparisonResult::IDENTICAL_TYPE; + } + if (source_type.id() == LogicalTypeId::LIST && target_type.id() == LogicalTypeId::LIST) { + return RequiresCast(ListType::GetChildType(source_type), ListType::GetChildType(target_type)); } - auto entry = BindFunctionFromArguments(name, functions, types, {}, error); + if (source_type.id() == LogicalTypeId::ARRAY && target_type.id() == LogicalTypeId::ARRAY) { + return RequiresCast(ArrayType::GetChildType(source_type), ArrayType::GetChildType(target_type)); + } + return LogicalTypeComparisonResult::DIFFERENT_TYPES; +} + +Value FunctionBinder::CastToParameterType(ClientContext &context, Value value, const LogicalType ¶meter_type) { + if (RequiresCast(value.type(), parameter_type) == LogicalTypeComparisonResult::DIFFERENT_TYPES) { + return value.CastAs(context, parameter_type); + } + return value; +} + +//! Fold an argument to the constant it was bound to. A constant expression carries its value directly - evaluating +//! one is both wasteful and impossible for the types that have no vector representation, such as TABLE +static Value FoldArgument(ClientContext &context, Expression &expr) { + if (expr.GetExpressionClass() == ExpressionClass::BOUND_CONSTANT) { + return expr.Cast().GetValue(); + } + return ExpressionExecutor::EvaluateScalar(context, expr, true); +} + +//! Fold an argument to a constant and cast it to the type of the parameter it fills +static Value PlaceArgument(ClientContext &context, Expression &expr, const LogicalType &target_type) { + if (target_type.id() == LogicalTypeId::TABLE) { + // A TABLE parameter is filled by the subquery itself rather than by a value, so its slot holds a plain + // NULL. A NULL of type TABLE would not do: TABLE has no physical type, so such a value cannot be read + // back when the plan is deserialized. + return Value(); + } + return FunctionBinder::CastToParameterType(context, FoldArgument(context, expr), target_type); +} + +//! Fold an option to a constant and cast it to its type like an explicit cast - overload selection never checked it. +//! A failed cast names the option, as the cast alone cannot tell which one it was +static Value PlaceOption(ClientContext &context, Expression &expr, const TypedKwarg &option) { + auto value = FoldArgument(context, expr); + if (RequiresCast(value.type(), option.type) != LogicalTypeComparisonResult::DIFFERENT_TYPES) { + return value; + } + string error_message; + auto result = value.TryCastAs(context, option.type, &error_message); + if (!result) { + throw InvalidInputException(expr, "Could not cast value %s to named parameter %s of type %s: %s", + value.ToSQLString(), option.name, option.type.ToString(), error_message); + } + return std::move(*result); +} + +//! Place the arguments of a call onto the parameters of the chosen overload: fold each to a constant and cast it to +//! the type that parameter declares. Every parameter that accepts a position gets its slot in "parameters", whether +//! the caller passed it by position, by name or not at all, so "range(1, col1 := 5)" reaches the callback exactly as +//! "range(1, 5)" does. Only keyword-only and "**kwargs" arguments are handed back in "named_parameters", keyed by the +//! name the caller wrote - or, for an option "**kwargs" declares, by the name of the option, cast to its type. A +//! parameter the call leaves out receives its default; an option the call leaves out is not passed. Overload selection +//! has already established that every parameter's cast is one the implicit rules allow. An option takes no part in +//! selection, so it is cast to its type like an explicit cast. +template +static void PlaceArguments(ClientContext &context, const T &function, + vector> &positional_arguments, + vector>> &named_arguments, vector ¶meters, + named_argument_map_t &named_parameters) { + auto &signature = function.GetSignature(); + const auto positional_count = signature.GetPositionalParameterCount(); + const auto passed_count = positional_arguments.size(); + + // the positional parameters the caller filled by name, by parameter index + vector> named_slots(positional_count); + identifier_set_t seen_names; + for (auto &named_argument : named_arguments) { + auto &argument_name = named_argument.first; + if (!seen_names.insert(argument_name).second) { + throw BinderException("Duplicate named argument %s for function %s", argument_name, + function.GetName().GetIdentifierName()); + } + auto param_idx = signature.GetParameterIndexByName(argument_name); + if (!param_idx.IsValid()) { + auto option_schema = signature.GetTypedKwargs(); + if (!option_schema) { + // received by "**kwargs" - cast to its type, as overload selection checked, unless that is ANY + auto &kwargs_type = signature.GetKwargs()->GetType(); + named_parameters.insert( + make_pair(argument_name, PlaceArgument(context, *named_argument.second, kwargs_type))); + continue; + } + auto &expr = *named_argument.second; + auto option_ptr = option_schema->Find(argument_name); + if (!option_ptr) { + // only the options that resemble the name - listing every option buries the one that was meant + const double similarity_threshold = 0.8; + auto lower_name = StringUtil::Lower(argument_name.GetIdentifierName()); + vector> scores; + for (auto &option_name : option_schema->GetNames()) { + auto score = StringUtil::SimilarityRating(option_name.GetIdentifierName(), lower_name); + if (score >= similarity_threshold) { + scores.emplace_back(option_name.GetIdentifierName(), score); + } + } + auto similar = StringUtil::TopNStrings(scores, 3, similarity_threshold); + throw BinderException(expr.GetQueryLocation(), "Invalid named parameter %s for function %s%s", + argument_name, function.GetName().GetIdentifierName(), + StringUtil::CandidatesMessage(similar, "Did you mean")); + } + auto &option = *option_ptr; + if (named_parameters.find(option.name) != named_parameters.end()) { + throw BinderException(named_argument.second->GetQueryLocation(), + "Named parameter %s was passed more than once in function call to %s", + option.name, function.GetName().GetIdentifierName()); + } + named_parameters.insert(make_pair(option.name, PlaceOption(context, *named_argument.second, option))); + continue; + } + auto ¶m = signature.GetParameter(param_idx.GetIndex()); + if (!param.AcceptsPosition()) { + named_parameters.insert( + make_pair(argument_name, PlaceArgument(context, *named_argument.second, param.GetType()))); + continue; + } + if (param_idx.GetIndex() < passed_count) { + throw BinderException(named_argument.second->GetQueryLocation(), + "Named argument '%s' cannot be used for parameter '%s' because it has already " + "been provided as a positional argument in function call to '%s'", + named_argument.second->ToString(), argument_name, + function.GetName().GetIdentifierName()); + } + named_slots[param_idx.GetIndex()] = *named_argument.second; + } + + for (idx_t i = 0; i < positional_count; i++) { + auto ¶m = signature.GetParameter(i); + if (i < passed_count) { + parameters.push_back(PlaceArgument(context, *positional_arguments[i], param.GetType())); + } else if (named_slots[i]) { + parameters.push_back(PlaceArgument(context, *named_slots[i], param.GetType())); + } else if (param.HasDefaultValue()) { + parameters.push_back( + FunctionBinder::CastToParameterType(context, *param.GetDefaultValue(), param.GetType())); + } else { + // overload selection only picks an overload whose required parameters the call fills + throw InternalException("Missing value for parameter %s in function call to %s", param.GetName(), + function.GetName().GetIdentifierName()); + } + } + if (passed_count > positional_count) { + // overload selection only picks an overload with "*args" for surplus positional arguments + auto &args_type = signature.GetArgs()->GetType(); + for (idx_t i = positional_count; i < passed_count; i++) { + parameters.push_back(PlaceArgument(context, *positional_arguments[i], args_type)); + } + } + signature.FillNamedDefaults(context, named_parameters); +} + +optional_idx FunctionBinder::BindFunction(const Identifier &name, const TableFunctionSet &functions, + vector> &positional_arguments, + vector>> &named_arguments, + vector ¶meters, named_argument_map_t &named_parameters, + ErrorData &error) { + VerifyNamedArgumentsAccepted(name, functions, named_arguments); + auto entry = BindFunction(name, functions, positional_arguments, named_arguments, error); if (!entry.IsValid()) { - error.Throw(); + return entry; } - const auto &candidate_function = *functions.GetFunctionByOffset(entry.GetIndex()); - // cast the input parameters - for (idx_t i = 0; i < parameters.size(); i++) { - auto target_type = i < candidate_function.GetArguments().size() ? candidate_function.GetArguments()[i] - : candidate_function.GetVarArgs(); - parameters[i] = parameters[i].CastAs(context, target_type); + PlaceArguments(context, *functions.GetFunctionByOffset(entry.GetIndex()), positional_arguments, named_arguments, + parameters, named_parameters); + return entry; +} + +optional_idx FunctionBinder::BindTableInOutFunction(const Identifier &name, const TableFunctionSet &functions, + const vector &input_types, ErrorData &error) { + return BindFunctionFromArguments(name, functions, input_types, {}, error); +} + +optional_idx FunctionBinder::BindFunction(const Identifier &name, const PragmaFunctionSet &functions, + vector> &positional_arguments, + vector>> &named_arguments, + vector ¶meters, named_argument_map_t &named_parameters, + ErrorData &error) { + VerifyNamedArgumentsAccepted(name, functions, named_arguments); + auto [args, kwargs] = GetArgumentsFromExpressions(positional_arguments, named_arguments); + auto entry = BindFunctionFromArguments(name, functions, args, kwargs, error); + if (!entry.IsValid()) { + error.Throw(); } + PlaceArguments(context, *functions.GetFunctionByOffset(entry.GetIndex()), positional_arguments, named_arguments, + parameters, named_parameters); return entry; } @@ -519,24 +697,6 @@ optional_idx FunctionBinder::BindFunction(const Identifier &name, const TableFun return BindFunctionFromArguments(name, functions, args, kwargs, error); } -enum class LogicalTypeComparisonResult : uint8_t { IDENTICAL_TYPE, TARGET_IS_ANY, DIFFERENT_TYPES }; - -static LogicalTypeComparisonResult RequiresCast(const LogicalType &source_type, const LogicalType &target_type) { - if (target_type.id() == LogicalTypeId::ANY) { - return LogicalTypeComparisonResult::TARGET_IS_ANY; - } - if (source_type == target_type) { - return LogicalTypeComparisonResult::IDENTICAL_TYPE; - } - if (source_type.id() == LogicalTypeId::LIST && target_type.id() == LogicalTypeId::LIST) { - return RequiresCast(ListType::GetChildType(source_type), ListType::GetChildType(target_type)); - } - if (source_type.id() == LogicalTypeId::ARRAY && target_type.id() == LogicalTypeId::ARRAY) { - return RequiresCast(ArrayType::GetChildType(source_type), ArrayType::GetChildType(target_type)); - } - return LogicalTypeComparisonResult::DIFFERENT_TYPES; -} - static bool TypeRequiresPrepare(const LogicalType &type) { if (type.id() == LogicalTypeId::ANY) { return true; @@ -1011,8 +1171,8 @@ static vector ResolveArguments(const SimpleFunction &function, Bound vector>> &named_arguments) { const auto &sig = function.GetSignature(); const auto positional_count = sig.GetPositionalParameterCount(); - const auto args_param = sig.GetArgsParameter(); - const auto kwargs_param = sig.GetKwargsParameter(); + const auto args_param = sig.GetArgs(); + const auto kwargs_param = sig.GetKwargs(); // The arguments that were passed by position auto positional_arguments = std::move(arguments); @@ -1051,7 +1211,7 @@ static vector ResolveArguments(const SimpleFunction &function, Bound } const auto param_idx = opt_param_idx.GetIndex(); - if (sig.GetParameter(param_idx).GetKind() == FunctionParameterKind::STANDARD && param_idx < passed_count) { + if (sig.GetParameter(param_idx).AcceptsPosition() && param_idx < passed_count) { throw BinderException(location, "Named argument '%s' cannot be used for parameter '%s' because it has already " "been provided as a positional argument in function call to '%s'", @@ -1092,7 +1252,7 @@ static vector ResolveArguments(const SimpleFunction &function, Bound break; } - if (param.GetKind() == FunctionParameterKind::STANDARD && param_idx < passed_count) { + if (param.AcceptsPosition() && param_idx < passed_count) { add_argument(std::move(positional_arguments[param_idx]), param.GetName()); } else if (keyword_arguments[param_idx]) { add_argument(std::move(keyword_arguments[param_idx]), param.GetName()); diff --git a/src/duckdb/src/function/pragma/pragma_queries.cpp b/src/duckdb/src/function/pragma/pragma_queries.cpp index 688199e4b..333ee91cf 100644 --- a/src/duckdb/src/function/pragma/pragma_queries.cpp +++ b/src/duckdb/src/function/pragma/pragma_queries.cpp @@ -216,23 +216,29 @@ static string PragmaUserAgent(ClientContext &context, const FunctionParameters & } void PragmaQueries::RegisterFunction(BuiltinFunctions &set) { - set.AddFunction(PragmaFunction::PragmaCall("table_info", PragmaTableInfo, {LogicalType::VARCHAR})); - set.AddFunction(PragmaFunction::PragmaCall("storage_info", PragmaStorageInfo, {LogicalType::VARCHAR})); + set.AddFunction(PragmaFunction::PragmaCall( + "table_info", PragmaTableInfo, FunctionSignature().AddPositionalOnly("table_name", LogicalType::VARCHAR))); + set.AddFunction(PragmaFunction::PragmaCall( + "storage_info", PragmaStorageInfo, FunctionSignature().AddPositionalOnly("table_name", LogicalType::VARCHAR))); set.AddFunction(PragmaFunction::PragmaCall("metadata_info", PragmaMetadataInfo, {})); set.AddFunction(PragmaFunction::PragmaStatement("show_tables", PragmaShowTables)); set.AddFunction(PragmaFunction::PragmaStatement("show_tables_expanded", PragmaShowTablesExpanded)); set.AddFunction(PragmaFunction::PragmaStatement("show_databases", PragmaShowDatabases)); set.AddFunction(PragmaFunction::PragmaStatement("database_list", PragmaDatabaseList)); set.AddFunction(PragmaFunction::PragmaStatement("collations", PragmaCollations)); - set.AddFunction(PragmaFunction::PragmaCall("show", PragmaShow, {LogicalType::VARCHAR})); + set.AddFunction(PragmaFunction::PragmaCall( + "show", PragmaShow, FunctionSignature().AddPositionalOnly("table_name", LogicalType::VARCHAR))); set.AddFunction(PragmaFunction::PragmaStatement("version", PragmaVersion)); set.AddFunction(PragmaFunction::PragmaStatement("extension_versions", PragmaExtensionVersions)); set.AddFunction(PragmaFunction::PragmaStatement("platform", PragmaPlatform)); set.AddFunction(PragmaFunction::PragmaStatement("database_size", PragmaDatabaseSize)); set.AddFunction(PragmaFunction::PragmaStatement("functions", PragmaFunctionsQuery)); - set.AddFunction(PragmaFunction::PragmaCall("import_database", PragmaImportDatabase, {LogicalType::VARCHAR})); - set.AddFunction( - PragmaFunction::PragmaCall("copy_database", PragmaCopyDatabase, {LogicalType::VARCHAR, LogicalType::VARCHAR})); + set.AddFunction(PragmaFunction::PragmaCall("import_database", PragmaImportDatabase, + FunctionSignature().AddPositionalOnly("path", LogicalType::VARCHAR))); + set.AddFunction(PragmaFunction::PragmaCall("copy_database", PragmaCopyDatabase, + FunctionSignature() + .AddPositionalOnly("from_database", LogicalType::VARCHAR) + .AddPositionalOnly("to_database", LogicalType::VARCHAR))); set.AddFunction(PragmaFunction::PragmaStatement("user_agent", PragmaUserAgent)); } diff --git a/src/duckdb/src/function/pragma_function.cpp b/src/duckdb/src/function/pragma_function.cpp index 9208a906b..d97396846 100644 --- a/src/duckdb/src/function/pragma_function.cpp +++ b/src/duckdb/src/function/pragma_function.cpp @@ -3,9 +3,22 @@ namespace duckdb { +//! A pragma's varargs are a positional list, so it declares "*args" and never a "**kwargs" - an argument named after +//! no parameter stays an error rather than being absorbed +static FunctionSignature PragmaSignature(vector arguments, LogicalType varargs) { + FunctionSignature signature; + for (auto &argument : arguments) { + signature.AddParameter(std::move(argument)); + } + if (varargs.id() != LogicalTypeId::INVALID) { + signature.AddArgs("args", std::move(varargs)); + } + return signature; +} + PragmaFunction::PragmaFunction(Identifier name, PragmaType pragma_type, pragma_query_t query, pragma_function_t function, vector arguments, LogicalType varargs) - : SimpleNamedParameterFunction(std::move(name), std::move(arguments), std::move(varargs)), type(pragma_type), + : SimpleFunction(std::move(name), PragmaSignature(std::move(arguments), std::move(varargs))), type(pragma_type), query(query), function(function) { } @@ -19,6 +32,20 @@ PragmaFunction PragmaFunction::PragmaCall(const Identifier &name, pragma_functio return PragmaFunction(name, PragmaType::PRAGMA_CALL, nullptr, function, std::move(arguments), std::move(varargs)); } +PragmaFunction::PragmaFunction(Identifier name, PragmaType pragma_type, pragma_query_t query, + pragma_function_t function, FunctionSignature signature) + : SimpleFunction(std::move(name), std::move(signature)), type(pragma_type), query(query), function(function) { +} + +PragmaFunction PragmaFunction::PragmaCall(const Identifier &name, pragma_query_t query, FunctionSignature signature) { + return PragmaFunction(name, PragmaType::PRAGMA_CALL, query, nullptr, std::move(signature)); +} + +PragmaFunction PragmaFunction::PragmaCall(const Identifier &name, pragma_function_t function, + FunctionSignature signature) { + return PragmaFunction(name, PragmaType::PRAGMA_CALL, nullptr, function, std::move(signature)); +} + PragmaFunction PragmaFunction::PragmaStatement(const Identifier &name, pragma_query_t query) { vector types; return PragmaFunction(name, PragmaType::PRAGMA_STATEMENT, query, nullptr, std::move(types), LogicalType::INVALID); @@ -35,7 +62,7 @@ string PragmaFunction::ToString() const { case PragmaType::PRAGMA_STATEMENT: return StringUtil::Format("PRAGMA %s", name); case PragmaType::PRAGMA_CALL: { - return StringUtil::Format("PRAGMA %s", SimpleNamedParameterFunction::ToString()); + return StringUtil::Format("PRAGMA %s", SimpleFunction::ToString()); } default: return "UNKNOWN"; diff --git a/src/duckdb/src/function/scalar/create_sort_key.cpp b/src/duckdb/src/function/scalar/create_sort_key.cpp index cb2a6f647..6dffd4ee7 100644 --- a/src/duckdb/src/function/scalar/create_sort_key.cpp +++ b/src/duckdb/src/function/scalar/create_sort_key.cpp @@ -1490,7 +1490,7 @@ ScalarFunction CreateSortKeyFun::GetFunction() { ScalarFunction sort_key_function("create_sort_key", {LogicalType::ANY}, LogicalType::BLOB, CreateSortKeyFunction, CreateSortKeyBind); sort_key_function.GetSignature().GetParameter(0).SetName("key1"); - sort_key_function.GetSignature().AddArgsParameter("args", LogicalType::ANY); + sort_key_function.GetSignature().AddArgs("args", LogicalType::ANY); sort_key_function.SetNullHandling(FunctionNullHandling::SPECIAL_HANDLING); return sort_key_function; } @@ -1521,7 +1521,7 @@ ScalarFunction DecodeSortKeyFun::GetFunction() { "decode_sort_key", {{"sort_key", LogicalType::ANY}, {"col", LogicalType::VARCHAR}, {"sort_specifier", LogicalType::VARCHAR}}, LogicalType::STRUCT({{"any", LogicalType::ANY}}), DecodeSortKeyFunction, DecodeSortKeyBind); - sort_key_function.GetSignature().AddArgsParameter("args", LogicalType::VARCHAR); + sort_key_function.GetSignature().AddArgs("args", LogicalType::VARCHAR); return sort_key_function; } diff --git a/src/duckdb/src/function/scalar/generic/constant_or_null.cpp b/src/duckdb/src/function/scalar/generic/constant_or_null.cpp index e4025b173..ffd587661 100644 --- a/src/duckdb/src/function/scalar/generic/constant_or_null.cpp +++ b/src/duckdb/src/function/scalar/generic/constant_or_null.cpp @@ -96,7 +96,7 @@ ScalarFunction ConstantOrNullFun::GetFunction() { auto fun = ScalarFunction("constant_or_null", {}, LogicalType::ANY, ConstantOrNullFunction); fun.GetSignature().AddParameter("arg1", LogicalType::ANY).AddParameter("arg2", LogicalType::ANY); fun.SetBindCallback(ConstantOrNullBind); - fun.GetSignature().AddArgsParameter("args", LogicalType::ANY); + fun.GetSignature().AddArgs("args", LogicalType::ANY); return fun; } diff --git a/src/duckdb/src/function/scalar/generic/invoke.cpp b/src/duckdb/src/function/scalar/generic/invoke.cpp index 81652e17a..baa8f1d78 100644 --- a/src/duckdb/src/function/scalar/generic/invoke.cpp +++ b/src/duckdb/src/function/scalar/generic/invoke.cpp @@ -153,7 +153,7 @@ ScalarFunction InvokeFun::GetFunction() { ScalarFunction fun("invoke", {}, LogicalType::ANY, LambdaInvokeFunction); fun.GetSignature().AddParameter("lambda", LogicalType::LAMBDA).AddParameter("arg1", LogicalType::ANY); fun.SetBindCallback(LambdaInvokeBind); - fun.GetSignature().AddArgsParameter("args", LogicalType::ANY); + fun.GetSignature().AddArgs("args", LogicalType::ANY); fun.SetNullHandling(FunctionNullHandling::SPECIAL_HANDLING); fun.SetBindLambdaCallback(LambdaInvokeBindParameters); fun.SetInitStateCallback(LambdaInvokeState::Init); diff --git a/src/duckdb/src/function/scalar/list/list_zip.cpp b/src/duckdb/src/function/scalar/list/list_zip.cpp index 6ab736cd5..e7318989f 100644 --- a/src/duckdb/src/function/scalar/list/list_zip.cpp +++ b/src/duckdb/src/function/scalar/list/list_zip.cpp @@ -175,7 +175,7 @@ static unique_ptr ListZipBind(BindScalarFunctionInput &input) { ScalarFunction ListZipFun::GetFunction() { auto fun = ScalarFunction({}, LogicalType::LIST(LogicalTypeId::STRUCT), ListZipFunction, ListZipBind); - fun.GetSignature().AddArgsParameter("args", LogicalType::ANY); + fun.GetSignature().AddArgs("args", LogicalType::ANY); fun.SetNullHandling(FunctionNullHandling::SPECIAL_HANDLING); return fun; } diff --git a/src/duckdb/src/function/scalar/string/concat.cpp b/src/duckdb/src/function/scalar/string/concat.cpp index c08723677..d3b05040c 100644 --- a/src/duckdb/src/function/scalar/string/concat.cpp +++ b/src/duckdb/src/function/scalar/string/concat.cpp @@ -341,7 +341,7 @@ ScalarFunction ListConcatFun::GetFunction() { // The arguments and return types are set in the binder function. auto fun = ScalarFunction({}, LogicalType::LIST(LogicalType::ANY), ConcatFunction, BindConcatFunction, ListConcatStats); - fun.GetSignature().AddArgsParameter("args", LogicalType::LIST(LogicalType::ANY)); + fun.GetSignature().AddArgs("args", LogicalType::LIST(LogicalType::ANY)); fun.SetNullHandling(FunctionNullHandling::SPECIAL_HANDLING); return fun; } @@ -357,7 +357,7 @@ ScalarFunction ListConcatFun::GetFunction() { ScalarFunction ConcatFun::GetFunction() { ScalarFunction concat = ScalarFunction("concat", {}, LogicalType::ANY, ConcatFunction, BindConcatFunction); concat.GetSignature().AddParameter("value", LogicalType::ANY); - concat.GetSignature().AddArgsParameter("args", LogicalType::ANY); + concat.GetSignature().AddArgs("args", LogicalType::ANY); concat.SetNullHandling(FunctionNullHandling::SPECIAL_HANDLING); return concat; } diff --git a/src/duckdb/src/function/scalar/string/concat_ws.cpp b/src/duckdb/src/function/scalar/string/concat_ws.cpp index 6a86059ba..f19c923a8 100644 --- a/src/duckdb/src/function/scalar/string/concat_ws.cpp +++ b/src/duckdb/src/function/scalar/string/concat_ws.cpp @@ -170,7 +170,7 @@ ScalarFunction ConcatWsFun::GetFunction() { ScalarFunction concat_ws = ScalarFunction("concat_ws", {}, LogicalType::VARCHAR, ConcatWSFunction, BindConcatWSFunction); concat_ws.GetSignature().AddParameter("separator", LogicalType::VARCHAR).AddParameter("string", LogicalType::ANY); - concat_ws.GetSignature().AddArgsParameter("args", LogicalType::ANY); + concat_ws.GetSignature().AddArgs("args", LogicalType::ANY); concat_ws.SetNullHandling(FunctionNullHandling::SPECIAL_HANDLING); return ScalarFunction(concat_ws); } diff --git a/src/duckdb/src/function/scalar/string/path_join.cpp b/src/duckdb/src/function/scalar/string/path_join.cpp index 15a356da2..3790786de 100644 --- a/src/duckdb/src/function/scalar/string/path_join.cpp +++ b/src/duckdb/src/function/scalar/string/path_join.cpp @@ -69,7 +69,7 @@ void PathJoinFunction(DataChunk &args, ExpressionState &state, Vector &result) { ScalarFunction PathJoinFun::GetFunction() { ScalarFunction path_join(PathJoinFun::Name, {}, LogicalType::VARCHAR, PathJoinFunction); path_join.GetSignature().AddParameter("path", LogicalType::VARCHAR); - path_join.GetSignature().AddArgsParameter("args", LogicalType::VARCHAR); + path_join.GetSignature().AddArgs("args", LogicalType::VARCHAR); path_join.SetNullHandling(FunctionNullHandling::DEFAULT_NULL_HANDLING); // throws if the paths that are joined are incompatible path_join.SetFallible(); diff --git a/src/duckdb/src/function/scalar/struct/struct_concat.cpp b/src/duckdb/src/function/scalar/struct/struct_concat.cpp index a51129a3a..2013b591d 100644 --- a/src/duckdb/src/function/scalar/struct/struct_concat.cpp +++ b/src/duckdb/src/function/scalar/struct/struct_concat.cpp @@ -103,7 +103,7 @@ static unique_ptr StructConcatStats(ClientContext &context, Func ScalarFunction StructConcatFun::GetFunction() { ScalarFunction fun("struct_concat", {}, LogicalTypeId::STRUCT, StructConcatFunction, StructConcatBind, StructConcatStats); - fun.GetSignature().AddArgsParameter("args", LogicalType::ANY); + fun.GetSignature().AddArgs("args", LogicalType::ANY); fun.SetNullHandling(FunctionNullHandling::SPECIAL_HANDLING); return fun; } diff --git a/src/duckdb/src/function/scalar/struct/struct_pack.cpp b/src/duckdb/src/function/scalar/struct/struct_pack.cpp index 7ebeee975..6a05cec46 100644 --- a/src/duckdb/src/function/scalar/struct/struct_pack.cpp +++ b/src/duckdb/src/function/scalar/struct/struct_pack.cpp @@ -99,11 +99,11 @@ static ScalarFunction GetStructPackFunction() { // struct_pack derives its field names from argument aliases, so the binder must capture argument expression // aliases as named-argument names. This also preserves the legacy behavior of allowing positional arguments // after named ones (the positional arguments simply take their expression's name as the field name). - fun.GetSignature().AddKwargsParameter("kwargs", LogicalType::ANY); + fun.GetSignature().AddKwargs("kwargs", LogicalType::ANY); fun.SetCaptureArgumentAliases(true); } else { // row produces an unnamed TUPLE, so it ignores the names of its arguments - fun.GetSignature().AddArgsParameter("args", LogicalType::ANY); + fun.GetSignature().AddArgs("args", LogicalType::ANY); } fun.SetNullHandling(FunctionNullHandling::SPECIAL_HANDLING); diff --git a/src/duckdb/src/function/scalar/system/write_log.cpp b/src/duckdb/src/function/scalar/system/write_log.cpp index af6a55c31..78c454354 100644 --- a/src/duckdb/src/function/scalar/system/write_log.cpp +++ b/src/duckdb/src/function/scalar/system/write_log.cpp @@ -171,7 +171,7 @@ ScalarFunctionSet WriteLogFun::GetFunctions() { ScalarFunction fun({{"string", LogicalType::VARCHAR}}, LogicalType::ANY, WriteLogFunction, WriteLogBind, nullptr, nullptr, LogicalType(LogicalTypeId::INVALID), FunctionStability::VOLATILE); - fun.GetSignature().AddKwargsParameter("kwargs", LogicalType::ANY); + fun.GetSignature().AddKwargs("kwargs", LogicalType::ANY); fun.GetProperties().SetRequiresExpressionNames(true); fun.SetUnbindCallback(WriteLogUnbind); set.AddFunction(std::move(fun)); diff --git a/src/duckdb/src/function/scalar_function.cpp b/src/duckdb/src/function/scalar_function.cpp index 06daf1ad0..6cc03f145 100644 --- a/src/duckdb/src/function/scalar_function.cpp +++ b/src/duckdb/src/function/scalar_function.cpp @@ -76,7 +76,10 @@ ScalarFunction::ScalarFunction(Identifier name, std::initializer_list= 1); result.Reference(input.data[0]); diff --git a/src/duckdb/src/function/table/checkpoint.cpp b/src/duckdb/src/function/table/checkpoint.cpp index 3dd2474ed..a59e3dd9d 100644 --- a/src/duckdb/src/function/table/checkpoint.cpp +++ b/src/duckdb/src/function/table/checkpoint.cpp @@ -56,13 +56,14 @@ static void TemplatedCheckpointFunction(ClientContext &context, TableFunctionInp void CheckpointFunction::RegisterFunction(BuiltinFunctions &set) { TableFunctionSet checkpoint("checkpoint"); checkpoint.AddFunction(TableFunction({}, TemplatedCheckpointFunction, CheckpointBind)); - checkpoint.AddFunction(TableFunction({LogicalType::VARCHAR}, TemplatedCheckpointFunction, CheckpointBind)); + checkpoint.AddFunction(TableFunction(FunctionSignature().AddPositionalOnly("database", LogicalType::VARCHAR), + TemplatedCheckpointFunction, CheckpointBind)); set.AddFunction(checkpoint); TableFunctionSet force_checkpoint("force_checkpoint"); force_checkpoint.AddFunction(TableFunction({}, TemplatedCheckpointFunction, CheckpointBind)); - force_checkpoint.AddFunction( - TableFunction({LogicalType::VARCHAR}, TemplatedCheckpointFunction, CheckpointBind)); + force_checkpoint.AddFunction(TableFunction(FunctionSignature().AddPositionalOnly("database", LogicalType::VARCHAR), + TemplatedCheckpointFunction, CheckpointBind)); set.AddFunction(force_checkpoint); } diff --git a/src/duckdb/src/function/table/glob.cpp b/src/duckdb/src/function/table/glob.cpp index ed269d241..1bf3f3164 100644 --- a/src/duckdb/src/function/table/glob.cpp +++ b/src/duckdb/src/function/table/glob.cpp @@ -83,7 +83,8 @@ static double GlobFunctionProgress(ClientContext &context, const FunctionData *b } void GlobTableFunction::RegisterFunction(BuiltinFunctions &set) { - TableFunction glob_function("glob", {LogicalType::VARCHAR}, GlobFunction, GlobFunctionBind, GlobFunctionInit); + TableFunction glob_function("glob", FunctionSignature().AddPositionalOnly("pattern", LogicalType::VARCHAR), + GlobFunction, GlobFunctionBind, GlobFunctionInit); glob_function.table_scan_progress = GlobFunctionProgress; set.AddFunction(MultiFileReader::CreateFunctionSet(glob_function)); } diff --git a/src/duckdb/src/function/table/query_function.cpp b/src/duckdb/src/function/table/query_function.cpp index a429f49c7..02784ea2a 100644 --- a/src/duckdb/src/function/table/query_function.cpp +++ b/src/duckdb/src/function/table/query_function.cpp @@ -96,19 +96,26 @@ static unique_ptr TableBindReplace(ClientContext &context, TableFuncti } void QueryTableFunction::RegisterFunction(BuiltinFunctions &set) { - TableFunction query("query", {LogicalType::VARCHAR}, nullptr, nullptr); + TableFunction query("query", FunctionSignature().AddPositionalOnly("query", LogicalType::VARCHAR), nullptr, + nullptr); query.bind_replace = QueryBindReplace; set.AddFunction(query); TableFunctionSet query_table("query_table"); - TableFunction query_table_function({LogicalType::VARCHAR}, nullptr, nullptr); + TableFunction query_table_function(FunctionSignature().AddPositionalOnly("table_name", LogicalType::VARCHAR), + nullptr, nullptr); query_table_function.bind_replace = TableBindReplace; query_table.AddFunction(query_table_function); - query_table_function.GetArguments() = {LogicalType::LIST(LogicalType::VARCHAR)}; + query_table_function.GetSignature() = + FunctionSignature().AddPositionalOnly("table_names", LogicalType::LIST(LogicalType::VARCHAR)); query_table.AddFunction(query_table_function); - // add by_name option - query_table_function.GetArguments().emplace_back(LogicalType::BOOLEAN); + // add by_name option, for a single table name as well as for a list of them + query_table_function.GetSignature().AddPositionalOnly("by_name", LogicalType::BOOLEAN); + query_table.AddFunction(query_table_function); + query_table_function.GetSignature() = FunctionSignature() + .AddPositionalOnly("table_name", LogicalType::VARCHAR) + .AddPositionalOnly("by_name", LogicalType::BOOLEAN); query_table.AddFunction(query_table_function); set.AddFunction(query_table); } diff --git a/src/duckdb/src/function/table/range.cpp b/src/duckdb/src/function/table/range.cpp index 353a0124a..8af91754c 100644 --- a/src/duckdb/src/function/table/range.cpp +++ b/src/duckdb/src/function/table/range.cpp @@ -478,7 +478,18 @@ static bool RangeIsRepeatable(optional_ptr) { void RangeTableFunction::RegisterFunction(BuiltinFunctions &set) { TableFunctionSet range("range"); - TableFunction range_function({LogicalType::BIGINT}, nullptr, RangeFunctionBind, RangeFunctionGlobalInit, + const auto stop_only = FunctionSignature().AddPositionalOnly("stop", LogicalType::BIGINT); + const auto start_stop = FunctionSignature() + .AddPositionalOnly("start", LogicalType::BIGINT) + .AddPositionalOnly("stop", LogicalType::BIGINT); + auto start_stop_step = start_stop; + start_stop_step.AddPositionalOnly("step", LogicalType::BIGINT); + const auto timestamps = FunctionSignature() + .AddPositionalOnly("start", LogicalType::TIMESTAMP) + .AddPositionalOnly("stop", LogicalType::TIMESTAMP) + .AddPositionalOnly("step", LogicalType::INTERVAL); + + TableFunction range_function(stop_only, nullptr, RangeFunctionBind, RangeFunctionGlobalInit, RangeFunctionLocalInit); range_function.table_scan_progress = RangeFunctionProgress; range_function.in_out_function = RangeFunction; @@ -490,13 +501,13 @@ void RangeTableFunction::RegisterFunction(BuiltinFunctions &set) { // single argument range: (end) - implicit start = 0 and increment = 1 range.AddFunction(range_function); // two arguments range: (start, end) - implicit increment = 1 - range_function.GetArguments() = {LogicalType::BIGINT, LogicalType::BIGINT}; + range_function.GetSignature() = start_stop; range.AddFunction(range_function); // three arguments range: (start, end, increment) - range_function.GetArguments() = {LogicalType::BIGINT, LogicalType::BIGINT, LogicalType::BIGINT}; + range_function.GetSignature() = start_stop_step; range.AddFunction(range_function); - TableFunction range_in_out({LogicalType::TIMESTAMP, LogicalType::TIMESTAMP, LogicalType::INTERVAL}, nullptr, - RangeDateTimeBind, RangeDateTimeGlobalInit, RangeDateTimeLocalInit); + TableFunction range_in_out(timestamps, nullptr, RangeDateTimeBind, RangeDateTimeGlobalInit, + RangeDateTimeLocalInit); range_in_out.table_scan_progress = RangeDateTimeProgress; range_in_out.in_out_function = RangeDateTimeFunction; range_in_out.cardinality = RangeDateTimeCardinality; @@ -510,14 +521,13 @@ void RangeTableFunction::RegisterFunction(BuiltinFunctions &set) { range_function.bind = RangeFunctionBind; range_function.in_out_function = RangeFunction; range_function.return_type = TableFunctionReturnType::SET_RETURNING_FUNCTION; - range_function.GetArguments() = {LogicalType::BIGINT}; + range_function.GetSignature() = stop_only; generate_series.AddFunction(range_function); - range_function.GetArguments() = {LogicalType::BIGINT, LogicalType::BIGINT}; + range_function.GetSignature() = start_stop; generate_series.AddFunction(range_function); - range_function.GetArguments() = {LogicalType::BIGINT, LogicalType::BIGINT, LogicalType::BIGINT}; + range_function.GetSignature() = start_stop_step; generate_series.AddFunction(range_function); - TableFunction generate_series_in_out({LogicalType::TIMESTAMP, LogicalType::TIMESTAMP, LogicalType::INTERVAL}, - nullptr, RangeDateTimeBind, RangeDateTimeGlobalInit, + TableFunction generate_series_in_out(timestamps, nullptr, RangeDateTimeBind, RangeDateTimeGlobalInit, RangeDateTimeLocalInit); generate_series_in_out.table_scan_progress = RangeDateTimeProgress; generate_series_in_out.in_out_function = RangeDateTimeFunction; diff --git a/src/duckdb/src/function/table/read_csv.cpp b/src/duckdb/src/function/table/read_csv.cpp index 18d2860b4..3512dfef3 100644 --- a/src/duckdb/src/function/table/read_csv.cpp +++ b/src/duckdb/src/function/table/read_csv.cpp @@ -58,59 +58,59 @@ void ReadCSVData::FinalizeRead(ClientContext &context) { } void ReadCSVTableFunction::ReadCSVAddNamedParameters(TableFunction &table_function) { - table_function.named_parameters["sep"] = LogicalType::VARCHAR; - table_function.named_parameters["delim"] = LogicalType::VARCHAR; - // aliases that the CSV options accept - COPY has always taken these, so the table function takes them too - table_function.named_parameters["separator"] = LogicalType::VARCHAR; - table_function.named_parameters["delimiter"] = LogicalType::VARCHAR; - table_function.named_parameters["null"] = LogicalType::ANY; - table_function.named_parameters["date_format"] = LogicalType::VARCHAR; - table_function.named_parameters["timestamp_format"] = LogicalType::VARCHAR; - table_function.named_parameters["quote"] = LogicalType::VARCHAR; - table_function.named_parameters["new_line"] = LogicalType::VARCHAR; - table_function.named_parameters["escape"] = LogicalType::VARCHAR; - table_function.named_parameters["nullstr"] = LogicalType::ANY; - table_function.named_parameters["columns"] = LogicalType::ANY; - table_function.named_parameters["auto_type_candidates"] = LogicalType::ANY; - table_function.named_parameters["header"] = LogicalType::BOOLEAN; - table_function.named_parameters["auto_detect"] = LogicalType::BOOLEAN; - table_function.named_parameters["sample_size"] = LogicalType::BIGINT; - table_function.named_parameters["all_varchar"] = LogicalType::BOOLEAN; - table_function.named_parameters["dateformat"] = LogicalType::VARCHAR; - table_function.named_parameters["timestampformat"] = LogicalType::VARCHAR; - table_function.named_parameters["normalize_names"] = LogicalType::BOOLEAN; - table_function.named_parameters["compression"] = LogicalType::VARCHAR; - table_function.named_parameters["skip"] = LogicalType::BIGINT; - table_function.named_parameters["max_line_size"] = LogicalType::VARCHAR; - table_function.named_parameters["maximum_line_size"] = LogicalType::VARCHAR; - table_function.named_parameters["ignore_errors"] = LogicalType::BOOLEAN; - table_function.named_parameters["store_rejects"] = LogicalType::BOOLEAN; - table_function.named_parameters["rejects_table"] = LogicalType::VARCHAR; - table_function.named_parameters["rejects_scan"] = LogicalType::VARCHAR; - table_function.named_parameters["rejects_limit"] = LogicalType::BIGINT; - table_function.named_parameters["rejects_line_size_limit"] = LogicalType::BIGINT; - table_function.named_parameters["force_not_null"] = LogicalType::LIST(LogicalType::VARCHAR); - table_function.named_parameters["buffer_size"] = LogicalType::UBIGINT; - table_function.named_parameters["decimal_separator"] = LogicalType::VARCHAR; - table_function.named_parameters["parallel"] = LogicalType::BOOLEAN; - table_function.named_parameters["null_padding"] = LogicalType::BOOLEAN; - table_function.named_parameters["allow_quoted_nulls"] = LogicalType::BOOLEAN; - table_function.named_parameters["column_types"] = LogicalType::ANY; - table_function.named_parameters["dtypes"] = LogicalType::ANY; - table_function.named_parameters["types"] = LogicalType::ANY; - table_function.named_parameters["names"] = LogicalType::LIST(LogicalType::VARCHAR); - table_function.named_parameters["column_names"] = LogicalType::LIST(LogicalType::VARCHAR); - table_function.named_parameters["comment"] = LogicalType::VARCHAR; - table_function.named_parameters["encoding"] = LogicalType::VARCHAR; - table_function.named_parameters["strict_mode"] = LogicalType::BOOLEAN; - table_function.named_parameters["thousands"] = LogicalType::VARCHAR; - table_function.named_parameters["files_to_sniff"] = LogicalType::BIGINT; - - MultiFileReader::AddParameters(table_function); + // the reader keeps the default of every option in CSVReaderOptions - an option the call leaves out is not passed + table_function.GetSignature().WithTypedKwargs("options", [](TypedKwargs &options) { + options.Add("sep", LogicalType::VARCHAR) + .Add("delim", LogicalType::VARCHAR) + .Add("separator", LogicalType::VARCHAR) + .Add("delimiter", LogicalType::VARCHAR) + .Add("null", LogicalType::ANY) + .Add("date_format", LogicalType::VARCHAR) + .Add("timestamp_format", LogicalType::VARCHAR) + .Add("quote", LogicalType::VARCHAR) + .Add("new_line", LogicalType::VARCHAR) + .Add("escape", LogicalType::VARCHAR) + .Add("nullstr", LogicalType::ANY) + .Add("columns", LogicalType::ANY) + .Add("auto_type_candidates", LogicalType::ANY) + .Add("header", LogicalType::BOOLEAN) + .Add("auto_detect", LogicalType::BOOLEAN) + .Add("sample_size", LogicalType::BIGINT) + .Add("all_varchar", LogicalType::BOOLEAN) + .Add("dateformat", LogicalType::VARCHAR) + .Add("timestampformat", LogicalType::VARCHAR) + .Add("normalize_names", LogicalType::BOOLEAN) + .Add("compression", LogicalType::VARCHAR) + .Add("skip", LogicalType::BIGINT) + .Add("max_line_size", LogicalType::BIGINT) + .Add("maximum_line_size", LogicalType::BIGINT) + .Add("ignore_errors", LogicalType::BOOLEAN) + .Add("store_rejects", LogicalType::BOOLEAN) + .Add("rejects_table", LogicalType::VARCHAR) + .Add("rejects_scan", LogicalType::VARCHAR) + .Add("rejects_limit", LogicalType::BIGINT) + .Add("rejects_line_size_limit", LogicalType::BIGINT) + .Add("force_not_null", LogicalType::LIST(LogicalType::VARCHAR)) + .Add("buffer_size", LogicalType::BIGINT) + .Add("decimal_separator", LogicalType::VARCHAR) + .Add("parallel", LogicalType::BOOLEAN) + .Add("null_padding", LogicalType::BOOLEAN) + .Add("allow_quoted_nulls", LogicalType::BOOLEAN) + .Add("column_types", LogicalType::ANY) + .Add("dtypes", LogicalType::ANY) + .Add("types", LogicalType::ANY) + .Add("names", LogicalType::LIST(LogicalType::VARCHAR)) + .Add("column_names", LogicalType::LIST(LogicalType::VARCHAR)) + .Add("comment", LogicalType::VARCHAR) + .Add("encoding", LogicalType::VARCHAR) + .Add("strict_mode", LogicalType::BOOLEAN) + .Add("thousands", LogicalType::VARCHAR) + .Add("files_to_sniff", LogicalType::BIGINT); + }); } static void CSVReaderSerialize(Serializer &serializer, const optional_ptr bind_data_p, - const TableFunction &function) { + const BoundTableFunction &function) { throw NotImplementedException("CSVReaderSerialize not implemented"); // auto &bind_data = bind_data_p->Cast(); // auto &csv_data = bind_data.bind_data->Cast(); @@ -127,7 +127,7 @@ static void CSVReaderSerialize(Serializer &serializer, const optional_ptr CSVReaderDeserialize(Deserializer &deserializer, TableFunction &function) { +static unique_ptr CSVReaderDeserialize(Deserializer &deserializer, BoundTableFunction &function) { throw NotImplementedException("CSVReaderDeserialize not implemented"); // auto &context = deserializer.Get(); // SerializedReadCSVData serialized_data; diff --git a/src/duckdb/src/function/table/read_duckdb.cpp b/src/duckdb/src/function/table/read_duckdb.cpp index 9687387cb..d8d1298b5 100644 --- a/src/duckdb/src/function/table/read_duckdb.cpp +++ b/src/duckdb/src/function/table/read_duckdb.cpp @@ -499,10 +499,10 @@ void DuckDBMultiFileInfo::GetVirtualColumns(ClientContext &, MultiFileBindData & } void ReadDuckDBAddNamedParameters(TableFunction &table_function) { - table_function.named_parameters["schema_name"] = LogicalType::VARCHAR; - table_function.named_parameters["table_name"] = LogicalType::VARCHAR; - - MultiFileReader::AddParameters(table_function); + // extends the options MultiFileFunction declares + table_function.GetSignature().ExtendTypedKwargs([](TypedKwargs &options) { + options.Add("schema_name", LogicalType::VARCHAR).Add("table_name", LogicalType::VARCHAR); + }); } static vector DuckDBGetRowIdColumns(ClientContext &, optional_ptr) { diff --git a/src/duckdb/src/function/table/read_file.cpp b/src/duckdb/src/function/table/read_file.cpp index f5b423354..2b536e9f8 100644 --- a/src/duckdb/src/function/table/read_file.cpp +++ b/src/duckdb/src/function/table/read_file.cpp @@ -187,13 +187,9 @@ struct ReadTextOperation { template static TableFunction GetFunction() { - MultiFileFunction> table_function(OP::NAME); - // Erase extra multi file reader options - table_function.named_parameters.erase("filename"); - table_function.named_parameters.erase("hive_partitioning"); - table_function.named_parameters.erase("union_by_name"); - table_function.named_parameters.erase("hive_types"); - table_function.named_parameters.erase("hive_types_autocast"); + // this function reads one file per call, so it takes none of the options that describe combining several + MultiFileFunction> table_function(OP::NAME, + MultiFileReader::MultiFileParameters::ALLOW_EMPTY_ONLY); return table_function; } diff --git a/src/duckdb/src/function/table/repeat.cpp b/src/duckdb/src/function/table/repeat.cpp index e049f5b63..ff9384d53 100644 --- a/src/duckdb/src/function/table/repeat.cpp +++ b/src/duckdb/src/function/table/repeat.cpp @@ -65,7 +65,11 @@ static unique_ptr RepeatCardinality(ClientContext &context, cons } void RepeatTableFunction::RegisterFunction(BuiltinFunctions &set) { - TableFunction repeat("repeat", {LogicalType::ANY, LogicalType::BIGINT}, RepeatFunction, RepeatBind, RepeatInit); + TableFunction repeat("repeat", + FunctionSignature() + .AddPositionalOnly("value", LogicalType::ANY) + .AddPositionalOnly("count", LogicalType::BIGINT), + RepeatFunction, RepeatBind, RepeatInit); repeat.cardinality = RepeatCardinality; repeat.table_scan_progress = RepeatProgress; set.AddFunction(repeat); diff --git a/src/duckdb/src/function/table/repeat_row.cpp b/src/duckdb/src/function/table/repeat_row.cpp index fe1f16fad..d61d00596 100644 --- a/src/duckdb/src/function/table/repeat_row.cpp +++ b/src/duckdb/src/function/table/repeat_row.cpp @@ -26,17 +26,14 @@ static unique_ptr RepeatRowBind(ClientContext &context, TableFunct return_types.push_back(inputs[input_idx].type()); names.emplace_back("column" + std::to_string(input_idx)); } - auto entry = input.named_parameters.find("num_rows"); - if (entry == input.named_parameters.end()) { - throw BinderException("repeat_rows requires num_rows to be specified"); - } + auto &num_rows = input.named_parameters.at("num_rows"); if (inputs.empty()) { throw BinderException("repeat_rows requires at least one column to be specified"); } - if (entry->second.IsNull()) { + if (num_rows.IsNull()) { throw BinderException("num_rows should be an integer value >= 0"); } - auto repeat_rows = entry->second.GetValue(); + auto repeat_rows = num_rows.GetValue(); if (repeat_rows < 0) { throw BinderException("num_rows cannot be less than zero"); } @@ -77,8 +74,9 @@ static unique_ptr RepeatRowCardinality(ClientContext &context, c void RepeatRowTableFunction::RegisterFunction(BuiltinFunctions &set) { TableFunction repeat_row("repeat_row", {}, RepeatRowFunction, RepeatRowBind, RepeatRowInit); - repeat_row.SetVarArgs(LogicalType::ANY); - repeat_row.named_parameters["num_rows"] = LogicalType::BIGINT; + // a positional list, so it declares "*args" and no "**kwargs" - an argument named after no parameter is an error + repeat_row.GetSignature().AddArgs("args", LogicalType::ANY); + repeat_row.GetSignature().AddKeywordOnly("num_rows", LogicalType::BIGINT); repeat_row.cardinality = RepeatRowCardinality; repeat_row.table_scan_progress = RepeatRowProgress; set.AddFunction(repeat_row); diff --git a/src/duckdb/src/function/table/sniff_csv.cpp b/src/duckdb/src/function/table/sniff_csv.cpp index ff564a1dc..a4d30aedc 100644 --- a/src/duckdb/src/function/table/sniff_csv.cpp +++ b/src/duckdb/src/function/table/sniff_csv.cpp @@ -48,14 +48,17 @@ static unique_ptr CSVSniffBind(ClientContext &context, TableFuncti throw InvalidInputException("sniff_csv function does not accept auto_detect variable set to false"); } // otherwise remove it - input.named_parameters.erase("auto_detect"); + input.named_parameters.erase(it); } // If we want to force the match of the sniffer it = input.named_parameters.find("force_match"); if (it != input.named_parameters.end()) { + if (it->second.IsNull()) { + throw BinderException("\"%s\" expects a non-null boolean value (e.g. TRUE or 1)", it->first); + } result->force_match = it->second.GetValue(); - input.named_parameters.erase("force_match"); + input.named_parameters.erase(it); } MultiFileOptions file_options; result->options.FromNamedParameters(input.named_parameters, context, file_options); @@ -319,10 +322,13 @@ static void CSVSniffFunction(ClientContext &context, TableFunctionInput &data_p, } void CSVSnifferFunction::RegisterFunction(BuiltinFunctions &set) { - TableFunction csv_sniffer("sniff_csv", {LogicalType::VARCHAR}, CSVSniffFunction, CSVSniffBind, CSVSniffInitGlobal); + TableFunction csv_sniffer("sniff_csv", FunctionSignature().AddPositionalOnly("path", LogicalType::VARCHAR), + CSVSniffFunction, CSVSniffBind, CSVSniffInitGlobal); // Accept same options as the actual csv reader ReadCSVTableFunction::ReadCSVAddNamedParameters(csv_sniffer); - csv_sniffer.named_parameters["force_match"] = LogicalType::BOOLEAN; + MultiFileReader::AddParameters(csv_sniffer); + csv_sniffer.GetSignature().ExtendTypedKwargs( + [](TypedKwargs &options) { options.Add("force_match", LogicalType::BOOLEAN); }); set.AddFunction(csv_sniffer); } } // namespace duckdb diff --git a/src/duckdb/src/function/table/summary.cpp b/src/duckdb/src/function/table/summary.cpp index 8c93dfca8..8660cbe93 100644 --- a/src/duckdb/src/function/table/summary.cpp +++ b/src/duckdb/src/function/table/summary.cpp @@ -42,7 +42,8 @@ static OperatorResultType SummaryFunction(ExecutionContext &context, TableFuncti } void SummaryTableFunction::RegisterFunction(BuiltinFunctions &set) { - TableFunction summary_function("summary", {LogicalType::TABLE}, nullptr, SummaryFunctionBind); + TableFunction summary_function("summary", FunctionSignature().AddPositionalOnly("input", LogicalType::TABLE), + nullptr, SummaryFunctionBind); summary_function.in_out_function = SummaryFunction; set.AddFunction(summary_function); } diff --git a/src/duckdb/src/function/table/system/create_external_resource.cpp b/src/duckdb/src/function/table/system/create_external_resource.cpp index f848a3a5d..068d961eb 100644 --- a/src/duckdb/src/function/table/system/create_external_resource.cpp +++ b/src/duckdb/src/function/table/system/create_external_resource.cpp @@ -123,7 +123,12 @@ static unique_ptr CreateExternalResourceBind(ClientContext &contex } else if (key == "resource_name" && !np.second.IsNull()) { result->resource_name = StringValue::Get(np.second); } else if (key == "handle" && !np.second.IsNull()) { - result->adopt_handle = np.second; + // declared ANY so that a STRUCT of the handle's fields is accepted as readily as a MAP - anything + // that is not convertible to the handle's shape is reported here + result->adopt_handle = + np.second.type().id() == LogicalTypeId::MAP + ? np.second + : np.second.DefaultCastAs(LogicalType::MAP(LogicalType::VARCHAR, LogicalType::VARCHAR)); } else if (key == "teardown_on_failure" && !np.second.IsNull()) { result->teardown_on_failure = BooleanValue::Get(np.second); } else if (key == "timeout_seconds" && !np.second.IsNull()) { @@ -362,14 +367,16 @@ static void CreateExternalResourceFunction(ClientContext &context, TableFunction } void CreateExternalResourceFun::RegisterFunction(BuiltinFunctions &set) { - TableFunction fn("create_external_resource", {LogicalType::VARCHAR}, CreateExternalResourceFunction, - CreateExternalResourceBind, CreateExternalResourceInit); - fn.named_parameters["params"] = LogicalType::MAP(LogicalType::VARCHAR, LogicalType::VARCHAR); - fn.named_parameters["resource_name"] = LogicalType::VARCHAR; - fn.named_parameters["handle"] = LogicalType::MAP(LogicalType::VARCHAR, LogicalType::VARCHAR); - fn.named_parameters["teardown_on_failure"] = LogicalType::BOOLEAN; - fn.named_parameters["timeout_seconds"] = LogicalType::BIGINT; - fn.named_parameters["poll_interval_seconds"] = LogicalType::BIGINT; + TableFunction fn("create_external_resource", FunctionSignature().AddPositionalOnly("type", LogicalType::VARCHAR), + CreateExternalResourceFunction, CreateExternalResourceBind, CreateExternalResourceInit); + fn.GetSignature().WithTypedKwargs("options", [](TypedKwargs &options) { + options.Add("params", LogicalType::MAP(LogicalType::VARCHAR, LogicalType::VARCHAR)) + .Add("resource_name", LogicalType::VARCHAR) + .Add("handle", LogicalType::ANY) + .Add("teardown_on_failure", LogicalType::BOOLEAN) + .Add("timeout_seconds", LogicalType::BIGINT) + .Add("poll_interval_seconds", LogicalType::BIGINT); + }); set.AddFunction(fn); } @@ -437,7 +444,10 @@ static void DestroyExternalResourceFunction(ClientContext &context, TableFunctio } void DestroyExternalResourceFun::RegisterFunction(BuiltinFunctions &set) { - set.AddFunction(TableFunction("destroy_external_resource", {LogicalType::VARCHAR, LogicalType::ANY}, + set.AddFunction(TableFunction("destroy_external_resource", + FunctionSignature() + .AddPositionalOnly("deleter_function", LogicalType::VARCHAR) + .AddPositionalOnly("payload", LogicalType::ANY), DestroyExternalResourceFunction, DestroyExternalResourceBind, DestroyExternalResourceInit)); } diff --git a/src/duckdb/src/function/table/system/duckdb_functions.cpp b/src/duckdb/src/function/table/system/duckdb_functions.cpp index 240bc4639..112780a31 100644 --- a/src/duckdb/src/function/table/system/duckdb_functions.cpp +++ b/src/duckdb/src/function/table/system/duckdb_functions.cpp @@ -142,9 +142,9 @@ Value FunctionStabilityToValue(FunctionStability stability) { //! The legacy "varargs" column cannot tell "*args" and "**kwargs" apart - report whichever the function has Value VariadicTypeValue(const FunctionSignature &signature) { - auto variadic = signature.GetArgsParameter(); + auto variadic = signature.GetArgs(); if (!variadic) { - variadic = signature.GetKwargsParameter(); + variadic = signature.GetKwargs(); } return variadic ? Value(variadic->GetType().ToString()) : Value(); } @@ -465,6 +465,17 @@ struct TableMacroExtractor { } }; +//! The options a "**kwargs" parameter declares are listed after the parameters, as they are passed by name like them +static void AddOptions(const FunctionSignature &signature, vector &results, bool types) { + auto option_schema = signature.GetTypedKwargs(); + if (!option_schema) { + return; + } + for (auto &option : option_schema->GetOptions()) { + results.emplace_back(types ? Value(option.type.ToString()) : Value(option.name)); + } +} + struct TableFunctionExtractor { static idx_t FunctionCount(TableFunctionCatalogEntry &entry) { return entry.functions.Size(); @@ -481,12 +492,13 @@ struct TableFunctionExtractor { static vector GetParameters(TableFunctionCatalogEntry &entry, idx_t offset) { vector results; const auto &fun = *entry.functions.GetFunctionByOffset(offset); - for (idx_t i = 0; i < fun.GetArguments().size(); i++) { - results.emplace_back("col" + to_string(i)); - } - for (auto ¶m : fun.named_parameters) { - results.emplace_back(param.first); + // the variadic parameters are reported in the "varargs" column instead + for (auto ¶m : fun.GetSignature().GetParameters()) { + if (!param.IsVariadic()) { + results.emplace_back(param.GetName()); + } } + AddOptions(fun.GetSignature(), results, false); return results; } @@ -494,23 +506,28 @@ struct TableFunctionExtractor { vector results; const auto &fun = *entry.functions.GetFunctionByOffset(offset); - for (idx_t i = 0; i < fun.GetArguments().size(); i++) { - results.emplace_back(fun.GetArguments()[i].ToString()); - } - for (auto ¶m : fun.named_parameters) { - results.emplace_back(param.second.ToString()); + for (auto ¶m : fun.GetSignature().GetParameters()) { + if (!param.IsVariadic()) { + results.emplace_back(param.GetType().ToString()); + } } + AddOptions(fun.GetSignature(), results, true); return Value::LIST(LogicalType::VARCHAR, std::move(results)); } static vector GetParameterLogicalTypes(TableFunctionCatalogEntry &entry, idx_t offset) { - const auto &fun = *entry.functions.GetFunctionByOffset(offset); - return fun.GetArguments(); + const auto &signature = entry.functions.GetFunctionByOffset(offset)->GetSignature(); + vector result; + for (idx_t i = 0; i < signature.GetPositionalParameterCount(); i++) { + result.push_back(signature.GetParameter(i).GetType()); + } + return result; } static Value GetVarArgs(TableFunctionCatalogEntry &entry, idx_t offset) { const auto &fun = *entry.functions.GetFunctionByOffset(offset); - return !fun.HasVarArgs() ? Value() : Value(fun.GetVarArgs().ToString()); + auto args = fun.GetSignature().GetArgs(); + return args ? Value(args->GetType().ToString()) : Value(); } static Value GetMacroDefinition(TableFunctionCatalogEntry &entry, idx_t offset) { @@ -542,13 +559,13 @@ struct PragmaFunctionExtractor { static vector GetParameters(PragmaFunctionCatalogEntry &entry, idx_t offset) { vector results; const auto &fun = *entry.functions.GetFunctionByOffset(offset); - - for (idx_t i = 0; i < fun.GetArguments().size(); i++) { - results.emplace_back("col" + to_string(i)); - } - for (auto ¶m : fun.named_parameters) { - results.emplace_back(param.first); + // the variadic parameters are reported in the "varargs" column instead + for (auto ¶m : fun.GetSignature().GetParameters()) { + if (!param.IsVariadic()) { + results.emplace_back(param.GetName()); + } } + AddOptions(fun.GetSignature(), results, false); return results; } @@ -556,23 +573,29 @@ struct PragmaFunctionExtractor { vector results; const auto &fun = *entry.functions.GetFunctionByOffset(offset); - for (idx_t i = 0; i < fun.GetArguments().size(); i++) { - results.emplace_back(fun.GetArguments()[i].ToString()); - } - for (auto ¶m : fun.named_parameters) { - results.emplace_back(param.second.ToString()); + for (auto ¶m : fun.GetSignature().GetParameters()) { + if (!param.IsVariadic()) { + results.emplace_back(param.GetType().ToString()); + } } + AddOptions(fun.GetSignature(), results, true); return Value::LIST(LogicalType::VARCHAR, std::move(results)); } static vector GetParameterLogicalTypes(PragmaFunctionCatalogEntry &entry, idx_t offset) { const auto &fun = *entry.functions.GetFunctionByOffset(offset); - return fun.GetArguments(); + const auto &signature = fun.GetSignature(); + vector result; + for (idx_t i = 0; i < signature.GetPositionalParameterCount(); i++) { + result.push_back(signature.GetParameter(i).GetType()); + } + return result; } static Value GetVarArgs(PragmaFunctionCatalogEntry &entry, idx_t offset) { const auto &fun = *entry.functions.GetFunctionByOffset(offset); - return !fun.HasVarArgs() ? Value() : Value(fun.GetVarArgs().ToString()); + auto args = fun.GetSignature().GetArgs(); + return args ? Value(args->GetType().ToString()) : Value(); } static Value GetMacroDefinition(PragmaFunctionCatalogEntry &entry, idx_t offset) { diff --git a/src/duckdb/src/function/table/system/duckdb_log.cpp b/src/duckdb/src/function/table/system/duckdb_log.cpp index 9287bb4ca..fdb15323b 100644 --- a/src/duckdb/src/function/table/system/duckdb_log.cpp +++ b/src/duckdb/src/function/table/system/duckdb_log.cpp @@ -119,7 +119,8 @@ void DuckDBLogFun::RegisterFunction(BuiltinFunctions &set) { TableFunction logs_fun("duckdb_logs", {}, DuckDBLogFunction, DuckDBLogBind, DuckDBLogInit); logs_fun.bind_replace = DuckDBLogBindReplace; logs_fun.table_scan_progress = DuckDBLogProgress; - logs_fun.named_parameters["denormalized_table"] = LogicalType::BOOLEAN; + logs_fun.GetSignature().WithTypedKwargs( + "options", [](TypedKwargs &options) { options.Add("denormalized_table", LogicalType::BOOLEAN); }); set.AddFunction(logs_fun); } diff --git a/src/duckdb/src/function/table/system/duckdb_secrets.cpp b/src/duckdb/src/function/table/system/duckdb_secrets.cpp index 2361ac633..81c59b5a3 100644 --- a/src/duckdb/src/function/table/system/duckdb_secrets.cpp +++ b/src/duckdb/src/function/table/system/duckdb_secrets.cpp @@ -137,7 +137,8 @@ void DuckDBSecretsFunction(ClientContext &context, TableFunctionInput &data_p, D void DuckDBSecretsFun::RegisterFunction(BuiltinFunctions &set) { TableFunctionSet functions("duckdb_secrets"); auto fun = TableFunction({}, DuckDBSecretsFunction, DuckDBSecretsBind, DuckDBSecretsInit); - fun.named_parameters["redact"] = LogicalType::BOOLEAN; + fun.GetSignature().WithTypedKwargs("options", + [](TypedKwargs &options) { options.Add("redact", LogicalType::BOOLEAN); }); functions.AddFunction(fun); set.AddFunction(functions); } diff --git a/src/duckdb/src/function/table/system/duckdb_settings.cpp b/src/duckdb/src/function/table/system/duckdb_settings.cpp index a7d836b63..60abe9ce6 100644 --- a/src/duckdb/src/function/table/system/duckdb_settings.cpp +++ b/src/duckdb/src/function/table/system/duckdb_settings.cpp @@ -55,6 +55,12 @@ static unique_ptr DuckDBSettingsBind(ClientContext &context, Table return_types.emplace_back(LogicalType::VARIANT()); auto result = make_uniq(); + for (auto name : {"debug", "deprecated"}) { + auto it = input.named_parameters.find(name); + if (it != input.named_parameters.end() && it->second.IsNull()) { + throw InvalidInputException("Cannot use NULL as argument for %s", name); + } + } if (auto it = input.named_parameters.find("debug"); it != input.named_parameters.end()) { result->debug = it->second.GetValue(); } @@ -182,8 +188,9 @@ void DuckDBSettingsFunction(ClientContext &context, TableFunctionInput &data_p, void DuckDBSettingsFun::RegisterFunction(BuiltinFunctions &set) { TableFunction settings_fun("duckdb_settings", {}, DuckDBSettingsFunction, DuckDBSettingsBind, DuckDBSettingsInit); - settings_fun.named_parameters["debug"] = LogicalType::BOOLEAN; - settings_fun.named_parameters["deprecated"] = LogicalType::BOOLEAN; + settings_fun.GetSignature().WithTypedKwargs("options", [](TypedKwargs &options) { + options.Add("debug", LogicalType::BOOLEAN).Add("deprecated", LogicalType::BOOLEAN); + }); set.AddFunction(settings_fun); } diff --git a/src/duckdb/src/function/table/system/duckdb_types.cpp b/src/duckdb/src/function/table/system/duckdb_types.cpp index b6d07a40a..c4679a757 100644 --- a/src/duckdb/src/function/table/system/duckdb_types.cpp +++ b/src/duckdb/src/function/table/system/duckdb_types.cpp @@ -248,9 +248,9 @@ void DuckDBTypesFunction(ClientContext &context, TableFunctionInput &data_p, Dat } parameters.Append(Value::LIST(LogicalType::VARCHAR, std::move(parameter_names))); parameter_types.Append(Value::LIST(LogicalType::VARCHAR, std::move(parameter_type_names))); - auto variadic = signature.GetArgsParameter(); + auto variadic = signature.GetArgs(); if (!variadic) { - variadic = signature.GetKwargsParameter(); + variadic = signature.GetKwargs(); } // the legacy "varargs" column cannot tell "*args" and "**kwargs" apart varargs.Append(variadic ? Value(variadic->GetType().ToString()) : Value()); diff --git a/src/duckdb/src/function/table/system/duckdb_which_secret.cpp b/src/duckdb/src/function/table/system/duckdb_which_secret.cpp index fc326fa41..e4462e1e4 100644 --- a/src/duckdb/src/function/table/system/duckdb_which_secret.cpp +++ b/src/duckdb/src/function/table/system/duckdb_which_secret.cpp @@ -67,7 +67,10 @@ void DuckDBWhichSecretFunction(ClientContext &context, TableFunctionInput &data_ } void DuckDBWhichSecretFun::RegisterFunction(BuiltinFunctions &set) { - set.AddFunction(TableFunction("which_secret", {duckdb::LogicalType::VARCHAR, duckdb::LogicalType::VARCHAR}, + set.AddFunction(TableFunction("which_secret", + FunctionSignature() + .AddPositionalOnly("path", LogicalType::VARCHAR) + .AddPositionalOnly("type", LogicalType::VARCHAR), DuckDBWhichSecretFunction, DuckDBWhichSecretBind, DuckDBWhichSecretInit)); } diff --git a/src/duckdb/src/function/table/system/enable_profiling.cpp b/src/duckdb/src/function/table/system/enable_profiling.cpp index b1fd0984d..0b830beb6 100644 --- a/src/duckdb/src/function/table/system/enable_profiling.cpp +++ b/src/duckdb/src/function/table/system/enable_profiling.cpp @@ -3,6 +3,7 @@ #include "duckdb/main/settings.hpp" #include "duckdb/common/file_system.hpp" #include "duckdb/main/profiler/gathered_metrics.hpp" +#include "duckdb/function/function_set.hpp" namespace duckdb { @@ -63,14 +64,8 @@ static void EnableProfiling(ClientContext &context, TableFunctionInput &data, Da static unique_ptr BindEnableProfiling(ClientContext &context, TableFunctionBindInput &input, vector &return_types, vector &names) { - if (input.inputs.size() > 1) { - throw InvalidInputException("EnableProfiling: expected 0 or 1 parameter"); - } - auto bind_data = make_uniq(); - bool metrics_set = false; - for (const auto &named_param : input.named_parameters) { const auto key = EnumUtil::FromString(named_param.first.GetIdentifierName()); switch (key) { @@ -86,30 +81,13 @@ static unique_ptr BindEnableProfiling(ClientContext &context, Tabl case ProfilingParameterNames::MODE: bind_data->mode = StringUtil::Lower(named_param.second.ToString()); break; - case ProfilingParameterNames::METRICS: { - if (named_param.second.type() != LogicalType::LIST(LogicalType::VARCHAR) && - named_param.second.type() != LogicalType::VARCHAR) { - throw InvalidInputException("EnableProfiling: metrics must be a list of strings or a VARCHAR pattern"); - } - - bind_data->metrics = named_param.second; - metrics_set = true; - } + case ProfilingParameterNames::METRICS: + throw InternalException("enable_profiling: metrics is placed by position"); } } - // Process positional param: metrics configs - if (!input.inputs.empty()) { - if (metrics_set) { - throw InvalidInputException("EnableProfiling: cannot specify both metrics and positional parameters"); - } - if (input.inputs[0].type() != LogicalType::LIST(LogicalType::VARCHAR) && - input.inputs[0].type() != LogicalType::VARCHAR) { - throw InvalidInputException("EnableProfiling: metrics must be a list of strings or a VARCHAR pattern"); - } - - bind_data->metrics = input.inputs[0]; - } + // The metrics are placed by position however they were passed; the overload settled pattern or list of names + bind_data->metrics = input.inputs[0]; return_types.emplace_back(LogicalType::BOOLEAN); names.emplace_back("Success"); @@ -131,19 +109,31 @@ static unique_ptr BindDisableProfiling(ClientContext &context, Tab } void EnableProfilingFun::RegisterFunction(BuiltinFunctions &set) { - auto enable_fun = TableFunction("enable_profiling", {}, EnableProfiling, BindEnableProfiling, nullptr, nullptr); - - enable_fun.named_parameters.emplace("format", LogicalType::VARCHAR); - enable_fun.named_parameters.emplace("coverage", LogicalType::VARCHAR); - enable_fun.named_parameters.emplace("save_location", LogicalType::VARCHAR); - enable_fun.named_parameters.emplace("mode", LogicalType::VARCHAR); - enable_fun.named_parameters.emplace("metrics", LogicalType::ANY); - - enable_fun.SetVarArgs(LogicalType::LIST(LogicalType::VARCHAR)); - set.AddFunction(enable_fun); + // The metrics are either a single pattern or a list of names + TableFunctionSet enable_set("enable_profiling"); + + enable_set.AddFunction(TableFunction(FunctionSignature() + .AddParameter("metrics", LogicalType::VARCHAR, Value(LogicalType::VARCHAR)) + .AddTypedKwargs("options", TypedKwargs() + .Add("format", LogicalType::VARCHAR) + .Add("coverage", LogicalType::VARCHAR) + .Add("save_location", LogicalType::VARCHAR) + .Add("mode", LogicalType::VARCHAR)), + EnableProfiling, BindEnableProfiling)); + + enable_set.AddFunction(TableFunction(FunctionSignature() + .AddParameter("metrics", LogicalType::LIST(LogicalType::VARCHAR)) + .AddTypedKwargs("options", TypedKwargs() + .Add("format", LogicalType::VARCHAR) + .Add("coverage", LogicalType::VARCHAR) + .Add("save_location", LogicalType::VARCHAR) + .Add("mode", LogicalType::VARCHAR)), + EnableProfiling, BindEnableProfiling)); + + set.AddFunction(std::move(enable_set)); auto disable_fun = TableFunction("disable_profiling", {}, DisableProfiling, BindDisableProfiling, nullptr, nullptr); - set.AddFunction(disable_fun); + set.AddFunction(std::move(disable_fun)); } } // namespace duckdb diff --git a/src/duckdb/src/function/table/system/external_resource_types.cpp b/src/duckdb/src/function/table/system/external_resource_types.cpp index 9ae9eb692..d5ded055c 100644 --- a/src/duckdb/src/function/table/system/external_resource_types.cpp +++ b/src/duckdb/src/function/table/system/external_resource_types.cpp @@ -153,14 +153,19 @@ static void ExternalResourceTypesFunction(ClientContext &context, TableFunctionI //===--------------------------------------------------------------------===// void RegisterExternalResourceTypeFun::RegisterFunction(BuiltinFunctions &set) { - TableFunction fn("register_external_resource_type", {LogicalType::VARCHAR}, RegisterExternalResourceTypeFunction, - RegisterExternalResourceTypeBind, RegisterExternalResourceTypeInit); - fn.named_parameters["kind"] = LogicalType::VARCHAR; - fn.named_parameters["create_function"] = LogicalType::VARCHAR; - fn.named_parameters["status_function"] = LogicalType::VARCHAR; - fn.named_parameters["destroy_function"] = LogicalType::VARCHAR; - fn.named_parameters["resolve_function"] = LogicalType::VARCHAR; - fn.named_parameters["list_function"] = LogicalType::VARCHAR; + TableFunction fn( + "register_external_resource_type", FunctionSignature().AddPositionalOnly("name", LogicalType::VARCHAR), + RegisterExternalResourceTypeFunction, RegisterExternalResourceTypeBind, RegisterExternalResourceTypeInit); + fn.GetSignature() + .AddKeywordOnly("kind", LogicalType::VARCHAR) + .AddKeywordOnly("create_function", LogicalType::VARCHAR) + .WithTypedKwargs("options", [](TypedKwargs &kwargs) { + kwargs.Add("status_function", LogicalType::VARCHAR) + .Add("destroy_function", LogicalType::VARCHAR) + .Add("resolve_function", LogicalType::VARCHAR) + .Add("list_function", LogicalType::VARCHAR); + }); + set.AddFunction(fn); } diff --git a/src/duckdb/src/function/table/system/external_resources.cpp b/src/duckdb/src/function/table/system/external_resources.cpp index 908b6e38f..4ad100f5c 100644 --- a/src/duckdb/src/function/table/system/external_resources.cpp +++ b/src/duckdb/src/function/table/system/external_resources.cpp @@ -211,7 +211,8 @@ static void ExternalResourcesFunction(ClientContext &context, TableFunctionInput void DuckDBExternalResourcesFun::RegisterFunction(BuiltinFunctions &set) { TableFunction fn("duckdb_external_resources", {}, ExternalResourcesFunction, ExternalResourcesBind, ExternalResourcesInit); - fn.named_parameters["discover"] = LogicalType::BOOLEAN; + fn.GetSignature().WithTypedKwargs("options", + [](TypedKwargs &options) { options.Add("discover", LogicalType::BOOLEAN); }); set.AddFunction(fn); } @@ -285,13 +286,17 @@ static void RegisterExternalResourceFunction(ClientContext &context, TableFuncti } void RegisterExternalResourceFun::RegisterFunction(BuiltinFunctions &set) { - TableFunction fn( - "register_external_resource", - {LogicalType::VARCHAR, LogicalType::VARCHAR, LogicalType::MAP(LogicalType::VARCHAR, LogicalType::VARCHAR)}, - RegisterExternalResourceFunction, RegisterExternalResourceBind, RegisterExternalResourceInit); - fn.named_parameters["uri"] = LogicalType::VARCHAR; - fn.named_parameters["attached_db_type"] = LogicalType::VARCHAR; - fn.named_parameters["deleter_function"] = LogicalType::VARCHAR; + TableFunction fn("register_external_resource", + FunctionSignature() + .AddPositionalOnly("type", LogicalType::VARCHAR) + .AddPositionalOnly("name", LogicalType::VARCHAR) + .AddPositionalOnly("handle", LogicalType::MAP(LogicalType::VARCHAR, LogicalType::VARCHAR)), + RegisterExternalResourceFunction, RegisterExternalResourceBind, RegisterExternalResourceInit); + fn.GetSignature().WithTypedKwargs("options", [](TypedKwargs &options) { + options.Add("uri", LogicalType::VARCHAR) + .Add("attached_db_type", LogicalType::VARCHAR) + .Add("deleter_function", LogicalType::VARCHAR); + }); set.AddFunction(fn); } @@ -343,9 +348,9 @@ static void DeregisterExternalResourceFunction(ClientContext &context, TableFunc } void DeregisterExternalResourceFun::RegisterFunction(BuiltinFunctions &set) { - set.AddFunction(TableFunction("deregister_external_resource", {LogicalType::VARCHAR}, - DeregisterExternalResourceFunction, DeregisterExternalResourceBind, - DeregisterExternalResourceInit)); + set.AddFunction(TableFunction( + "deregister_external_resource", FunctionSignature().AddPositionalOnly("name", LogicalType::VARCHAR), + DeregisterExternalResourceFunction, DeregisterExternalResourceBind, DeregisterExternalResourceInit)); } } // namespace duckdb diff --git a/src/duckdb/src/function/table/system/logging_utils.cpp b/src/duckdb/src/function/table/system/logging_utils.cpp index 67386917d..a8be73e7f 100644 --- a/src/duckdb/src/function/table/system/logging_utils.cpp +++ b/src/duckdb/src/function/table/system/logging_utils.cpp @@ -69,6 +69,9 @@ static unique_ptr BindEnableLogging(ClientContext &context, TableF for (const auto ¶m : input.named_parameters) { auto &key = param.first; if (key == "level") { + if (param.second.IsNull()) { + throw InvalidInputException("EnableLogging: level cannot be NULL"); + } result->config.level = EnumUtil::FromString(param.second.ToString()); } else if (key == "storage") { storage_isset = true; @@ -174,17 +177,18 @@ static unique_ptr BindTruncateLogs(ClientContext &context, TableFu void EnableLoggingFun::RegisterFunction(BuiltinFunctions &set) { auto enable_fun = TableFunction("enable_logging", {}, EnableLogging, BindEnableLogging, nullptr, nullptr); - // Base config - enable_fun.named_parameters.emplace("level", LogicalType::VARCHAR); - enable_fun.named_parameters.emplace("storage", LogicalType::VARCHAR); - enable_fun.named_parameters.emplace("storage_config", LogicalType::ANY); - - // Config that is forwarded to the storage_config struct as syntactic sugar - enable_fun.named_parameters.emplace("storage_path", LogicalType::VARCHAR); - enable_fun.named_parameters.emplace("storage_normalize", LogicalType::BOOLEAN); - enable_fun.named_parameters.emplace("storage_buffer_size", LogicalType::UBIGINT); + enable_fun.GetSignature() + .AddArgs("args", LogicalType::ANY) + .AddKeywordOnly("level", LogicalType::VARCHAR, Value("INFO")) + .WithTypedKwargs("options", [](TypedKwargs &options) { + options.Add("storage", LogicalType::VARCHAR) + .Add("storage_config", LogicalType::ANY) + // forwarded to the storage_config struct as syntactic sugar + .Add("storage_path", LogicalType::VARCHAR) + .Add("storage_normalize", LogicalType::BOOLEAN) + .Add("storage_buffer_size", LogicalType::UBIGINT); + }); - enable_fun.SetVarArgs(LogicalType::ANY); set.AddFunction(enable_fun); auto disable_fun = TableFunction("disable_logging", {}, DisableLogging, BindDisableLogging, nullptr, nullptr); diff --git a/src/duckdb/src/function/table/system/pragma_metadata_info.cpp b/src/duckdb/src/function/table/system/pragma_metadata_info.cpp index 5deb58c3f..9df9956c5 100644 --- a/src/duckdb/src/function/table/system/pragma_metadata_info.cpp +++ b/src/duckdb/src/function/table/system/pragma_metadata_info.cpp @@ -86,7 +86,8 @@ void PragmaMetadataInfo::RegisterFunction(BuiltinFunctions &set) { TableFunctionSet metadata_info("pragma_metadata_info"); metadata_info.AddFunction( TableFunction({}, PragmaMetadataInfoFunction, PragmaMetadataInfoBind, PragmaMetadataInfoInit)); - metadata_info.AddFunction(TableFunction({LogicalType::VARCHAR}, PragmaMetadataInfoFunction, PragmaMetadataInfoBind, + metadata_info.AddFunction(TableFunction(FunctionSignature().AddPositionalOnly("database", LogicalType::VARCHAR), + PragmaMetadataInfoFunction, PragmaMetadataInfoBind, PragmaMetadataInfoInit)); set.AddFunction(metadata_info); } diff --git a/src/duckdb/src/function/table/system/pragma_storage_info.cpp b/src/duckdb/src/function/table/system/pragma_storage_info.cpp index 39bfc7112..e76d24a2f 100644 --- a/src/duckdb/src/function/table/system/pragma_storage_info.cpp +++ b/src/duckdb/src/function/table/system/pragma_storage_info.cpp @@ -97,10 +97,16 @@ static unique_ptr PragmaStorageInfoBind(ClientContext &context, Ta ColumnSegmentInfoScanOptions options; auto include_entry = input.named_parameters.find("include_segment_info"); if (include_entry != input.named_parameters.end()) { + if (include_entry->second.IsNull()) { + throw InvalidInputException("Cannot use NULL as argument for include_segment_info"); + } options.include_segment_info = include_entry->second.GetValue(); } auto loaded_only_entry = input.named_parameters.find("loaded_segments_only"); if (loaded_only_entry != input.named_parameters.end()) { + if (loaded_only_entry->second.IsNull()) { + throw InvalidInputException("Cannot use NULL as argument for loaded_segments_only"); + } options.loaded_segments_only = loaded_only_entry->second.GetValue(); } @@ -259,12 +265,14 @@ static OperatorPartitionData PragmaStorageInfoGetPartitionData(ClientContext &co } void PragmaStorageInfo::RegisterFunction(BuiltinFunctions &set) { - TableFunction storage_info("pragma_storage_info", {LogicalType::VARCHAR}, PragmaStorageInfoFunction, - PragmaStorageInfoBind, PragmaStorageInfoInitGlobal, PragmaStorageInfoInitLocal); + TableFunction storage_info( + "pragma_storage_info", FunctionSignature().AddPositionalOnly("table_name", LogicalType::VARCHAR), + PragmaStorageInfoFunction, PragmaStorageInfoBind, PragmaStorageInfoInitGlobal, PragmaStorageInfoInitLocal); storage_info.get_partition_data = PragmaStorageInfoGetPartitionData; storage_info.table_scan_progress = PragmaStorageInfoProgress; - storage_info.named_parameters["include_segment_info"] = LogicalType::BOOLEAN; - storage_info.named_parameters["loaded_segments_only"] = LogicalType::BOOLEAN; + storage_info.GetSignature().WithTypedKwargs("options", [](TypedKwargs &options) { + options.Add("include_segment_info", LogicalType::BOOLEAN).Add("loaded_segments_only", LogicalType::BOOLEAN); + }); set.AddFunction(std::move(storage_info)); } diff --git a/src/duckdb/src/function/table/system/pragma_table_info.cpp b/src/duckdb/src/function/table/system/pragma_table_info.cpp index 5b70fddc6..71b7e9516 100644 --- a/src/duckdb/src/function/table/system/pragma_table_info.cpp +++ b/src/duckdb/src/function/table/system/pragma_table_info.cpp @@ -288,10 +288,12 @@ static void PragmaTableInfoFunction(ClientContext &context, TableFunctionInput & } void PragmaTableInfo::RegisterFunction(BuiltinFunctions &set) { - set.AddFunction(TableFunction("pragma_table_info", {LogicalType::VARCHAR}, PragmaTableInfoFunction, - PragmaTableInfoBind, PragmaTableInfoInit)); - set.AddFunction(TableFunction("pragma_show", {LogicalType::VARCHAR}, PragmaTableInfoFunction, - PragmaTableInfoBind, PragmaTableInfoInit)); + set.AddFunction(TableFunction("pragma_table_info", + FunctionSignature().AddPositionalOnly("table_name", LogicalType::VARCHAR), + PragmaTableInfoFunction, PragmaTableInfoBind, PragmaTableInfoInit)); + set.AddFunction(TableFunction("pragma_show", + FunctionSignature().AddPositionalOnly("table_name", LogicalType::VARCHAR), + PragmaTableInfoFunction, PragmaTableInfoBind, PragmaTableInfoInit)); } } // namespace duckdb diff --git a/src/duckdb/src/function/table/system/pragma_table_sample.cpp b/src/duckdb/src/function/table/system/pragma_table_sample.cpp index 1c83a2f21..9f14accbe 100644 --- a/src/duckdb/src/function/table/system/pragma_table_sample.cpp +++ b/src/duckdb/src/function/table/system/pragma_table_sample.cpp @@ -89,8 +89,9 @@ static void DuckDBTableSampleFunction(ClientContext &context, TableFunctionInput } void DuckDBTableSample::RegisterFunction(BuiltinFunctions &set) { - set.AddFunction(TableFunction("duckdb_table_sample", {LogicalType::VARCHAR}, DuckDBTableSampleFunction, - DuckDBTableSampleBind, DuckDBTableSampleInit)); + set.AddFunction(TableFunction("duckdb_table_sample", + FunctionSignature().AddPositionalOnly("table_name", LogicalType::VARCHAR), + DuckDBTableSampleFunction, DuckDBTableSampleBind, DuckDBTableSampleInit)); } } // namespace duckdb diff --git a/src/duckdb/src/function/table/system/test_all_types.cpp b/src/duckdb/src/function/table/system/test_all_types.cpp index 2af0bbae7..a7ceecdfc 100644 --- a/src/duckdb/src/function/table/system/test_all_types.cpp +++ b/src/duckdb/src/function/table/system/test_all_types.cpp @@ -445,8 +445,9 @@ static void TestAllTypesFunction(ClientContext &context, TableFunctionInput &dat void TestAllTypesFun::RegisterFunction(BuiltinFunctions &set) { TableFunction test_all_types("test_all_types", {}, TestAllTypesFunction, TestAllTypesBind, TestAllTypesInit); - test_all_types.named_parameters["use_large_enum"] = LogicalType::BOOLEAN; - test_all_types.named_parameters["use_large_bignum"] = LogicalType::BOOLEAN; + test_all_types.GetSignature().WithTypedKwargs("options", [](TypedKwargs &options) { + options.Add("use_large_enum", LogicalType::BOOLEAN).Add("use_large_bignum", LogicalType::BOOLEAN); + }); set.AddFunction(test_all_types); } diff --git a/src/duckdb/src/function/table/system/test_vector_types.cpp b/src/duckdb/src/function/table/system/test_vector_types.cpp index 2a0a74258..cddd1c0b7 100644 --- a/src/duckdb/src/function/table/system/test_vector_types.cpp +++ b/src/duckdb/src/function/table/system/test_vector_types.cpp @@ -343,10 +343,12 @@ static double TestVectorTypesProgress(ClientContext &context, const FunctionData } void TestVectorTypesFun::RegisterFunction(BuiltinFunctions &set) { - TableFunction test_vector_types("test_vector_types", {LogicalType::ANY}, TestVectorTypesFunction, - TestVectorTypesBind, TestVectorTypesInit); - test_vector_types.SetVarArgs(LogicalType::ANY); - test_vector_types.named_parameters["all_flat"] = LogicalType::BOOLEAN; + TableFunction test_vector_types("test_vector_types", + FunctionSignature().AddPositionalOnly("column", LogicalType::ANY), + TestVectorTypesFunction, TestVectorTypesBind, TestVectorTypesInit); + test_vector_types.GetSignature() + .AddArgs("args", LogicalType::ANY) + .WithTypedKwargs("options", [](TypedKwargs &options) { options.Add("all_flat", LogicalType::BOOLEAN); }); test_vector_types.table_scan_progress = TestVectorTypesProgress; set.AddFunction(std::move(test_vector_types)); diff --git a/src/duckdb/src/function/table/table_scan.cpp b/src/duckdb/src/function/table/table_scan.cpp index 0e8131533..ee18c7077 100644 --- a/src/duckdb/src/function/table/table_scan.cpp +++ b/src/duckdb/src/function/table/table_scan.cpp @@ -1156,7 +1156,7 @@ InsertionOrderPreservingMap TableScanToString(TableFunctionToStringInput } static void TableScanSerialize(Serializer &serializer, const optional_ptr bind_data_p, - const TableFunction &function) { + const BoundTableFunction &function) { auto &bind_data = bind_data_p->Cast(); // the catalog/schema/name are only the innermost qualification - "qualified_name" carries the full (possibly // nested) schema path @@ -1170,7 +1170,7 @@ static void TableScanSerialize(Serializer &serializer, const optional_ptr TableScanDeserialize(Deserializer &deserializer, TableFunction &function) { +static unique_ptr TableScanDeserialize(Deserializer &deserializer, BoundTableFunction &function) { auto catalog = deserializer.ReadProperty(100, "catalog"); auto schema = deserializer.ReadProperty(101, "schema"); auto table = deserializer.ReadProperty(102, "table"); diff --git a/src/duckdb/src/function/table/unnest.cpp b/src/duckdb/src/function/table/unnest.cpp index 76cf40ef6..df6b95b3c 100644 --- a/src/duckdb/src/function/table/unnest.cpp +++ b/src/duckdb/src/function/table/unnest.cpp @@ -90,7 +90,8 @@ static OperatorResultType UnnestFunction(ExecutionContext &context, TableFunctio } void UnnestTableFunction::RegisterFunction(BuiltinFunctions &set) { - TableFunction unnest_function("unnest", {LogicalType::ANY}, nullptr, UnnestBind, UnnestInit, UnnestLocalInit); + TableFunction unnest_function("unnest", FunctionSignature().AddPositionalOnly("list", LogicalType::ANY), nullptr, + UnnestBind, UnnestInit, UnnestLocalInit); unnest_function.in_out_function = UnnestFunction; unnest_function.return_type = TableFunctionReturnType::SET_RETURNING_FUNCTION; set.AddFunction(unnest_function); diff --git a/src/duckdb/src/function/table/version/pragma_version.cpp b/src/duckdb/src/function/table/version/pragma_version.cpp index f3ad38db6..7fa1ef309 100644 --- a/src/duckdb/src/function/table/version/pragma_version.cpp +++ b/src/duckdb/src/function/table/version/pragma_version.cpp @@ -1,5 +1,5 @@ #ifndef DUCKDB_PATCH_VERSION -#define DUCKDB_PATCH_VERSION "0-alpha43586" +#define DUCKDB_PATCH_VERSION "0-alpha43678" #endif #ifndef DUCKDB_MINOR_VERSION #define DUCKDB_MINOR_VERSION 0 @@ -8,10 +8,10 @@ #define DUCKDB_MAJOR_VERSION 2 #endif #ifndef DUCKDB_VERSION -#define DUCKDB_VERSION "v2.0.0-alpha43586" +#define DUCKDB_VERSION "v2.0.0-alpha43678" #endif #ifndef DUCKDB_SOURCE_ID -#define DUCKDB_SOURCE_ID "09eb7f7004" +#define DUCKDB_SOURCE_ID "d591bb1da2" #endif #include "duckdb/function/table/system_functions.hpp" #include "duckdb/main/database.hpp" diff --git a/src/duckdb/src/function/table_function.cpp b/src/duckdb/src/function/table_function.cpp index 28801bbd6..0ce7ca0a7 100644 --- a/src/duckdb/src/function/table_function.cpp +++ b/src/duckdb/src/function/table_function.cpp @@ -1,5 +1,8 @@ #include "duckdb/function/table_function.hpp" #include "duckdb/function/partition_stats.hpp" +#include "duckdb/common/string_util.hpp" + +#include namespace duckdb { @@ -15,40 +18,172 @@ PartitionStatistics::PartitionStatistics() : row_start(0), count(0), count_type( TableFunctionInfo::~TableFunctionInfo() { } +BaseTableFunction::BaseTableFunction(table_function_t function_, table_function_bind_t bind, + table_function_init_global_t init_global, table_function_init_local_t init_local) + : bind(bind), bind_replace(nullptr), bind_operator(nullptr), init_global(init_global), init_local(init_local), + function(function_), in_out_function(nullptr), in_out_function_final(nullptr), statistics(nullptr), + statistics_extended(nullptr), dependency(nullptr), cardinality(nullptr), get_metrics(nullptr), + pushdown_complex_filter(nullptr), pushdown_expression(nullptr), combine_schema(nullptr), claim_batch(nullptr), + finish_batch(nullptr), supports_read_ahead(nullptr), schedule_io(nullptr), to_string(nullptr), + table_scan_progress(nullptr), get_partition_data(nullptr), get_bind_info(nullptr), + projection_expression_pushdown(nullptr), get_multi_file_reader(nullptr), supports_pushdown_type(nullptr), + supports_pushdown_extract(nullptr), is_repeatable(nullptr), get_partition_info(nullptr), + get_partition_stats(nullptr), get_virtual_columns(nullptr), get_row_id_columns(nullptr), set_scan_order(nullptr), + serialize(nullptr), deserialize(nullptr), projection_pushdown(false), supports_cast_map(false), + filter_pushdown(false), filter_prune(false), sampling_pushdown(false), late_materialization(false), + return_type(TableFunctionReturnType::TABLE_RETURNING_FUNCTION) { +} + TableFunction::TableFunction(Identifier name, const vector &arguments, table_function_t function_, table_function_bind_t bind, table_function_init_global_t init_global, table_function_init_local_t init_local) - : SimpleNamedParameterFunction(std::move(name), arguments), bind(bind), bind_replace(nullptr), - bind_operator(nullptr), init_global(init_global), init_local(init_local), function(function_), - in_out_function(nullptr), in_out_function_final(nullptr), statistics(nullptr), statistics_extended(nullptr), - dependency(nullptr), cardinality(nullptr), get_metrics(nullptr), pushdown_complex_filter(nullptr), - pushdown_expression(nullptr), combine_schema(nullptr), claim_batch(nullptr), finish_batch(nullptr), - supports_read_ahead(nullptr), schedule_io(nullptr), to_string(nullptr), table_scan_progress(nullptr), - get_partition_data(nullptr), get_bind_info(nullptr), projection_expression_pushdown(nullptr), - get_multi_file_reader(nullptr), supports_pushdown_type(nullptr), supports_pushdown_extract(nullptr), - is_repeatable(nullptr), get_partition_info(nullptr), get_partition_stats(nullptr), get_virtual_columns(nullptr), - get_row_id_columns(nullptr), set_scan_order(nullptr), serialize(nullptr), deserialize(nullptr), - projection_pushdown(false), supports_cast_map(false), filter_pushdown(false), filter_prune(false), - sampling_pushdown(false), late_materialization(false), - return_type(TableFunctionReturnType::TABLE_RETURNING_FUNCTION) { + : BaseTableFunction(function_, bind, init_global, init_local), + SimpleFunction(std::move(name), arguments, LogicalType::INVALID) { } -TableFunction::TableFunction(Identifier name, const vector &arguments, std::nullptr_t function_, +TableFunction::TableFunction(Identifier name, const vector &arguments, std::nullptr_t, table_function_bind_t bind, table_function_init_global_t init_global, table_function_init_local_t init_local) - : SimpleNamedParameterFunction(std::move(name), arguments), bind(bind), bind_replace(nullptr), - bind_operator(nullptr), init_global(init_global), init_local(init_local), function(nullptr), - in_out_function(nullptr), in_out_function_final(nullptr), statistics(nullptr), statistics_extended(nullptr), - dependency(nullptr), cardinality(nullptr), get_metrics(nullptr), pushdown_complex_filter(nullptr), - pushdown_expression(nullptr), combine_schema(nullptr), claim_batch(nullptr), finish_batch(nullptr), - supports_read_ahead(nullptr), schedule_io(nullptr), to_string(nullptr), table_scan_progress(nullptr), - get_partition_data(nullptr), get_bind_info(nullptr), projection_expression_pushdown(nullptr), - get_multi_file_reader(nullptr), supports_pushdown_type(nullptr), supports_pushdown_extract(nullptr), - is_repeatable(nullptr), get_partition_info(nullptr), get_partition_stats(nullptr), get_virtual_columns(nullptr), - get_row_id_columns(nullptr), set_scan_order(nullptr), serialize(nullptr), deserialize(nullptr), - projection_pushdown(false), supports_cast_map(false), filter_pushdown(false), filter_prune(false), - sampling_pushdown(false), late_materialization(false), - return_type(TableFunctionReturnType::TABLE_RETURNING_FUNCTION) { + : BaseTableFunction(nullptr, bind, init_global, init_local), + SimpleFunction(std::move(name), arguments, LogicalType::INVALID) { +} + +TableFunction::TableFunction(Identifier name, FunctionSignature signature, table_function_t function_, + table_function_bind_t bind, table_function_init_global_t init_global, + table_function_init_local_t init_local) + : BaseTableFunction(function_, bind, init_global, init_local), + SimpleFunction(std::move(name), std::move(signature)) { +} + +TableFunction::TableFunction(FunctionSignature signature, table_function_t function_, table_function_bind_t bind, + table_function_init_global_t init_global, table_function_init_local_t init_local) + : BaseTableFunction(function_, bind, init_global, init_local), SimpleFunction("", std::move(signature)) { +} + +TableFunction::TableFunction(Identifier name, FunctionSignature signature, std::nullptr_t, table_function_bind_t bind, + table_function_init_global_t init_global, table_function_init_local_t init_local) + : BaseTableFunction(nullptr, bind, init_global, init_local), SimpleFunction(std::move(name), std::move(signature)) { +} + +BoundTableFunction::BoundTableFunction() : BaseTableFunction(nullptr, nullptr, nullptr, nullptr) { +} + +BoundTableFunction::BoundTableFunction(const TableFunction &function) + // the function does not come from a function set - copy it into a definition of its own + : BoundTableFunction(make_shared_ptr(function)) { +} + +BoundTableFunction::BoundTableFunction(shared_ptr function_p) + : BaseTableFunction(nullptr, nullptr, nullptr, nullptr) { + definition = std::move(function_p); + auto &function = *definition; + qualified_name = function.GetQualifiedName(); + extra_info = function.extra_info; + + // the behaviour is taken over one member at a time - the declaration stays behind on the definition + bind = function.bind; + bind_replace = function.bind_replace; + bind_operator = function.bind_operator; + init_global = function.init_global; + init_local = function.init_local; + this->function = function.function; + in_out_function = function.in_out_function; + in_out_function_final = function.in_out_function_final; + statistics = function.statistics; + statistics_extended = function.statistics_extended; + dependency = function.dependency; + cardinality = function.cardinality; + get_metrics = function.get_metrics; + pushdown_complex_filter = function.pushdown_complex_filter; + pushdown_expression = function.pushdown_expression; + combine_schema = function.combine_schema; + claim_batch = function.claim_batch; + finish_batch = function.finish_batch; + supports_read_ahead = function.supports_read_ahead; + schedule_io = function.schedule_io; + to_string = function.to_string; + to_sql = function.to_sql; + table_scan_progress = function.table_scan_progress; + get_partition_data = function.get_partition_data; + get_bind_info = function.get_bind_info; + projection_expression_pushdown = function.projection_expression_pushdown; + get_multi_file_reader = function.get_multi_file_reader; + supports_pushdown_type = function.supports_pushdown_type; + supports_pushdown_extract = function.supports_pushdown_extract; + is_repeatable = function.is_repeatable; + get_partition_info = function.get_partition_info; + get_partition_stats = function.get_partition_stats; + get_virtual_columns = function.get_virtual_columns; + get_row_id_columns = function.get_row_id_columns; + set_scan_order = function.set_scan_order; + set_partitions_to_scan = function.set_partitions_to_scan; + serialize = function.serialize; + deserialize = function.deserialize; + verify_serialization = function.verify_serialization; + projection_pushdown = function.projection_pushdown; + supports_cast_map = function.supports_cast_map; + filter_pushdown = function.filter_pushdown; + filter_prune = function.filter_prune; + sampling_pushdown = function.sampling_pushdown; + late_materialization = function.late_materialization; + function_info = function.function_info; + BaseTableFunction::return_type = function.return_type; + call_return_type = function.call_return_type; + order_preservation_type = function.order_preservation_type; + global_initialization = function.global_initialization; + parallelism = function.parallelism; + + // the parameters a call fills by position - these are the types plan serialization records, so the named + // options that follow them take no part + auto &signature = function.GetSignature(); + for (idx_t i = 0; i < signature.GetPositionalParameterCount(); i++) { + arguments.push_back(signature.GetParameter(i).GetType()); + } + positional_arguments = arguments.size(); +} + +void BoundTableFunction::SetCallArguments(const vector ¶meters, + const named_argument_map_t &named_parameters) { + auto &signature = GetSignature(); + const auto positional_count = signature.GetPositionalParameterCount(); + arguments.clear(); + for (idx_t i = 0; i < positional_count; i++) { + arguments.push_back(signature.GetParameter(i).GetType()); + } + auto args = signature.GetArgs(); + for (idx_t i = positional_count; i < parameters.size(); i++) { + auto is_typed = args && args->GetType().id() != LogicalTypeId::ANY; + arguments.push_back(is_typed ? args->GetType() : parameters[i].type()); + } + const auto positional_argument_count = arguments.size(); + + // only the options the signature receives by name, in the order they were passed + vector names; + for (auto &entry : named_parameters) { + auto param_idx = signature.GetParameterIndexByName(entry.first); + if (!param_idx.IsValid()) { + if (signature.GetKwargs()) { + names.push_back(entry.first); + arguments.push_back(entry.second.type()); + } + continue; + } + auto ¶m = signature.GetParameter(param_idx.GetIndex()); + if (!param.AcceptsPosition()) { + names.push_back(entry.first); + arguments.push_back(param.GetType()); + } + } + SetNamedArguments(positional_argument_count, std::move(names)); +} + +bool BoundTableFunction::operator==(const BoundTableFunction &rhs) const { + return GetQualifiedName() == rhs.GetQualifiedName() && GetArguments() == rhs.GetArguments() && + BaseTableFunction::operator==(rhs); +} + +bool BoundTableFunction::operator!=(const BoundTableFunction &rhs) const { + return !(*this == rhs); } TableFunction::TableFunction(const vector &arguments, table_function_t function_, @@ -65,12 +200,11 @@ TableFunction::TableFunction(const vector &arguments, std::nullptr_ TableFunction::TableFunction() : TableFunction("", {}, nullptr, nullptr, nullptr, nullptr) { } -bool TableFunction::operator==(const TableFunction &rhs) const { - return name == rhs.name && arguments == rhs.GetArguments() && varargs == rhs.GetVarArgs() && bind == rhs.bind && - bind_replace == rhs.bind_replace && bind_operator == rhs.bind_operator && init_global == rhs.init_global && - init_local == rhs.init_local && function == rhs.function && in_out_function == rhs.in_out_function && - in_out_function_final == rhs.in_out_function_final && statistics == rhs.statistics && - dependency == rhs.dependency && cardinality == rhs.cardinality && +bool BaseTableFunction::operator==(const BaseTableFunction &rhs) const { + return bind == rhs.bind && bind_replace == rhs.bind_replace && bind_operator == rhs.bind_operator && + init_global == rhs.init_global && init_local == rhs.init_local && function == rhs.function && + in_out_function == rhs.in_out_function && in_out_function_final == rhs.in_out_function_final && + statistics == rhs.statistics && dependency == rhs.dependency && cardinality == rhs.cardinality && pushdown_complex_filter == rhs.pushdown_complex_filter && pushdown_expression == rhs.pushdown_expression && to_string == rhs.to_string && to_sql == rhs.to_sql && table_scan_progress == rhs.table_scan_progress && get_partition_data == rhs.get_partition_data && get_bind_info == rhs.get_bind_info && @@ -86,27 +220,12 @@ bool TableFunction::operator==(const TableFunction &rhs) const { global_initialization == rhs.global_initialization; } -bool TableFunction::operator!=(const TableFunction &rhs) const { - return !(*this == rhs); +bool TableFunction::operator==(const TableFunction &rhs) const { + return name == rhs.name && GetSignature() == rhs.GetSignature() && BaseTableFunction::operator==(rhs); } -bool TableFunction::Equal(const TableFunction &rhs) const { - // number of types - if (this->GetArguments().size() != rhs.GetArguments().size()) { - return false; - } - // argument types - for (idx_t i = 0; i < this->GetArguments().size(); ++i) { - if (this->GetArguments()[i] != rhs.GetArguments()[i]) { - return false; - } - } - // varargs - if (this->GetVarArgs() != rhs.GetVarArgs()) { - return false; - } - - return true; // they are equal +bool TableFunction::operator!=(const TableFunction &rhs) const { + return !(*this == rhs); } bool TableFunctionInput::HandleBlocked(AsyncResult &blocked_result) { diff --git a/src/duckdb/src/function/type_constructor.cpp b/src/duckdb/src/function/type_constructor.cpp index ab30af74d..d98c126ea 100644 --- a/src/duckdb/src/function/type_constructor.cpp +++ b/src/duckdb/src/function/type_constructor.cpp @@ -34,7 +34,7 @@ TypeConstructor TypeConstructor::Identity(Identifier name) { TypeConstructor TypeConstructor::Unchecked(Identifier name, bind_logical_type_function_t bind) { // accepts anything, the bind function validates the arguments itself auto signature = Signature(); - signature.AddArgsParameter("args", LogicalType::ANY).AddKwargsParameter("kwargs", LogicalType::ANY); + signature.AddArgs("args", LogicalType::ANY).AddKwargs("kwargs", LogicalType::ANY); return TypeConstructor(std::move(name), std::move(signature), bind); } @@ -208,7 +208,7 @@ vector NormalizeArguments(const Identifier &type_name, const TypeC auto arg_name = ArgumentName(Identifier(arg.GetName()), entry.first); auto location = arg.GetQueryLocation(); // a named modifier is received by "**kwargs", an unnamed one by "*args" - auto param = arg.HasName() ? sig.GetKwargsParameter() : sig.GetArgsParameter(); + auto param = arg.HasName() ? sig.GetKwargs() : sig.GetArgs(); auto &target = param ? param->GetType() : LogicalType::ANY; result.emplace_back(arg.GetName(), CastArgument(type_name, arg_name, arg.GetValue(), target, location), location); diff --git a/src/duckdb/src/include/duckdb/common/multi_file/multi_file_function.hpp b/src/duckdb/src/include/duckdb/common/multi_file/multi_file_function.hpp index 4a7503e52..b3882f7b7 100644 --- a/src/duckdb/src/include/duckdb/common/multi_file/multi_file_function.hpp +++ b/src/duckdb/src/include/duckdb/common/multi_file/multi_file_function.hpp @@ -91,9 +91,10 @@ struct MultiFileReaderInterface { template class MultiFileFunction : public TableFunction { public: - explicit MultiFileFunction(Identifier name_p) - : TableFunction(std::move(name_p), {LogicalType::VARCHAR}, MultiFileScan, MultiFileBind, MultiFileInitGlobal, - MultiFileInitLocal) { + explicit MultiFileFunction( + Identifier name_p, MultiFileReader::MultiFileParameters parameters = MultiFileReader::MultiFileParameters::ALL) + : TableFunction(std::move(name_p), FunctionSignature().AddPositionalOnly("path", LogicalType::VARCHAR), + MultiFileScan, MultiFileBind, MultiFileInitGlobal, MultiFileInitLocal) { cardinality = MultiFileCardinality; table_scan_progress = MultiFileProgress; get_partition_data = MultiFileGetPartitionData; @@ -103,7 +104,7 @@ class MultiFileFunction : public TableFunction { get_partition_info = MultiFileGetPartitionInfo; get_virtual_columns = MultiFileGetVirtualColumns; get_metrics = MultiFileGetMetrics; - MultiFileReader::AddParameters(*this); + MultiFileReader::AddParameters(*this, parameters); } static bool IsEmptyResult(const MultiFileBindData &bind_data) { diff --git a/src/duckdb/src/include/duckdb/common/multi_file/multi_file_reader.hpp b/src/duckdb/src/include/duckdb/common/multi_file/multi_file_reader.hpp index c60760b9e..3878b713b 100644 --- a/src/duckdb/src/include/duckdb/common/multi_file/multi_file_reader.hpp +++ b/src/duckdb/src/include/duckdb/common/multi_file/multi_file_reader.hpp @@ -107,7 +107,7 @@ struct MultiFileReader { virtual ~MultiFileReader(); //! Create a MultiFileReader for a specific TableFunction, using its function name for errors - DUCKDB_API static unique_ptr Create(const TableFunction &table_function); + DUCKDB_API static unique_ptr Create(const BoundTableFunction &table_function); //! Create a default MultiFileReader, function_name is used for errors DUCKDB_API static unique_ptr CreateDefault(const string &function_name = ""); @@ -115,7 +115,11 @@ struct MultiFileReader { static Value CreateValueFromFileList(const vector &files); //! Add the parameters for multi-file readers (e.g. union_by_name, filename) to a table function - DUCKDB_API static void AddParameters(TableFunction &table_function); + //! Which of the multi-file options to declare on a function. A function that reads exactly one file per call + //! takes only "allow_empty"; the others describe how several files are combined + enum class MultiFileParameters { ALL, ALLOW_EMPTY_ONLY }; + DUCKDB_API static void AddParameters(TableFunction &table_function, + MultiFileParameters which = MultiFileParameters::ALL); //! Creates a table function set from a single reader function (including e.g. list parameters, etc) DUCKDB_API static TableFunctionSet CreateFunctionSet(TableFunction table_function); diff --git a/src/duckdb/src/include/duckdb/common/multi_file/table_function_multi_file.hpp b/src/duckdb/src/include/duckdb/common/multi_file/table_function_multi_file.hpp index 1b0fa88d9..27427ca0c 100644 --- a/src/duckdb/src/include/duckdb/common/multi_file/table_function_multi_file.hpp +++ b/src/duckdb/src/include/duckdb/common/multi_file/table_function_multi_file.hpp @@ -17,7 +17,7 @@ namespace duckdb { //! The options of a wrapped single-file table function - the named parameters that are forwarded to it as-is class TableFunctionFileReaderOptions : public BaseFileReaderOptions { public: - named_parameter_map_t named_parameters; + named_argument_map_t named_parameters; //! The schema the files are expected to produce - set by COPY, which takes its columns from the target table vector expected_names; vector expected_types; @@ -83,7 +83,7 @@ class TableFunctionUnionData : public BaseUnionData { //! Reads a single file by binding and executing the wrapped table function over that file class TableFunctionFileReader : public BaseFileReader { public: - TableFunctionFileReader(TableFunction function, OpenFileInfo file, named_parameter_map_t named_parameters, + TableFunctionFileReader(TableFunction function, OpenFileInfo file, named_argument_map_t named_parameters, string reader_type); ~TableFunctionFileReader() override; @@ -139,7 +139,7 @@ class TableFunctionFileReader : public BaseFileReader { private: //! The named parameters that are passed on to the wrapped function - named_parameter_map_t named_parameters; + named_argument_map_t named_parameters; //! How the files are referred to in error messages string reader_type; //! Guards the initialization of the global state below @@ -221,6 +221,9 @@ class TableFunctionMultiFileWrapper : public MultiFileReaderInterface { private: //! Parse a named parameter of the wrapped function - returns false if the function has no such parameter bool ParseNamedParameter(const Identifier &key, const Value &val, TableFunctionFileReaderOptions &options) const; + //! The name and type of the wrapped function's option of that name or alias - a keyword-only parameter or an + //! option its "**kwargs" declares - or empty if it declares none + optional> GetDeclaredOption(const Identifier &key) const; //! Release the per-file bind data that is only needed while combining schemas static void ReleaseBindData(const vector> &union_data); diff --git a/src/duckdb/src/include/duckdb/common/named_parameter_map.hpp b/src/duckdb/src/include/duckdb/common/named_parameter_map.hpp index 690eb6249..8ed134089 100644 --- a/src/duckdb/src/include/duckdb/common/named_parameter_map.hpp +++ b/src/duckdb/src/include/duckdb/common/named_parameter_map.hpp @@ -9,10 +9,14 @@ #pragma once #include "duckdb/common/case_insensitive_map.hpp" +#include "duckdb/common/identifier.hpp" +#include "duckdb/common/insertion_order_preserving_map.hpp" #include "duckdb/common/types.hpp" namespace duckdb { using named_parameter_type_map_t = identifier_map_t; using named_parameter_map_t = identifier_map_t; +//! The named arguments of a call, in the order they were passed +using named_argument_map_t = InsertionOrderPreservingMap>; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/csv_reader_options.hpp b/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/csv_reader_options.hpp index eae558048..60905b57b 100644 --- a/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/csv_reader_options.hpp +++ b/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/csv_reader_options.hpp @@ -193,7 +193,7 @@ struct CSVReaderOptions { void SetWriteOption(const Identifier &loption, const Value &value); void SetDateFormat(LogicalTypeId type, const string &format, bool read_format); void ToNamedParameters(named_parameter_map_t &out) const; - void FromNamedParameters(const named_parameter_map_t &in, ClientContext &context, MultiFileOptions &file_options); + void FromNamedParameters(const named_argument_map_t &in, ClientContext &context, MultiFileOptions &file_options); void ParseOption(ClientContext &context, const Identifier &key, const Value &val); //! Verify options are not conflicting void Verify(MultiFileOptions &file_options); diff --git a/src/duckdb/src/include/duckdb/execution/operator/projection/physical_tableinout_function.hpp b/src/duckdb/src/include/duckdb/execution/operator/projection/physical_tableinout_function.hpp index 4d16a4551..b1ef99565 100644 --- a/src/duckdb/src/include/duckdb/execution/operator/projection/physical_tableinout_function.hpp +++ b/src/duckdb/src/include/duckdb/execution/operator/projection/physical_tableinout_function.hpp @@ -20,7 +20,7 @@ class PhysicalTableInOutFunction : public PhysicalOperator { static constexpr const PhysicalOperatorType TYPE = PhysicalOperatorType::INOUT_FUNCTION; public: - PhysicalTableInOutFunction(PhysicalPlan &physical_plan, vector types, TableFunction function_p, + PhysicalTableInOutFunction(PhysicalPlan &physical_plan, vector types, BoundTableFunction function_p, unique_ptr bind_data_p, vector column_ids_p, vector projection_ids_p, unique_ptr table_filters_p, idx_t estimated_cardinality, vector projected_input); @@ -54,7 +54,7 @@ class PhysicalTableInOutFunction : public PhysicalOperator { private: //! The table function - TableFunction function; + BoundTableFunction function; //! Bind data of the function unique_ptr bind_data; //! The set of column ids to fetch diff --git a/src/duckdb/src/include/duckdb/execution/operator/scan/physical_table_scan.hpp b/src/duckdb/src/include/duckdb/execution/operator/scan/physical_table_scan.hpp index f76265eb6..84d390952 100644 --- a/src/duckdb/src/include/duckdb/execution/operator/scan/physical_table_scan.hpp +++ b/src/duckdb/src/include/duckdb/execution/operator/scan/physical_table_scan.hpp @@ -28,14 +28,14 @@ class PhysicalTableScan : public PhysicalOperator { public: //! Table scan that immediately projects out filter columns that are unused in the remainder of the query plan - PhysicalTableScan(PhysicalPlan &physical_plan, vector types, TableFunction function, + PhysicalTableScan(PhysicalPlan &physical_plan, vector types, BoundTableFunction function, unique_ptr bind_data, vector returned_types, vector column_ids, vector projection_ids, vector names, unique_ptr table_filters, idx_t estimated_cardinality, ExtraOperatorInfo extra_info, vector parameters, virtual_column_map_t virtual_columns); //! The table function - TableFunction function; + BoundTableFunction function; //! Bind data of the function unique_ptr bind_data; //! The types of ALL columns that can be returned by the table function diff --git a/src/duckdb/src/include/duckdb/function/function.hpp b/src/duckdb/src/include/duckdb/function/function.hpp index f051e6842..b2629c854 100644 --- a/src/duckdb/src/include/duckdb/function/function.hpp +++ b/src/duckdb/src/include/duckdb/function/function.hpp @@ -115,26 +115,34 @@ struct FunctionLocalState { struct FunctionParameters { vector values; - named_parameter_map_t named_parameters; + named_argument_map_t named_parameters; }; -//! How a parameter receives its arguments, mirroring Python's parameter kinds -//! STANDARD -> can be passed by position or by name -//! VAR_POSITIONAL -> "*args", receives all remaining positional arguments -//! VAR_KEYWORD -> "**kwargs", receives all named arguments that do not match another parameter -//! KEYWORD_ONLY -> declared after "*args", can only be passed by name -enum class FunctionParameterKind : uint8_t { STANDARD = 0, VAR_POSITIONAL = 1, VAR_KEYWORD = 2, KEYWORD_ONLY = 3 }; +//! How a parameter receives its arguments, mirroring Python's parameter kinds, in the order a signature declares them +//! POSITIONAL_ONLY -> declared before "/", can only be passed by position. Its name is invisible to a caller, so an +//! argument of that name is unmatched and reaches "**kwargs" instead +//! STANDARD -> can be passed by position or by name +//! VAR_POSITIONAL -> "*args", receives all remaining positional arguments +//! KEYWORD_ONLY -> declared after "*args", can only be passed by name +//! VAR_KEYWORD -> "**kwargs", receives all named arguments that do not match another parameter +enum class FunctionParameterKind : uint8_t { + POSITIONAL_ONLY = 0, + STANDARD = 1, + VAR_POSITIONAL = 2, + KEYWORD_ONLY = 3, + VAR_KEYWORD = 4 +}; class FunctionParameter { public: - FunctionParameter(Identifier name, LogicalType type, FunctionParameterKind kind = FunctionParameterKind::STANDARD) - : name(std::move(name)), type(std::move(type)), default_value(nullptr), kind(kind) { - } - - FunctionParameter(Identifier name, LogicalType type, Value value, + FunctionParameter(Identifier name, LogicalType type, optional value = {}, FunctionParameterKind kind = FunctionParameterKind::STANDARD) - : name(std::move(name)), type(std::move(type)), default_value(make_shared_ptr(std::move(value))), - kind(kind) { + : name(std::move(name)), type(std::move(type)), kind(kind) { + if (value) { + default_value = make_shared_ptr(std::move(*value)); + } else { + default_value = nullptr; + } } string ToString() const; @@ -173,6 +181,14 @@ class FunctionParameter { auto IsVariadic() const -> bool { return kind == FunctionParameterKind::VAR_POSITIONAL || kind == FunctionParameterKind::VAR_KEYWORD; } + //! Whether a caller can pass this parameter by position + auto AcceptsPosition() const -> bool { + return kind == FunctionParameterKind::STANDARD || kind == FunctionParameterKind::POSITIONAL_ONLY; + } + //! Whether a caller can pass this parameter by name + auto AcceptsName() const -> bool { + return kind == FunctionParameterKind::STANDARD || kind == FunctionParameterKind::KEYWORD_ONLY; + } private: Identifier name; @@ -181,31 +197,69 @@ class FunctionParameter { FunctionParameterKind kind; }; +//! An option a function receives through its "**kwargs" parameter +class TypedKwarg { +public: + TypedKwarg(Identifier name, LogicalType type); + + //! The name the function receives the option under + Identifier name; + //! Other names a caller can pass the option by + vector aliases; + //! The type a passed value is cast to - ANY passes it through as-is, for the function to check + LogicalType type; + +public: + DUCKDB_API bool operator==(const TypedKwarg &other) const; + DUCKDB_API bool operator!=(const TypedKwarg &other) const; + DUCKDB_API string ToString() const; +}; + +//! The "options" a function receives through its "**kwargs" parameter +//! This is basically just a way to have the binder enforce a set of accepted types and names +//! as trailing keyword-only parameters, without having to declare them as actual parameters. +//! "options" are not really part of the function signature, so they do not affect overload resolution +class TypedKwargs { +public: + //! Adds an option - a call that leaves it out does not pass it, the function decides what that means + DUCKDB_API TypedKwargs &Add(Identifier name, LogicalType type); + //! Adds another name for the option added last + DUCKDB_API TypedKwargs &Alias(Identifier alias); + + //! A schema holding the options of this one followed by those of the other + DUCKDB_API TypedKwargs Merge(const TypedKwargs &other) const; + + //! The option a name or an alias refers to, or nullptr if the schema declares no such name + DUCKDB_API optional_ptr Find(const Identifier &name) const; + //! The options in the order they were added + DUCKDB_API const vector &GetOptions() const; + //! Every name and alias the schema declares + DUCKDB_API vector GetNames() const; + + DUCKDB_API bool operator==(const TypedKwargs &other) const; + DUCKDB_API bool operator!=(const TypedKwargs &other) const; + DUCKDB_API hash_t Hash() const; + + //! Adding does not check the names - this does, once the schema is complete + //! @throws InvalidInputException if a name or an alias is declared twice + DUCKDB_API void Verify() const; + +private: + vector options; +}; + class FunctionSignature { public: FunctionSignature() = default; - FunctionSignature(vector arguments, LogicalType varargs, LogicalType return_type) - : return_type(std::move(return_type)) { - for (auto &arg : arguments) { - AddParameter(std::move(arg)); - } - if (varargs.id() != LogicalTypeId::INVALID) { - SetVarArgs(std::move(varargs)); - } - } FunctionSignature(vector parameters, LogicalType return_type) : parameters(std::move(parameters)), return_type(std::move(return_type)) { } - FunctionSignature(vector parameters, LogicalType varargs, LogicalType return_type) - : parameters(std::move(parameters)), return_type(std::move(return_type)) { - if (varargs.id() != LogicalTypeId::INVALID) { - SetVarArgs(std::move(varargs)); + FunctionSignature(vector arguments, LogicalType return_type) : return_type(std::move(return_type)) { + for (auto &arg : arguments) { + AddParameter(std::move(arg)); } } - FunctionSignature(vector arguments, LogicalType return_type) - : FunctionSignature(std::move(arguments), LogicalType(LogicalTypeId::INVALID), std::move(return_type)) { - } string ToString() const; @@ -213,6 +267,15 @@ class FunctionSignature { bool operator!=(const FunctionSignature &other) const; bool Equal(const FunctionSignature &other) const; + //! Whether both declare the same overload. As in C++ and Postgres, the types identify an overload, and a call that + //! matches two distinct ones is reported as ambiguous when it is made. They are the same when: + //! - the parameters a caller can pass by position match in order, by type - whatever their names, and whether + //! they are positional-only or not + //! - "*args" and "**kwargs" match, by type + //! - the keyword-only parameters match by name and type, in any order - a caller can only pass them by name + //! Defaults and the options of "**kwargs" are ignored: every call the overload without a default accepts, both + //! accept at the same cost, and options take no part in overload selection + DUCKDB_API bool IsSameOverload(const FunctionSignature &other) const; public: auto GetParameter(idx_t index) const -> const FunctionParameter & { @@ -227,7 +290,6 @@ class FunctionSignature { auto GetParameterCount() const -> idx_t { return parameters.size(); } - auto GetReturnType() const -> const LogicalType & { return return_type; } @@ -235,56 +297,78 @@ class FunctionSignature { return_type = std::move(return_type_p); } - //! Whether the signature has a "*args" parameter - auto HasVarArgs() const -> bool { - return GetArgsParameter() != nullptr; + auto IsVariadic() const -> bool { + for (auto ¶m : parameters) { + if (param.IsVariadic()) { + return true; + } + } + return false; } - //! The type of the "*args" parameter, or INVALID if there is none - DUCKDB_API auto GetVarArgs() const -> const LogicalType &; - //! Replaces the variadic parameters by an "*args" and "**kwargs" of the given type, so that any trailing argument - //! is accepted. Removes the variadic parameters if the type is INVALID. - DUCKDB_API auto SetVarArgs(LogicalType varargs_p) -> void; - auto GetArgsParameter() const -> optional_ptr { - return GetParameterByKind(FunctionParameterKind::VAR_POSITIONAL); + auto GetArgs() const -> optional_ptr { + for (auto ¶m : parameters) { + if (param.GetKind() == FunctionParameterKind::VAR_POSITIONAL) { + return ¶m; + } + } + return nullptr; } - auto GetKwargsParameter() const -> optional_ptr { - return GetParameterByKind(FunctionParameterKind::VAR_KEYWORD); + + auto GetKwargs() const -> optional_ptr { + for (auto ¶m : parameters) { + if (param.GetKind() == FunctionParameterKind::VAR_KEYWORD) { + return ¶m; + } + } + return nullptr; } - //! A parameter added after "*args" is keyword-only - auto AddParameter(Identifier name, LogicalType type, Value default_value) -> FunctionSignature & { - parameters.emplace_back(std::move(name), std::move(type), std::move(default_value), GetNextKind()); - return *this; + //! The schema the "**kwargs" parameter receives, or nullptr if it accepts any kwargs + auto GetTypedKwargs() const -> optional_ptr { + return typed_kwargs.get(); } - auto AddParameter(Identifier name, LogicalType type) -> FunctionSignature & { - parameters.emplace_back(std::move(name), std::move(type), GetNextKind()); + auto AddParameter(Identifier name, LogicalType type, optional default_value = {}, + FunctionParameterKind kind = FunctionParameterKind::STANDARD) -> FunctionSignature & { + parameters.emplace_back(std::move(name), std::move(type), std::move(default_value), kind); return *this; } - + //! Adds a positional-only parameter named "col", after its position - a caller cannot pass it by a name that + //! was never declared auto AddParameter(LogicalType type) -> FunctionSignature & { - auto name = StringUtil::Format("col%d", parameters.size()); - return AddParameter(Identifier(name), std::move(type)); + auto name = Identifier(StringUtil::Format("col%d", parameters.size())); + return AddPositionalOnly(std::move(name), std::move(type)); } - - //! Adds a "*args" parameter, receiving all remaining positional arguments - auto AddArgsParameter(Identifier name, LogicalType type) -> FunctionSignature & { - parameters.emplace_back(std::move(name), std::move(type), FunctionParameterKind::VAR_POSITIONAL); - return *this; + auto AddKeywordOnly(Identifier name, LogicalType type, optional default_value = {}) -> FunctionSignature & { + return AddParameter(std::move(name), std::move(type), std::move(default_value), + FunctionParameterKind::KEYWORD_ONLY); } - - //! Adds a "**kwargs" parameter, receiving all named arguments that do not match another parameter - auto AddKwargsParameter(Identifier name, LogicalType type) -> FunctionSignature & { - parameters.emplace_back(std::move(name), std::move(type), FunctionParameterKind::VAR_KEYWORD); - return *this; + auto AddPositionalOnly(Identifier name, LogicalType type) -> FunctionSignature & { + return AddParameter(std::move(name), std::move(type), {}, FunctionParameterKind::POSITIONAL_ONLY); + } + auto AddArgs(Identifier name, LogicalType type) -> FunctionSignature & { + return AddParameter(std::move(name), std::move(type), {}, FunctionParameterKind::VAR_POSITIONAL); } + auto AddKwargs(Identifier name, LogicalType type) -> FunctionSignature & { + return AddParameter(std::move(name), std::move(type), {}, FunctionParameterKind::VAR_KEYWORD); + } + + //! Adds a "**name" parameter that receives only the options of the given schema + DUCKDB_API auto AddTypedKwargs(Identifier name, TypedKwargs schema) -> FunctionSignature &; + //! The same, with the schema declared by the given callback + DUCKDB_API auto WithTypedKwargs(Identifier name, const std::function &configure) + -> FunctionSignature &; + //! Adds options to the schema of the "**kwargs" parameter + //! @throws InternalException if the signature has no typed "**kwargs" parameter + DUCKDB_API auto ExtendTypedKwargs(const std::function &configure) -> FunctionSignature &; - //! Returns the index of the non-variadic parameter with the given name + //! Returns the index of the parameter a caller can pass by the given name. Skips the variadic parameters and the + //! positional-only ones, whose names a caller cannot use auto GetParameterIndexByName(const Identifier &name) const -> optional_idx { // Parameter names are matched case-insensitively, consistent with SQL identifier semantics. for (idx_t i = 0; i < parameters.size(); i++) { - if (!parameters[i].IsVariadic() && parameters[i].GetName() == name) { + if (parameters[i].AcceptsName() && parameters[i].GetName() == name) { return i; } } @@ -294,7 +378,16 @@ class FunctionSignature { //! The number of leading parameters that can be passed by position auto GetPositionalParameterCount() const -> idx_t { idx_t result = 0; - while (result < parameters.size() && parameters[result].GetKind() == FunctionParameterKind::STANDARD) { + while (result < parameters.size() && parameters[result].AcceptsPosition()) { + result++; + } + return result; + } + + //! The number of leading parameters that can ONLY be passed by position + auto GetPositionalOnlyParameterCount() const -> idx_t { + idx_t result = 0; + while (result < parameters.size() && parameters[result].GetKind() == FunctionParameterKind::POSITIONAL_ONLY) { result++; } return result; @@ -310,30 +403,18 @@ class FunctionSignature { return result; } + //! Puts the named arguments in binding order: every keyword-only parameter in declaration order, with its default + //! if the call left it out, then the arguments "**kwargs" receives in the order they were passed + //! A default is cast to its parameter's type, as FunctionBinder::CastToParameterType casts an argument + DUCKDB_API void FillNamedDefaults(ClientContext &context, named_argument_map_t &named_parameters) const; + DUCKDB_API void Verify() const; hash_t Hash() const; -private: - auto GetParameterByKind(FunctionParameterKind kind) const -> optional_ptr { - for (const auto ¶m : parameters) { - if (param.GetKind() == kind) { - return param; - } - } - return nullptr; - } - auto GetNextKind() const -> FunctionParameterKind { - for (const auto ¶m : parameters) { - if (param.GetKind() != FunctionParameterKind::STANDARD) { - return FunctionParameterKind::KEYWORD_ONLY; - } - } - return FunctionParameterKind::STANDARD; - } - private: vector parameters; + shared_ptr typed_kwargs; // optional "schema" for the accepted **kwargs LogicalType return_type; }; @@ -392,10 +473,6 @@ class Function { DUCKDB_API static string CallToString(const Identifier &catalog_name, const Identifier &schema_name, const Identifier &name, const vector &arguments, const LogicalType &varargs, const LogicalType &return_type); - //! Returns the formatted string name(arg1, arg2.., np1=a, np2=b, ...) - DUCKDB_API static string CallToString(const Identifier &catalog_name, const Identifier &schema_name, - const Identifier &name, const vector &arguments, - const named_parameter_type_map_t &named_parameters); private: QualifiedName qualified_name; @@ -422,18 +499,6 @@ class SimpleFunction : public Function { return signature; } - const LogicalType &GetVarArgs() const { - return signature.GetVarArgs(); - } - - void SetVarArgs(LogicalType varargs_p) { - signature.SetVarArgs(std::move(varargs_p)); - } - - DUCKDB_API bool HasVarArgs() const { - return signature.HasVarArgs(); - } - void SetReturnType(LogicalType return_type_p) { signature.SetReturnType(std::move(return_type_p)); } @@ -442,47 +507,6 @@ class SimpleFunction : public Function { } }; -class SimpleNamedParameterFunction : public Function { -public: - DUCKDB_API SimpleNamedParameterFunction(Identifier name, vector arguments, - LogicalType varargs = LogicalType(LogicalTypeId::INVALID)); - DUCKDB_API ~SimpleNamedParameterFunction() override; - - //! The set of arguments of the function - vector arguments; - //! The type of varargs to support, or LogicalTypeId::INVALID if the function does not accept variable length - //! arguments - LogicalType varargs; - - //! The named parameters of the function - named_parameter_type_map_t named_parameters; - -public: - DUCKDB_API virtual string ToString() const; - DUCKDB_API bool HasNamedParameters() const; - - vector &GetArguments() { - return arguments; - } - const vector &GetArguments() const { - return arguments; - } - - const LogicalType &GetVarArgs() const { - return varargs; - } - LogicalType &GetVarArgs() { - return varargs; - } - // TODO: Dont expose mutable accessor - void SetVarArgs(LogicalType varargs_p) { - varargs = std::move(varargs_p); - } - bool HasVarArgs() const { - return varargs.id() != LogicalTypeId::INVALID; - } -}; - class FunctionProperties { public: auto GetStability() const -> FunctionStability { diff --git a/src/duckdb/src/include/duckdb/function/function_binder.hpp b/src/duckdb/src/include/duckdb/function/function_binder.hpp index ed8d32f59..967252fcc 100644 --- a/src/duckdb/src/include/duckdb/function/function_binder.hpp +++ b/src/duckdb/src/include/duckdb/function/function_binder.hpp @@ -36,9 +36,6 @@ struct FunctionOverloads { DUCKDB_API static optional_idx Cost(optional_ptr context, const SimpleFunction &func, const vector &arguments, const vector> &named_arguments); - DUCKDB_API static optional_idx Cost(optional_ptr context, const SimpleNamedParameterFunction &func, - const vector &arguments, - const vector> &); //! All overloads that match at the lowest cost. Empty (and error set) if none match. template @@ -119,9 +116,29 @@ class FunctionBinder { const vector>> &keyword_args, ErrorData &error); + //! Bind a table function: select the overload, check the named arguments against its signature, and cast both + //! the positional and the named arguments to the types it declares + DUCKDB_API optional_idx BindFunction(const Identifier &name, const TableFunctionSet &functions, + vector> &positional_arguments, + vector>> &named_arguments, + vector ¶meters, named_argument_map_t &named_parameters, + ErrorData &error); + + //! Casts a constant to the type of the parameter it fills, as an argument of any function is cast - a parameter + //! whose type is not concrete, such as ANY, takes it as it is + DUCKDB_API static Value CastToParameterType(ClientContext &context, Value value, const LogicalType ¶meter_type); + + //! Bind a table in-out function. Its arguments are the columns of an input table, so there is nothing to place + //! or fold - only the overload is chosen + DUCKDB_API optional_idx BindTableInOutFunction(const Identifier &name, const TableFunctionSet &functions, + const vector &input_types, ErrorData &error); + //! Bind a pragma function from the set of functions and input arguments DUCKDB_API optional_idx BindFunction(const Identifier &name, const PragmaFunctionSet &functions, - vector ¶meters, ErrorData &error); + vector> &positional_arguments, + vector>> &named_arguments, + vector ¶meters, named_argument_map_t &named_parameters, + ErrorData &error); DUCKDB_API unique_ptr BindScalarFunction(const Identifier &schema, const Identifier &name, vector> children, ErrorData &error, diff --git a/src/duckdb/src/include/duckdb/function/function_serialization.hpp b/src/duckdb/src/include/duckdb/function/function_serialization.hpp index aadc052be..a31811d25 100644 --- a/src/duckdb/src/include/duckdb/function/function_serialization.hpp +++ b/src/duckdb/src/include/duckdb/function/function_serialization.hpp @@ -80,7 +80,7 @@ class FunctionSerializer { if (!serializer.ShouldSerialize(StorageVersion::V2_0_0)) { serializer.WriteProperty(500, "name", function.GetName()); } - serializer.WriteProperty(501, "arguments", function.GetArguments()); + serializer.WriteProperty(501, "arguments", GetSerializedArguments(serializer, function)); if (!serializer.ShouldSerialize(StorageVersion::V2_0_0)) { // binds no longer erase the arguments they fold into their bind data, so the argument list above is // always the full one - older versions read this field unconditionally, so write it (empty) for them @@ -106,6 +106,33 @@ class FunctionSerializer { } } + //! Older versions select a table function by its positional arguments alone + template + static vector GetSerializedArguments(Serializer &serializer, const FUNC &function) { + if constexpr (std::is_same_v) { + if (!serializer.ShouldSerialize(StorageVersion::V2_0_0)) { + VerifyLegacyTableFunctionArguments(function); + auto &arguments = function.GetArguments(); + auto positional_end = arguments.begin() + NumericCast(function.GetPositionalArgumentCount()); + return vector(arguments.begin(), positional_end); + } + } + return function.GetArguments(); + } + + //! A required keyword-only option selects its overload, which an older version cannot be told about + static void VerifyLegacyTableFunctionArguments(const BoundTableFunction &function) { + auto &signature = function.GetSignature(); + for (auto &name : function.GetNamedArguments()) { + auto param_idx = signature.GetParameterIndexByName(name); + if (param_idx.IsValid() && !signature.GetParameter(param_idx.GetIndex()).HasDefaultValue()) { + throw SerializationException("Table function %s has a required keyword-only parameter %s, which " + "cannot be serialized to a storage version older than v2.0.0", + function.GetName(), name); + } + } + } + //! Only written if the function was called with keyword-only or "**kwargs" arguments template static void SerializeNamedArguments(Serializer &serializer, const FUNC &function) { @@ -113,6 +140,12 @@ class FunctionSerializer { if (named_arguments.empty()) { return; } + if constexpr (std::is_same_v) { + if (!serializer.ShouldSerialize(StorageVersion::V2_0_0)) { + // older versions read a table function's options from the operator's named parameters instead + return; + } + } if (!serializer.ShouldSerialize(StorageVersion::V2_0_0)) { if (named_arguments.size() > function.GetKwargsCount()) { throw SerializationException("Function %s has keyword-only parameters, which cannot be serialized " @@ -134,44 +167,89 @@ class FunctionSerializer { } } - template - static FUNC DeserializeFunction(ClientContext &context, CatalogType catalog_type, - const QualifiedName &qualified_name, const vector &arguments) { - auto &func_catalog = Catalog::GetEntry(context, catalog_type, qualified_name); - - if (func_catalog.type != catalog_type) { - throw InternalException("DeserializeFunction - cant find catalog entry for function %s", - qualified_name.Name().GetIdentifierName()); + //! Splits the argument types a plan recorded into those passed by position and those passed by name + static void SplitArgumentTypes(const QualifiedName &qualified_name, const vector &arguments, + idx_t positional_count, const vector &named_arguments, + vector &positional_types, + vector> &keyword_types) { + if (positional_count + named_arguments.size() != arguments.size()) { + throw SerializationException("Function %s has %llu argument types, but %llu positional and %llu named " + "arguments", + qualified_name.ToString(), arguments.size(), positional_count, + named_arguments.size()); + } + for (idx_t arg_idx = 0; arg_idx < arguments.size(); arg_idx++) { + if (arg_idx < positional_count) { + positional_types.push_back(arguments[arg_idx]); + } else { + keyword_types.emplace_back(named_arguments[arg_idx - positional_count], arguments[arg_idx]); + } } - auto &functions = func_catalog.Cast(); - return *functions.functions.GetFunctionByArguments(context, arguments); } - template - static pair DeserializeBase(Deserializer &deserializer, CatalogType catalog_type, - optional_ptr>> children = nullptr) { + //! Selects the overload of a plan written before v2.0.0, which records its named arguments only as the operator's + //! named parameters. Required keyword-only parameters are treated as if they had a default - the bind receives + //! those named parameters and rejects a missing one, as it did when the plan was written + static optional_idx SelectWithoutNamedArguments(FunctionBinder &binder, const Identifier &name, + const TableFunctionSet &functions, + const vector &positional_types) { + auto relaxed = functions; + relaxed.ApplyToFunctions([](TableFunction &function) { + auto &signature = function.GetSignature(); + for (idx_t i = 0; i < signature.GetParameterCount(); i++) { + auto ¶m = signature.GetParameter(i); + if (param.GetKind() == FunctionParameterKind::KEYWORD_ONLY && !param.HasDefaultValue()) { + // selection only checks that there is a default - an untyped NULL suits a parameter of any type + param.SetDefaultValue(Value()); + } + } + }); + ErrorData error; + return binder.BindFunction(name, relaxed, positional_types, {}, error); + } + + //! Deserializes a table function, and whether the plan holds its bind data. Without it, the caller binds again + static pair DeserializeTableFunction(Deserializer &deserializer) { auto &context = deserializer.Get(); auto name = deserializer.ReadPropertyWithDefault(500, "name"); auto arguments = deserializer.ReadProperty>(501, "arguments"); auto original_arguments = deserializer.ReadPropertyWithDefault>(502, "original_arguments"); auto qualified_name = DeserializeQualifiedName(deserializer, std::move(name)); + auto has_serialize = deserializer.ReadProperty(503, "has_serialize"); + auto positional_count = deserializer.ReadPropertyWithDefault(508, "positional_arguments"); + auto named_arguments = deserializer.ReadPropertyWithDefault>(509, "named_arguments"); + RestoreErasedArguments(arguments, original_arguments); + if (named_arguments.empty()) { + positional_count = arguments.size(); + } - if (arguments.empty() && children && !children->empty()) { - // The function is specified as having no arguments, but somehow expressions were passed anyway - // Assume this is a "varargs" function and use the types of the expressions as the arguments - // This can happen when we change a function that used to take varargs, to no longer do so. - arguments.reserve(children->size()); - for (auto &child : *children) { - arguments.push_back(child->GetReturnType()); - } + auto &func_catalog = Catalog::GetEntry(context, CatalogType::TABLE_FUNCTION_ENTRY, qualified_name); + if (func_catalog.type != CatalogType::TABLE_FUNCTION_ENTRY) { + throw InternalException("DeserializeTableFunction - cant find catalog entry for function %s", + qualified_name.Name().GetIdentifierName()); } + auto &functions = func_catalog.Cast().functions; - auto function = DeserializeFunction(context, catalog_type, qualified_name, arguments); - auto has_serialize = deserializer.ReadProperty(503, "has_serialize"); - if (has_serialize) { - function.GetArguments() = std::move(arguments); + // the named arguments take part in selecting the overload, exactly as they did when the call was bound + vector positional_types; + vector> keyword_types; + SplitArgumentTypes(qualified_name, arguments, positional_count, named_arguments, positional_types, + keyword_types); + FunctionBinder binder(context); + ErrorData error; + auto func_idx = binder.BindFunction(qualified_name.Name(), functions, positional_types, keyword_types, error); + if (!func_idx.IsValid() && named_arguments.empty()) { + func_idx = SelectWithoutNamedArguments(binder, qualified_name.Name(), functions, positional_types); + } + if (!func_idx.IsValid()) { + throw SerializationException("Failed to find function %s(%s)\n%s", qualified_name.ToString(), + StringUtil::ToString(arguments, ","), error.RawMessage()); } + + BoundTableFunction function(functions.GetFunctionByOffset(func_idx.GetIndex())); + function.GetArguments() = std::move(arguments); + function.SetNamedArguments(positional_count, std::move(named_arguments)); return make_pair(std::move(function), has_serialize); } @@ -234,7 +312,7 @@ class FunctionSerializer { idx_t standard_count = 0; for (auto &function : functions.functions) { auto &signature = function->GetSignature(); - if (!signature.GetKwargsParameter()) { + if (!signature.GetKwargs()) { continue; } takes_named = true; diff --git a/src/duckdb/src/include/duckdb/function/function_set_base.hpp b/src/duckdb/src/include/duckdb/function/function_set_base.hpp index 181588c78..5778a2267 100644 --- a/src/duckdb/src/include/duckdb/function/function_set_base.hpp +++ b/src/duckdb/src/include/duckdb/function/function_set_base.hpp @@ -30,8 +30,9 @@ class FunctionSet { vector> functions; public: - void AddFunction(T function) { + auto AddFunction(T function) & -> FunctionSet & { functions.push_back(make_shared_ptr(std::move(function))); + return *this; } void AddFunction(shared_ptr function) { functions.push_back(std::move(function)); @@ -61,7 +62,8 @@ class FunctionSet { for (auto &new_func : new_functions.functions) { bool overwritten = false; for (auto &func : functions) { - if (new_func->Equal(*func)) { + // the same rule for every kind of function - see FunctionSignature::IsSameOverload + if (new_func->GetSignature().IsSameOverload(func->GetSignature())) { // function overload already exists if (override) { // override it diff --git a/src/duckdb/src/include/duckdb/function/pragma_function.hpp b/src/duckdb/src/include/duckdb/function/pragma_function.hpp index f06783b57..200f7a8f6 100644 --- a/src/duckdb/src/include/duckdb/function/pragma_function.hpp +++ b/src/duckdb/src/include/duckdb/function/pragma_function.hpp @@ -28,7 +28,7 @@ typedef void (*pragma_function_t)(ClientContext &context, const FunctionParamete //! -> this is similar to a call pragma but without parameters //! Pragma functions can either return a new query to execute (pragma_query_t) //! or they can -class PragmaFunction : public SimpleNamedParameterFunction { // NOLINT: work-around bug in clang-tidy +class PragmaFunction : public SimpleFunction { // NOLINT: work-around bug in clang-tidy public: // Call DUCKDB_API static PragmaFunction PragmaCall(const Identifier &name, pragma_query_t query, @@ -37,22 +37,40 @@ class PragmaFunction : public SimpleNamedParameterFunction { // NOLINT: work-aro DUCKDB_API static PragmaFunction PragmaCall(const Identifier &name, pragma_function_t function, vector arguments, LogicalType varargs = LogicalType::INVALID); + //! Overloads taking a braced list, so that "{}" does not also match FunctionSignature + static PragmaFunction PragmaCall(const Identifier &name, pragma_query_t query, + std::initializer_list arguments, + LogicalType varargs = LogicalType::INVALID) { + return PragmaCall(name, query, vector(arguments), std::move(varargs)); + } + static PragmaFunction PragmaCall(const Identifier &name, pragma_function_t function, + std::initializer_list arguments, + LogicalType varargs = LogicalType::INVALID) { + return PragmaCall(name, function, vector(arguments), std::move(varargs)); + } + //! The same, declaring the parameters in full - so that they carry their own names and defaults instead of the + //! synthetic "colN" the type-only overloads give them + DUCKDB_API static PragmaFunction PragmaCall(const Identifier &name, pragma_query_t query, + FunctionSignature signature); + DUCKDB_API static PragmaFunction PragmaCall(const Identifier &name, pragma_function_t function, + FunctionSignature signature); // Statement DUCKDB_API static PragmaFunction PragmaStatement(const Identifier &name, pragma_query_t query); DUCKDB_API static PragmaFunction PragmaStatement(const Identifier &name, pragma_function_t function); - DUCKDB_API string ToString() const override; + DUCKDB_API string ToString() const; public: PragmaType type; pragma_query_t query; pragma_function_t function; - named_parameter_type_map_t named_parameters; private: PragmaFunction(Identifier name, PragmaType pragma_type, pragma_query_t query, pragma_function_t function, vector arguments, LogicalType varargs); + PragmaFunction(Identifier name, PragmaType pragma_type, pragma_query_t query, pragma_function_t function, + FunctionSignature signature); }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/function/scalar_function.hpp b/src/duckdb/src/include/duckdb/function/scalar_function.hpp index 0df23f0da..90650f647 100644 --- a/src/duckdb/src/include/duckdb/function/scalar_function.hpp +++ b/src/duckdb/src/include/duckdb/function/scalar_function.hpp @@ -460,8 +460,6 @@ class ScalarFunction : public BaseScalarFunction, DUCKDB_API bool operator==(const ScalarFunction &rhs) const; DUCKDB_API bool operator!=(const ScalarFunction &rhs) const; - DUCKDB_API bool Equal(const ScalarFunction &rhs) const; - public: unique_ptr Bind(ClientContext &context, vector> arguments, optional_ptr binder = nullptr) const; diff --git a/src/duckdb/src/include/duckdb/function/table_function.hpp b/src/duckdb/src/include/duckdb/function/table_function.hpp index fe85651e1..31514ce06 100644 --- a/src/duckdb/src/include/duckdb/function/table_function.hpp +++ b/src/duckdb/src/include/duckdb/function/table_function.hpp @@ -38,6 +38,7 @@ class BaseStatistics; class LogicalDependencyList; class LogicalGet; class TableFunction; +class BoundTableFunction; class TableFilterSet; class TableFunctionRef; class TableCatalogEntry; @@ -109,10 +110,10 @@ struct LocalTableFunctionState { }; struct TableFunctionBindInput { - TableFunctionBindInput(vector &inputs, named_parameter_map_t &named_parameters, + TableFunctionBindInput(vector &inputs, named_argument_map_t &named_parameters, vector &input_table_types, vector &input_table_names, optional_ptr info, optional_ptr binder, - TableFunction &table_function, const TableFunctionRef &ref, + BoundTableFunction &table_function, const TableFunctionRef &ref, optional_ptr> input_plan = nullptr) : inputs(inputs), named_parameters(named_parameters), input_table_types(input_table_types), input_table_names(input_table_names), info(info), binder(binder), table_function(table_function), ref(ref), @@ -120,12 +121,12 @@ struct TableFunctionBindInput { } vector &inputs; - named_parameter_map_t &named_parameters; + named_argument_map_t &named_parameters; vector &input_table_types; vector &input_table_names; optional_ptr info; optional_ptr binder; - TableFunction &table_function; + BoundTableFunction &table_function; const TableFunctionRef &ref; optional_ptr> input_plan; //! (Optional) The schema this bind is expected to produce. This is set when binding a single file of a @@ -256,10 +257,10 @@ struct TableFunctionProjectionExpressionInput { }; struct TableFunctionToStringInput { - TableFunctionToStringInput(const TableFunction &table_function_p, optional_ptr bind_data_p) + TableFunctionToStringInput(const BoundTableFunction &table_function_p, optional_ptr bind_data_p) : table_function(table_function_p), bind_data(bind_data_p) { } - const TableFunction &table_function; + const BoundTableFunction &table_function; optional_ptr bind_data; }; @@ -292,11 +293,11 @@ struct TableFunctionGetStatisticsInput { }; struct GetPartitionStatsInput { - GetPartitionStatsInput(const TableFunction &table_function_p, optional_ptr bind_data_p) + GetPartitionStatsInput(const BoundTableFunction &table_function_p, optional_ptr bind_data_p) : table_function(table_function_p), bind_data(bind_data_p) { } - const TableFunction &table_function; + const BoundTableFunction &table_function; optional_ptr bind_data; }; @@ -385,7 +386,7 @@ typedef OperatorPartitionData (*table_function_get_partition_data_t)(ClientConte typedef BindInfo (*table_function_get_bind_info_t)(const optional_ptr bind_data); -typedef unique_ptr (*table_function_get_multi_file_reader_t)(const TableFunction &); +typedef unique_ptr (*table_function_get_multi_file_reader_t)(const BoundTableFunction &); typedef bool (*table_function_supports_pushdown_type_t)(const FunctionData &bind_data, idx_t col_idx); @@ -437,8 +438,9 @@ struct TableFunctionToSQLResult { typedef TableFunctionToSQLResult (*table_function_to_sql_t)(ClientContext &context, const LogicalGet &get); typedef void (*table_function_serialize_t)(Serializer &serializer, const optional_ptr bind_data, - const TableFunction &function); -typedef unique_ptr (*table_function_deserialize_t)(Deserializer &deserializer, TableFunction &function); + const BoundTableFunction &function); +typedef unique_ptr (*table_function_deserialize_t)(Deserializer &deserializer, + BoundTableFunction &function); typedef bool (*table_function_projection_expression_pushdown_t)(ClientContext &context, const TableFunctionProjectionExpressionInput &input); @@ -465,25 +467,13 @@ enum class TableFunctionInitialization { INITIALIZE_ON_EXECUTE, INITIALIZE_ON_SC enum class TableFunctionReturnType { TABLE_RETURNING_FUNCTION, SET_RETURNING_FUNCTION }; -class TableFunction : public SimpleNamedParameterFunction { // NOLINT: work-around bug in clang-tidy +//! The callbacks and flags that make up a table function's behaviour, shared by the unbound TableFunction and by the +//! BoundTableFunction that a bound call produces. It deliberately does not derive from Function, so that each of the +//! two can pair it with its own name and argument representation - the split BaseScalarFunction makes for scalars +class BaseTableFunction { public: - DUCKDB_API TableFunction(); - // Overloads taking table_function_t - DUCKDB_API - TableFunction(Identifier name, const vector &arguments, table_function_t function, - table_function_bind_t bind = nullptr, table_function_init_global_t init_global = nullptr, - table_function_init_local_t init_local = nullptr); - DUCKDB_API - TableFunction(const vector &arguments, table_function_t function, table_function_bind_t bind = nullptr, - table_function_init_global_t init_global = nullptr, table_function_init_local_t init_local = nullptr); - // Overloads taking std::nullptr - DUCKDB_API - TableFunction(Identifier name, const vector &arguments, std::nullptr_t function, - table_function_bind_t bind = nullptr, table_function_init_global_t init_global = nullptr, - table_function_init_local_t init_local = nullptr); - DUCKDB_API - TableFunction(const vector &arguments, std::nullptr_t function, table_function_bind_t bind = nullptr, - table_function_init_global_t init_global = nullptr, table_function_init_local_t init_local = nullptr); + DUCKDB_API BaseTableFunction(table_function_t function, table_function_bind_t bind, + table_function_init_global_t init_global, table_function_init_local_t init_local); bool HasBindCallback() const { return bind != nullptr; @@ -640,9 +630,109 @@ class TableFunction : public SimpleNamedParameterFunction { // NOLINT: work-arou //! How this table function manages parallelism TableFunctionParallelism parallelism = TableFunctionParallelism::SELF_MANAGED_PARALLELISM; - DUCKDB_API bool Equal(const TableFunction &rhs) const; + DUCKDB_API bool operator==(const BaseTableFunction &rhs) const; +}; + +//! A table function as it is registered in the catalog: its behaviour, plus the signature declaring what it accepts +class TableFunction : public BaseTableFunction, public SimpleFunction { // NOLINT: work-around bug in clang-tidy +public: + DUCKDB_API TableFunction(); + // Overloads taking table_function_t + DUCKDB_API + TableFunction(Identifier name, const vector &arguments, table_function_t function, + table_function_bind_t bind = nullptr, table_function_init_global_t init_global = nullptr, + table_function_init_local_t init_local = nullptr); + DUCKDB_API + TableFunction(const vector &arguments, table_function_t function, table_function_bind_t bind = nullptr, + table_function_init_global_t init_global = nullptr, table_function_init_local_t init_local = nullptr); + // Overloads taking std::nullptr + DUCKDB_API + TableFunction(Identifier name, const vector &arguments, std::nullptr_t function, + table_function_bind_t bind = nullptr, table_function_init_global_t init_global = nullptr, + table_function_init_local_t init_local = nullptr); + DUCKDB_API + TableFunction(const vector &arguments, std::nullptr_t function, table_function_bind_t bind = nullptr, + table_function_init_global_t init_global = nullptr, table_function_init_local_t init_local = nullptr); + // Overloads taking a braced list, so that "{}" does not also match FunctionSignature + TableFunction(Identifier name, std::initializer_list arguments, table_function_t function, + table_function_bind_t bind = nullptr, table_function_init_global_t init_global = nullptr, + table_function_init_local_t init_local = nullptr) + : TableFunction(std::move(name), vector(arguments), function, bind, init_global, init_local) { + } + TableFunction(Identifier name, std::initializer_list arguments, std::nullptr_t function, + table_function_bind_t bind = nullptr, table_function_init_global_t init_global = nullptr, + table_function_init_local_t init_local = nullptr) + : TableFunction(std::move(name), vector(arguments), function, bind, init_global, init_local) { + } + TableFunction(std::initializer_list arguments, table_function_t function, + table_function_bind_t bind = nullptr, table_function_init_global_t init_global = nullptr, + table_function_init_local_t init_local = nullptr) + : TableFunction(vector(arguments), function, bind, init_global, init_local) { + } + TableFunction(std::initializer_list arguments, std::nullptr_t function, + table_function_bind_t bind = nullptr, table_function_init_global_t init_global = nullptr, + table_function_init_local_t init_local = nullptr) + : TableFunction(vector(arguments), function, bind, init_global, init_local) { + } + // Overloads taking proper signatures + DUCKDB_API + TableFunction(Identifier name, FunctionSignature signature, table_function_t function, + table_function_bind_t bind = nullptr, table_function_init_global_t init_global = nullptr, + table_function_init_local_t init_local = nullptr); + DUCKDB_API + TableFunction(Identifier name, FunctionSignature signature, std::nullptr_t function, + table_function_bind_t bind = nullptr, table_function_init_global_t init_global = nullptr, + table_function_init_local_t init_local = nullptr); + + DUCKDB_API + TableFunction(FunctionSignature signature, table_function_t function, table_function_bind_t bind = nullptr, + table_function_init_global_t init_global = nullptr, table_function_init_local_t init_local = nullptr); + +public: DUCKDB_API bool operator==(const TableFunction &rhs) const; DUCKDB_API bool operator!=(const TableFunction &rhs) const; }; +//! A table function as a bound call refers to it: its behaviour, plus the argument types the call was bound with. +//! Those are the types plan serialization records, so they must survive independently of the catalog's declaration +class BoundTableFunction : public BaseTableFunction, public BoundSimpleFunction { +public: + DUCKDB_API BoundTableFunction(); + DUCKDB_API explicit BoundTableFunction(const TableFunction &function); + DUCKDB_API explicit BoundTableFunction(shared_ptr function); + + //! The function this was bound from. For a function bound from a TableFunctionSet this is the set's own + //! overload, so it compares equal by pointer across binds. Functions bound outside of a set are copied into a + //! definition of their own. Only null in a moved-from bound function + const shared_ptr &GetDefinition() const { + return definition; + } + //! The signature this call was bound against + const FunctionSignature &GetSignature() const { + return definition->GetSignature(); + } + //! The number of arguments that were received by "*args", they directly follow the standard parameters + idx_t GetVarArgsCount() const { + return BoundSimpleFunction::GetVarArgsCount(definition->GetSignature()); + } + //! The number of arguments that were received by "**kwargs", they are the last arguments + idx_t GetKwargsCount() const { + return BoundSimpleFunction::GetKwargsCount(definition->GetSignature()); + } + //! The kind of the parameter that received the argument at the given index + FunctionParameterKind GetArgumentParameterKind(idx_t argument_index) const { + return BoundSimpleFunction::GetArgumentParameterKind(definition->GetSignature(), argument_index); + } + //! Records the arguments of the call this was bound to, laid out as [standard | *args | keyword-only | **kwargs]. + //! Plan serialization writes them, so that deserialization selects the same overload the call did + DUCKDB_API void SetCallArguments(const vector ¶meters, const named_argument_map_t &named_parameters); + +private: + shared_ptr definition; + +public: + DUCKDB_API bool operator==(const BoundTableFunction &rhs) const; + DUCKDB_API bool operator!=(const BoundTableFunction &rhs) const; +}; + } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/main/capi/capi_function_signature.hpp b/src/duckdb/src/include/duckdb/main/capi/capi_function_signature.hpp new file mode 100644 index 000000000..74dcaee5b --- /dev/null +++ b/src/duckdb/src/include/duckdb/main/capi/capi_function_signature.hpp @@ -0,0 +1,84 @@ +//===----------------------------------------------------------------------===// +// DuckDB +// +// duckdb/main/capi/capi_function_signature.hpp +// +// +//===----------------------------------------------------------------------===// + +#pragma once + +#include "duckdb/common/string_util.hpp" +#include "duckdb/function/function.hpp" + +#include + +namespace duckdb { + +//! The C APIs let a caller declare parameters and varargs in any order, while a signature expects its parameters +//! ordered by kind. These rebuild the signature in that order. +struct CAPIFunctionSignature { + //! Adds the parameter after the existing ones of its kind + static void AddParameter(FunctionSignature &signature, FunctionParameter parameter) { + auto parameters = signature.GetParameters(); + parameters.push_back(std::move(parameter)); + SetParameters(signature, std::move(parameters)); + } + + //! Adds a positional-only parameter named "col", after the existing positional-only ones + static void AddPositionalOnly(FunctionSignature &signature, LogicalType type) { + auto name = Identifier(StringUtil::Format("col%d", signature.GetPositionalOnlyParameterCount())); + AddParameter(signature, + FunctionParameter(std::move(name), std::move(type), {}, FunctionParameterKind::POSITIONAL_ONLY)); + } + + //! Replaces the "*args" by one of the given type, or removes it if the type is INVALID. A named argument the + //! signature does not declare stays an error, as the callback could not tell its name + static void SetArgs(FunctionSignature &signature, const LogicalType &type) { + SetVariadic(signature, type, false); + } + + //! The same, adding a "**kwargs" of the type too - a named argument the signature does not declare is received + //! as a trailing value, as v1 functions always received it + static void SetVarArgs(FunctionSignature &signature, const LogicalType &type) { + SetVariadic(signature, type, true); + } + +private: + static void SetVariadic(FunctionSignature &signature, const LogicalType &type, bool with_kwargs) { + vector parameters; + for (auto ¶m : signature.GetParameters()) { + if (!param.IsVariadic()) { + parameters.push_back(param); + } + } + if (type.id() != LogicalTypeId::INVALID) { + parameters.emplace_back("args", type, optional(), FunctionParameterKind::VAR_POSITIONAL); + if (with_kwargs) { + parameters.emplace_back("kwargs", type, optional(), FunctionParameterKind::VAR_KEYWORD); + } + } + SetParameters(signature, std::move(parameters)); + } + + static void SetParameters(FunctionSignature &signature, vector parameters) { + // the kinds are declared in the order a signature expects them + std::stable_sort( + parameters.begin(), parameters.end(), + [](const FunctionParameter &lhs, const FunctionParameter &rhs) { return lhs.GetKind() < rhs.GetKind(); }); + // a typed "**kwargs" keeps its schema + auto typed_kwargs = signature.GetTypedKwargs(); + optional kwargs_name; + if (typed_kwargs && !parameters.empty() && parameters.back().GetKind() == FunctionParameterKind::VAR_KEYWORD) { + kwargs_name = parameters.back().GetName(); + parameters.pop_back(); + } + FunctionSignature result(std::move(parameters), signature.GetReturnType()); + if (kwargs_name) { + result.AddTypedKwargs(*kwargs_name, *typed_kwargs); + } + signature = std::move(result); + } +}; + +} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/main/capi/capi_internal_table.hpp b/src/duckdb/src/include/duckdb/main/capi/capi_internal_table.hpp index 6384f2ba6..bcd57340f 100644 --- a/src/duckdb/src/include/duckdb/main/capi/capi_internal_table.hpp +++ b/src/duckdb/src/include/duckdb/main/capi/capi_internal_table.hpp @@ -56,7 +56,7 @@ struct CTableBindData : public TableFunctionData { struct CTableInternalBindInfo { CTableInternalBindInfo(ClientContext &context, const vector ¶meters, - const named_parameter_map_t &named_parameters, vector &return_types, + const named_argument_map_t &named_parameters, vector &return_types, vector &names, CTableBindData &bind_data, CTableFunctionInfo &function_info) : context(context), parameters(parameters), named_parameters(named_parameters), return_types(return_types), names(names), bind_data(bind_data), function_info(function_info), success(true) { @@ -65,7 +65,7 @@ struct CTableInternalBindInfo { ClientContext &context; vector parameters; - named_parameter_map_t named_parameters; + named_argument_map_t named_parameters; vector &return_types; vector &names; diff --git a/src/duckdb/src/include/duckdb/main/capi_v2/capi_v2_internal.hpp b/src/duckdb/src/include/duckdb/main/capi_v2/capi_v2_internal.hpp index 4927d66f2..a49eb004f 100644 --- a/src/duckdb/src/include/duckdb/main/capi_v2/capi_v2_internal.hpp +++ b/src/duckdb/src/include/duckdb/main/capi_v2/capi_v2_internal.hpp @@ -74,9 +74,21 @@ inline auto Convert(duckdb_v2_str str) -> std::string_view { } return std::string_view(str.ptr, str.len); } +inline auto Convert(const duckdb_v2_str *str) -> std::string_view { + if (!str) { + throw InvalidInputException("byte range cannot be null"); + } + return Convert(*str); +} // Validates identifier UTF-8 and returns its text; throws on invalid input. Defined in capi_v2_utf8.cpp. auto ConvertIdentifierName(duckdb_v2_identifier_t name) -> std::string_view; +inline auto ConvertIdentifierName(const duckdb_v2_identifier_t *name) -> std::string_view { + if (!name) { + throw InvalidInputException("identifier cannot be null"); + } + return ConvertIdentifierName(*name); +} inline auto Convert(std::string_view str) -> duckdb_v2_str { return duckdb_v2_str {str.data(), str.size()}; @@ -93,6 +105,18 @@ inline auto Convert(duckdb_v2_hugeint_t value) -> hugeint_t { inline auto Convert(duckdb_v2_uhugeint_t value) -> uhugeint_t { return uhugeint_t(value.upper, value.lower); } +inline auto Convert(const duckdb_v2_hugeint_t *value) -> hugeint_t { + if (!value) { + throw InvalidInputException("hugeint value cannot be null"); + } + return Convert(*value); +} +inline auto Convert(const duckdb_v2_uhugeint_t *value) -> uhugeint_t { + if (!value) { + throw InvalidInputException("uhugeint value cannot be null"); + } + return Convert(*value); +} inline auto Convert(hugeint_t value) -> duckdb_v2_hugeint_t { return duckdb_v2_hugeint_t {value.lower, value.upper}; } @@ -109,6 +133,12 @@ inline auto Convert(duckdb_v2_interval_t value) -> interval_t { out.micros = value.micros; return out; } +inline auto Convert(const duckdb_v2_interval_t *value) -> interval_t { + if (!value) { + throw InvalidInputException("interval value cannot be null"); + } + return Convert(*value); +} // The V2 enum surfaces core's StatementType under the same numeric values; every spec member is pinned, and the count // pins the highest one - appending a member in core fails to compile until the v2 spec mirrors it. @@ -455,14 +485,15 @@ auto NullArgumentError(duckdb_v2_error_info_handle *err, const char *function, c auto RenderCaughtError(DUCKDB_V2_ERROR &code, string &text, optional &raw_message) noexcept -> void; // The null test behind DUCKDB_CHECK_ARG: a pointer/handle is invalid when null; a string/identifier view is invalid -// when its pointer is null while it carries a non-zero length. +// when it is null, or when its pointer is null while it carries a non-zero length. template bool IsNullArgument(const T &arg) { - if constexpr (std::is_pointer_v) { - return arg == nullptr; - } else { - return !arg.ptr && arg.len > 0; - } + static_assert(std::is_pointer_v, "DUCKDB_CHECK_ARG takes a pointer or handle"); + return arg == nullptr; +} + +inline bool IsNullArgument(const duckdb_v2_str *arg) { + return !arg || (!arg->ptr && arg->len > 0); } // Check if an argument is null and return DUCKDB_V2_ERROR_INPUT_INVALID with a message if it is. @@ -593,7 +624,7 @@ inline void InvokeTextSink(duckdb_v2_text_sink_fn sink, duckdb_v2_str text, void // The slot is always live: sinks populate it, they never allocate or destroy it. CV2ErrorInfo info; auto handle = Convert(&info); - sink(text, user_data, &handle); + sink(&text, user_data, &handle); if (info.HasError()) { info.ThrowAsException(); } diff --git a/src/duckdb/src/include/duckdb/main/capi_v2/extension_api_v2.hpp b/src/duckdb/src/include/duckdb/main/capi_v2/extension_api_v2.hpp index 162648fda..fc0a076e7 100644 --- a/src/duckdb/src/include/duckdb/main/capi_v2/extension_api_v2.hpp +++ b/src/duckdb/src/include/duckdb/main/capi_v2/extension_api_v2.hpp @@ -63,17 +63,18 @@ typedef struct { const duckdb_v2_value_handle *param_values, idx_t param_count, duckdb_v2_logical_type_handle *out_type, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_connection_create_type_from_text) - (duckdb_v2_connection_handle conn, duckdb_v2_str text, duckdb_v2_logical_type_handle *out_type, + (duckdb_v2_connection_handle conn, const duckdb_v2_str *text, duckdb_v2_logical_type_handle *out_type, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_connection_create_type_with_alias) - (duckdb_v2_connection_handle conn, duckdb_v2_logical_type_handle base_type, duckdb_v2_identifier_t alias_name, - duckdb_v2_logical_type_handle *out_type, duckdb_v2_error_info_handle *err); + (duckdb_v2_connection_handle conn, duckdb_v2_logical_type_handle base_type, + const duckdb_v2_identifier_t *alias_name, duckdb_v2_logical_type_handle *out_type, + duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR (*duckdb_v2_connection_destroy)(duckdb_v2_connection_handle *conn); DUCKDB_V2_ERROR(*duckdb_v2_connection_get_option_by_index) (duckdb_v2_connection_handle conn, idx_t index, duckdb_v2_option_handle *out_option, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_connection_get_option_by_name) - (duckdb_v2_connection_handle conn, duckdb_v2_identifier_t name, duckdb_v2_option_handle *out_option, + (duckdb_v2_connection_handle conn, const duckdb_v2_identifier_t *name, duckdb_v2_option_handle *out_option, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_connection_get_option_count) (duckdb_v2_connection_handle conn, idx_t *out_count, duckdb_v2_error_info_handle *err); @@ -83,7 +84,7 @@ typedef struct { (duckdb_v2_connection_handle conn, double *out_percentage, uint64_t *out_rows_processed, uint64_t *out_total_rows_to_process, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_connection_set_option) - (duckdb_v2_connection_handle conn, duckdb_v2_identifier_t name, duckdb_v2_str setting, + (duckdb_v2_connection_handle conn, const duckdb_v2_identifier_t *name, const duckdb_v2_str *setting, DUCKDB_V2_SETTING_SCOPE scope, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_context_create_type_from_id) (duckdb_v2_context_handle ctx, DUCKDB_V2_LOGICAL_TYPE_ID type_id, const duckdb_v2_identifier_t *param_names, @@ -94,10 +95,10 @@ typedef struct { const duckdb_v2_value_handle *param_values, idx_t param_count, duckdb_v2_logical_type_handle *out_type, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_context_create_type_from_text) - (duckdb_v2_context_handle ctx, duckdb_v2_str text, duckdb_v2_logical_type_handle *out_type, + (duckdb_v2_context_handle ctx, const duckdb_v2_str *text, duckdb_v2_logical_type_handle *out_type, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_context_create_type_with_alias) - (duckdb_v2_context_handle ctx, duckdb_v2_logical_type_handle base_type, duckdb_v2_identifier_t alias_name, + (duckdb_v2_context_handle ctx, duckdb_v2_logical_type_handle base_type, const duckdb_v2_identifier_t *alias_name, duckdb_v2_logical_type_handle *out_type, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_data_chunk_copy_with_connection) (duckdb_v2_connection_handle conn, duckdb_v2_data_chunk_handle chunk, duckdb_v2_data_chunk_handle *out_chunk, @@ -132,25 +133,25 @@ typedef struct { DUCKDB_V2_ERROR (*duckdb_v2_error_info_get_raw_text)(duckdb_v2_error_info_handle info, duckdb_v2_str *out_raw_text); DUCKDB_V2_ERROR (*duckdb_v2_error_info_get_text)(duckdb_v2_error_info_handle info, duckdb_v2_str *out_text); DUCKDB_V2_ERROR (*duckdb_v2_error_info_set_code)(duckdb_v2_error_info_handle info, DUCKDB_V2_ERROR code); - DUCKDB_V2_ERROR (*duckdb_v2_error_info_set_text)(duckdb_v2_error_info_handle info, duckdb_v2_str text); + DUCKDB_V2_ERROR (*duckdb_v2_error_info_set_text)(duckdb_v2_error_info_handle info, const duckdb_v2_str *text); DUCKDB_V2_ERROR(*duckdb_v2_instance_attach) - (duckdb_v2_instance_handle instance, duckdb_v2_str path, duckdb_v2_identifier_t *name, + (duckdb_v2_instance_handle instance, const duckdb_v2_str *path, const duckdb_v2_identifier_t *name, duckdb_v2_attach_options_handle options, bool make_default, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_instance_create) (duckdb_v2_environment_handle env, duckdb_v2_instance_handle *out_instance, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR (*duckdb_v2_instance_destroy)(duckdb_v2_instance_handle *instance); DUCKDB_V2_ERROR(*duckdb_v2_instance_detach) - (duckdb_v2_instance_handle instance, duckdb_v2_str path, duckdb_v2_error_info_handle *err); + (duckdb_v2_instance_handle instance, const duckdb_v2_str *path, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_instance_get_option_by_index) (duckdb_v2_instance_handle instance, idx_t index, duckdb_v2_option_handle *out_option, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_instance_get_option_by_name) - (duckdb_v2_instance_handle instance, duckdb_v2_identifier_t name, duckdb_v2_option_handle *out_option, + (duckdb_v2_instance_handle instance, const duckdb_v2_identifier_t *name, duckdb_v2_option_handle *out_option, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_instance_get_option_count) (duckdb_v2_instance_handle instance, idx_t *out_count, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_instance_set_option) - (duckdb_v2_instance_handle instance, duckdb_v2_identifier_t name, duckdb_v2_str setting, + (duckdb_v2_instance_handle instance, const duckdb_v2_identifier_t *name, const duckdb_v2_str *setting, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR (*duckdb_v2_library_version)(duckdb_v2_str *out_version, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_logical_type_copy) @@ -201,8 +202,9 @@ typedef struct { DUCKDB_V2_ERROR(*duckdb_v2_result_get_statement_type) (duckdb_v2_result_handle result, DUCKDB_V2_STATEMENT_TYPE *out_type, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_result_render_box) - (duckdb_v2_result_handle *result, idx_t max_rows, idx_t max_width, idx_t max_col_width, duckdb_v2_str null_value, - idx_t render_mode, idx_t limit, duckdb_v2_text_sink_fn sink, void *user_data, duckdb_v2_error_info_handle *err); + (duckdb_v2_result_handle *result, idx_t max_rows, idx_t max_width, idx_t max_col_width, + const duckdb_v2_str *null_value, idx_t render_mode, idx_t limit, duckdb_v2_text_sink_fn sink, void *user_data, + duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_result_step) (duckdb_v2_result_handle result, duckdb_v2_data_chunk_handle *out_chunk, DUCKDB_V2_RESULT_STEP_STATUS *out_status, duckdb_v2_error_info_handle *err); @@ -244,22 +246,22 @@ typedef struct { (duckdb_v2_context_handle ctx, int64_t in_value, duckdb_v2_value_handle *out_value, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_value_create_bignum_with_connection) - (duckdb_v2_connection_handle conn, duckdb_v2_str in_value, duckdb_v2_value_handle *out_value, + (duckdb_v2_connection_handle conn, const duckdb_v2_str *in_value, duckdb_v2_value_handle *out_value, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_value_create_bignum_with_context) - (duckdb_v2_context_handle ctx, duckdb_v2_str in_value, duckdb_v2_value_handle *out_value, + (duckdb_v2_context_handle ctx, const duckdb_v2_str *in_value, duckdb_v2_value_handle *out_value, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_value_create_bit_with_connection) - (duckdb_v2_connection_handle conn, duckdb_v2_str in_value, duckdb_v2_value_handle *out_value, + (duckdb_v2_connection_handle conn, const duckdb_v2_str *in_value, duckdb_v2_value_handle *out_value, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_value_create_bit_with_context) - (duckdb_v2_context_handle ctx, duckdb_v2_str in_value, duckdb_v2_value_handle *out_value, + (duckdb_v2_context_handle ctx, const duckdb_v2_str *in_value, duckdb_v2_value_handle *out_value, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_value_create_blob_with_connection) - (duckdb_v2_connection_handle conn, duckdb_v2_str in_value, duckdb_v2_value_handle *out_value, + (duckdb_v2_connection_handle conn, const duckdb_v2_str *in_value, duckdb_v2_value_handle *out_value, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_value_create_blob_with_context) - (duckdb_v2_context_handle ctx, duckdb_v2_str in_value, duckdb_v2_value_handle *out_value, + (duckdb_v2_context_handle ctx, const duckdb_v2_str *in_value, duckdb_v2_value_handle *out_value, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_value_create_bool_with_connection) (duckdb_v2_connection_handle conn, bool in_value, duckdb_v2_value_handle *out_value, @@ -273,10 +275,10 @@ typedef struct { (duckdb_v2_context_handle ctx, int32_t in_value, duckdb_v2_value_handle *out_value, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_value_create_decimal_with_connection) - (duckdb_v2_connection_handle conn, duckdb_v2_hugeint_t in_value, uint8_t width, uint8_t scale, + (duckdb_v2_connection_handle conn, const duckdb_v2_hugeint_t *in_value, uint8_t width, uint8_t scale, duckdb_v2_value_handle *out_value, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_value_create_decimal_with_context) - (duckdb_v2_context_handle ctx, duckdb_v2_hugeint_t in_value, uint8_t width, uint8_t scale, + (duckdb_v2_context_handle ctx, const duckdb_v2_hugeint_t *in_value, uint8_t width, uint8_t scale, duckdb_v2_value_handle *out_value, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_value_create_double_with_connection) (duckdb_v2_connection_handle conn, double in_value, duckdb_v2_value_handle *out_value, @@ -290,10 +292,10 @@ typedef struct { DUCKDB_V2_ERROR(*duckdb_v2_value_create_float_with_context) (duckdb_v2_context_handle ctx, float in_value, duckdb_v2_value_handle *out_value, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_value_create_hugeint_with_connection) - (duckdb_v2_connection_handle conn, duckdb_v2_hugeint_t in_value, duckdb_v2_value_handle *out_value, + (duckdb_v2_connection_handle conn, const duckdb_v2_hugeint_t *in_value, duckdb_v2_value_handle *out_value, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_value_create_hugeint_with_context) - (duckdb_v2_context_handle ctx, duckdb_v2_hugeint_t in_value, duckdb_v2_value_handle *out_value, + (duckdb_v2_context_handle ctx, const duckdb_v2_hugeint_t *in_value, duckdb_v2_value_handle *out_value, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_value_create_int_with_connection) (duckdb_v2_connection_handle conn, int32_t in_value, duckdb_v2_value_handle *out_value, @@ -302,10 +304,10 @@ typedef struct { (duckdb_v2_context_handle ctx, int32_t in_value, duckdb_v2_value_handle *out_value, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_value_create_interval_with_connection) - (duckdb_v2_connection_handle conn, duckdb_v2_interval_t in_value, duckdb_v2_value_handle *out_value, + (duckdb_v2_connection_handle conn, const duckdb_v2_interval_t *in_value, duckdb_v2_value_handle *out_value, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_value_create_interval_with_context) - (duckdb_v2_context_handle ctx, duckdb_v2_interval_t in_value, duckdb_v2_value_handle *out_value, + (duckdb_v2_context_handle ctx, const duckdb_v2_interval_t *in_value, duckdb_v2_value_handle *out_value, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_value_create_list_with_connection) (duckdb_v2_connection_handle conn, duckdb_v2_logical_type_handle child_type, const duckdb_v2_value_handle *children, @@ -420,10 +422,10 @@ typedef struct { (duckdb_v2_context_handle ctx, uint64_t in_value, duckdb_v2_value_handle *out_value, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_value_create_uhugeint_with_connection) - (duckdb_v2_connection_handle conn, duckdb_v2_uhugeint_t in_value, duckdb_v2_value_handle *out_value, + (duckdb_v2_connection_handle conn, const duckdb_v2_uhugeint_t *in_value, duckdb_v2_value_handle *out_value, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_value_create_uhugeint_with_context) - (duckdb_v2_context_handle ctx, duckdb_v2_uhugeint_t in_value, duckdb_v2_value_handle *out_value, + (duckdb_v2_context_handle ctx, const duckdb_v2_uhugeint_t *in_value, duckdb_v2_value_handle *out_value, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_value_create_uint_with_connection) (duckdb_v2_connection_handle conn, uint32_t in_value, duckdb_v2_value_handle *out_value, @@ -444,16 +446,16 @@ typedef struct { (duckdb_v2_context_handle ctx, uint8_t in_value, duckdb_v2_value_handle *out_value, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_value_create_uuid_with_connection) - (duckdb_v2_connection_handle conn, duckdb_v2_hugeint_t in_value, duckdb_v2_value_handle *out_value, + (duckdb_v2_connection_handle conn, const duckdb_v2_hugeint_t *in_value, duckdb_v2_value_handle *out_value, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_value_create_uuid_with_context) - (duckdb_v2_context_handle ctx, duckdb_v2_hugeint_t in_value, duckdb_v2_value_handle *out_value, + (duckdb_v2_context_handle ctx, const duckdb_v2_hugeint_t *in_value, duckdb_v2_value_handle *out_value, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_value_create_varchar_with_connection) - (duckdb_v2_connection_handle conn, duckdb_v2_str in_value, duckdb_v2_value_handle *out_value, + (duckdb_v2_connection_handle conn, const duckdb_v2_str *in_value, duckdb_v2_value_handle *out_value, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_value_create_varchar_with_context) - (duckdb_v2_context_handle ctx, duckdb_v2_str in_value, duckdb_v2_value_handle *out_value, + (duckdb_v2_context_handle ctx, const duckdb_v2_str *in_value, duckdb_v2_value_handle *out_value, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR (*duckdb_v2_value_destroy)(duckdb_v2_value_handle *value); DUCKDB_V2_ERROR(*duckdb_v2_value_get_bigint) @@ -570,10 +572,10 @@ typedef struct { (duckdb_v2_aggregate_function_bind_info_handle info, idx_t index, duckdb_v2_value_handle *value, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_context_log) - (duckdb_v2_context_handle ctx, DUCKDB_V2_LOG_LEVEL level, duckdb_v2_str log_type, duckdb_v2_str message, - duckdb_v2_error_info_handle *err); + (duckdb_v2_context_handle ctx, DUCKDB_V2_LOG_LEVEL level, const duckdb_v2_str *log_type, + const duckdb_v2_str *message, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_function_signature_add_parameter) - (duckdb_v2_function_signature_handle sig, duckdb_v2_identifier_t name, duckdb_v2_logical_type_handle type, + (duckdb_v2_function_signature_handle sig, const duckdb_v2_identifier_t *name, duckdb_v2_logical_type_handle type, duckdb_v2_value_handle value, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_function_signature_set_return_type) (duckdb_v2_function_signature_handle sig, duckdb_v2_logical_type_handle type, duckdb_v2_error_info_handle *err); @@ -638,7 +640,7 @@ typedef struct { (duckdb_v2_scalar_function_handle function, duckdb_v2_scalar_function_init_callback_fn callback, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_scalar_function_set_name) - (duckdb_v2_scalar_function_handle function, duckdb_v2_identifier_t *name, duckdb_v2_error_info_handle *err); + (duckdb_v2_scalar_function_handle function, const duckdb_v2_identifier_t *name, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_scalar_function_set_user_data) (duckdb_v2_scalar_function_handle function, duckdb_v2_opaque *data, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_aggregate_function_bind_get_user_data) @@ -715,7 +717,8 @@ typedef struct { (duckdb_v2_aggregate_function_handle function, duckdb_v2_aggregate_function_init_callback_fn callback, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_aggregate_function_set_name) - (duckdb_v2_aggregate_function_handle function, duckdb_v2_identifier_t *name, duckdb_v2_error_info_handle *err); + (duckdb_v2_aggregate_function_handle function, const duckdb_v2_identifier_t *name, + duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_aggregate_function_set_size_callback) (duckdb_v2_aggregate_function_handle function, duckdb_v2_aggregate_function_size_callback_fn callback, duckdb_v2_error_info_handle *err); @@ -750,8 +753,8 @@ typedef struct { (duckdb_v2_scalar_function_handle function, DUCKDB_V2_FUNCTION_PROPERTY_KEY key, DUCKDB_V2_FUNCTION_PROPERTY_VALUE value, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_table_function_bind_add_result_column) - (duckdb_v2_table_function_bind_info_handle info, duckdb_v2_identifier_t name, duckdb_v2_logical_type_handle type, - duckdb_v2_error_info_handle *err); + (duckdb_v2_table_function_bind_info_handle info, const duckdb_v2_identifier_t *name, + duckdb_v2_logical_type_handle type, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_table_function_bind_get_arg_count) (duckdb_v2_table_function_bind_info_handle info, idx_t *count, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_table_function_bind_get_arg_type) @@ -826,7 +829,7 @@ typedef struct { (duckdb_v2_table_function_handle function, duckdb_v2_table_function_init_local_callback_fn callback, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_table_function_set_name) - (duckdb_v2_table_function_handle function, duckdb_v2_identifier_t *name, duckdb_v2_error_info_handle *err); + (duckdb_v2_table_function_handle function, const duckdb_v2_identifier_t *name, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_table_function_set_progress_callback) (duckdb_v2_table_function_handle function, duckdb_v2_table_function_progress_callback_fn callback, duckdb_v2_error_info_handle *err); @@ -875,7 +878,7 @@ typedef struct { DUCKDB_V2_ERROR(*duckdb_v2_custom_type_set_base_type) (duckdb_v2_custom_type_handle type, duckdb_v2_logical_type_handle base_type, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_custom_type_set_name) - (duckdb_v2_custom_type_handle type, duckdb_v2_identifier_t name, duckdb_v2_error_info_handle *err); + (duckdb_v2_custom_type_handle type, const duckdb_v2_identifier_t *name, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR (*duckdb_v2_file_close)(duckdb_v2_file_handle file, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR (*duckdb_v2_file_destroy)(duckdb_v2_file_handle *file); DUCKDB_V2_ERROR(*duckdb_v2_file_open_options_create) @@ -885,7 +888,7 @@ typedef struct { DUCKDB_V2_ERROR(*duckdb_v2_file_open_options_set_flag) (duckdb_v2_file_open_options_handle options, DUCKDB_V2_FILE_FLAG flag, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_file_open_options_set_value) - (duckdb_v2_file_open_options_handle options, duckdb_v2_str name, duckdb_v2_value_handle value, + (duckdb_v2_file_open_options_handle options, const duckdb_v2_str *name, duckdb_v2_value_handle value, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_file_read) (duckdb_v2_file_handle file, void *buffer, idx_t buffer_size, idx_t *bytes_read, duckdb_v2_error_info_handle *err); @@ -901,8 +904,8 @@ typedef struct { DUCKDB_V2_ERROR(*duckdb_v2_file_system_get_from_context) (duckdb_v2_context_handle context, duckdb_v2_file_system_handle *file_system, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_file_system_open) - (duckdb_v2_file_system_handle file_system, duckdb_v2_str file_path, duckdb_v2_file_open_options_handle options, - duckdb_v2_file_handle *file, duckdb_v2_error_info_handle *err); + (duckdb_v2_file_system_handle file_system, const duckdb_v2_str *file_path, + duckdb_v2_file_open_options_handle options, duckdb_v2_file_handle *file, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_file_tell) (duckdb_v2_file_handle file, idx_t *position, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_file_write) @@ -924,14 +927,14 @@ typedef struct { DUCKDB_V2_ERROR(*duckdb_v2_qname_hash) (duckdb_v2_qname_handle name, uint64_t *hash, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_qname_parse) - (duckdb_v2_str text, duckdb_v2_qname_handle *name, duckdb_v2_error_info_handle *err); + (const duckdb_v2_str *text, duckdb_v2_qname_handle *name, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_qname_render) (duckdb_v2_qname_handle name, char *out_text, idx_t out_capacity, idx_t *out_length, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_replacement_scan_add_argument) (duckdb_v2_replacement_scan_info_handle info, duckdb_v2_value_handle value, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_replacement_scan_add_named_argument) - (duckdb_v2_replacement_scan_info_handle info, duckdb_v2_identifier_t name, duckdb_v2_value_handle value, + (duckdb_v2_replacement_scan_info_handle info, const duckdb_v2_identifier_t *name, duckdb_v2_value_handle value, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_replacement_scan_create_with_connection) (duckdb_v2_connection_handle connection, duckdb_v2_replacement_scan_handle *scan, duckdb_v2_error_info_handle *err); @@ -947,7 +950,8 @@ typedef struct { DUCKDB_V2_ERROR(*duckdb_v2_replacement_scan_register) (duckdb_v2_replacement_scan_handle scan, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_replacement_scan_set_alias) - (duckdb_v2_replacement_scan_info_handle info, duckdb_v2_identifier_t alias, duckdb_v2_error_info_handle *err); + (duckdb_v2_replacement_scan_info_handle info, const duckdb_v2_identifier_t *alias, + duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_replacement_scan_set_callback) (duckdb_v2_replacement_scan_handle scan, duckdb_v2_replacement_scan_callback_fn callback, duckdb_v2_error_info_handle *err); @@ -957,7 +961,7 @@ typedef struct { DUCKDB_V2_ERROR(*duckdb_v2_replacement_scan_set_function_name) (duckdb_v2_replacement_scan_info_handle info, duckdb_v2_qname_handle name, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_replacement_scan_set_subquery) - (duckdb_v2_replacement_scan_info_handle info, duckdb_v2_str sql, duckdb_v2_error_info_handle *err); + (duckdb_v2_replacement_scan_info_handle info, const duckdb_v2_str *sql, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_replacement_scan_set_user_data) (duckdb_v2_replacement_scan_handle scan, duckdb_v2_opaque *data, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_arrow_exporter_append) @@ -1077,7 +1081,7 @@ typedef struct { DUCKDB_V2_ERROR(*duckdb_v2_copy_function_register) (duckdb_v2_copy_function_handle function, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_copy_function_set_name) - (duckdb_v2_copy_function_handle function, duckdb_v2_identifier_t *name, duckdb_v2_error_info_handle *err); + (duckdb_v2_copy_function_handle function, const duckdb_v2_identifier_t *name, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_copy_function_set_user_data) (duckdb_v2_copy_function_handle function, duckdb_v2_opaque *data, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_copy_to_batch_get_bind_data) @@ -1179,7 +1183,7 @@ typedef struct { DUCKDB_V2_ERROR(*duckdb_v2_expression_get_type) (duckdb_v2_expression_handle expression, DUCKDB_V2_EXPRESSION_TYPE *type, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_identifier_render_quoted) - (duckdb_v2_identifier_t name, char *out_text, idx_t out_capacity, idx_t *out_length, + (const duckdb_v2_identifier_t *name, char *out_text, idx_t out_capacity, idx_t *out_length, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_prepared_statement_create) (duckdb_v2_connection_handle conn, duckdb_v2_sql_statement_handle statement, bool require_cacheable, @@ -1256,24 +1260,24 @@ typedef struct { (duckdb_v2_token_iterator_handle iterator, DUCKDB_V2_TOKEN_TYPE *out_type, idx_t *out_start, idx_t *out_length, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_tokenize_sql) - (duckdb_v2_connection_handle conn, duckdb_v2_str sql, duckdb_v2_token_iterator_handle *out_iterator, + (duckdb_v2_connection_handle conn, const duckdb_v2_str *sql, duckdb_v2_token_iterator_handle *out_iterator, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_attach_options_create) (duckdb_v2_instance_handle instance, duckdb_v2_attach_options_handle *out_options, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR (*duckdb_v2_attach_options_destroy)(duckdb_v2_attach_options_handle *options); DUCKDB_V2_ERROR(*duckdb_v2_attach_options_set) - (duckdb_v2_attach_options_handle options, duckdb_v2_identifier_t key, duckdb_v2_str setting, + (duckdb_v2_attach_options_handle options, const duckdb_v2_identifier_t *key, const duckdb_v2_str *setting, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_context_get_option_by_index) (duckdb_v2_context_handle ctx, idx_t index, duckdb_v2_option_handle *out_option, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_context_get_option_by_name) - (duckdb_v2_context_handle ctx, duckdb_v2_identifier_t name, duckdb_v2_option_handle *out_option, + (duckdb_v2_context_handle ctx, const duckdb_v2_identifier_t *name, duckdb_v2_option_handle *out_option, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_context_get_option_count) (duckdb_v2_context_handle ctx, idx_t *out_count, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_instance_set_default) - (duckdb_v2_instance_handle instance, duckdb_v2_str path, duckdb_v2_error_info_handle *err); + (duckdb_v2_instance_handle instance, const duckdb_v2_str *path, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_table_function_partition_data_get_bind_data) (duckdb_v2_table_function_partition_data_info_handle info, void **data, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_table_function_partition_data_get_global_state) @@ -1314,7 +1318,10 @@ typedef struct { DUCKDB_V2_ERROR(*duckdb_v2_table_function_set_partitioning_callback) (duckdb_v2_table_function_handle function, duckdb_v2_table_function_partitioning_callback_fn callback, duckdb_v2_error_info_handle *err); - DUCKDB_V2_ERROR (*duckdb_v2_validate_utf8)(duckdb_v2_str text, duckdb_v2_error_info_handle *err); + DUCKDB_V2_ERROR (*duckdb_v2_validate_utf8)(const duckdb_v2_str *text, duckdb_v2_error_info_handle *err); + DUCKDB_V2_ERROR(*duckdb_v2_table_function_bind_set_order_preservation) + (duckdb_v2_table_function_bind_info_handle info, DUCKDB_V2_ORDER_PRESERVATION order, + duckdb_v2_error_info_handle *err); } duckdb_ext_api_v2; //===--------------------------------------------------------------------===// @@ -1910,6 +1917,7 @@ inline duckdb_ext_api_v2 CreateAPIv2(void) { result.duckdb_v2_table_function_set_partition_data_callback = duckdb_v2_table_function_set_partition_data_callback; result.duckdb_v2_table_function_set_partitioning_callback = duckdb_v2_table_function_set_partitioning_callback; result.duckdb_v2_validate_utf8 = duckdb_v2_validate_utf8; + result.duckdb_v2_table_function_bind_set_order_preservation = duckdb_v2_table_function_bind_set_order_preservation; return result; } diff --git a/src/duckdb/src/include/duckdb/parser/grammar_change.hpp b/src/duckdb/src/include/duckdb/parser/grammar_change.hpp index dfc0565e7..eadc18c2f 100644 --- a/src/duckdb/src/include/duckdb/parser/grammar_change.hpp +++ b/src/duckdb/src/include/duckdb/parser/grammar_change.hpp @@ -38,8 +38,10 @@ class GrammarChange { grammar_cursor_function_t find_cursor); DUCKDB_API static GrammarChange ReplaceRule(const string &rule_definition, grammar_transform_process_function_t transform_process = nullptr); + //! See ParsedGrammar::SetTransformProcess for the meaning of collapsible DUCKDB_API static GrammarChange SetTransformProcess(const string &rule_name, - grammar_transform_process_function_t transform_process); + grammar_transform_process_function_t transform_process, + bool collapsible = false); DUCKDB_API static GrammarChange AddTerminalRuleOverride(const string &rule_name, terminal_rule_matcher_factory_t matcher_factory); @@ -60,14 +62,14 @@ class GrammarChange { static GrammarChange Create(GrammarChangeType type, string rule_name, string definition, grammar_transform_process_function_t transform_process = nullptr, grammar_cursor_function_t find_cursor = nullptr, - terminal_rule_matcher_factory_t matcher_factory = nullptr); + terminal_rule_matcher_factory_t matcher_factory = nullptr, bool collapsible = false); GrammarChange(GrammarChangeType type_p, string rule_name_p, string definition_p, grammar_transform_process_function_t transform_process_p, grammar_cursor_function_t find_cursor_p, - terminal_rule_matcher_factory_t matcher_factory_p) + terminal_rule_matcher_factory_t matcher_factory_p, bool collapsible_p) : type(type_p), rule_name(std::move(rule_name_p)), definition(std::move(definition_p)), transform_process(std::move(transform_process_p)), find_cursor(std::move(find_cursor_p)), - matcher_factory(std::move(matcher_factory_p)) { + matcher_factory(std::move(matcher_factory_p)), collapsible(collapsible_p) { } private: @@ -78,6 +80,7 @@ class GrammarChange { grammar_transform_process_function_t transform_process; grammar_cursor_function_t find_cursor; terminal_rule_matcher_factory_t matcher_factory; + bool collapsible; }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/parser/parsed_data/bound_pragma_info.hpp b/src/duckdb/src/include/duckdb/parser/parsed_data/bound_pragma_info.hpp index 90f7c27b3..0422b7741 100644 --- a/src/duckdb/src/include/duckdb/parser/parsed_data/bound_pragma_info.hpp +++ b/src/duckdb/src/include/duckdb/parser/parsed_data/bound_pragma_info.hpp @@ -13,7 +13,7 @@ namespace duckdb { struct BoundPragmaInfo { - BoundPragmaInfo(PragmaFunction function_p, vector parameters_p, named_parameter_map_t named_parameters_p) + BoundPragmaInfo(PragmaFunction function_p, vector parameters_p, named_argument_map_t named_parameters_p) : function(std::move(function_p)), parameters(std::move(parameters_p)), named_parameters(std::move(named_parameters_p)) { } @@ -22,7 +22,7 @@ struct BoundPragmaInfo { //! Parameter list (if any) vector parameters; //! Named parameter list (if any) - named_parameter_map_t named_parameters; + named_argument_map_t named_parameters; }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/parser/peg/matcher.hpp b/src/duckdb/src/include/duckdb/parser/peg/matcher.hpp index dfdeec1bd..e19ab4cfa 100644 --- a/src/duckdb/src/include/duckdb/parser/peg/matcher.hpp +++ b/src/duckdb/src/include/duckdb/parser/peg/matcher.hpp @@ -308,6 +308,13 @@ class Matcher { bool IsPackratMemoized() const { return packrat_memoized; } + //! See ParsedGrammar::SetTransformProcess + void SetCollapsible() { + collapsible = true; + } + bool IsCollapsible() const { + return collapsible; + } public: template @@ -332,6 +339,7 @@ class Matcher { string name; optional_idx packrat_id; bool packrat_memoized = false; + bool collapsible = false; optional_ptr rule; }; diff --git a/src/duckdb/src/include/duckdb/parser/peg/parsed_grammar.hpp b/src/duckdb/src/include/duckdb/parser/peg/parsed_grammar.hpp index 48cbd37ac..abe159852 100644 --- a/src/duckdb/src/include/duckdb/parser/peg/parsed_grammar.hpp +++ b/src/duckdb/src/include/duckdb/parser/peg/parsed_grammar.hpp @@ -38,6 +38,8 @@ struct ParsedGrammarRule { string name; PEGRule recipe; grammar_transform_process_function_t transform_process; + //! See ParsedGrammar::SetTransformProcess + bool collapsible = false; }; //! Mutable, owning representation of a PEG grammar before matcher compilation. @@ -64,8 +66,12 @@ class ParsedGrammar { const grammar_cursor_function_t &find_cursor); DUCKDB_API void ReplaceRule(const string &rule_definition, grammar_transform_process_function_t transform_process = nullptr); - DUCKDB_API void SetTransformProcess(const string &rule_name, - grammar_transform_process_function_t transform_process); + //! A collapsible transform promises to return its only child's result unchanged whenever the rule matched no + //! other child with a result, such as a level of the operator precedence hierarchy that matched no tail. The + //! matcher then skips building a result for the rule and the child is transformed as itself. Setting a new + //! transform clears that promise unless the caller repeats it, since it is a property of the transform. + DUCKDB_API void SetTransformProcess(const string &rule_name, grammar_transform_process_function_t transform_process, + bool collapsible = false); DUCKDB_API void AddTerminalRuleOverride(const string &rule_name, terminal_rule_matcher_factory_t matcher_factory); private: @@ -93,14 +99,17 @@ class ParsedGrammar { //! Immutable semantic data referenced directly by matchers and parse results. struct CompiledGrammarRule { - CompiledGrammarRule(string name_p, grammar_transform_process_function_t transform_process_p) - : name(std::move(name_p)), transform_process(std::move(transform_process_p)) { + CompiledGrammarRule(string name_p, grammar_transform_process_function_t transform_process_p, + bool collapsible_p = false) + : name(std::move(name_p)), transform_process(std::move(transform_process_p)), collapsible(collapsible_p) { } unique_ptr StartTransform(PEGTransformer &transformer, ParseResult &parse_result) const; string name; grammar_transform_process_function_t transform_process; + //! See ParsedGrammar::SetTransformProcess + bool collapsible; }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/parser/peg/transformer/parse_result.hpp b/src/duckdb/src/include/duckdb/parser/peg/transformer/parse_result.hpp index 9f745968f..b610d386f 100644 --- a/src/duckdb/src/include/duckdb/parser/peg/transformer/parse_result.hpp +++ b/src/duckdb/src/include/duckdb/parser/peg/transformer/parse_result.hpp @@ -136,6 +136,9 @@ class ParseResult { ParseResultType type; string name; optional_ptr rule; + //! Set when a collapsible rule handed this result out in place of its own, so the transformer runs this + //! result's rule rather than the one the parent asked for + bool collapsed = false; optional_idx offset; //! Source length: for leaf tokens the token length; for composite results the enclosing extent of children optional_idx length; diff --git a/src/duckdb/src/include/duckdb/parser/peg/transformer/peg_transformer.hpp b/src/duckdb/src/include/duckdb/parser/peg/transformer/peg_transformer.hpp index 512b7352a..b1860eb0c 100644 --- a/src/duckdb/src/include/duckdb/parser/peg/transformer/peg_transformer.hpp +++ b/src/duckdb/src/include/duckdb/parser/peg/transformer/peg_transformer.hpp @@ -273,6 +273,10 @@ struct TransformInput { } optional_ptr GetRule() const { + // A collapsed result stands in for a rule that would have returned it unchanged; transform it as itself + if (parse_result.collapsed) { + return parse_result.GetRule(); + } return rule ? rule : parse_result.GetRule(); } diff --git a/src/duckdb/src/include/duckdb/planner/binder.hpp b/src/duckdb/src/include/duckdb/planner/binder.hpp index 59e656786..d13fdc7f7 100644 --- a/src/duckdb/src/include/duckdb/planner/binder.hpp +++ b/src/duckdb/src/include/duckdb/planner/binder.hpp @@ -60,7 +60,9 @@ class LogicalVacuum; class ColumnList; class ExternalDependency; +class FunctionSignature; class TableFunction; +class BoundTableFunction; class TableStorageInfo; class BoundConstraint; class AtClause; @@ -308,9 +310,6 @@ class Binder : public enable_shared_from_this { SchemaCatalogEntry &BindCreateFunctionInfo(CreateInfo &info); SchemaCatalogEntry &BindCreateTriggerInfo(CreateTriggerInfo &info); - //! Check usage, and cast named parameters to their types - void BindNamedParameters(named_parameter_type_map_t &types, named_parameter_map_t &values, - QueryErrorContext &error_context, const Identifier &func_name); unique_ptr BindPragma(PragmaInfo &info, QueryErrorContext error_context); BoundStatement Bind(TableRef &ref); @@ -594,13 +593,14 @@ class Binder : public enable_shared_from_this { unique_ptr BindAtClause(optional_ptr at_clause); bool BindTableFunctionParameters(TableFunctionCatalogEntry &table_function, - vector> &expressions, vector &arguments, - vector ¶meters, named_parameter_map_t &named_parameters, - BoundStatement &subquery, ErrorData &error); + vector> &expressions, + vector> &positional_arguments, + vector>> &named_arguments, + BoundStatement &subquery, bool &table_in_out, ErrorData &error); void BindTableInTableOutFunction(vector> &expressions, BoundStatement &subquery); BoundStatement BindTableFunction(TableFunction &function, vector parameters); - BoundStatement BindTableFunctionInternal(TableFunction &table_function, const TableFunctionRef &ref, - vector parameters, named_parameter_map_t named_parameters, + BoundStatement BindTableFunctionInternal(BoundTableFunction &table_function, const TableFunctionRef &ref, + vector parameters, named_argument_map_t named_parameters, vector input_table_types, vector input_table_names, optional_ptr> input_plan); diff --git a/src/duckdb/src/include/duckdb/planner/operator/logical_get.hpp b/src/duckdb/src/include/duckdb/planner/operator/logical_get.hpp index fc69ede99..9e6c031ef 100644 --- a/src/duckdb/src/include/duckdb/planner/operator/logical_get.hpp +++ b/src/duckdb/src/include/duckdb/planner/operator/logical_get.hpp @@ -31,14 +31,14 @@ class LogicalGet : public LogicalOperator { static constexpr const LogicalOperatorType TYPE = LogicalOperatorType::LOGICAL_GET; public: - LogicalGet(TableIndex table_index, TableFunction function, unique_ptr bind_data, + LogicalGet(TableIndex table_index, BoundTableFunction function, unique_ptr bind_data, vector returned_types, vector returned_names, virtual_column_map_t virtual_columns = virtual_column_map_t()); //! The table index in the current bind context TableIndex table_index; - //! The function that is called - TableFunction function; + //! The function that is called, together with the argument types this call was bound with + BoundTableFunction function; //! The bind data of the function unique_ptr bind_data; //! Process-local input that cannot be reconstructed from SQL parameters @@ -56,7 +56,7 @@ class LogicalGet : public LogicalOperator { //! The set of input parameters for the table function vector parameters; //! The set of named input parameters for the table function - named_parameter_map_t named_parameters; + named_argument_map_t named_parameters; //! Whether the source invocation requested an ordinality column OrdinalityType source_ordinality = OrdinalityType::WITHOUT_ORDINALITY; //! The set of named input table types for the table-in table-out function diff --git a/src/duckdb/src/include/duckdb_extension_v2.h b/src/duckdb/src/include/duckdb_extension_v2.h index 294f3b258..5b7c9e686 100644 --- a/src/duckdb/src/include/duckdb_extension_v2.h +++ b/src/duckdb/src/include/duckdb_extension_v2.h @@ -128,17 +128,18 @@ typedef struct { const duckdb_v2_value_handle *param_values, idx_t param_count, duckdb_v2_logical_type_handle *out_type, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_connection_create_type_from_text) - (duckdb_v2_connection_handle conn, duckdb_v2_str text, duckdb_v2_logical_type_handle *out_type, + (duckdb_v2_connection_handle conn, const duckdb_v2_str *text, duckdb_v2_logical_type_handle *out_type, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_connection_create_type_with_alias) - (duckdb_v2_connection_handle conn, duckdb_v2_logical_type_handle base_type, duckdb_v2_identifier_t alias_name, - duckdb_v2_logical_type_handle *out_type, duckdb_v2_error_info_handle *err); + (duckdb_v2_connection_handle conn, duckdb_v2_logical_type_handle base_type, + const duckdb_v2_identifier_t *alias_name, duckdb_v2_logical_type_handle *out_type, + duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR (*duckdb_v2_connection_destroy)(duckdb_v2_connection_handle *conn); DUCKDB_V2_ERROR(*duckdb_v2_connection_get_option_by_index) (duckdb_v2_connection_handle conn, idx_t index, duckdb_v2_option_handle *out_option, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_connection_get_option_by_name) - (duckdb_v2_connection_handle conn, duckdb_v2_identifier_t name, duckdb_v2_option_handle *out_option, + (duckdb_v2_connection_handle conn, const duckdb_v2_identifier_t *name, duckdb_v2_option_handle *out_option, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_connection_get_option_count) (duckdb_v2_connection_handle conn, idx_t *out_count, duckdb_v2_error_info_handle *err); @@ -148,7 +149,7 @@ typedef struct { (duckdb_v2_connection_handle conn, double *out_percentage, uint64_t *out_rows_processed, uint64_t *out_total_rows_to_process, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_connection_set_option) - (duckdb_v2_connection_handle conn, duckdb_v2_identifier_t name, duckdb_v2_str setting, + (duckdb_v2_connection_handle conn, const duckdb_v2_identifier_t *name, const duckdb_v2_str *setting, DUCKDB_V2_SETTING_SCOPE scope, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_context_create_type_from_id) (duckdb_v2_context_handle ctx, DUCKDB_V2_LOGICAL_TYPE_ID type_id, const duckdb_v2_identifier_t *param_names, @@ -159,10 +160,10 @@ typedef struct { const duckdb_v2_value_handle *param_values, idx_t param_count, duckdb_v2_logical_type_handle *out_type, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_context_create_type_from_text) - (duckdb_v2_context_handle ctx, duckdb_v2_str text, duckdb_v2_logical_type_handle *out_type, + (duckdb_v2_context_handle ctx, const duckdb_v2_str *text, duckdb_v2_logical_type_handle *out_type, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_context_create_type_with_alias) - (duckdb_v2_context_handle ctx, duckdb_v2_logical_type_handle base_type, duckdb_v2_identifier_t alias_name, + (duckdb_v2_context_handle ctx, duckdb_v2_logical_type_handle base_type, const duckdb_v2_identifier_t *alias_name, duckdb_v2_logical_type_handle *out_type, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_data_chunk_copy_with_connection) (duckdb_v2_connection_handle conn, duckdb_v2_data_chunk_handle chunk, duckdb_v2_data_chunk_handle *out_chunk, @@ -197,25 +198,25 @@ typedef struct { DUCKDB_V2_ERROR (*duckdb_v2_error_info_get_raw_text)(duckdb_v2_error_info_handle info, duckdb_v2_str *out_raw_text); DUCKDB_V2_ERROR (*duckdb_v2_error_info_get_text)(duckdb_v2_error_info_handle info, duckdb_v2_str *out_text); DUCKDB_V2_ERROR (*duckdb_v2_error_info_set_code)(duckdb_v2_error_info_handle info, DUCKDB_V2_ERROR code); - DUCKDB_V2_ERROR (*duckdb_v2_error_info_set_text)(duckdb_v2_error_info_handle info, duckdb_v2_str text); + DUCKDB_V2_ERROR (*duckdb_v2_error_info_set_text)(duckdb_v2_error_info_handle info, const duckdb_v2_str *text); DUCKDB_V2_ERROR(*duckdb_v2_instance_attach) - (duckdb_v2_instance_handle instance, duckdb_v2_str path, duckdb_v2_identifier_t *name, + (duckdb_v2_instance_handle instance, const duckdb_v2_str *path, const duckdb_v2_identifier_t *name, duckdb_v2_attach_options_handle options, bool make_default, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_instance_create) (duckdb_v2_environment_handle env, duckdb_v2_instance_handle *out_instance, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR (*duckdb_v2_instance_destroy)(duckdb_v2_instance_handle *instance); DUCKDB_V2_ERROR(*duckdb_v2_instance_detach) - (duckdb_v2_instance_handle instance, duckdb_v2_str path, duckdb_v2_error_info_handle *err); + (duckdb_v2_instance_handle instance, const duckdb_v2_str *path, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_instance_get_option_by_index) (duckdb_v2_instance_handle instance, idx_t index, duckdb_v2_option_handle *out_option, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_instance_get_option_by_name) - (duckdb_v2_instance_handle instance, duckdb_v2_identifier_t name, duckdb_v2_option_handle *out_option, + (duckdb_v2_instance_handle instance, const duckdb_v2_identifier_t *name, duckdb_v2_option_handle *out_option, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_instance_get_option_count) (duckdb_v2_instance_handle instance, idx_t *out_count, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_instance_set_option) - (duckdb_v2_instance_handle instance, duckdb_v2_identifier_t name, duckdb_v2_str setting, + (duckdb_v2_instance_handle instance, const duckdb_v2_identifier_t *name, const duckdb_v2_str *setting, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR (*duckdb_v2_library_version)(duckdb_v2_str *out_version, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_logical_type_copy) @@ -266,8 +267,9 @@ typedef struct { DUCKDB_V2_ERROR(*duckdb_v2_result_get_statement_type) (duckdb_v2_result_handle result, DUCKDB_V2_STATEMENT_TYPE *out_type, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_result_render_box) - (duckdb_v2_result_handle *result, idx_t max_rows, idx_t max_width, idx_t max_col_width, duckdb_v2_str null_value, - idx_t render_mode, idx_t limit, duckdb_v2_text_sink_fn sink, void *user_data, duckdb_v2_error_info_handle *err); + (duckdb_v2_result_handle *result, idx_t max_rows, idx_t max_width, idx_t max_col_width, + const duckdb_v2_str *null_value, idx_t render_mode, idx_t limit, duckdb_v2_text_sink_fn sink, void *user_data, + duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_result_step) (duckdb_v2_result_handle result, duckdb_v2_data_chunk_handle *out_chunk, DUCKDB_V2_RESULT_STEP_STATUS *out_status, duckdb_v2_error_info_handle *err); @@ -309,22 +311,22 @@ typedef struct { (duckdb_v2_context_handle ctx, int64_t in_value, duckdb_v2_value_handle *out_value, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_value_create_bignum_with_connection) - (duckdb_v2_connection_handle conn, duckdb_v2_str in_value, duckdb_v2_value_handle *out_value, + (duckdb_v2_connection_handle conn, const duckdb_v2_str *in_value, duckdb_v2_value_handle *out_value, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_value_create_bignum_with_context) - (duckdb_v2_context_handle ctx, duckdb_v2_str in_value, duckdb_v2_value_handle *out_value, + (duckdb_v2_context_handle ctx, const duckdb_v2_str *in_value, duckdb_v2_value_handle *out_value, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_value_create_bit_with_connection) - (duckdb_v2_connection_handle conn, duckdb_v2_str in_value, duckdb_v2_value_handle *out_value, + (duckdb_v2_connection_handle conn, const duckdb_v2_str *in_value, duckdb_v2_value_handle *out_value, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_value_create_bit_with_context) - (duckdb_v2_context_handle ctx, duckdb_v2_str in_value, duckdb_v2_value_handle *out_value, + (duckdb_v2_context_handle ctx, const duckdb_v2_str *in_value, duckdb_v2_value_handle *out_value, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_value_create_blob_with_connection) - (duckdb_v2_connection_handle conn, duckdb_v2_str in_value, duckdb_v2_value_handle *out_value, + (duckdb_v2_connection_handle conn, const duckdb_v2_str *in_value, duckdb_v2_value_handle *out_value, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_value_create_blob_with_context) - (duckdb_v2_context_handle ctx, duckdb_v2_str in_value, duckdb_v2_value_handle *out_value, + (duckdb_v2_context_handle ctx, const duckdb_v2_str *in_value, duckdb_v2_value_handle *out_value, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_value_create_bool_with_connection) (duckdb_v2_connection_handle conn, bool in_value, duckdb_v2_value_handle *out_value, @@ -338,10 +340,10 @@ typedef struct { (duckdb_v2_context_handle ctx, int32_t in_value, duckdb_v2_value_handle *out_value, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_value_create_decimal_with_connection) - (duckdb_v2_connection_handle conn, duckdb_v2_hugeint_t in_value, uint8_t width, uint8_t scale, + (duckdb_v2_connection_handle conn, const duckdb_v2_hugeint_t *in_value, uint8_t width, uint8_t scale, duckdb_v2_value_handle *out_value, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_value_create_decimal_with_context) - (duckdb_v2_context_handle ctx, duckdb_v2_hugeint_t in_value, uint8_t width, uint8_t scale, + (duckdb_v2_context_handle ctx, const duckdb_v2_hugeint_t *in_value, uint8_t width, uint8_t scale, duckdb_v2_value_handle *out_value, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_value_create_double_with_connection) (duckdb_v2_connection_handle conn, double in_value, duckdb_v2_value_handle *out_value, @@ -355,10 +357,10 @@ typedef struct { DUCKDB_V2_ERROR(*duckdb_v2_value_create_float_with_context) (duckdb_v2_context_handle ctx, float in_value, duckdb_v2_value_handle *out_value, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_value_create_hugeint_with_connection) - (duckdb_v2_connection_handle conn, duckdb_v2_hugeint_t in_value, duckdb_v2_value_handle *out_value, + (duckdb_v2_connection_handle conn, const duckdb_v2_hugeint_t *in_value, duckdb_v2_value_handle *out_value, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_value_create_hugeint_with_context) - (duckdb_v2_context_handle ctx, duckdb_v2_hugeint_t in_value, duckdb_v2_value_handle *out_value, + (duckdb_v2_context_handle ctx, const duckdb_v2_hugeint_t *in_value, duckdb_v2_value_handle *out_value, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_value_create_int_with_connection) (duckdb_v2_connection_handle conn, int32_t in_value, duckdb_v2_value_handle *out_value, @@ -367,10 +369,10 @@ typedef struct { (duckdb_v2_context_handle ctx, int32_t in_value, duckdb_v2_value_handle *out_value, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_value_create_interval_with_connection) - (duckdb_v2_connection_handle conn, duckdb_v2_interval_t in_value, duckdb_v2_value_handle *out_value, + (duckdb_v2_connection_handle conn, const duckdb_v2_interval_t *in_value, duckdb_v2_value_handle *out_value, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_value_create_interval_with_context) - (duckdb_v2_context_handle ctx, duckdb_v2_interval_t in_value, duckdb_v2_value_handle *out_value, + (duckdb_v2_context_handle ctx, const duckdb_v2_interval_t *in_value, duckdb_v2_value_handle *out_value, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_value_create_list_with_connection) (duckdb_v2_connection_handle conn, duckdb_v2_logical_type_handle child_type, const duckdb_v2_value_handle *children, @@ -485,10 +487,10 @@ typedef struct { (duckdb_v2_context_handle ctx, uint64_t in_value, duckdb_v2_value_handle *out_value, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_value_create_uhugeint_with_connection) - (duckdb_v2_connection_handle conn, duckdb_v2_uhugeint_t in_value, duckdb_v2_value_handle *out_value, + (duckdb_v2_connection_handle conn, const duckdb_v2_uhugeint_t *in_value, duckdb_v2_value_handle *out_value, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_value_create_uhugeint_with_context) - (duckdb_v2_context_handle ctx, duckdb_v2_uhugeint_t in_value, duckdb_v2_value_handle *out_value, + (duckdb_v2_context_handle ctx, const duckdb_v2_uhugeint_t *in_value, duckdb_v2_value_handle *out_value, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_value_create_uint_with_connection) (duckdb_v2_connection_handle conn, uint32_t in_value, duckdb_v2_value_handle *out_value, @@ -509,16 +511,16 @@ typedef struct { (duckdb_v2_context_handle ctx, uint8_t in_value, duckdb_v2_value_handle *out_value, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_value_create_uuid_with_connection) - (duckdb_v2_connection_handle conn, duckdb_v2_hugeint_t in_value, duckdb_v2_value_handle *out_value, + (duckdb_v2_connection_handle conn, const duckdb_v2_hugeint_t *in_value, duckdb_v2_value_handle *out_value, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_value_create_uuid_with_context) - (duckdb_v2_context_handle ctx, duckdb_v2_hugeint_t in_value, duckdb_v2_value_handle *out_value, + (duckdb_v2_context_handle ctx, const duckdb_v2_hugeint_t *in_value, duckdb_v2_value_handle *out_value, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_value_create_varchar_with_connection) - (duckdb_v2_connection_handle conn, duckdb_v2_str in_value, duckdb_v2_value_handle *out_value, + (duckdb_v2_connection_handle conn, const duckdb_v2_str *in_value, duckdb_v2_value_handle *out_value, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_value_create_varchar_with_context) - (duckdb_v2_context_handle ctx, duckdb_v2_str in_value, duckdb_v2_value_handle *out_value, + (duckdb_v2_context_handle ctx, const duckdb_v2_str *in_value, duckdb_v2_value_handle *out_value, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR (*duckdb_v2_value_destroy)(duckdb_v2_value_handle *value); DUCKDB_V2_ERROR(*duckdb_v2_value_get_bigint) @@ -635,10 +637,10 @@ typedef struct { (duckdb_v2_aggregate_function_bind_info_handle info, idx_t index, duckdb_v2_value_handle *value, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_context_log) - (duckdb_v2_context_handle ctx, DUCKDB_V2_LOG_LEVEL level, duckdb_v2_str log_type, duckdb_v2_str message, - duckdb_v2_error_info_handle *err); + (duckdb_v2_context_handle ctx, DUCKDB_V2_LOG_LEVEL level, const duckdb_v2_str *log_type, + const duckdb_v2_str *message, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_function_signature_add_parameter) - (duckdb_v2_function_signature_handle sig, duckdb_v2_identifier_t name, duckdb_v2_logical_type_handle type, + (duckdb_v2_function_signature_handle sig, const duckdb_v2_identifier_t *name, duckdb_v2_logical_type_handle type, duckdb_v2_value_handle value, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_function_signature_set_return_type) (duckdb_v2_function_signature_handle sig, duckdb_v2_logical_type_handle type, duckdb_v2_error_info_handle *err); @@ -703,7 +705,7 @@ typedef struct { (duckdb_v2_scalar_function_handle function, duckdb_v2_scalar_function_init_callback_fn callback, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_scalar_function_set_name) - (duckdb_v2_scalar_function_handle function, duckdb_v2_identifier_t *name, duckdb_v2_error_info_handle *err); + (duckdb_v2_scalar_function_handle function, const duckdb_v2_identifier_t *name, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_scalar_function_set_user_data) (duckdb_v2_scalar_function_handle function, duckdb_v2_opaque *data, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_aggregate_function_bind_get_user_data) @@ -780,7 +782,8 @@ typedef struct { (duckdb_v2_aggregate_function_handle function, duckdb_v2_aggregate_function_init_callback_fn callback, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_aggregate_function_set_name) - (duckdb_v2_aggregate_function_handle function, duckdb_v2_identifier_t *name, duckdb_v2_error_info_handle *err); + (duckdb_v2_aggregate_function_handle function, const duckdb_v2_identifier_t *name, + duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_aggregate_function_set_size_callback) (duckdb_v2_aggregate_function_handle function, duckdb_v2_aggregate_function_size_callback_fn callback, duckdb_v2_error_info_handle *err); @@ -815,8 +818,8 @@ typedef struct { (duckdb_v2_scalar_function_handle function, DUCKDB_V2_FUNCTION_PROPERTY_KEY key, DUCKDB_V2_FUNCTION_PROPERTY_VALUE value, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_table_function_bind_add_result_column) - (duckdb_v2_table_function_bind_info_handle info, duckdb_v2_identifier_t name, duckdb_v2_logical_type_handle type, - duckdb_v2_error_info_handle *err); + (duckdb_v2_table_function_bind_info_handle info, const duckdb_v2_identifier_t *name, + duckdb_v2_logical_type_handle type, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_table_function_bind_get_arg_count) (duckdb_v2_table_function_bind_info_handle info, idx_t *count, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_table_function_bind_get_arg_type) @@ -891,7 +894,7 @@ typedef struct { (duckdb_v2_table_function_handle function, duckdb_v2_table_function_init_local_callback_fn callback, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_table_function_set_name) - (duckdb_v2_table_function_handle function, duckdb_v2_identifier_t *name, duckdb_v2_error_info_handle *err); + (duckdb_v2_table_function_handle function, const duckdb_v2_identifier_t *name, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_table_function_set_progress_callback) (duckdb_v2_table_function_handle function, duckdb_v2_table_function_progress_callback_fn callback, duckdb_v2_error_info_handle *err); @@ -940,7 +943,7 @@ typedef struct { DUCKDB_V2_ERROR(*duckdb_v2_custom_type_set_base_type) (duckdb_v2_custom_type_handle type, duckdb_v2_logical_type_handle base_type, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_custom_type_set_name) - (duckdb_v2_custom_type_handle type, duckdb_v2_identifier_t name, duckdb_v2_error_info_handle *err); + (duckdb_v2_custom_type_handle type, const duckdb_v2_identifier_t *name, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR (*duckdb_v2_file_close)(duckdb_v2_file_handle file, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR (*duckdb_v2_file_destroy)(duckdb_v2_file_handle *file); DUCKDB_V2_ERROR(*duckdb_v2_file_open_options_create) @@ -950,7 +953,7 @@ typedef struct { DUCKDB_V2_ERROR(*duckdb_v2_file_open_options_set_flag) (duckdb_v2_file_open_options_handle options, DUCKDB_V2_FILE_FLAG flag, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_file_open_options_set_value) - (duckdb_v2_file_open_options_handle options, duckdb_v2_str name, duckdb_v2_value_handle value, + (duckdb_v2_file_open_options_handle options, const duckdb_v2_str *name, duckdb_v2_value_handle value, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_file_read) (duckdb_v2_file_handle file, void *buffer, idx_t buffer_size, idx_t *bytes_read, duckdb_v2_error_info_handle *err); @@ -966,8 +969,8 @@ typedef struct { DUCKDB_V2_ERROR(*duckdb_v2_file_system_get_from_context) (duckdb_v2_context_handle context, duckdb_v2_file_system_handle *file_system, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_file_system_open) - (duckdb_v2_file_system_handle file_system, duckdb_v2_str file_path, duckdb_v2_file_open_options_handle options, - duckdb_v2_file_handle *file, duckdb_v2_error_info_handle *err); + (duckdb_v2_file_system_handle file_system, const duckdb_v2_str *file_path, + duckdb_v2_file_open_options_handle options, duckdb_v2_file_handle *file, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_file_tell) (duckdb_v2_file_handle file, idx_t *position, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_file_write) @@ -989,14 +992,14 @@ typedef struct { DUCKDB_V2_ERROR(*duckdb_v2_qname_hash) (duckdb_v2_qname_handle name, uint64_t *hash, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_qname_parse) - (duckdb_v2_str text, duckdb_v2_qname_handle *name, duckdb_v2_error_info_handle *err); + (const duckdb_v2_str *text, duckdb_v2_qname_handle *name, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_qname_render) (duckdb_v2_qname_handle name, char *out_text, idx_t out_capacity, idx_t *out_length, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_replacement_scan_add_argument) (duckdb_v2_replacement_scan_info_handle info, duckdb_v2_value_handle value, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_replacement_scan_add_named_argument) - (duckdb_v2_replacement_scan_info_handle info, duckdb_v2_identifier_t name, duckdb_v2_value_handle value, + (duckdb_v2_replacement_scan_info_handle info, const duckdb_v2_identifier_t *name, duckdb_v2_value_handle value, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_replacement_scan_create_with_connection) (duckdb_v2_connection_handle connection, duckdb_v2_replacement_scan_handle *scan, duckdb_v2_error_info_handle *err); @@ -1012,7 +1015,8 @@ typedef struct { DUCKDB_V2_ERROR(*duckdb_v2_replacement_scan_register) (duckdb_v2_replacement_scan_handle scan, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_replacement_scan_set_alias) - (duckdb_v2_replacement_scan_info_handle info, duckdb_v2_identifier_t alias, duckdb_v2_error_info_handle *err); + (duckdb_v2_replacement_scan_info_handle info, const duckdb_v2_identifier_t *alias, + duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_replacement_scan_set_callback) (duckdb_v2_replacement_scan_handle scan, duckdb_v2_replacement_scan_callback_fn callback, duckdb_v2_error_info_handle *err); @@ -1022,7 +1026,7 @@ typedef struct { DUCKDB_V2_ERROR(*duckdb_v2_replacement_scan_set_function_name) (duckdb_v2_replacement_scan_info_handle info, duckdb_v2_qname_handle name, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_replacement_scan_set_subquery) - (duckdb_v2_replacement_scan_info_handle info, duckdb_v2_str sql, duckdb_v2_error_info_handle *err); + (duckdb_v2_replacement_scan_info_handle info, const duckdb_v2_str *sql, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_replacement_scan_set_user_data) (duckdb_v2_replacement_scan_handle scan, duckdb_v2_opaque *data, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_arrow_exporter_append) @@ -1142,7 +1146,7 @@ typedef struct { DUCKDB_V2_ERROR(*duckdb_v2_copy_function_register) (duckdb_v2_copy_function_handle function, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_copy_function_set_name) - (duckdb_v2_copy_function_handle function, duckdb_v2_identifier_t *name, duckdb_v2_error_info_handle *err); + (duckdb_v2_copy_function_handle function, const duckdb_v2_identifier_t *name, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_copy_function_set_user_data) (duckdb_v2_copy_function_handle function, duckdb_v2_opaque *data, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_copy_to_batch_get_bind_data) @@ -1244,7 +1248,7 @@ typedef struct { DUCKDB_V2_ERROR(*duckdb_v2_expression_get_type) (duckdb_v2_expression_handle expression, DUCKDB_V2_EXPRESSION_TYPE *type, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_identifier_render_quoted) - (duckdb_v2_identifier_t name, char *out_text, idx_t out_capacity, idx_t *out_length, + (const duckdb_v2_identifier_t *name, char *out_text, idx_t out_capacity, idx_t *out_length, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_prepared_statement_create) (duckdb_v2_connection_handle conn, duckdb_v2_sql_statement_handle statement, bool require_cacheable, @@ -1321,24 +1325,24 @@ typedef struct { (duckdb_v2_token_iterator_handle iterator, DUCKDB_V2_TOKEN_TYPE *out_type, idx_t *out_start, idx_t *out_length, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_tokenize_sql) - (duckdb_v2_connection_handle conn, duckdb_v2_str sql, duckdb_v2_token_iterator_handle *out_iterator, + (duckdb_v2_connection_handle conn, const duckdb_v2_str *sql, duckdb_v2_token_iterator_handle *out_iterator, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_attach_options_create) (duckdb_v2_instance_handle instance, duckdb_v2_attach_options_handle *out_options, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR (*duckdb_v2_attach_options_destroy)(duckdb_v2_attach_options_handle *options); DUCKDB_V2_ERROR(*duckdb_v2_attach_options_set) - (duckdb_v2_attach_options_handle options, duckdb_v2_identifier_t key, duckdb_v2_str setting, + (duckdb_v2_attach_options_handle options, const duckdb_v2_identifier_t *key, const duckdb_v2_str *setting, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_context_get_option_by_index) (duckdb_v2_context_handle ctx, idx_t index, duckdb_v2_option_handle *out_option, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_context_get_option_by_name) - (duckdb_v2_context_handle ctx, duckdb_v2_identifier_t name, duckdb_v2_option_handle *out_option, + (duckdb_v2_context_handle ctx, const duckdb_v2_identifier_t *name, duckdb_v2_option_handle *out_option, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_context_get_option_count) (duckdb_v2_context_handle ctx, idx_t *out_count, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_instance_set_default) - (duckdb_v2_instance_handle instance, duckdb_v2_str path, duckdb_v2_error_info_handle *err); + (duckdb_v2_instance_handle instance, const duckdb_v2_str *path, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_table_function_partition_data_get_bind_data) (duckdb_v2_table_function_partition_data_info_handle info, void **data, duckdb_v2_error_info_handle *err); DUCKDB_V2_ERROR(*duckdb_v2_table_function_partition_data_get_global_state) @@ -1379,7 +1383,10 @@ typedef struct { DUCKDB_V2_ERROR(*duckdb_v2_table_function_set_partitioning_callback) (duckdb_v2_table_function_handle function, duckdb_v2_table_function_partitioning_callback_fn callback, duckdb_v2_error_info_handle *err); - DUCKDB_V2_ERROR (*duckdb_v2_validate_utf8)(duckdb_v2_str text, duckdb_v2_error_info_handle *err); + DUCKDB_V2_ERROR (*duckdb_v2_validate_utf8)(const duckdb_v2_str *text, duckdb_v2_error_info_handle *err); + DUCKDB_V2_ERROR(*duckdb_v2_table_function_bind_set_order_preservation) + (duckdb_v2_table_function_bind_info_handle info, DUCKDB_V2_ORDER_PRESERVATION order, + duckdb_v2_error_info_handle *err); // capigen:end appended } duckdb_ext_api_v2; @@ -2022,6 +2029,8 @@ typedef struct { #define duckdb_v2_table_function_set_partitioning_callback \ duckdb_ext_api.duckdb_v2_table_function_set_partitioning_callback #define duckdb_v2_validate_utf8 duckdb_ext_api.duckdb_v2_validate_utf8 +#define duckdb_v2_table_function_bind_set_order_preservation \ + duckdb_ext_api.duckdb_v2_table_function_bind_set_order_preservation // capigen:end appended #endif // DUCKDB_BUILD_STATIC_EXTENSION diff --git a/src/duckdb/src/include/duckdb_v2.h b/src/duckdb/src/include/duckdb_v2.h index a35241a1e..04cf2a4eb 100644 --- a/src/duckdb/src/include/duckdb_v2.h +++ b/src/duckdb/src/include/duckdb_v2.h @@ -185,6 +185,31 @@ typedef struct _duckdb_extension_info *duckdb_v2_extension_handle; /* --- Enums for common --- */ +/*! + * The order guarantee a producer of rows makes about its output, which decides whether the rows it produces must be + * kept in order downstream. + */ +typedef enum DUCKDB_V2_ORDER_PRESERVATION { + /*! + * The rows have no meaningful order. The engine may reorder them freely, and consumers that otherwise keep + * insertion order, such as query results, INSERT and COPY, run in parallel without ordering them. + */ + DUCKDB_V2_ORDER_PRESERVATION_NO_ORDER = 0, + + /*! + * The rows are produced in insertion order, which the engine keeps unless the `preserve_insertion_order` setting is + * disabled. + */ + DUCKDB_V2_ORDER_PRESERVATION_INSERTION_ORDER = 1, + + /*! + * The rows are produced in an order that must be kept, as if sorted by an `ORDER BY`, even when the + * `preserve_insertion_order` setting is disabled. + */ + DUCKDB_V2_ORDER_PRESERVATION_FIXED_ORDER = 2, + DUCKDB_V2_ORDER_PRESERVATION_MAX_ENUM = 0x7FFFFFFF, +} DUCKDB_V2_ORDER_PRESERVATION; + /* --- Struct forward declarations for common --- */ typedef struct duckdb_v2_str duckdb_v2_str; @@ -359,8 +384,8 @@ typedef duckdb_v2_str duckdb_v2_identifier_t; * * Invoked exactly once per producing call, with the complete text in a single view. * - * The view is borrowed for the duration of the call only. Copy what you need before returning, and do not retain - * `text.ptr`. The bytes are NOT guaranteed to be null-terminated. + * The view is borrowed for the duration of the call only. Copy what you need before returning, and do not retain `text` + * or `text->ptr`. The bytes are NOT guaranteed to be null-terminated. * * `err` is a live error slot, never NULL. Populate it with `duckdb_v2_error_info_set_code()` / * `duckdb_v2_error_info_set_text()` to signal failure to DuckDB. Do not destroy it yourself. @@ -368,7 +393,7 @@ typedef duckdb_v2_str duckdb_v2_identifier_t; * The sink runs inside DuckDB's call frame: it must not throw or unwind across the boundary, and it must not re-enter * the API on the handle being operated on. */ -typedef void (*duckdb_v2_text_sink_fn)(duckdb_v2_str text, void *user_data, duckdb_v2_error_info_handle *err); +typedef void (*duckdb_v2_text_sink_fn)(const duckdb_v2_str *text, void *user_data, duckdb_v2_error_info_handle *err); /*! * Compares two caller-defined resources for equality. @@ -404,6 +429,9 @@ typedef void (*duckdb_v2_opaque_destroy_fn)(void *data); * dereferenced when `len` is 0. Not to be confused with `bytes`, the transparent 16-byte *storage* format for a * variable-size value in a vector. * + * Functions take an input view as a `const str *`, which must not be NULL; a NULL pointer, or a view whose `ptr` is + * NULL while `len` is nonzero, fails with ERROR_INPUT_INVALID. Point at a `{NULL, 0}` view to pass an empty string. + * * Text inputs, such as VARCHAR values and names, must contain valid UTF-8. The caller is responsible for ensuring this; * API functions do not necessarily validate the input. Binary inputs, such as BLOB values, do not require valid UTF-8. */ @@ -1654,7 +1682,7 @@ DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_option_get_alias(duckdb_v2_option_handle * @return DUCKDB_V2_ERROR */ DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_context_get_option_by_name(duckdb_v2_context_handle ctx, - duckdb_v2_identifier_t name, + const duckdb_v2_identifier_t *name, duckdb_v2_option_handle *out_option, duckdb_v2_error_info_handle *err); @@ -1781,7 +1809,7 @@ DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_custom_type_create_with_extension(duckdb_ * @return DUCKDB_V2_ERROR */ DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_custom_type_set_name(duckdb_v2_custom_type_handle type, - duckdb_v2_identifier_t name, + const duckdb_v2_identifier_t *name, duckdb_v2_error_info_handle *err); /*! @@ -2192,7 +2220,7 @@ DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_error_info_set_code(duckdb_v2_error_info_ * @param text The error text to set in the info. * @return DUCKDB_V2_ERROR */ -DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_error_info_set_text(duckdb_v2_error_info_handle info, duckdb_v2_str text); +DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_error_info_set_text(duckdb_v2_error_info_handle info, const duckdb_v2_str *text); /*! * Destroys an error info handle and frees its resources. @@ -2458,7 +2486,8 @@ DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_file_open_options_set_flag(duckdb_v2_file * @return DUCKDB_V2_ERROR */ DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_file_open_options_set_value(duckdb_v2_file_open_options_handle options, - duckdb_v2_str name, duckdb_v2_value_handle value, + const duckdb_v2_str *name, + duckdb_v2_value_handle value, duckdb_v2_error_info_handle *err); /*! @@ -2504,7 +2533,7 @@ DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_file_open_options_destroy(duckdb_v2_file_ * @return DUCKDB_V2_ERROR */ DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_file_system_open(duckdb_v2_file_system_handle file_system, - duckdb_v2_str file_path, + const duckdb_v2_str *file_path, duckdb_v2_file_open_options_handle options, duckdb_v2_file_handle *file, duckdb_v2_error_info_handle *err); @@ -2735,7 +2764,7 @@ typedef struct _duckdb_v2_function_signature { * @return DUCKDB_V2_ERROR */ DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_function_signature_add_parameter(duckdb_v2_function_signature_handle sig, - duckdb_v2_identifier_t name, + const duckdb_v2_identifier_t *name, duckdb_v2_logical_type_handle type, duckdb_v2_value_handle value, duckdb_v2_error_info_handle *err); @@ -2825,7 +2854,7 @@ DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_function_signature_set_return_type(duckdb * `duckdb_v2_error_info_destroy()`. * @return DUCKDB_V2_ERROR */ -DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_identifier_render_quoted(duckdb_v2_identifier_t name, char *out_text, +DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_identifier_render_quoted(const duckdb_v2_identifier_t *name, char *out_text, idx_t out_capacity, idx_t *out_length, duckdb_v2_error_info_handle *err); @@ -2921,8 +2950,8 @@ DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_instance_destroy(duckdb_v2_instance_handl * `duckdb_v2_error_info_destroy()`. * @return DUCKDB_V2_ERROR */ -DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_instance_attach(duckdb_v2_instance_handle instance, duckdb_v2_str path, - duckdb_v2_identifier_t *name, +DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_instance_attach(duckdb_v2_instance_handle instance, const duckdb_v2_str *path, + const duckdb_v2_identifier_t *name, duckdb_v2_attach_options_handle options, bool make_default, duckdb_v2_error_info_handle *err); @@ -2945,7 +2974,7 @@ DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_instance_attach(duckdb_v2_instance_handle * `duckdb_v2_error_info_destroy()`. * @return DUCKDB_V2_ERROR */ -DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_instance_detach(duckdb_v2_instance_handle instance, duckdb_v2_str path, +DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_instance_detach(duckdb_v2_instance_handle instance, const duckdb_v2_str *path, duckdb_v2_error_info_handle *err); /*! @@ -2968,7 +2997,8 @@ DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_instance_detach(duckdb_v2_instance_handle * `duckdb_v2_error_info_destroy()`. * @return DUCKDB_V2_ERROR */ -DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_instance_set_default(duckdb_v2_instance_handle instance, duckdb_v2_str path, +DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_instance_set_default(duckdb_v2_instance_handle instance, + const duckdb_v2_str *path, duckdb_v2_error_info_handle *err); /*! @@ -3010,7 +3040,8 @@ DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_attach_options_create(duckdb_v2_instance_ * @return DUCKDB_V2_ERROR */ DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_attach_options_set(duckdb_v2_attach_options_handle options, - duckdb_v2_identifier_t key, duckdb_v2_str setting, + const duckdb_v2_identifier_t *key, + const duckdb_v2_str *setting, duckdb_v2_error_info_handle *err); /*! @@ -3047,7 +3078,8 @@ DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_attach_options_destroy(duckdb_v2_attach_o * @return DUCKDB_V2_ERROR */ DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_instance_set_option(duckdb_v2_instance_handle instance, - duckdb_v2_identifier_t name, duckdb_v2_str setting, + const duckdb_v2_identifier_t *name, + const duckdb_v2_str *setting, duckdb_v2_error_info_handle *err); /*! @@ -3070,7 +3102,7 @@ DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_instance_set_option(duckdb_v2_instance_ha * @return DUCKDB_V2_ERROR */ DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_instance_get_option_by_name(duckdb_v2_instance_handle instance, - duckdb_v2_identifier_t name, + const duckdb_v2_identifier_t *name, duckdb_v2_option_handle *out_option, duckdb_v2_error_info_handle *err); @@ -3188,7 +3220,7 @@ typedef enum DUCKDB_V2_LOG_LEVEL { * @return DUCKDB_V2_ERROR */ DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_context_log(duckdb_v2_context_handle ctx, DUCKDB_V2_LOG_LEVEL level, - duckdb_v2_str log_type, duckdb_v2_str message, + const duckdb_v2_str *log_type, const duckdb_v2_str *message, duckdb_v2_error_info_handle *err); /* --- Struct definitions for logging --- */ @@ -3237,7 +3269,7 @@ typedef struct _duckdb_v2_qname { * `duckdb_v2_error_info_destroy()`. * @return DUCKDB_V2_ERROR */ -DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_qname_parse(duckdb_v2_str text, duckdb_v2_qname_handle *name, +DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_qname_parse(const duckdb_v2_str *text, duckdb_v2_qname_handle *name, duckdb_v2_error_info_handle *err); /*! @@ -3533,7 +3565,7 @@ typedef struct _duckdb_v2_token_iterator { * @param err Optional. On failure, receives an opaque info handle the caller must destroy via error_info_destroy. * @return DUCKDB_V2_ERROR */ -DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_tokenize_sql(duckdb_v2_connection_handle conn, duckdb_v2_str sql, +DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_tokenize_sql(duckdb_v2_connection_handle conn, const duckdb_v2_str *sql, duckdb_v2_token_iterator_handle *out_iterator, duckdb_v2_error_info_handle *err); @@ -4084,13 +4116,14 @@ DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_bignum_encode(const uint8_t *in_data, idx duckdb_v2_error_info_handle *err); /*! - * Validates all text.len bytes as UTF-8, including bytes after embedded NUL characters. + * Validates all text->len bytes as UTF-8, including bytes after embedded NUL characters. * - * Returns ERROR_INPUT_INVALID if either: - * - text.ptr is NULL and text.len is nonzero. + * Returns ERROR_INPUT_INVALID if any of: + * - text is NULL. + * - text->ptr is NULL and text->len is nonzero. * - The input contains malformed UTF-8. * - * A NULL pointer with zero length is valid. + * A view with a NULL ptr and zero length is valid. * * history: * - stable: v2.0.0 @@ -4099,7 +4132,7 @@ DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_bignum_encode(const uint8_t *in_data, idx * @param err Optional. On failure, receives an opaque info handle the caller must destroy via error_info_destroy. * @return DUCKDB_V2_ERROR */ -DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_validate_utf8(duckdb_v2_str text, duckdb_v2_error_info_handle *err); +DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_validate_utf8(const duckdb_v2_str *text, duckdb_v2_error_info_handle *err); /* --- Struct definitions for vector --- */ @@ -4303,7 +4336,7 @@ DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_aggregate_function_create_with_extension( * @return DUCKDB_V2_ERROR */ DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_aggregate_function_set_name(duckdb_v2_aggregate_function_handle function, - duckdb_v2_identifier_t *name, + const duckdb_v2_identifier_t *name, duckdb_v2_error_info_handle *err); /*! @@ -5763,7 +5796,8 @@ DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_connection_destroy(duckdb_v2_connection_h * @return DUCKDB_V2_ERROR */ DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_connection_set_option(duckdb_v2_connection_handle conn, - duckdb_v2_identifier_t name, duckdb_v2_str setting, + const duckdb_v2_identifier_t *name, + const duckdb_v2_str *setting, DUCKDB_V2_SETTING_SCOPE scope, duckdb_v2_error_info_handle *err); @@ -5786,7 +5820,7 @@ DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_connection_set_option(duckdb_v2_connectio * @return DUCKDB_V2_ERROR */ DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_connection_get_option_by_name(duckdb_v2_connection_handle conn, - duckdb_v2_identifier_t name, + const duckdb_v2_identifier_t *name, duckdb_v2_option_handle *out_option, duckdb_v2_error_info_handle *err); @@ -6106,7 +6140,7 @@ DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_copy_function_create_with_extension(duckd * @return DUCKDB_V2_ERROR */ DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_copy_function_set_name(duckdb_v2_copy_function_handle function, - duckdb_v2_identifier_t *name, + const duckdb_v2_identifier_t *name, duckdb_v2_error_info_handle *err); /*! @@ -7867,7 +7901,8 @@ DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_context_create_type_from_name( * @param err Optional. On failure, receives an opaque info handle the caller must destroy via error_info_destroy. * @return DUCKDB_V2_ERROR */ -DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_context_create_type_from_text(duckdb_v2_context_handle ctx, duckdb_v2_str text, +DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_context_create_type_from_text(duckdb_v2_context_handle ctx, + const duckdb_v2_str *text, duckdb_v2_logical_type_handle *out_type, duckdb_v2_error_info_handle *err); @@ -7963,7 +7998,7 @@ DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_connection_create_type_from_name( * @return DUCKDB_V2_ERROR */ DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_connection_create_type_from_text(duckdb_v2_connection_handle conn, - duckdb_v2_str text, + const duckdb_v2_str *text, duckdb_v2_logical_type_handle *out_type, duckdb_v2_error_info_handle *err); @@ -8152,7 +8187,7 @@ DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_logical_type_get_param(duckdb_v2_logical_ */ DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_context_create_type_with_alias(duckdb_v2_context_handle ctx, duckdb_v2_logical_type_handle base_type, - duckdb_v2_identifier_t alias_name, + const duckdb_v2_identifier_t *alias_name, duckdb_v2_logical_type_handle *out_type, duckdb_v2_error_info_handle *err); @@ -8179,7 +8214,7 @@ DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_context_create_type_with_alias(duckdb_v2_ */ DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_connection_create_type_with_alias(duckdb_v2_connection_handle conn, duckdb_v2_logical_type_handle base_type, - duckdb_v2_identifier_t alias_name, + const duckdb_v2_identifier_t *alias_name, duckdb_v2_logical_type_handle *out_type, duckdb_v2_error_info_handle *err); @@ -8435,7 +8470,7 @@ DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_replacement_scan_add_argument(duckdb_v2_r * @return DUCKDB_V2_ERROR */ DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_replacement_scan_add_named_argument(duckdb_v2_replacement_scan_info_handle info, - duckdb_v2_identifier_t name, + const duckdb_v2_identifier_t *name, duckdb_v2_value_handle value, duckdb_v2_error_info_handle *err); @@ -8500,7 +8535,7 @@ DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_replacement_scan_set_collection( * @return DUCKDB_V2_ERROR */ DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_replacement_scan_set_subquery(duckdb_v2_replacement_scan_info_handle info, - duckdb_v2_str sql, + const duckdb_v2_str *sql, duckdb_v2_error_info_handle *err); /*! @@ -8520,7 +8555,7 @@ DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_replacement_scan_set_subquery(duckdb_v2_r * @return DUCKDB_V2_ERROR */ DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_replacement_scan_set_alias(duckdb_v2_replacement_scan_info_handle info, - duckdb_v2_identifier_t alias, + const duckdb_v2_identifier_t *alias, duckdb_v2_error_info_handle *err); /*! @@ -8689,7 +8724,7 @@ DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_scalar_function_create_with_extension(duc * @return DUCKDB_V2_ERROR */ DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_scalar_function_set_name(duckdb_v2_scalar_function_handle function, - duckdb_v2_identifier_t *name, + const duckdb_v2_identifier_t *name, duckdb_v2_error_info_handle *err); /*! @@ -10089,7 +10124,7 @@ DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_value_create_ubigint_with_context(duckdb_ * @return DUCKDB_V2_ERROR */ DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_value_create_uhugeint_with_context(duckdb_v2_context_handle ctx, - duckdb_v2_uhugeint_t in_value, + const duckdb_v2_uhugeint_t *in_value, duckdb_v2_value_handle *out_value, duckdb_v2_error_info_handle *err); @@ -10181,7 +10216,7 @@ DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_value_create_bigint_with_context(duckdb_v * @return DUCKDB_V2_ERROR */ DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_value_create_hugeint_with_context(duckdb_v2_context_handle ctx, - duckdb_v2_hugeint_t in_value, + const duckdb_v2_hugeint_t *in_value, duckdb_v2_value_handle *out_value, duckdb_v2_error_info_handle *err); @@ -10200,7 +10235,7 @@ DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_value_create_hugeint_with_context(duckdb_ * @return DUCKDB_V2_ERROR */ DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_value_create_varchar_with_context(duckdb_v2_context_handle ctx, - duckdb_v2_str in_value, + const duckdb_v2_str *in_value, duckdb_v2_value_handle *out_value, duckdb_v2_error_info_handle *err); @@ -10219,7 +10254,7 @@ DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_value_create_varchar_with_context(duckdb_ * @return DUCKDB_V2_ERROR */ DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_value_create_blob_with_context(duckdb_v2_context_handle ctx, - duckdb_v2_str in_value, + const duckdb_v2_str *in_value, duckdb_v2_value_handle *out_value, duckdb_v2_error_info_handle *err); @@ -10407,7 +10442,7 @@ DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_value_create_ubigint_with_connection(duck * @return DUCKDB_V2_ERROR */ DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_value_create_uhugeint_with_connection(duckdb_v2_connection_handle conn, - duckdb_v2_uhugeint_t in_value, + const duckdb_v2_uhugeint_t *in_value, duckdb_v2_value_handle *out_value, duckdb_v2_error_info_handle *err); @@ -10502,7 +10537,7 @@ DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_value_create_bigint_with_connection(duckd * @return DUCKDB_V2_ERROR */ DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_value_create_hugeint_with_connection(duckdb_v2_connection_handle conn, - duckdb_v2_hugeint_t in_value, + const duckdb_v2_hugeint_t *in_value, duckdb_v2_value_handle *out_value, duckdb_v2_error_info_handle *err); @@ -10521,7 +10556,7 @@ DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_value_create_hugeint_with_connection(duck * @return DUCKDB_V2_ERROR */ DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_value_create_varchar_with_connection(duckdb_v2_connection_handle conn, - duckdb_v2_str in_value, + const duckdb_v2_str *in_value, duckdb_v2_value_handle *out_value, duckdb_v2_error_info_handle *err); @@ -10540,7 +10575,7 @@ DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_value_create_varchar_with_connection(duck * @return DUCKDB_V2_ERROR */ DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_value_create_blob_with_connection(duckdb_v2_connection_handle conn, - duckdb_v2_str in_value, + const duckdb_v2_str *in_value, duckdb_v2_value_handle *out_value, duckdb_v2_error_info_handle *err); @@ -11021,7 +11056,7 @@ DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_value_create_timestamp_tz_ns_with_connect * @return DUCKDB_V2_ERROR */ DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_value_create_interval_with_context(duckdb_v2_context_handle ctx, - duckdb_v2_interval_t in_value, + const duckdb_v2_interval_t *in_value, duckdb_v2_value_handle *out_value, duckdb_v2_error_info_handle *err); @@ -11041,7 +11076,7 @@ DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_value_create_interval_with_context(duckdb * @return DUCKDB_V2_ERROR */ DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_value_create_interval_with_connection(duckdb_v2_connection_handle conn, - duckdb_v2_interval_t in_value, + const duckdb_v2_interval_t *in_value, duckdb_v2_value_handle *out_value, duckdb_v2_error_info_handle *err); @@ -11065,8 +11100,8 @@ DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_value_create_interval_with_connection(duc * @return DUCKDB_V2_ERROR */ DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_value_create_decimal_with_context(duckdb_v2_context_handle ctx, - duckdb_v2_hugeint_t in_value, uint8_t width, - uint8_t scale, + const duckdb_v2_hugeint_t *in_value, + uint8_t width, uint8_t scale, duckdb_v2_value_handle *out_value, duckdb_v2_error_info_handle *err); @@ -11090,8 +11125,8 @@ DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_value_create_decimal_with_context(duckdb_ * @return DUCKDB_V2_ERROR */ DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_value_create_decimal_with_connection(duckdb_v2_connection_handle conn, - duckdb_v2_hugeint_t in_value, uint8_t width, - uint8_t scale, + const duckdb_v2_hugeint_t *in_value, + uint8_t width, uint8_t scale, duckdb_v2_value_handle *out_value, duckdb_v2_error_info_handle *err); @@ -11112,7 +11147,7 @@ DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_value_create_decimal_with_connection(duck * @return DUCKDB_V2_ERROR */ DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_value_create_uuid_with_context(duckdb_v2_context_handle ctx, - duckdb_v2_hugeint_t in_value, + const duckdb_v2_hugeint_t *in_value, duckdb_v2_value_handle *out_value, duckdb_v2_error_info_handle *err); @@ -11133,7 +11168,7 @@ DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_value_create_uuid_with_context(duckdb_v2_ * @return DUCKDB_V2_ERROR */ DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_value_create_uuid_with_connection(duckdb_v2_connection_handle conn, - duckdb_v2_hugeint_t in_value, + const duckdb_v2_hugeint_t *in_value, duckdb_v2_value_handle *out_value, duckdb_v2_error_info_handle *err); @@ -11154,7 +11189,7 @@ DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_value_create_uuid_with_connection(duckdb_ * @return DUCKDB_V2_ERROR */ DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_value_create_bit_with_context(duckdb_v2_context_handle ctx, - duckdb_v2_str in_value, + const duckdb_v2_str *in_value, duckdb_v2_value_handle *out_value, duckdb_v2_error_info_handle *err); @@ -11175,7 +11210,7 @@ DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_value_create_bit_with_context(duckdb_v2_c * @return DUCKDB_V2_ERROR */ DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_value_create_bit_with_connection(duckdb_v2_connection_handle conn, - duckdb_v2_str in_value, + const duckdb_v2_str *in_value, duckdb_v2_value_handle *out_value, duckdb_v2_error_info_handle *err); @@ -11196,7 +11231,7 @@ DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_value_create_bit_with_connection(duckdb_v * @return DUCKDB_V2_ERROR */ DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_value_create_bignum_with_context(duckdb_v2_context_handle ctx, - duckdb_v2_str in_value, + const duckdb_v2_str *in_value, duckdb_v2_value_handle *out_value, duckdb_v2_error_info_handle *err); @@ -11217,7 +11252,7 @@ DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_value_create_bignum_with_context(duckdb_v * @return DUCKDB_V2_ERROR */ DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_value_create_bignum_with_connection(duckdb_v2_connection_handle conn, - duckdb_v2_str in_value, + const duckdb_v2_str *in_value, duckdb_v2_value_handle *out_value, duckdb_v2_error_info_handle *err); @@ -12029,9 +12064,10 @@ DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_result_wait(duckdb_v2_result_handle resul * @return DUCKDB_V2_ERROR */ DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_result_render_box(duckdb_v2_result_handle *result, idx_t max_rows, - idx_t max_width, idx_t max_col_width, duckdb_v2_str null_value, - idx_t render_mode, idx_t limit, duckdb_v2_text_sink_fn sink, - void *user_data, duckdb_v2_error_info_handle *err); + idx_t max_width, idx_t max_col_width, + const duckdb_v2_str *null_value, idx_t render_mode, + idx_t limit, duckdb_v2_text_sink_fn sink, void *user_data, + duckdb_v2_error_info_handle *err); /*! * Runs the result to completion and reports the changed-row count. @@ -12335,7 +12371,7 @@ DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_table_function_create_with_extension(duck * @return DUCKDB_V2_ERROR */ DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_table_function_set_name(duckdb_v2_table_function_handle function, - duckdb_v2_identifier_t *name, + const duckdb_v2_identifier_t *name, duckdb_v2_error_info_handle *err); /*! @@ -12693,8 +12729,8 @@ DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_table_function_bind_get_arg_value(duckdb_ * @return DUCKDB_V2_ERROR */ DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_table_function_bind_add_result_column( - duckdb_v2_table_function_bind_info_handle info, duckdb_v2_identifier_t name, duckdb_v2_logical_type_handle type, - duckdb_v2_error_info_handle *err); + duckdb_v2_table_function_bind_info_handle info, const duckdb_v2_identifier_t *name, + duckdb_v2_logical_type_handle type, duckdb_v2_error_info_handle *err); /*! * Sets the estimated number of rows the scan will produce. @@ -12715,6 +12751,29 @@ DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_table_function_bind_add_result_column( DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_table_function_bind_set_cardinality( duckdb_v2_table_function_bind_info_handle info, idx_t cardinality, bool is_exact, duckdb_v2_error_info_handle *err); +/*! + * Sets the order guarantee of the rows this call of the function produces. Defaults to + * `ORDER_PRESERVATION_INSERTION_ORDER`. + * + * With `ORDER_PRESERVATION_NO_ORDER`, a scan that reports more than one thread via + * `duckdb_v2_table_function_init_global_set_max_threads()` runs in parallel into query results, INSERT and COPY without + * a `duckdb_v2_table_function_set_partition_data_callback()`, and the rows arrive in no particular order. With + * insertion order kept, those consumers need the partition data callback to run in parallel. Fails with + * `ERROR_INPUT_INVALID` when order is not one of the enum's declared values. + * + * history: + * - stable: v2.0.0 + * + * @param info The bind info handle. + * @param order The order guarantee of the produced rows. + * @param err Optional. On failure, receives an opaque info handle the caller must destroy via + * `duckdb_v2_error_info_destroy()`. + * @return DUCKDB_V2_ERROR + */ +DUCKDB_C_API DUCKDB_V2_ERROR duckdb_v2_table_function_bind_set_order_preservation( + duckdb_v2_table_function_bind_info_handle info, DUCKDB_V2_ORDER_PRESERVATION order, + duckdb_v2_error_info_handle *err); + /*! * Retrieves the user data set via `duckdb_v2_table_function_set_user_data()`. * diff --git a/src/duckdb/src/main/capi/v1/aggregate_function-c.cpp b/src/duckdb/src/main/capi/v1/aggregate_function-c.cpp index 7cebd2005..4bd2fac49 100644 --- a/src/duckdb/src/main/capi/v1/aggregate_function-c.cpp +++ b/src/duckdb/src/main/capi/v1/aggregate_function-c.cpp @@ -1,4 +1,5 @@ #include "duckdb/catalog/catalog.hpp" +#include "duckdb/main/capi/capi_function_signature.hpp" #include "duckdb/common/type_visitor.hpp" #include "duckdb/common/types.hpp" #include "duckdb/function/function.hpp" @@ -186,7 +187,8 @@ void duckdb_aggregate_function_add_parameter(duckdb_aggregate_function function, } auto &aggregate_function = GetCAggregateFunction(function); auto logical_type = reinterpret_cast(type); - aggregate_function.GetSignature().AddParameter(*logical_type); + // v1 declares no parameter name, so the parameter is positional-only - see duckdb_scalar_function_add_parameter + duckdb::CAPIFunctionSignature::AddPositionalOnly(aggregate_function.GetSignature(), *logical_type); } void duckdb_aggregate_function_set_return_type(duckdb_aggregate_function function, duckdb_logical_type type) { diff --git a/src/duckdb/src/main/capi/v1/copy_function-c.cpp b/src/duckdb/src/main/capi/v1/copy_function-c.cpp index c4f45391c..5e1bc17bc 100644 --- a/src/duckdb/src/main/capi/v1/copy_function-c.cpp +++ b/src/duckdb/src/main/capi/v1/copy_function-c.cpp @@ -650,12 +650,12 @@ unique_ptr CCopyFromBind(ClientContext &context, CopyFromFunctionB auto &tf_info = info.tf.function_info->Cast(); auto result = make_uniq(tf_info); - named_parameter_map_t named_parameters; + named_argument_map_t named_parameters; // Turn all options into named parameters for (auto opt : info.info.options) { - auto param_it = info.tf.named_parameters.find(Identifier(opt.first)); - if (param_it == info.tf.named_parameters.end()) { + auto option_schema = info.tf.GetSignature().GetTypedKwargs(); + if (!option_schema || !option_schema->Find(Identifier(opt.first))) { // Option not found in the table function's named parameters throw BinderException("'%s' is not a supported option for copy function '%s'", opt.first.c_str(), info.tf.name.c_str()); @@ -724,14 +724,21 @@ void duckdb_copy_function_set_copy_from_function(duckdb_copy_function copy_funct if (!tf_info.bind || !tf_info.init || !tf_info.function) { return; } - for (auto it = tf.named_parameters.begin(); it != tf.named_parameters.end(); it++) { - if (duckdb::TypeVisitor::Contains(it->second, duckdb::LogicalTypeId::INVALID)) { + for (auto ¶m : tf.GetSignature().GetParameters()) { + // a variadic parameter carries no type of its own + if (param.IsVariadic()) { + continue; + } + if (duckdb::TypeVisitor::Contains(param.GetType(), duckdb::LogicalTypeId::INVALID)) { return; } } - for (const auto &argument : tf.GetArguments()) { - if (duckdb::TypeVisitor::Contains(argument, duckdb::LogicalTypeId::INVALID)) { - return; + auto option_schema = tf.GetSignature().GetTypedKwargs(); + if (option_schema) { + for (auto &option : option_schema->GetOptions()) { + if (duckdb::TypeVisitor::Contains(option.type, duckdb::LogicalTypeId::INVALID)) { + return; + } } } diff --git a/src/duckdb/src/main/capi/v1/scalar_function-c.cpp b/src/duckdb/src/main/capi/v1/scalar_function-c.cpp index 600a62261..5140b8806 100644 --- a/src/duckdb/src/main/capi/v1/scalar_function-c.cpp +++ b/src/duckdb/src/main/capi/v1/scalar_function-c.cpp @@ -1,4 +1,5 @@ #include "duckdb/catalog/catalog.hpp" +#include "duckdb/main/capi/capi_function_signature.hpp" #include "duckdb/common/type_visitor.hpp" #include "duckdb/common/types.hpp" #include "duckdb/function/function.hpp" @@ -251,7 +252,7 @@ void duckdb_scalar_function_set_varargs(duckdb_scalar_function function, duckdb_ } auto &scalar_function = GetCScalarFunction(function); auto logical_type = reinterpret_cast(type); - scalar_function.SetVarArgs(*logical_type); + duckdb::CAPIFunctionSignature::SetVarArgs(scalar_function.GetSignature(), *logical_type); } void duckdb_scalar_function_set_special_handling(duckdb_scalar_function function) { @@ -276,12 +277,9 @@ void duckdb_scalar_function_add_parameter(duckdb_scalar_function function, duckd } auto &scalar_function = GetCScalarFunction(function); auto logical_type = reinterpret_cast(type); - // the varargs can be set before the parameters, but they come after them in the signature - auto &signature = scalar_function.GetSignature(); - auto varargs = signature.GetVarArgs(); - signature.SetVarArgs(duckdb::LogicalType(duckdb::LogicalTypeId::INVALID)); - signature.AddParameter(*logical_type); - signature.SetVarArgs(std::move(varargs)); + // v1 declares no parameter name, so the caller cannot mean one: the parameter is positional-only, and the + // synthetic "colN" it is given stays invisible. It goes ahead of any varargs set beforehand. + duckdb::CAPIFunctionSignature::AddPositionalOnly(scalar_function.GetSignature(), *logical_type); } void duckdb_scalar_function_set_return_type(duckdb_scalar_function function, duckdb_logical_type type) { diff --git a/src/duckdb/src/main/capi/v1/table_function-c.cpp b/src/duckdb/src/main/capi/v1/table_function-c.cpp index 7fd048c33..88b2a5c84 100644 --- a/src/duckdb/src/main/capi/v1/table_function-c.cpp +++ b/src/duckdb/src/main/capi/v1/table_function-c.cpp @@ -1,4 +1,5 @@ #include "duckdb/catalog/catalog.hpp" +#include "duckdb/main/capi/capi_function_signature.hpp" #include "duckdb/common/type_visitor.hpp" #include "duckdb/common/types.hpp" #include "duckdb/function/table_function.hpp" @@ -9,6 +10,7 @@ #include "duckdb/storage/statistics/node_statistics.hpp" namespace duckdb { + namespace { //===--------------------------------------------------------------------===// // Structures @@ -111,6 +113,7 @@ unique_ptr CTableFunctionBind(ClientContext &context, TableFunctio D_ASSERT(info.bind && info.function && info.init); auto result = make_uniq(info); + // the cast values are kept, so that a plan that repeats this bind needs no literal types CTableInternalBindInfo bind_info(context, input.inputs, input.named_parameters, return_types, names, *result, info); info.bind(ToCTableFunctionBindInfo(bind_info)); if (!bind_info.success) { @@ -205,7 +208,9 @@ void duckdb_table_function_add_parameter(duckdb_table_function function, duckdb_ } auto &tf = GetCTableFunction(function); auto logical_type = reinterpret_cast(type); - tf.GetArguments().push_back(*logical_type); + // v1 declares no parameter name, so the parameter is positional-only - see duckdb_scalar_function_add_parameter. + // duckdb_table_function_add_named_parameter is the one that declares a name a caller can use + duckdb::CAPIFunctionSignature::AddPositionalOnly(tf.GetSignature(), *logical_type); } void duckdb_table_function_add_named_parameter(duckdb_table_function function, const char *name, @@ -215,7 +220,19 @@ void duckdb_table_function_add_named_parameter(duckdb_table_function function, c } auto &tf = GetCTableFunction(function); auto logical_type = reinterpret_cast(type); - tf.named_parameters.insert({name, *logical_type}); + // an option the call leaves out does not reach the bind, where duckdb_bind_get_named_parameter reports it absent + auto add_option = [&](duckdb::TypedKwargs &options) { + auto option_name = duckdb::Identifier(name); + if (!options.Find(option_name)) { + options.Add(std::move(option_name), *logical_type); + } + }; + auto &signature = tf.GetSignature(); + if (signature.GetTypedKwargs()) { + signature.ExtendTypedKwargs(add_option); + } else { + signature.WithTypedKwargs("options", add_option); + } } void duckdb_table_function_set_extra_info(duckdb_table_function function, void *extra_info, @@ -284,14 +301,20 @@ duckdb_state duckdb_register_table_function(duckdb_connection connection, duckdb if (tf.name.empty() || !info.bind || !info.init || !info.function) { return DuckDBError; } - for (auto it = tf.named_parameters.begin(); it != tf.named_parameters.end(); it++) { - if (duckdb::TypeVisitor::Contains(it->second, duckdb::LogicalTypeId::INVALID)) { + for (auto ¶m : tf.GetSignature().GetParameters()) { + // a variadic parameter carries no type of its own + if (param.IsVariadic()) { + continue; + } + if (duckdb::TypeVisitor::Contains(param.GetType(), duckdb::LogicalTypeId::INVALID)) { return DuckDBError; } } - for (const auto &argument : tf.GetArguments()) { - if (duckdb::TypeVisitor::Contains(argument, duckdb::LogicalTypeId::INVALID)) { - return DuckDBError; + if (auto option_schema = tf.GetSignature().GetTypedKwargs()) { + for (auto &option : option_schema->GetOptions()) { + if (duckdb::TypeVisitor::Contains(option.type, duckdb::LogicalTypeId::INVALID)) { + return DuckDBError; + } } } diff --git a/src/duckdb/src/main/capi/v2/capi_v2_arrow.cpp b/src/duckdb/src/main/capi/v2/capi_v2_arrow.cpp index 540e2fc2c..a59879d02 100644 --- a/src/duckdb/src/main/capi/v2/capi_v2_arrow.cpp +++ b/src/duckdb/src/main/capi/v2/capi_v2_arrow.cpp @@ -305,6 +305,36 @@ void CV2ArrowStreamRelease(ArrowArrayStream *stream) { // Import conversion //---------------------------------------------------------------------------------------------------------------------- +//! The record-batch struct may carry a validity bitmap of its own: a clear bit marks the whole row null, so +//! it has to apply to every column alike. Returns null when the array carries no bitmap, or no row is null. +auto CV2TopLevelValidity(const ArrowArray &array, idx_t from, idx_t rows) -> unique_ptr { + if (array.null_count == 0 || array.n_buffers == 0 || !array.buffers || !array.buffers[0]) { + return nullptr; + } + auto bits = static_cast(array.buffers[0]); + auto mask = make_uniq(rows); + for (idx_t row = 0; row < rows; row++) { + auto index = NumericCast(array.offset) + from + row; + if (!(bits[index / 8] & (1 << (index % 8)))) { + mask->SetInvalid(row); + } + } + if (!mask->CanHaveNull()) { + return nullptr; + } + return mask; +} + +//! Marks the rows the record batch calls null as null in this vector too. +void CV2ApplyTopLevelMask(Vector &vector, const ValidityMask &top_level_mask, idx_t rows) { + auto &mask = FlatVector::ValidityMutable(vector); + for (idx_t row = 0; row < rows; row++) { + if (!top_level_mask.RowIsValid(row)) { + mask.SetInvalid(row); + } + } +} + //! Converts `rows` rows starting at `from` of `array` into a fresh chunk, through the resolved per-column Arrow types. //! `owner` is the shared owner the chunk's zero-copy vectors keep alive; it is null when the caller kept the array, in //! which case the result is materialized instead. @@ -316,29 +346,37 @@ auto CV2ConvertArrowSlice(ClientContext &context, CV2ArrowImporter &importer, Ar auto chunk = make_uniq(); chunk->Initialize(Allocator::DefaultAllocator(), types, MaxValue(rows, 1)); chunk->SetChildCardinality(rows); + auto top_level_mask = CV2TopLevelValidity(array, from, rows); for (idx_t i = 0; i < chunk->ColumnCount(); i++) { auto *child_array = array.children[i]; auto arrow_type = arrow_types.at(i); // A fresh scan state per slice, so nothing cached for one array leaks into the next. The cost is re-decoding a // dictionary per chunk. auto array_state = make_uniq(context); - array_state->owned_data = owner; + // The dictionary conversion requires a non-null owned_data to attach to its vectors. When + // there is no owner the chunk is materialized below, so an inert wrapper is enough. + array_state->owned_data = owner ? owner : duckdb::make_shared_ptr(); switch (arrow_type->GetPhysicalType()) { case ArrowArrayPhysicalType::DICTIONARY_ENCODED: if (!child_array->dictionary) { throw InvalidInputException("Dictionary-encoded Arrow array has no dictionary"); } + // the dictionary conversion folds the mask into its selection vector itself ArrowToDuckDBConversion::ColumnArrowToDuckDBDictionary(chunk->data[i], *child_array, from, *array_state, - rows, *arrow_type); + rows, *arrow_type, -1, top_level_mask.get()); break; case ArrowArrayPhysicalType::RUN_END_ENCODED: ArrowToDuckDBConversion::ColumnArrowToDuckDBRunEndEncoded(chunk->data[i], *child_array, from, *array_state, - rows, *arrow_type); + rows, *arrow_type, -1, top_level_mask.get()); break; case ArrowArrayPhysicalType::DEFAULT: ArrowToDuckDBConversion::SetValidityMask(chunk->data[i], *child_array, from, rows, array.offset, -1); + // Merging before the conversion lets a struct or union column propagate the nulls to its children. + if (top_level_mask) { + CV2ApplyTopLevelMask(chunk->data[i], *top_level_mask, rows); + } ArrowToDuckDBConversion::ColumnArrowToDuckDB(chunk->data[i], *child_array, from, *array_state, rows, - *arrow_type); + *arrow_type, -1, top_level_mask.get()); break; default: throw NotImplementedException("Only default Arrow physical types are currently supported"); @@ -346,6 +384,10 @@ auto CV2ConvertArrowSlice(ClientContext &context, CV2ArrowImporter &importer, Ar // Re-assert the size after the conversion, mirroring the engine's own scan loop: a dictionary or run-end // conversion replaces the vector rather than filling it. FlatVector::SetSize(chunk->data[i], count_t(rows)); + // A conversion may rebuild the validity mask from its own buffers, so the top-level nulls go in again. + if (top_level_mask && chunk->data[i].GetVectorType() == VectorType::FLAT_VECTOR) { + CV2ApplyTopLevelMask(chunk->data[i], *top_level_mask, rows); + } } chunk->CheckCardinality(rows); if (owner) { @@ -378,6 +420,10 @@ void CV2ValidateArrowArray(CV2ArrowImporter &importer, ArrowArray &array) { throw InvalidInputException("Arrow array child length does not match the array length"); } } + // A positive null count is only meaningful with the validity bitmap to read it from. + if (array.null_count > 0 && (array.n_buffers == 0 || !array.buffers || !array.buffers[0])) { + throw InvalidInputException("Arrow array has a non-zero null count but no validity bitmap"); + } } } // namespace @@ -617,7 +663,7 @@ DUCKDB_V2_ERROR duckdb_v2_arrow_exporter_create(duckdb_v2_context_handle context if (!types[i]) { throw duckdb::InvalidInputException("null logical type at index %llu", i); } - if (IsNullArgument(names[i])) { + if (IsNullArgument(&names[i])) { throw duckdb::InvalidInputException("malformed column name at index %llu", i); } exporter->types.push_back(*Convert(types[i])); diff --git a/src/duckdb/src/main/capi/v2/capi_v2_connection.cpp b/src/duckdb/src/main/capi/v2/capi_v2_connection.cpp index f2d27ee21..824bf29d8 100644 --- a/src/duckdb/src/main/capi/v2/capi_v2_connection.cpp +++ b/src/duckdb/src/main/capi/v2/capi_v2_connection.cpp @@ -48,8 +48,8 @@ DUCKDB_V2_ERROR duckdb_v2_connection_destroy(duckdb_v2_connection_handle *conn) }); } -DUCKDB_V2_ERROR duckdb_v2_connection_set_option(duckdb_v2_connection_handle conn, duckdb_v2_identifier_t name, - duckdb_v2_str setting, DUCKDB_V2_SETTING_SCOPE scope, +DUCKDB_V2_ERROR duckdb_v2_connection_set_option(duckdb_v2_connection_handle conn, const duckdb_v2_identifier_t *name, + const duckdb_v2_str *setting, DUCKDB_V2_SETTING_SCOPE scope, duckdb_v2_error_info_handle *err) { DUCKDB_CHECK_ARG(conn); DUCKDB_CHECK_ARG(name); @@ -61,7 +61,8 @@ DUCKDB_V2_ERROR duckdb_v2_connection_set_option(duckdb_v2_connection_handle conn }); } -DUCKDB_V2_ERROR duckdb_v2_connection_get_option_by_name(duckdb_v2_connection_handle conn, duckdb_v2_identifier_t name, +DUCKDB_V2_ERROR duckdb_v2_connection_get_option_by_name(duckdb_v2_connection_handle conn, + const duckdb_v2_identifier_t *name, duckdb_v2_option_handle *out_option, duckdb_v2_error_info_handle *err) { DUCKDB_CHECK_ARG(conn); diff --git a/src/duckdb/src/main/capi/v2/capi_v2_custom_type.cpp b/src/duckdb/src/main/capi/v2/capi_v2_custom_type.cpp index 4a26e6021..cd69e9de5 100644 --- a/src/duckdb/src/main/capi/v2/capi_v2_custom_type.cpp +++ b/src/duckdb/src/main/capi/v2/capi_v2_custom_type.cpp @@ -112,7 +112,7 @@ DUCKDB_V2_ERROR duckdb_v2_custom_type_create_with_extension(duckdb_v2_extension_ }); } -DUCKDB_V2_ERROR duckdb_v2_custom_type_set_name(duckdb_v2_custom_type_handle type, duckdb_v2_identifier_t name, +DUCKDB_V2_ERROR duckdb_v2_custom_type_set_name(duckdb_v2_custom_type_handle type, const duckdb_v2_identifier_t *name, duckdb_v2_error_info_handle *err) { DUCKDB_CHECK_ARG(type); DUCKDB_CHECK_ARG(name); diff --git a/src/duckdb/src/main/capi/v2/capi_v2_error.cpp b/src/duckdb/src/main/capi/v2/capi_v2_error.cpp index bd766385a..792d688cb 100644 --- a/src/duckdb/src/main/capi/v2/capi_v2_error.cpp +++ b/src/duckdb/src/main/capi/v2/capi_v2_error.cpp @@ -20,8 +20,8 @@ DUCKDB_V2_ERROR duckdb_v2_error_info_get_raw_text(duckdb_v2_error_info_handle in return DUCKDB_V2_ERROR_NONE; } -DUCKDB_V2_ERROR duckdb_v2_error_info_set_text(duckdb_v2_error_info_handle info, duckdb_v2_str text) { - if (!info || (!text.ptr && text.len > 0)) { +DUCKDB_V2_ERROR duckdb_v2_error_info_set_text(duckdb_v2_error_info_handle info, const duckdb_v2_str *text) { + if (!info || IsNullArgument(text)) { return DUCKDB_V2_ERROR_INPUT_INVALID; } auto *ei = Convert(info); diff --git a/src/duckdb/src/main/capi/v2/capi_v2_file_system.cpp b/src/duckdb/src/main/capi/v2/capi_v2_file_system.cpp index bef1a730d..7d61def5a 100644 --- a/src/duckdb/src/main/capi/v2/capi_v2_file_system.cpp +++ b/src/duckdb/src/main/capi/v2/capi_v2_file_system.cpp @@ -151,8 +151,9 @@ DUCKDB_V2_ERROR duckdb_v2_file_open_options_set_flag(duckdb_v2_file_open_options return WithErrorHandler(err, [&]() { ApplyFileFlag(*Convert(options), flag); }); } -DUCKDB_V2_ERROR duckdb_v2_file_open_options_set_value(duckdb_v2_file_open_options_handle options, duckdb_v2_str name, - duckdb_v2_value_handle value, duckdb_v2_error_info_handle *err) { +DUCKDB_V2_ERROR duckdb_v2_file_open_options_set_value(duckdb_v2_file_open_options_handle options, + const duckdb_v2_str *name, duckdb_v2_value_handle value, + duckdb_v2_error_info_handle *err) { DUCKDB_CHECK_ARG(options); DUCKDB_CHECK_ARG(name); DUCKDB_CHECK_ARG(value); @@ -177,7 +178,7 @@ DUCKDB_V2_ERROR duckdb_v2_file_open_options_destroy(duckdb_v2_file_open_options_ }); } -DUCKDB_V2_ERROR duckdb_v2_file_system_open(duckdb_v2_file_system_handle file_system, duckdb_v2_str file_path, +DUCKDB_V2_ERROR duckdb_v2_file_system_open(duckdb_v2_file_system_handle file_system, const duckdb_v2_str *file_path, duckdb_v2_file_open_options_handle options, duckdb_v2_file_handle *out_file_handle, duckdb_v2_error_info_handle *err) { DUCKDB_CHECK_ARG(file_system); diff --git a/src/duckdb/src/main/capi/v2/capi_v2_func_aggregate.cpp b/src/duckdb/src/main/capi/v2/capi_v2_func_aggregate.cpp index 373d13f03..884810690 100644 --- a/src/duckdb/src/main/capi/v2/capi_v2_func_aggregate.cpp +++ b/src/duckdb/src/main/capi/v2/capi_v2_func_aggregate.cpp @@ -452,12 +452,11 @@ DUCKDB_V2_ERROR duckdb_v2_aggregate_function_create_with_extension(duckdb_v2_ext }); } -DUCKDB_V2_ERROR duckdb_v2_aggregate_function_set_name(duckdb_v2_aggregate_function_handle function, duckdb_v2_str *name, - duckdb_v2_error_info_handle *err) { +DUCKDB_V2_ERROR duckdb_v2_aggregate_function_set_name(duckdb_v2_aggregate_function_handle function, + const duckdb_v2_str *name, duckdb_v2_error_info_handle *err) { DUCKDB_CHECK_ARG(function); DUCKDB_CHECK_ARG(name); - DUCKDB_CHECK_ARG(*name); - return WithErrorHandler(err, [&]() { Convert(function)->name = duckdb::Identifier(ConvertIdentifierName(*name)); }); + return WithErrorHandler(err, [&]() { Convert(function)->name = duckdb::Identifier(ConvertIdentifierName(name)); }); } DUCKDB_V2_ERROR duckdb_v2_aggregate_function_get_signature(duckdb_v2_aggregate_function_handle function, diff --git a/src/duckdb/src/main/capi/v2/capi_v2_func_copy.cpp b/src/duckdb/src/main/capi/v2/capi_v2_func_copy.cpp index 9e146a481..d6cb7c91e 100644 --- a/src/duckdb/src/main/capi/v2/capi_v2_func_copy.cpp +++ b/src/duckdb/src/main/capi/v2/capi_v2_func_copy.cpp @@ -837,12 +837,11 @@ DUCKDB_V2_ERROR duckdb_v2_copy_function_create_with_extension(duckdb_v2_extensio }); } -DUCKDB_V2_ERROR duckdb_v2_copy_function_set_name(duckdb_v2_copy_function_handle function, duckdb_v2_str *name, +DUCKDB_V2_ERROR duckdb_v2_copy_function_set_name(duckdb_v2_copy_function_handle function, const duckdb_v2_str *name, duckdb_v2_error_info_handle *err) { DUCKDB_CHECK_ARG(function); DUCKDB_CHECK_ARG(name); - DUCKDB_CHECK_ARG(*name); - return WithErrorHandler(err, [&]() { Convert(function)->name = duckdb::Identifier(ConvertIdentifierName(*name)); }); + return WithErrorHandler(err, [&]() { Convert(function)->name = duckdb::Identifier(ConvertIdentifierName(name)); }); } DUCKDB_V2_ERROR duckdb_v2_copy_function_set_user_data(duckdb_v2_copy_function_handle function, duckdb_v2_opaque *data, diff --git a/src/duckdb/src/main/capi/v2/capi_v2_func_scalar.cpp b/src/duckdb/src/main/capi/v2/capi_v2_func_scalar.cpp index fecb99561..234b71773 100644 --- a/src/duckdb/src/main/capi/v2/capi_v2_func_scalar.cpp +++ b/src/duckdb/src/main/capi/v2/capi_v2_func_scalar.cpp @@ -304,12 +304,11 @@ DUCKDB_V2_ERROR duckdb_v2_scalar_function_create_with_extension(duckdb_v2_extens }); } -DUCKDB_V2_ERROR duckdb_v2_scalar_function_set_name(duckdb_v2_scalar_function_handle function, duckdb_v2_str *name, +DUCKDB_V2_ERROR duckdb_v2_scalar_function_set_name(duckdb_v2_scalar_function_handle function, const duckdb_v2_str *name, duckdb_v2_error_info_handle *err) { DUCKDB_CHECK_ARG(function); DUCKDB_CHECK_ARG(name); - DUCKDB_CHECK_ARG(*name); - return WithErrorHandler(err, [&]() { Convert(function)->name = duckdb::Identifier(ConvertIdentifierName(*name)); }); + return WithErrorHandler(err, [&]() { Convert(function)->name = duckdb::Identifier(ConvertIdentifierName(name)); }); } DUCKDB_V2_ERROR duckdb_v2_scalar_function_get_signature(duckdb_v2_scalar_function_handle function, diff --git a/src/duckdb/src/main/capi/v2/capi_v2_func_signature.cpp b/src/duckdb/src/main/capi/v2/capi_v2_func_signature.cpp index 95933f18c..87c216358 100644 --- a/src/duckdb/src/main/capi/v2/capi_v2_func_signature.cpp +++ b/src/duckdb/src/main/capi/v2/capi_v2_func_signature.cpp @@ -1,9 +1,10 @@ #include "duckdb/main/capi_v2/capi_v2_internal.hpp" +#include "duckdb/main/capi/capi_function_signature.hpp" using namespace duckdb::capiv2; DUCKDB_V2_ERROR duckdb_v2_function_signature_add_parameter(duckdb_v2_function_signature_handle sig, - duckdb_v2_identifier_t name, + const duckdb_v2_identifier_t *name, duckdb_v2_logical_type_handle type, duckdb_v2_value_handle value, duckdb_v2_error_info_handle *err) { @@ -13,15 +14,13 @@ DUCKDB_V2_ERROR duckdb_v2_function_signature_add_parameter(duckdb_v2_function_si return WithErrorHandler(err, [&]() { auto &signature = *Convert(sig); auto param_name = duckdb::Identifier(ConvertIdentifierName(name)); - // the varargs can be set before the parameters, but they come after them in the signature - auto varargs = signature.GetVarArgs(); - signature.SetVarArgs(duckdb::LogicalType(duckdb::LogicalTypeId::INVALID)); + duckdb::optional default_value; if (value) { - signature.AddParameter(std::move(param_name), *Convert(type), *Convert(value)); - } else { - signature.AddParameter(std::move(param_name), *Convert(type)); + default_value = *Convert(value); } - signature.SetVarArgs(std::move(varargs)); + // the varargs can be set before the parameters, but they come after them in the signature + duckdb::CAPIFunctionSignature::AddParameter( + signature, duckdb::FunctionParameter(std::move(param_name), *Convert(type), std::move(default_value))); }); } @@ -33,7 +32,8 @@ DUCKDB_V2_ERROR duckdb_v2_function_signature_set_varargs(duckdb_v2_function_sign return WithErrorHandler(err, [&]() { auto &signature = *Convert(sig); - signature.SetVarArgs(*Convert(type)); + // the v2 callbacks receive no argument names, so the varargs take positional arguments only + duckdb::CAPIFunctionSignature::SetArgs(signature, *Convert(type)); }); } diff --git a/src/duckdb/src/main/capi/v2/capi_v2_func_table.cpp b/src/duckdb/src/main/capi/v2/capi_v2_func_table.cpp index 7ecc1c470..7686655a6 100644 --- a/src/duckdb/src/main/capi/v2/capi_v2_func_table.cpp +++ b/src/duckdb/src/main/capi/v2/capi_v2_func_table.cpp @@ -124,6 +124,7 @@ class CV2TableBindInfo { idx_t out_cardinality = 0; bool out_cardinality_is_exact = false; bool out_cardinality_set = false; + OrderPreservationType out_order_preservation = OrderPreservationType::INSERTION_ORDER; }; static auto Convert(duckdb_v2_table_function_bind_info_handle info) -> CV2TableBindInfo * { @@ -279,6 +280,20 @@ static auto CV2ConvertPartitionInfo(DUCKDB_V2_TABLE_PARTITION_INFO value) -> Tab return static_cast(value); } +static_assert(static_cast(OrderPreservationType::NO_ORDER) == DUCKDB_V2_ORDER_PRESERVATION_NO_ORDER, + "OrderPreservationType::NO_ORDER mismatch"); +static_assert(static_cast(OrderPreservationType::INSERTION_ORDER) == DUCKDB_V2_ORDER_PRESERVATION_INSERTION_ORDER, + "OrderPreservationType::INSERTION_ORDER mismatch"); +static_assert(static_cast(OrderPreservationType::FIXED_ORDER) == DUCKDB_V2_ORDER_PRESERVATION_FIXED_ORDER, + "OrderPreservationType::FIXED_ORDER mismatch"); + +static auto CV2ConvertOrderPreservation(DUCKDB_V2_ORDER_PRESERVATION value) -> OrderPreservationType { + if (static_cast(value) > DUCKDB_V2_ORDER_PRESERVATION_FIXED_ORDER) { + throw duckdb::InvalidInputException("Invalid value in duckdb_v2_table_function_bind_set_order_preservation"); + } + return static_cast(value); +} + class CV2TableFunctionInfo : public TableFunctionInfo { public: duckdb_v2_table_function_bind_callback_fn bind_cb = nullptr; @@ -293,50 +308,16 @@ class CV2TableFunctionInfo : public TableFunctionInfo { bool projection_pushdown = false; Identifier name; - - // The signature's slot plan, captured at registration: every parameter name in signature order, how many of them - // lead the positional prefix (the ones without a default), and the default of each remaining parameter. The bind - // wrapper assembles the argument list from it, injecting the default for a parameter the call site omitted, so - // the bind callback observes a value for every parameter. - vector parameter_names; - idx_t positional_count = 0; - identifier_map_t named_parameter_defaults; }; -//! Assembles the call's arguments in signature-slot order: first the parameters without a default, taken from the -//! positional arguments, then the parameters with one, taken from the named arguments or the declared default when -//! the call site omitted them, then the variadic tail. -static auto CV2TableCollectArguments(const CV2TableFunctionInfo &info, TableFunctionBindInput &input) -> vector { - vector arguments; - const auto positional_count = MinValue(info.positional_count, input.inputs.size()); - - for (idx_t i = 0; i < positional_count; i++) { - arguments.push_back(input.inputs[i]); - } - for (idx_t i = info.positional_count; i < info.parameter_names.size(); i++) { - const auto &name = info.parameter_names[i]; - auto provided = input.named_parameters.find(name); - if (provided != input.named_parameters.end()) { - arguments.push_back(provided->second); - } else { - arguments.push_back(info.named_parameter_defaults.at(name)); - } - } - for (idx_t i = positional_count; i < input.inputs.size(); i++) { - arguments.push_back(input.inputs[i]); - } - return arguments; -} - static auto CV2TableBind(ClientContext &context, TableFunctionBindInput &input, vector &return_types, vector &names) -> unique_ptr { const auto &info = input.info->Cast(); - auto arguments = CV2TableCollectArguments(info, input); - CV2TableBindInfo args = {}; args.in_user_data = info.user_data ? info.user_data->GetData() : nullptr; - args.in_args = &arguments; + // the binder places every argument in its signature slot, defaults included, so the call reads them as-is + args.in_args = &input.inputs; CV2ErrorInfo err = {}; auto err_ptr = Convert(&err); @@ -359,9 +340,12 @@ static auto CV2TableBind(ClientContext &context, TableFunctionBindInput &input, if (args.out_column_types.empty()) { throw InvalidInputException("The bind callback of table function \"%s\" did not declare any result columns.", - input.table_function.name); + input.table_function.GetName()); } + // The binder hands each call site its own copy of the function, so this does not leak into other calls. + input.table_function.order_preservation_type = args.out_order_preservation; + result->column_types = args.out_column_types; return_types = std::move(args.out_column_types); names = std::move(args.out_column_names); @@ -658,20 +642,9 @@ class CV2TableFunction { signature.Verify(); - // Route the signature onto the two ways SQL passes arguments to a table function: a parameter without a - // default value is a required positional argument, a parameter with one is an optional named argument. - vector positional; - for (idx_t i = 0; i < signature.GetParameterCount(); i++) { - const auto ¶m = signature.GetParameter(i); - if (!param.IsVariadic() && !param.HasDefaultValue()) { - positional.push_back(param.GetType()); - } - } - - TableFunction function(name, positional, CV2TableExec, CV2TableBind, CV2TableInitGlobal, CV2TableInitLocal); - if (signature.HasVarArgs()) { - function.SetVarArgs(signature.GetVarArgs()); - } + // A table function holds a signature of its own, so the declared one is handed over as-is + TableFunction function(name, {}, CV2TableExec, CV2TableBind, CV2TableInitGlobal, CV2TableInitLocal); + function.GetSignature() = signature; // Always wired: it serves the estimate a bind callback may set, which is not known at registration. It // reports no estimate when the bind callback sets none. @@ -691,20 +664,7 @@ class CV2TableFunction { function.projection_pushdown = info.projection_pushdown; info.name = name; - auto function_info = make_shared_ptr(std::move(info)); - for (idx_t i = 0; i < signature.GetParameterCount(); i++) { - const auto ¶m = signature.GetParameter(i); - if (param.IsVariadic()) { - continue; - } - if (param.HasDefaultValue()) { - function.named_parameters[param.GetName()] = param.GetType(); - function_info->named_parameter_defaults[param.GetName()] = *param.GetDefaultValue(); - } - function_info->parameter_names.push_back(param.GetName()); - } - function_info->positional_count = positional.size(); - function.function_info = std::move(function_info); + function.function_info = make_shared_ptr(std::move(info)); // Call the implementation to register RegisterToCatalog(std::move(function)); @@ -793,12 +753,11 @@ DUCKDB_V2_ERROR duckdb_v2_table_function_create_with_extension(duckdb_v2_extensi }); } -DUCKDB_V2_ERROR duckdb_v2_table_function_set_name(duckdb_v2_table_function_handle function, duckdb_v2_str *name, +DUCKDB_V2_ERROR duckdb_v2_table_function_set_name(duckdb_v2_table_function_handle function, const duckdb_v2_str *name, duckdb_v2_error_info_handle *err) { DUCKDB_CHECK_ARG(function); DUCKDB_CHECK_ARG(name); - DUCKDB_CHECK_ARG(*name); - return WithErrorHandler(err, [&]() { Convert(function)->name = duckdb::Identifier(ConvertIdentifierName(*name)); }); + return WithErrorHandler(err, [&]() { Convert(function)->name = duckdb::Identifier(ConvertIdentifierName(name)); }); } DUCKDB_V2_ERROR duckdb_v2_table_function_get_signature(duckdb_v2_table_function_handle function, @@ -938,7 +897,7 @@ DUCKDB_V2_ERROR duckdb_v2_table_function_bind_get_arg_value(duckdb_v2_table_func } DUCKDB_V2_ERROR duckdb_v2_table_function_bind_add_result_column(duckdb_v2_table_function_bind_info_handle info, - duckdb_v2_identifier_t name, + const duckdb_v2_identifier_t *name, duckdb_v2_logical_type_handle type, duckdb_v2_error_info_handle *err) { DUCKDB_CHECK_ARG(info); @@ -968,6 +927,13 @@ DUCKDB_V2_ERROR duckdb_v2_table_function_bind_set_cardinality(duckdb_v2_table_fu }); } +DUCKDB_V2_ERROR duckdb_v2_table_function_bind_set_order_preservation(duckdb_v2_table_function_bind_info_handle info, + DUCKDB_V2_ORDER_PRESERVATION order, + duckdb_v2_error_info_handle *err) { + DUCKDB_CHECK_ARG(info); + return WithErrorHandler(err, [&]() { Convert(info)->out_order_preservation = CV2ConvertOrderPreservation(order); }); +} + DUCKDB_V2_ERROR duckdb_v2_table_function_init_global_get_user_data(duckdb_v2_table_function_init_global_info_handle info, void **data, duckdb_v2_error_info_handle *err) { diff --git a/src/duckdb/src/main/capi/v2/capi_v2_identifier.cpp b/src/duckdb/src/main/capi/v2/capi_v2_identifier.cpp index e94b11fa0..9af919b2b 100644 --- a/src/duckdb/src/main/capi/v2/capi_v2_identifier.cpp +++ b/src/duckdb/src/main/capi/v2/capi_v2_identifier.cpp @@ -3,8 +3,9 @@ using namespace duckdb::capiv2; -DUCKDB_V2_ERROR duckdb_v2_identifier_render_quoted(duckdb_v2_identifier_t name, char *out_text, idx_t out_capacity, - idx_t *out_length, duckdb_v2_error_info_handle *err) { +DUCKDB_V2_ERROR duckdb_v2_identifier_render_quoted(const duckdb_v2_identifier_t *name, char *out_text, + idx_t out_capacity, idx_t *out_length, + duckdb_v2_error_info_handle *err) { DUCKDB_CHECK_ARG(name); DUCKDB_CHECK_ARG(out_length); return WithErrorHandler(err, [&]() { diff --git a/src/duckdb/src/main/capi/v2/capi_v2_instance.cpp b/src/duckdb/src/main/capi/v2/capi_v2_instance.cpp index 26636371c..6738d46c7 100644 --- a/src/duckdb/src/main/capi/v2/capi_v2_instance.cpp +++ b/src/duckdb/src/main/capi/v2/capi_v2_instance.cpp @@ -225,18 +225,18 @@ DUCKDB_V2_ERROR duckdb_v2_instance_destroy(duckdb_v2_instance_handle *instance) }); } -DUCKDB_V2_ERROR duckdb_v2_instance_attach(duckdb_v2_instance_handle instance, duckdb_v2_str path, - duckdb_v2_identifier_t *name, duckdb_v2_attach_options_handle options, +DUCKDB_V2_ERROR duckdb_v2_instance_attach(duckdb_v2_instance_handle instance, const duckdb_v2_str *path, + const duckdb_v2_identifier_t *name, duckdb_v2_attach_options_handle options, bool make_default, duckdb_v2_error_info_handle *err) { DUCKDB_CHECK_ARG(instance); DUCKDB_CHECK_ARG(path); if (name) { - DUCKDB_CHECK_ARG(*name); + DUCKDB_CHECK_ARG(name); } return WithErrorHandler(err, [&]() { auto &wrapper = *Convert(instance); duckdb::lock_guard guard(wrapper.lock); - duckdb::Identifier attach_name = name ? duckdb::Identifier(ConvertIdentifierName(*name)) : duckdb::Identifier(); + duckdb::Identifier attach_name = name ? duckdb::Identifier(ConvertIdentifierName(name)) : duckdb::Identifier(); wrapper.Attach(duckdb::string(Convert(path)), attach_name, Convert(options), make_default); }); } @@ -253,8 +253,8 @@ DUCKDB_V2_ERROR duckdb_v2_attach_options_create(duckdb_v2_instance_handle instan }); } -DUCKDB_V2_ERROR duckdb_v2_attach_options_set(duckdb_v2_attach_options_handle options, duckdb_v2_identifier_t key, - duckdb_v2_str setting, duckdb_v2_error_info_handle *err) { +DUCKDB_V2_ERROR duckdb_v2_attach_options_set(duckdb_v2_attach_options_handle options, const duckdb_v2_identifier_t *key, + const duckdb_v2_str *setting, duckdb_v2_error_info_handle *err) { DUCKDB_CHECK_ARG(options); DUCKDB_CHECK_ARG(key); DUCKDB_CHECK_ARG(setting); @@ -277,7 +277,7 @@ DUCKDB_V2_ERROR duckdb_v2_attach_options_destroy(duckdb_v2_attach_options_handle }); } -DUCKDB_V2_ERROR duckdb_v2_instance_detach(duckdb_v2_instance_handle instance, duckdb_v2_str path, +DUCKDB_V2_ERROR duckdb_v2_instance_detach(duckdb_v2_instance_handle instance, const duckdb_v2_str *path, duckdb_v2_error_info_handle *err) { DUCKDB_CHECK_ARG(instance); DUCKDB_CHECK_ARG(path); @@ -288,7 +288,7 @@ DUCKDB_V2_ERROR duckdb_v2_instance_detach(duckdb_v2_instance_handle instance, du }); } -DUCKDB_V2_ERROR duckdb_v2_instance_set_default(duckdb_v2_instance_handle instance, duckdb_v2_str path, +DUCKDB_V2_ERROR duckdb_v2_instance_set_default(duckdb_v2_instance_handle instance, const duckdb_v2_str *path, duckdb_v2_error_info_handle *err) { DUCKDB_CHECK_ARG(instance); DUCKDB_CHECK_ARG(path); @@ -299,8 +299,8 @@ DUCKDB_V2_ERROR duckdb_v2_instance_set_default(duckdb_v2_instance_handle instanc }); } -DUCKDB_V2_ERROR duckdb_v2_instance_set_option(duckdb_v2_instance_handle instance, duckdb_v2_identifier_t name, - duckdb_v2_str setting, duckdb_v2_error_info_handle *err) { +DUCKDB_V2_ERROR duckdb_v2_instance_set_option(duckdb_v2_instance_handle instance, const duckdb_v2_identifier_t *name, + const duckdb_v2_str *setting, duckdb_v2_error_info_handle *err) { DUCKDB_CHECK_ARG(instance); DUCKDB_CHECK_ARG(name); DUCKDB_CHECK_ARG(setting); @@ -311,7 +311,8 @@ DUCKDB_V2_ERROR duckdb_v2_instance_set_option(duckdb_v2_instance_handle instance }); } -DUCKDB_V2_ERROR duckdb_v2_instance_get_option_by_name(duckdb_v2_instance_handle instance, duckdb_v2_identifier_t name, +DUCKDB_V2_ERROR duckdb_v2_instance_get_option_by_name(duckdb_v2_instance_handle instance, + const duckdb_v2_identifier_t *name, duckdb_v2_option_handle *out_option, duckdb_v2_error_info_handle *err) { DUCKDB_CHECK_ARG(instance); diff --git a/src/duckdb/src/main/capi/v2/capi_v2_logging.cpp b/src/duckdb/src/main/capi/v2/capi_v2_logging.cpp index 56a4ec522..723116b8d 100644 --- a/src/duckdb/src/main/capi/v2/capi_v2_logging.cpp +++ b/src/duckdb/src/main/capi/v2/capi_v2_logging.cpp @@ -34,8 +34,9 @@ static LogLevel ConvertLogLevel(DUCKDB_V2_LOG_LEVEL level) { using namespace duckdb::capiv2; -DUCKDB_V2_ERROR duckdb_v2_context_log(duckdb_v2_context_handle ctx, DUCKDB_V2_LOG_LEVEL level, duckdb_v2_str log_type, - duckdb_v2_str message, duckdb_v2_error_info_handle *err) { +DUCKDB_V2_ERROR duckdb_v2_context_log(duckdb_v2_context_handle ctx, DUCKDB_V2_LOG_LEVEL level, + const duckdb_v2_str *log_type, const duckdb_v2_str *message, + duckdb_v2_error_info_handle *err) { DUCKDB_CHECK_ARG(ctx); return WithErrorHandler(err, [&]() { const auto log_level = ConvertLogLevel(level); diff --git a/src/duckdb/src/main/capi/v2/capi_v2_logical_type.cpp b/src/duckdb/src/main/capi/v2/capi_v2_logical_type.cpp index 8d211f095..cf2cf903d 100644 --- a/src/duckdb/src/main/capi/v2/capi_v2_logical_type.cpp +++ b/src/duckdb/src/main/capi/v2/capi_v2_logical_type.cpp @@ -269,7 +269,7 @@ DUCKDB_V2_ERROR duckdb_v2_connection_create_type_from_id(duckdb_v2_connection_ha }); } -static void CreateLogicalTypeFromTextV2(duckdb::ClientContext &context, duckdb_v2_str text, +static void CreateLogicalTypeFromTextV2(duckdb::ClientContext &context, const duckdb_v2_str *text, duckdb_v2_logical_type_handle *out_type) { *out_type = nullptr; // Parse and bind errors propagate. @@ -278,7 +278,7 @@ static void CreateLogicalTypeFromTextV2(duckdb::ClientContext &context, duckdb_v *out_type = Convert(new duckdb::LogicalType(std::move(parsed))); } -DUCKDB_V2_ERROR duckdb_v2_context_create_type_from_text(duckdb_v2_context_handle ctx, duckdb_v2_str text, +DUCKDB_V2_ERROR duckdb_v2_context_create_type_from_text(duckdb_v2_context_handle ctx, const duckdb_v2_str *text, duckdb_v2_logical_type_handle *out_type, duckdb_v2_error_info_handle *err) { DUCKDB_CHECK_ARG(ctx); @@ -290,7 +290,7 @@ DUCKDB_V2_ERROR duckdb_v2_context_create_type_from_text(duckdb_v2_context_handle }); } -DUCKDB_V2_ERROR duckdb_v2_connection_create_type_from_text(duckdb_v2_connection_handle conn, duckdb_v2_str text, +DUCKDB_V2_ERROR duckdb_v2_connection_create_type_from_text(duckdb_v2_connection_handle conn, const duckdb_v2_str *text, duckdb_v2_logical_type_handle *out_type, duckdb_v2_error_info_handle *err) { DUCKDB_CHECK_ARG(conn); @@ -456,20 +456,21 @@ namespace { // The alias keeps the base type's internal representation; only the name and // its catalog identity change. -duckdb::LogicalType AliasOf(duckdb_v2_logical_type_handle base_type, duckdb_v2_identifier_t alias_name, +duckdb::LogicalType AliasOf(duckdb_v2_logical_type_handle base_type, const duckdb_v2_identifier_t *alias_name, duckdb_v2_logical_type_handle *out_type) { *out_type = nullptr; - if (alias_name.len == 0) { + auto name = ConvertIdentifierName(alias_name); + if (name.empty()) { throw duckdb::InvalidInputException("alias name cannot be empty"); } - return Convert(base_type)->WithAlias(std::string(ConvertIdentifierName(alias_name))); + return Convert(base_type)->WithAlias(std::string(name)); } } // namespace DUCKDB_V2_ERROR duckdb_v2_context_create_type_with_alias(duckdb_v2_context_handle ctx, duckdb_v2_logical_type_handle base_type, - duckdb_v2_identifier_t alias_name, + const duckdb_v2_identifier_t *alias_name, duckdb_v2_logical_type_handle *out_type, duckdb_v2_error_info_handle *err) { DUCKDB_CHECK_ARG(ctx); @@ -482,7 +483,7 @@ DUCKDB_V2_ERROR duckdb_v2_context_create_type_with_alias(duckdb_v2_context_handl DUCKDB_V2_ERROR duckdb_v2_connection_create_type_with_alias(duckdb_v2_connection_handle conn, duckdb_v2_logical_type_handle base_type, - duckdb_v2_identifier_t alias_name, + const duckdb_v2_identifier_t *alias_name, duckdb_v2_logical_type_handle *out_type, duckdb_v2_error_info_handle *err) { DUCKDB_CHECK_ARG(conn); diff --git a/src/duckdb/src/main/capi/v2/capi_v2_option.cpp b/src/duckdb/src/main/capi/v2/capi_v2_option.cpp index 4fa60bda7..1e59460e0 100644 --- a/src/duckdb/src/main/capi/v2/capi_v2_option.cpp +++ b/src/duckdb/src/main/capi/v2/capi_v2_option.cpp @@ -75,7 +75,7 @@ DUCKDB_V2_ERROR duckdb_v2_option_get_alias(duckdb_v2_option_handle option, idx_t // Context option getters: the connection's cascade, read from inside DuckDB // --------------------------------------------------------------------------- -DUCKDB_V2_ERROR duckdb_v2_context_get_option_by_name(duckdb_v2_context_handle ctx, duckdb_v2_identifier_t name, +DUCKDB_V2_ERROR duckdb_v2_context_get_option_by_name(duckdb_v2_context_handle ctx, const duckdb_v2_identifier_t *name, duckdb_v2_option_handle *out_option, duckdb_v2_error_info_handle *err) { DUCKDB_CHECK_ARG(ctx); diff --git a/src/duckdb/src/main/capi/v2/capi_v2_qname.cpp b/src/duckdb/src/main/capi/v2/capi_v2_qname.cpp index 20e3a0945..7a7c5e234 100644 --- a/src/duckdb/src/main/capi/v2/capi_v2_qname.cpp +++ b/src/duckdb/src/main/capi/v2/capi_v2_qname.cpp @@ -26,7 +26,7 @@ static void CheckQNameParts(const QualifiedName &name, const char *function_name using namespace duckdb::capiv2; -DUCKDB_V2_ERROR duckdb_v2_qname_parse(duckdb_v2_str text, duckdb_v2_qname_handle *out_name, +DUCKDB_V2_ERROR duckdb_v2_qname_parse(const duckdb_v2_str *text, duckdb_v2_qname_handle *out_name, duckdb_v2_error_info_handle *err) { DUCKDB_CHECK_ARG(text); DUCKDB_CHECK_ARG(out_name); diff --git a/src/duckdb/src/main/capi/v2/capi_v2_replacement_scan.cpp b/src/duckdb/src/main/capi/v2/capi_v2_replacement_scan.cpp index 1bd502690..73fb194c7 100644 --- a/src/duckdb/src/main/capi/v2/capi_v2_replacement_scan.cpp +++ b/src/duckdb/src/main/capi/v2/capi_v2_replacement_scan.cpp @@ -292,7 +292,8 @@ DUCKDB_V2_ERROR duckdb_v2_replacement_scan_add_argument(duckdb_v2_replacement_sc } DUCKDB_V2_ERROR duckdb_v2_replacement_scan_add_named_argument(duckdb_v2_replacement_scan_info_handle info, - duckdb_v2_identifier_t name, duckdb_v2_value_handle value, + const duckdb_v2_identifier_t *name, + duckdb_v2_value_handle value, duckdb_v2_error_info_handle *err) { DUCKDB_CHECK_ARG(info); DUCKDB_CHECK_ARG(name); @@ -339,8 +340,8 @@ DUCKDB_V2_ERROR duckdb_v2_replacement_scan_set_collection(duckdb_v2_replacement_ }); } -DUCKDB_V2_ERROR duckdb_v2_replacement_scan_set_subquery(duckdb_v2_replacement_scan_info_handle info, duckdb_v2_str sql, - duckdb_v2_error_info_handle *err) { +DUCKDB_V2_ERROR duckdb_v2_replacement_scan_set_subquery(duckdb_v2_replacement_scan_info_handle info, + const duckdb_v2_str *sql, duckdb_v2_error_info_handle *err) { DUCKDB_CHECK_ARG(info); DUCKDB_CHECK_ARG(sql); return WithErrorHandler(err, [&]() { @@ -364,7 +365,8 @@ DUCKDB_V2_ERROR duckdb_v2_replacement_scan_set_subquery(duckdb_v2_replacement_sc } DUCKDB_V2_ERROR duckdb_v2_replacement_scan_set_alias(duckdb_v2_replacement_scan_info_handle info, - duckdb_v2_identifier_t alias, duckdb_v2_error_info_handle *err) { + const duckdb_v2_identifier_t *alias, + duckdb_v2_error_info_handle *err) { DUCKDB_CHECK_ARG(info); DUCKDB_CHECK_ARG(alias); return WithErrorHandler(err, diff --git a/src/duckdb/src/main/capi/v2/capi_v2_result.cpp b/src/duckdb/src/main/capi/v2/capi_v2_result.cpp index 658fb563e..9d28c7c83 100644 --- a/src/duckdb/src/main/capi/v2/capi_v2_result.cpp +++ b/src/duckdb/src/main/capi/v2/capi_v2_result.cpp @@ -480,13 +480,13 @@ DUCKDB_V2_ERROR duckdb_v2_result_drain(duckdb_v2_result_handle result, idx_t *ou } DUCKDB_V2_ERROR duckdb_v2_result_render_box(duckdb_v2_result_handle *result, idx_t max_rows, idx_t max_width, - idx_t max_col_width, duckdb_v2_str null_value, idx_t render_mode, + idx_t max_col_width, const duckdb_v2_str *null_value, idx_t render_mode, idx_t limit, duckdb_v2_text_sink_fn sink, void *user_data, duckdb_v2_error_info_handle *err) { DUCKDB_CHECK_ARG(result); DUCKDB_CHECK_ARG(*result); DUCKDB_CHECK_ARG(sink); - // Validate the by-value arguments before consuming the result, so an + // Validate the view arguments before consuming the result, so an // argument rejection leaves the caller's result intact (as the null-arg // rejections above do). DUCKDB_CHECK_ARG(null_value); @@ -532,8 +532,8 @@ DUCKDB_V2_ERROR duckdb_v2_result_render_box(duckdb_v2_result_handle *result, idx if (max_col_width != 0) { config.max_col_width = max_col_width; } - if (null_value.len) { - config.null_value = std::string(null_value.ptr, null_value.len); + if (null_value->len) { + config.null_value = std::string(null_value->ptr, null_value->len); } config.render_mode = render_mode == 1 ? duckdb::RenderMode::COLUMNS : duckdb::RenderMode::ROWS; // The caller's query-side LIMIT: when the materialized result fills it, the diff --git a/src/duckdb/src/main/capi/v2/capi_v2_tokenizer.cpp b/src/duckdb/src/main/capi/v2/capi_v2_tokenizer.cpp index c9a693714..9049b7b96 100644 --- a/src/duckdb/src/main/capi/v2/capi_v2_tokenizer.cpp +++ b/src/duckdb/src/main/capi/v2/capi_v2_tokenizer.cpp @@ -69,7 +69,7 @@ auto Convert(TokenIteratorWrapperV2 *ptr) -> duckdb_v2_token_iterator_handle { using namespace duckdb::capiv2; -DUCKDB_V2_ERROR duckdb_v2_tokenize_sql(duckdb_v2_connection_handle conn, duckdb_v2_str sql, +DUCKDB_V2_ERROR duckdb_v2_tokenize_sql(duckdb_v2_connection_handle conn, const duckdb_v2_str *sql, duckdb_v2_token_iterator_handle *out_iterator, duckdb_v2_error_info_handle *err) { DUCKDB_CHECK_ARG(out_iterator); diff --git a/src/duckdb/src/main/capi/v2/capi_v2_utf8.cpp b/src/duckdb/src/main/capi/v2/capi_v2_utf8.cpp index ceccf99b3..49bacb166 100644 --- a/src/duckdb/src/main/capi/v2/capi_v2_utf8.cpp +++ b/src/duckdb/src/main/capi/v2/capi_v2_utf8.cpp @@ -16,7 +16,7 @@ auto ConvertIdentifierName(duckdb_v2_identifier_t name) -> std::string_view { using namespace duckdb::capiv2; -DUCKDB_V2_ERROR duckdb_v2_validate_utf8(duckdb_v2_str text, duckdb_v2_error_info_handle *err) { +DUCKDB_V2_ERROR duckdb_v2_validate_utf8(const duckdb_v2_str *text, duckdb_v2_error_info_handle *err) { return WithErrorHandler(err, [&]() { auto bytes = Convert(text); if (!duckdb::Utf8Proc::IsValid(bytes.data(), bytes.size())) { diff --git a/src/duckdb/src/main/capi/v2/capi_v2_value.cpp b/src/duckdb/src/main/capi/v2/capi_v2_value.cpp index 2d219f380..1050cdf5b 100644 --- a/src/duckdb/src/main/capi/v2/capi_v2_value.cpp +++ b/src/duckdb/src/main/capi/v2/capi_v2_value.cpp @@ -105,7 +105,7 @@ const LogicalType &RequireValueType(duckdb_v2_logical_type_handle type) { // constructor covers only the widest one, so the narrower tiers go through the // int64 form. Width and scale are gated here: an out-of-range pair would build // a broken type rather than a bad value. -Value BuildDecimal(duckdb_v2_hugeint_t in_value, uint8_t width, uint8_t scale) { +Value BuildDecimal(const duckdb_v2_hugeint_t *in_value, uint8_t width, uint8_t scale) { if (width < 1 || width > Decimal::MAX_WIDTH_DECIMAL) { throw InvalidInputException(": DECIMAL width must be between 1 and " + std::to_string(Decimal::MAX_WIDTH_DECIMAL)); @@ -127,7 +127,7 @@ Value BuildDecimal(duckdb_v2_hugeint_t in_value, uint8_t width, uint8_t scale) { // BIT carries a mandatory padding-header byte, BIGNUM a header plus at least // one magnitude byte; anything shorter is not addressable storage. -Value BuildBit(duckdb_v2_str in_value) { +Value BuildBit(const duckdb_v2_str *in_value) { auto bytes = Convert(in_value); if (bytes.empty()) { throw InvalidInputException("the BIT wire form carries a mandatory padding header byte"); @@ -135,7 +135,7 @@ Value BuildBit(duckdb_v2_str in_value) { return Value::BIT(const_data_ptr_cast(bytes.data()), bytes.size()); } -Value BuildBignum(duckdb_v2_str in_value) { +Value BuildBignum(const duckdb_v2_str *in_value) { auto bytes = Convert(in_value); if (bytes.size() <= Bignum::BIGNUM_HEADER_SIZE) { throw InvalidInputException("the BIGNUM storage form requires more than " + @@ -559,7 +559,8 @@ DUCKDB_V2_ERROR duckdb_v2_value_create_bigint_with_connection(duckdb_v2_connecti return WithErrorHandler(err, [&]() { *out_value = Emit(duckdb::Value::BIGINT(in_value)); }); } -DUCKDB_V2_ERROR duckdb_v2_value_create_hugeint_with_context(duckdb_v2_context_handle ctx, duckdb_v2_hugeint_t in_value, +DUCKDB_V2_ERROR duckdb_v2_value_create_hugeint_with_context(duckdb_v2_context_handle ctx, + const duckdb_v2_hugeint_t *in_value, duckdb_v2_value_handle *out_value, duckdb_v2_error_info_handle *err) { DUCKDB_CHECK_ARG(ctx); @@ -569,7 +570,7 @@ DUCKDB_V2_ERROR duckdb_v2_value_create_hugeint_with_context(duckdb_v2_context_ha } DUCKDB_V2_ERROR duckdb_v2_value_create_hugeint_with_connection(duckdb_v2_connection_handle conn, - duckdb_v2_hugeint_t in_value, + const duckdb_v2_hugeint_t *in_value, duckdb_v2_value_handle *out_value, duckdb_v2_error_info_handle *err) { DUCKDB_CHECK_ARG(conn); @@ -651,7 +652,7 @@ DUCKDB_V2_ERROR duckdb_v2_value_create_ubigint_with_connection(duckdb_v2_connect } DUCKDB_V2_ERROR duckdb_v2_value_create_uhugeint_with_context(duckdb_v2_context_handle ctx, - duckdb_v2_uhugeint_t in_value, + const duckdb_v2_uhugeint_t *in_value, duckdb_v2_value_handle *out_value, duckdb_v2_error_info_handle *err) { DUCKDB_CHECK_ARG(ctx); @@ -661,7 +662,7 @@ DUCKDB_V2_ERROR duckdb_v2_value_create_uhugeint_with_context(duckdb_v2_context_h } DUCKDB_V2_ERROR duckdb_v2_value_create_uhugeint_with_connection(duckdb_v2_connection_handle conn, - duckdb_v2_uhugeint_t in_value, + const duckdb_v2_uhugeint_t *in_value, duckdb_v2_value_handle *out_value, duckdb_v2_error_info_handle *err) { DUCKDB_CHECK_ARG(conn); @@ -706,7 +707,7 @@ DUCKDB_V2_ERROR duckdb_v2_value_create_double_with_connection(duckdb_v2_connecti return WithErrorHandler(err, [&]() { *out_value = Emit(duckdb::Value::DOUBLE(in_value)); }); } -DUCKDB_V2_ERROR duckdb_v2_value_create_varchar_with_context(duckdb_v2_context_handle ctx, duckdb_v2_str in_value, +DUCKDB_V2_ERROR duckdb_v2_value_create_varchar_with_context(duckdb_v2_context_handle ctx, const duckdb_v2_str *in_value, duckdb_v2_value_handle *out_value, duckdb_v2_error_info_handle *err) { DUCKDB_CHECK_ARG(ctx); @@ -715,7 +716,8 @@ DUCKDB_V2_ERROR duckdb_v2_value_create_varchar_with_context(duckdb_v2_context_ha return WithErrorHandler(err, [&]() { *out_value = Emit(duckdb::Value(Convert(in_value))); }); } -DUCKDB_V2_ERROR duckdb_v2_value_create_varchar_with_connection(duckdb_v2_connection_handle conn, duckdb_v2_str in_value, +DUCKDB_V2_ERROR duckdb_v2_value_create_varchar_with_connection(duckdb_v2_connection_handle conn, + const duckdb_v2_str *in_value, duckdb_v2_value_handle *out_value, duckdb_v2_error_info_handle *err) { DUCKDB_CHECK_ARG(conn); @@ -724,7 +726,7 @@ DUCKDB_V2_ERROR duckdb_v2_value_create_varchar_with_connection(duckdb_v2_connect return WithErrorHandler(err, [&]() { *out_value = Emit(duckdb::Value(Convert(in_value))); }); } -DUCKDB_V2_ERROR duckdb_v2_value_create_blob_with_context(duckdb_v2_context_handle ctx, duckdb_v2_str in_value, +DUCKDB_V2_ERROR duckdb_v2_value_create_blob_with_context(duckdb_v2_context_handle ctx, const duckdb_v2_str *in_value, duckdb_v2_value_handle *out_value, duckdb_v2_error_info_handle *err) { DUCKDB_CHECK_ARG(ctx); @@ -733,7 +735,8 @@ DUCKDB_V2_ERROR duckdb_v2_value_create_blob_with_context(duckdb_v2_context_handl return WithErrorHandler(err, [&]() { *out_value = Emit(duckdb::Value::BLOB_RAW(std::string(Convert(in_value)))); }); } -DUCKDB_V2_ERROR duckdb_v2_value_create_blob_with_connection(duckdb_v2_connection_handle conn, duckdb_v2_str in_value, +DUCKDB_V2_ERROR duckdb_v2_value_create_blob_with_connection(duckdb_v2_connection_handle conn, + const duckdb_v2_str *in_value, duckdb_v2_value_handle *out_value, duckdb_v2_error_info_handle *err) { DUCKDB_CHECK_ARG(conn); @@ -980,7 +983,7 @@ DUCKDB_V2_ERROR duckdb_v2_value_create_timestamp_tz_ns_with_connection(duckdb_v2 } DUCKDB_V2_ERROR duckdb_v2_value_create_interval_with_context(duckdb_v2_context_handle ctx, - duckdb_v2_interval_t in_value, + const duckdb_v2_interval_t *in_value, duckdb_v2_value_handle *out_value, duckdb_v2_error_info_handle *err) { DUCKDB_CHECK_ARG(ctx); @@ -990,7 +993,7 @@ DUCKDB_V2_ERROR duckdb_v2_value_create_interval_with_context(duckdb_v2_context_h } DUCKDB_V2_ERROR duckdb_v2_value_create_interval_with_connection(duckdb_v2_connection_handle conn, - duckdb_v2_interval_t in_value, + const duckdb_v2_interval_t *in_value, duckdb_v2_value_handle *out_value, duckdb_v2_error_info_handle *err) { DUCKDB_CHECK_ARG(conn); @@ -1006,9 +1009,9 @@ DUCKDB_V2_ERROR duckdb_v2_value_create_interval_with_connection(duckdb_v2_connec // plus its width and scale, an internal 128-bit form, or opaque storage bytes. // --------------------------------------------------------------------------- -DUCKDB_V2_ERROR duckdb_v2_value_create_decimal_with_context(duckdb_v2_context_handle ctx, duckdb_v2_hugeint_t in_value, - uint8_t width, uint8_t scale, - duckdb_v2_value_handle *out_value, +DUCKDB_V2_ERROR duckdb_v2_value_create_decimal_with_context(duckdb_v2_context_handle ctx, + const duckdb_v2_hugeint_t *in_value, uint8_t width, + uint8_t scale, duckdb_v2_value_handle *out_value, duckdb_v2_error_info_handle *err) { DUCKDB_CHECK_ARG(ctx); DUCKDB_CHECK_ARG(out_value); @@ -1016,7 +1019,8 @@ DUCKDB_V2_ERROR duckdb_v2_value_create_decimal_with_context(duckdb_v2_context_ha return WithErrorHandler(err, [&]() { *out_value = Emit(BuildDecimal(in_value, width, scale)); }); } -DUCKDB_V2_ERROR duckdb_v2_value_create_uuid_with_context(duckdb_v2_context_handle ctx, duckdb_v2_hugeint_t in_value, +DUCKDB_V2_ERROR duckdb_v2_value_create_uuid_with_context(duckdb_v2_context_handle ctx, + const duckdb_v2_hugeint_t *in_value, duckdb_v2_value_handle *out_value, duckdb_v2_error_info_handle *err) { DUCKDB_CHECK_ARG(ctx); @@ -1025,7 +1029,7 @@ DUCKDB_V2_ERROR duckdb_v2_value_create_uuid_with_context(duckdb_v2_context_handl return WithErrorHandler(err, [&]() { *out_value = Emit(duckdb::Value::UUID(Convert(in_value))); }); } -DUCKDB_V2_ERROR duckdb_v2_value_create_bit_with_context(duckdb_v2_context_handle ctx, duckdb_v2_str in_value, +DUCKDB_V2_ERROR duckdb_v2_value_create_bit_with_context(duckdb_v2_context_handle ctx, const duckdb_v2_str *in_value, duckdb_v2_value_handle *out_value, duckdb_v2_error_info_handle *err) { DUCKDB_CHECK_ARG(ctx); @@ -1034,7 +1038,7 @@ DUCKDB_V2_ERROR duckdb_v2_value_create_bit_with_context(duckdb_v2_context_handle return WithErrorHandler(err, [&]() { *out_value = Emit(BuildBit(in_value)); }); } -DUCKDB_V2_ERROR duckdb_v2_value_create_bignum_with_context(duckdb_v2_context_handle ctx, duckdb_v2_str in_value, +DUCKDB_V2_ERROR duckdb_v2_value_create_bignum_with_context(duckdb_v2_context_handle ctx, const duckdb_v2_str *in_value, duckdb_v2_value_handle *out_value, duckdb_v2_error_info_handle *err) { DUCKDB_CHECK_ARG(ctx); @@ -1044,7 +1048,7 @@ DUCKDB_V2_ERROR duckdb_v2_value_create_bignum_with_context(duckdb_v2_context_han } DUCKDB_V2_ERROR duckdb_v2_value_create_decimal_with_connection(duckdb_v2_connection_handle conn, - duckdb_v2_hugeint_t in_value, uint8_t width, + const duckdb_v2_hugeint_t *in_value, uint8_t width, uint8_t scale, duckdb_v2_value_handle *out_value, duckdb_v2_error_info_handle *err) { DUCKDB_CHECK_ARG(conn); @@ -1054,7 +1058,7 @@ DUCKDB_V2_ERROR duckdb_v2_value_create_decimal_with_connection(duckdb_v2_connect } DUCKDB_V2_ERROR duckdb_v2_value_create_uuid_with_connection(duckdb_v2_connection_handle conn, - duckdb_v2_hugeint_t in_value, + const duckdb_v2_hugeint_t *in_value, duckdb_v2_value_handle *out_value, duckdb_v2_error_info_handle *err) { DUCKDB_CHECK_ARG(conn); @@ -1063,7 +1067,8 @@ DUCKDB_V2_ERROR duckdb_v2_value_create_uuid_with_connection(duckdb_v2_connection return WithErrorHandler(err, [&]() { *out_value = Emit(duckdb::Value::UUID(Convert(in_value))); }); } -DUCKDB_V2_ERROR duckdb_v2_value_create_bit_with_connection(duckdb_v2_connection_handle conn, duckdb_v2_str in_value, +DUCKDB_V2_ERROR duckdb_v2_value_create_bit_with_connection(duckdb_v2_connection_handle conn, + const duckdb_v2_str *in_value, duckdb_v2_value_handle *out_value, duckdb_v2_error_info_handle *err) { DUCKDB_CHECK_ARG(conn); @@ -1072,7 +1077,8 @@ DUCKDB_V2_ERROR duckdb_v2_value_create_bit_with_connection(duckdb_v2_connection_ return WithErrorHandler(err, [&]() { *out_value = Emit(BuildBit(in_value)); }); } -DUCKDB_V2_ERROR duckdb_v2_value_create_bignum_with_connection(duckdb_v2_connection_handle conn, duckdb_v2_str in_value, +DUCKDB_V2_ERROR duckdb_v2_value_create_bignum_with_connection(duckdb_v2_connection_handle conn, + const duckdb_v2_str *in_value, duckdb_v2_value_handle *out_value, duckdb_v2_error_info_handle *err) { DUCKDB_CHECK_ARG(conn); diff --git a/src/duckdb/src/main/relation/read_csv_relation.cpp b/src/duckdb/src/main/relation/read_csv_relation.cpp index 90a94de5b..11d6c649d 100644 --- a/src/duckdb/src/main/relation/read_csv_relation.cpp +++ b/src/duckdb/src/main/relation/read_csv_relation.cpp @@ -42,7 +42,11 @@ CSVReaderOptions ReadCSVRelationBind(const shared_ptr &context, c CSVReaderOptions csv_options; csv_options.file_path = file_name.path; vector empty; - csv_options.FromNamedParameters(options, *context, file_options); + named_argument_map_t named_arguments; + for (auto &option : options) { + named_arguments.insert(option.first, option.second); + } + csv_options.FromNamedParameters(named_arguments, *context, file_options); // Run the auto-detect, populating the options with the detected settings SimpleMultiFileList multi_file_list(files); diff --git a/src/duckdb/src/optimizer/common_subplan_optimizer.cpp b/src/duckdb/src/optimizer/common_subplan_optimizer.cpp index ff0557cfe..cc8a097d8 100644 --- a/src/duckdb/src/optimizer/common_subplan_optimizer.cpp +++ b/src/duckdb/src/optimizer/common_subplan_optimizer.cpp @@ -617,12 +617,12 @@ class PlanSignature { return true; case LogicalOperatorType::LOGICAL_GET: { auto &get = op.Cast(); - if (get.bind_data && !get.function.HasSerializationCallbacks() && get.parameters.empty() && - get.named_parameters.empty()) { + if (get.bind_data && !get.function.HasSerializationCallbacks() && get.parameters.empty()) { // Without serialization callbacks, the serialized form carries only the call parameters - // (see LogicalGet::Serialize). A parameter-less scan - e.g., one created through an - // attached catalog - keeps its identity solely in the bind data, so equal serialized - // bytes cannot prove that two scans read the same table. + // (see LogicalGet::Serialize). A scan without positional parameters - e.g., one created through + // an attached catalog - keeps its identity solely in the bind data, and its options do not + // identify what it reads, so equal serialized bytes cannot prove that two scans read the same + // table. return false; } return true; diff --git a/src/duckdb/src/optimizer/unnest_rewriter.cpp b/src/duckdb/src/optimizer/unnest_rewriter.cpp index 1414f571f..bd31d874d 100644 --- a/src/duckdb/src/optimizer/unnest_rewriter.cpp +++ b/src/duckdb/src/optimizer/unnest_rewriter.cpp @@ -168,7 +168,7 @@ void UnnestRewriter::FindCandidates(unique_ptr &root, unique_pt curr_op = &delim_join.children[other_idx]; if (curr_op->get()->type == LogicalOperatorType::LOGICAL_GET) { auto &get = curr_op->get()->Cast(); - if (!ExpressionBinder::IsUnnestFunction(get.function.name)) { + if (!ExpressionBinder::IsUnnestFunction(get.function.GetName())) { return; } // pattern2: delim_get -> projection -> table_in_out(unnest) @@ -242,7 +242,7 @@ static bool ConvertCTETableInOutUnnest(unique_ptr &root, unique return false; } auto &get = op->Cast(); - if (!ExpressionBinder::IsUnnestFunction(get.function.name) || get.ordinality_idx.IsValid()) { + if (!ExpressionBinder::IsUnnestFunction(get.function.GetName()) || get.ordinality_idx.IsValid()) { return false; } if (op->children.size() != 1 || op->children[0]->type != LogicalOperatorType::LOGICAL_PROJECTION) { diff --git a/src/duckdb/src/parallel/progress_verifier.cpp b/src/duckdb/src/parallel/progress_verifier.cpp index cfb715ed0..4b0b02ee8 100644 --- a/src/duckdb/src/parallel/progress_verifier.cpp +++ b/src/duckdb/src/parallel/progress_verifier.cpp @@ -36,7 +36,7 @@ ProgressVerifier::ProgressVerifier(ClientContext &context, DebugProgressVerifica string ProgressVerifier::OperatorName(const PhysicalOperator &op) { if (op.type == PhysicalOperatorType::TABLE_SCAN) { // table functions implement progress individually - attribute to the function - return StringUtil::Upper(op.Cast().function.name.GetIdentifierName()); + return StringUtil::Upper(op.Cast().function.GetName().GetIdentifierName()); } return PhysicalOperatorToString(op.type); } diff --git a/src/duckdb/src/parser/parsed_data/create_pragma_function_info.cpp b/src/duckdb/src/parser/parsed_data/create_pragma_function_info.cpp index 5448e0fb3..569ee84ef 100644 --- a/src/duckdb/src/parser/parsed_data/create_pragma_function_info.cpp +++ b/src/duckdb/src/parser/parsed_data/create_pragma_function_info.cpp @@ -5,12 +5,16 @@ namespace duckdb { CreatePragmaFunctionInfo::CreatePragmaFunctionInfo(PragmaFunction function) : CreateFunctionInfo(CatalogType::PRAGMA_FUNCTION_ENTRY), functions(function.name) { SetFunctionName(function.name); + function.GetSignature().Verify(); functions.AddFunction(std::move(function)); internal = true; } CreatePragmaFunctionInfo::CreatePragmaFunctionInfo(PragmaFunctionSet functions_p) : CreateFunctionInfo(CatalogType::PRAGMA_FUNCTION_ENTRY), functions(std::move(functions_p)) { SetFunctionName(functions.name); + for (auto &func : functions.functions) { + func->GetSignature().Verify(); + } internal = true; } CreatePragmaFunctionInfo::CreatePragmaFunctionInfo(Identifier name, PragmaFunctionSet functions_p) diff --git a/src/duckdb/src/parser/parsed_data/create_table_function_info.cpp b/src/duckdb/src/parser/parsed_data/create_table_function_info.cpp index fd5b4bb3d..c05f8532b 100644 --- a/src/duckdb/src/parser/parsed_data/create_table_function_info.cpp +++ b/src/duckdb/src/parser/parsed_data/create_table_function_info.cpp @@ -6,12 +6,16 @@ namespace duckdb { CreateTableFunctionInfo::CreateTableFunctionInfo(TableFunction function) : CreateFunctionInfo(CatalogType::TABLE_FUNCTION_ENTRY), functions(function.name) { SetFunctionName(function.name); + function.GetSignature().Verify(); functions.AddFunction(std::move(function)); internal = true; } CreateTableFunctionInfo::CreateTableFunctionInfo(TableFunctionSet set) : CreateFunctionInfo(CatalogType::TABLE_FUNCTION_ENTRY), functions(std::move(set)) { SetFunctionName(functions.name); + for (auto &func : functions.functions) { + func->GetSignature().Verify(); + } functions.ApplyToFunctions([&](TableFunction &func) { func.name = functions.name; }); internal = true; } diff --git a/src/duckdb/src/parser/peg/compiled_grammar.cpp b/src/duckdb/src/parser/peg/compiled_grammar.cpp index 03f72e0ed..9bb6f9d86 100644 --- a/src/duckdb/src/parser/peg/compiled_grammar.cpp +++ b/src/duckdb/src/parser/peg/compiled_grammar.cpp @@ -153,7 +153,7 @@ shared_ptr CompiledGrammar::Create(const vector(rule.name, rule.transform_process)); + rules.emplace(rule.name, make_uniq(rule.name, rule.transform_process, rule.collapsible)); } MatcherAllocator allocator; diff --git a/src/duckdb/src/parser/peg/dialect_extension.cpp b/src/duckdb/src/parser/peg/dialect_extension.cpp index cfd4d65fd..6d866c3d4 100644 --- a/src/duckdb/src/parser/peg/dialect_extension.cpp +++ b/src/duckdb/src/parser/peg/dialect_extension.cpp @@ -40,7 +40,7 @@ shared_ptr DialectExtension::GetCompiledGrammar(const ClientCon compiled_rules_map_t rules; for (auto &entry : parsed_grammar.rules) { auto &rule = *entry.second; - rules.emplace(rule.name, make_uniq(rule.name, rule.transform_process)); + rules.emplace(rule.name, make_uniq(rule.name, rule.transform_process, rule.collapsible)); } auto terminal_rule_overrides = parsed_grammar.BuildTerminalRuleOverrides(*keyword_helper); CreateMatcherFactoryInput matcher_factory_input {allocator, parsed_grammar, rules, *keyword_helper, diff --git a/src/duckdb/src/parser/peg/grammar_change.cpp b/src/duckdb/src/parser/peg/grammar_change.cpp index 0c383ac08..9bc7bc94a 100644 --- a/src/duckdb/src/parser/peg/grammar_change.cpp +++ b/src/duckdb/src/parser/peg/grammar_change.cpp @@ -5,9 +5,9 @@ namespace duckdb { GrammarChange GrammarChange::Create(GrammarChangeType type, string rule_name, string definition, grammar_transform_process_function_t transform_process, grammar_cursor_function_t find_cursor, - terminal_rule_matcher_factory_t matcher_factory) { + terminal_rule_matcher_factory_t matcher_factory, bool collapsible) { return GrammarChange(type, std::move(rule_name), std::move(definition), std::move(transform_process), - std::move(find_cursor), std::move(matcher_factory)); + std::move(find_cursor), std::move(matcher_factory), collapsible); } GrammarChange GrammarChange::AddRule(const string &rule_definition, @@ -42,8 +42,10 @@ GrammarChange GrammarChange::ReplaceRule(const string &rule_definition, } GrammarChange GrammarChange::SetTransformProcess(const string &rule_name, - grammar_transform_process_function_t transform_process) { - return Create(GrammarChangeType::SET_TRANSFORM, rule_name, string(), std::move(transform_process)); + grammar_transform_process_function_t transform_process, + bool collapsible) { + return Create(GrammarChangeType::SET_TRANSFORM, rule_name, string(), std::move(transform_process), nullptr, nullptr, + collapsible); } GrammarChange GrammarChange::AddTerminalRuleOverride(const string &rule_name, @@ -73,7 +75,7 @@ void GrammarChange::Apply(ParsedGrammar &grammar) const { grammar.ReplaceRule(definition, transform_process); break; case GrammarChangeType::SET_TRANSFORM: - grammar.SetTransformProcess(rule_name, transform_process); + grammar.SetTransformProcess(rule_name, transform_process, collapsible); break; case GrammarChangeType::ADD_TERMINAL_RULE_OVERRIDE: grammar.AddTerminalRuleOverride(rule_name, matcher_factory); diff --git a/src/duckdb/src/parser/peg/matcher_factory.cpp b/src/duckdb/src/parser/peg/matcher_factory.cpp index 6f1185f88..a2ebc9ca0 100644 --- a/src/duckdb/src/parser/peg/matcher_factory.cpp +++ b/src/duckdb/src/parser/peg/matcher_factory.cpp @@ -166,6 +166,9 @@ Matcher &MatcherFactory::CreateMatcher(string_t rule_name, vector().suppress_suggestions = true; } diff --git a/src/duckdb/src/parser/peg/matcher_process.cpp b/src/duckdb/src/parser/peg/matcher_process.cpp index 078994cac..b8da72b6f 100644 --- a/src/duckdb/src/parser/peg/matcher_process.cpp +++ b/src/duckdb/src/parser/peg/matcher_process.cpp @@ -90,12 +90,48 @@ class ListMatchProcess : public MatchProcess { } state.token_iterator.SetPosition(list_state.token_iterator); DiscardSuggestions(); + if (matcher.IsCollapsible()) { + auto collapsible = FindCollapsibleResult(); + if (collapsible) { + collapsible->collapsed = true; + return MatchStep::Complete(MatcherResult::Success(collapsible)); + } + } auto list_name = matcher.HasName() ? matcher.GetName() : string(); return MatchStep::Complete( state.AllocateParseResult(std::move(results), std::move(list_name), start_offset)); } private: + //! The child that can stand in for this rule's own result, or nullptr when the rule has to build one + optional_ptr FindCollapsibleResult() const { + optional_ptr collapsible; + for (auto &child : results) { + auto &child_result = child.get(); + // an optional that matched nothing carries no value, so it does not stop the rule from collapsing + if (child_result.type == ParseResultType::OPTIONAL && + !child_result.Cast().HasResult()) { + continue; + } + + // a second child with a result means the rule combines them rather than forwarding one of them + if (collapsible) { + return nullptr; + } + + collapsible = child_result; + } + + // only results that carry a rule of their own are collapsible into this one, since the result is + // transformed by that rule + if (collapsible && !collapsible->GetRule()) { + return nullptr; + } + + // null when no child produced a result, so a rule that matched empty still gets a result of its own + return collapsible; + } + void DiscardSuggestions() { if (!matcher.suppress_suggestions) { return; diff --git a/src/duckdb/src/parser/peg/parsed_grammar.cpp b/src/duckdb/src/parser/peg/parsed_grammar.cpp index a09bfc8a8..3612eaa2e 100644 --- a/src/duckdb/src/parser/peg/parsed_grammar.cpp +++ b/src/duckdb/src/parser/peg/parsed_grammar.cpp @@ -217,10 +217,11 @@ void ParsedGrammar::ReplaceRule(const string &rule_definition, grammar_transform entry->second = make_uniq(std::move(rule)); } -void ParsedGrammar::SetTransformProcess(const string &rule_name, - grammar_transform_process_function_t transform_process) { +void ParsedGrammar::SetTransformProcess(const string &rule_name, grammar_transform_process_function_t transform_process, + bool collapsible) { auto &rule = GetMutableRule(rule_name); rule.transform_process = std::move(transform_process); + rule.collapsible = collapsible; } void ParsedGrammar::AddTerminalRuleOverride(const string &rule_name, terminal_rule_matcher_factory_t matcher_factory) { diff --git a/src/duckdb/src/parser/peg/transformer/peg_transformer_factory.cpp b/src/duckdb/src/parser/peg/transformer/peg_transformer_factory.cpp index f390b093f..4a29dce4d 100644 --- a/src/duckdb/src/parser/peg/transformer/peg_transformer_factory.cpp +++ b/src/duckdb/src/parser/peg/transformer/peg_transformer_factory.cpp @@ -110,13 +110,47 @@ unique_ptr PEGTransformerFactory::TransformTopLevelStatement(Token } PEGTransformerFactory::PEGTransformerFactory(ParsedGrammar &grammar_p) : grammar(grammar_p) { + case_insensitive_set_t collapsible_rules; + //===--------------------------------------------------------------------===// + // START GENERATED COLLAPSIBLE RULES + //===--------------------------------------------------------------------===// + collapsible_rules.insert("Expression"); + collapsible_rules.insert("ColumnDefaultExpr"); + collapsible_rules.insert("LambdaArrowExpression"); + collapsible_rules.insert("LogicalOrExpression"); + collapsible_rules.insert("ColDefOrExpr"); + collapsible_rules.insert("LogicalAndExpression"); + collapsible_rules.insert("ColDefAndExpr"); + collapsible_rules.insert("LogicalNotExpression"); + collapsible_rules.insert("IsExpression"); + collapsible_rules.insert("IsDistinctFromExpression"); + collapsible_rules.insert("ComparisonExpression"); + collapsible_rules.insert("BetweenInLikeExpression"); + collapsible_rules.insert("OtherOperatorExpression"); + collapsible_rules.insert("InfixOtherOperatorExpression"); + collapsible_rules.insert("BitwiseExpression"); + collapsible_rules.insert("AdditiveExpression"); + collapsible_rules.insert("MultiplicativeExpression"); + collapsible_rules.insert("ExponentiationExpression"); + collapsible_rules.insert("CollateExpression"); + collapsible_rules.insert("AtTimeZoneExpression"); + collapsible_rules.insert("PrefixExpression"); + collapsible_rules.insert("BaseExpression"); + collapsible_rules.insert("SelectSetOpChain"); + collapsible_rules.insert("IntersectChain"); + collapsible_rules.insert("TableRef"); + //===--------------------------------------------------------------------===// + // END GENERATED COLLAPSIBLE RULES + //===--------------------------------------------------------------------===// + for (auto &entry : GeneratedTransformFrameOps()) { auto process_info = entry.second; grammar.SetTransformProcess( entry.first, [process_info](PEGTransformer &transformer, ParseResult &parse_result) -> unique_ptr { return make_uniq(transformer, TransformInput {parse_result}, *process_info); - }); + }, + collapsible_rules.count(entry.first) > 0); } } diff --git a/src/duckdb/src/planner/binder/statement/bind_copy.cpp b/src/duckdb/src/planner/binder/statement/bind_copy.cpp index f3579c2f8..0b29c4a55 100644 --- a/src/duckdb/src/planner/binder/statement/bind_copy.cpp +++ b/src/duckdb/src/planner/binder/statement/bind_copy.cpp @@ -693,7 +693,7 @@ BoundStatement Binder::BindCopyFrom(CopyStatement &stmt, const CopyFunction &fun auto copy_from_function = function.copy_from_function; CopyFromFunctionBindInput input(*stmt.info, copy_from_function); auto function_data = function.copy_from_bind(context, input, expected_names, expected_types); - auto get = make_uniq(source_bindings[0].table_index, std::move(copy_from_function), + auto get = make_uniq(source_bindings[0].table_index, BoundTableFunction(copy_from_function), std::move(function_data), expected_types, expected_names); for (idx_t i = 0; i < expected_types.size(); i++) { get->AddColumnId(i); diff --git a/src/duckdb/src/planner/binder/statement/bind_pragma.cpp b/src/duckdb/src/planner/binder/statement/bind_pragma.cpp index 3e0b36adc..69af2a1a5 100644 --- a/src/duckdb/src/planner/binder/statement/bind_pragma.cpp +++ b/src/duckdb/src/planner/binder/statement/bind_pragma.cpp @@ -11,21 +11,17 @@ namespace duckdb { unique_ptr Binder::BindPragma(PragmaInfo &info, QueryErrorContext error_context) { - vector params; - named_parameter_map_t named_parameters; + // the arguments are bound here and folded to constants only after the overload has been chosen, so that a + // literal keeps its literal type for overload selection - as for every other function kind + vector> positional_arguments; + vector>> named_arguments; - // resolve the parameters ConstantBinder pragma_binder(*this, context, "PRAGMA value"); for (auto ¶m : info.parameters) { - auto bound_value = pragma_binder.Bind(param); - auto value = ExpressionExecutor::EvaluateScalar(context, *bound_value, true); - params.push_back(std::move(value)); + positional_arguments.push_back(pragma_binder.Bind(param)); } - for (auto &entry : info.named_parameters) { - auto bound_value = pragma_binder.Bind(entry.second); - auto value = ExpressionExecutor::EvaluateScalar(context, *bound_value, true); - named_parameters.insert(make_pair(entry.first, std::move(value))); + named_arguments.emplace_back(Identifier(entry.first), pragma_binder.Bind(entry.second)); } // bind the pragma function @@ -51,15 +47,17 @@ unique_ptr Binder::BindPragma(PragmaInfo &info, QueryErrorConte FunctionBinder function_binder(*this); ErrorData error; - auto bound_idx = function_binder.BindFunction(entry->name, entry->functions, params, error); + // selection, folding, casting and named-argument checking all happen in the function binder + vector params; + named_argument_map_t named_parameters; + auto bound_idx = function_binder.BindFunction(entry->name, entry->functions, positional_arguments, named_arguments, + params, named_parameters, error); if (!bound_idx.IsValid()) { D_ASSERT(error.HasError()); error.AddQueryLocation(error_context); error.Throw(); } auto bound_function = *entry->functions.GetFunctionByOffset(bound_idx.GetIndex()); - // bind and check named params - BindNamedParameters(bound_function.named_parameters, named_parameters, error_context, bound_function.name); return make_uniq(std::move(bound_function), std::move(params), std::move(named_parameters)); } diff --git a/src/duckdb/src/planner/binder/tableref/bind_basetableref.cpp b/src/duckdb/src/planner/binder/tableref/bind_basetableref.cpp index 7fc21e99e..5fef48a72 100644 --- a/src/duckdb/src/planner/binder/tableref/bind_basetableref.cpp +++ b/src/duckdb/src/planner/binder/tableref/bind_basetableref.cpp @@ -283,8 +283,8 @@ BoundStatement Binder::Bind(BaseTableRef &ref) { virtual_columns = table.GetVirtualColumns(); } auto logical_get = - make_uniq(table_index, scan_function, std::move(bind_data), std::move(return_types), - std::move(return_names), std::move(virtual_columns)); + make_uniq(table_index, BoundTableFunction(scan_function), std::move(bind_data), + std::move(return_types), std::move(return_names), std::move(virtual_columns)); if (entry_at_clause) { logical_get->at_clause = make_uniq(entry_at_clause->Unit(), entry_at_clause->GetValue()); } diff --git a/src/duckdb/src/planner/binder/tableref/bind_named_parameters.cpp b/src/duckdb/src/planner/binder/tableref/bind_named_parameters.cpp deleted file mode 100644 index c1bec0bd6..000000000 --- a/src/duckdb/src/planner/binder/tableref/bind_named_parameters.cpp +++ /dev/null @@ -1,49 +0,0 @@ -#include "duckdb/planner/binder.hpp" - -namespace duckdb { - -template -map order_case_insensitive_map(const case_insensitive_map_t &input_map) { - return map(input_map.begin(), input_map.end()); -} - -template -map order_case_insensitive_map(const identifier_map_t &input_map) { - map result; - for (auto &entry : input_map) { - result[entry.first.GetIdentifierName()] = entry.second; - } - return result; -} - -void Binder::BindNamedParameters(named_parameter_type_map_t &types, named_parameter_map_t &values, - QueryErrorContext &error_context, const Identifier &func_name) { - for (auto &kv : values) { - auto entry = types.find(kv.first); - if (entry == types.end()) { - auto ordered_params = order_case_insensitive_map(types); - // create a list of named parameters for the error - string named_params; - for (auto &kv_ordered_params : ordered_params) { - named_params += " "; - named_params += kv_ordered_params.first; - named_params += " "; - named_params += kv_ordered_params.second.ToString(); - named_params += "\n"; - } - string error_msg; - if (named_params.empty()) { - error_msg = "Function does not accept any named parameters."; - } else { - error_msg = "Candidates:\n" + named_params; - } - throw BinderException(error_context, "Invalid named parameter %s for function %s\n%s", kv.first, - func_name.GetIdentifierName(), error_msg); - } - if (entry->second.id() != LogicalTypeId::ANY) { - kv.second = kv.second.CastAs(context, entry->second); - } - } -} - -} // namespace duckdb diff --git a/src/duckdb/src/planner/binder/tableref/bind_table_function.cpp b/src/duckdb/src/planner/binder/tableref/bind_table_function.cpp index ac3719064..5c65977a6 100644 --- a/src/duckdb/src/planner/binder/tableref/bind_table_function.cpp +++ b/src/duckdb/src/planner/binder/tableref/bind_table_function.cpp @@ -1,6 +1,5 @@ #include "duckdb/catalog/catalog.hpp" #include "duckdb/catalog/catalog_entry/table_macro_catalog_entry.hpp" -#include "duckdb/execution/expression_executor.hpp" #include "duckdb/function/builtin_function_lookup.hpp" #include "duckdb/parser/expression/columnref_expression.hpp" #include "duckdb/parser/expression/comparison_expression.hpp" @@ -19,6 +18,7 @@ #include "duckdb/planner/expression/bound_window_expression.hpp" #include "duckdb/planner/operator/logical_window.hpp" +#include "duckdb/planner/expression/bound_constant_expression.hpp" namespace duckdb { @@ -45,8 +45,8 @@ static TableFunctionBindType GetTableFunctionBindType(TableFunctionCatalogEntry bool has_table_parameter = false; for (idx_t function_idx = 0; function_idx < table_function.functions.Size(); function_idx++) { const auto &function = *table_function.functions.GetFunctionByOffset(function_idx); - for (auto &arg : function.GetArguments()) { - if (arg.id() == LogicalTypeId::TABLE) { + for (auto ¶m : function.GetSignature().GetParameters()) { + if (param.GetType().id() == LogicalTypeId::TABLE) { has_table_parameter = true; } } @@ -87,15 +87,14 @@ void Binder::BindTableInTableOutFunction(vector> &e bool Binder::BindTableFunctionParameters(TableFunctionCatalogEntry &table_function, vector> &expressions, - vector &arguments, vector ¶meters, - named_parameter_map_t &named_parameters, BoundStatement &subquery, - ErrorData &error) { + vector> &positional_arguments, + vector>> &named_arguments, + BoundStatement &subquery, bool &table_in_out, ErrorData &error) { auto bind_type = GetTableFunctionBindType(table_function, expressions); if (bind_type == TableFunctionBindType::TABLE_IN_OUT_FUNCTION) { - // bind table in-out function + // bind table in-out function - its arguments are the columns of the subquery, so there is nothing to fold BindTableInTableOutFunction(expressions, subquery); - // fetch the arguments from the subquery - arguments = subquery.types; + table_in_out = true; return true; } bool seen_subquery = false; @@ -121,7 +120,7 @@ bool Binder::BindTableFunctionParameters(TableFunctionCatalogEntry &table_functi child->GetExpressionType() == ExpressionType::SUBQUERY) { D_ASSERT(table_function.functions.Size() == 1); const auto &fun = *table_function.functions.GetFunctionByOffset(0); - if (table_function.functions.Size() != 1 || fun.GetArguments().empty()) { + if (table_function.functions.Size() != 1 || fun.GetSignature().GetPositionalParameterCount() == 0) { throw BinderException( "Only table-in-out functions can have subquery parameters - %s only accepts constant parameters", fun.GetName()); @@ -136,14 +135,12 @@ bool Binder::BindTableFunctionParameters(TableFunctionCatalogEntry &table_functi subquery = binder->BindNode(*se.Subquery()->node); MoveCorrelatedExpressions(*binder); seen_subquery = true; - arguments.emplace_back(LogicalTypeId::TABLE); - parameters.emplace_back(); + positional_arguments.push_back(make_uniq(Value(LogicalType::TABLE))); continue; } TableFunctionBinder binder(*this, context, table_function.name.GetIdentifierName()); - LogicalType sql_type; - auto expr = binder.Bind(child, &sql_type); + auto expr = binder.Bind(child); if (expr->HasParameter()) { throw ParameterNotResolvedException(); } @@ -151,17 +148,18 @@ bool Binder::BindTableFunctionParameters(TableFunctionCatalogEntry &table_functi // should have been eliminated before throw InternalException("Table function requires a constant parameter"); } - auto constant = ExpressionExecutor::EvaluateScalar(context, *expr, true); + // The argument is folded to a constant only after the overload has been chosen, so that the bound + // expression's STRING_LITERAL / INTEGER_LITERAL type reaches overload selection - which is what lets + // "header = 1" match a BOOLEAN option, exactly as it already does for scalar functions if (parameter_name.empty()) { // unnamed parameter - if (!named_parameters.empty()) { + if (!named_arguments.empty()) { error = ErrorData("Unnamed parameters cannot come after named parameters"); return false; } - arguments.emplace_back(constant.IsNull() ? LogicalType::SQLNULL : sql_type); - parameters.emplace_back(std::move(constant)); + positional_arguments.push_back(std::move(expr)); } else { - named_parameters[parameter_name] = std::move(constant); + named_arguments.emplace_back(parameter_name, std::move(expr)); } } return true; @@ -181,8 +179,8 @@ static string GetAlias(const TableFunctionRef &ref) { //! Postgres names the single column of a set-returning function after the alias of the function //! (e.g. "SELECT t FROM generate_series(1, 2) t" returns the values, not a struct) //! returns the original column name, which is kept available as a column alias -static Identifier ApplyPostgresSetofAliasCompatibility(const TableFunction &table_function, const TableFunctionRef &ref, - vector &return_names) { +static Identifier ApplyPostgresSetofAliasCompatibility(const BaseTableFunction &table_function, + const TableFunctionRef &ref, vector &return_names) { if (table_function.return_type != TableFunctionReturnType::SET_RETURNING_FUNCTION || ref.alias.empty() || !ref.column_name_alias.empty() || return_names.size() != 1) { return Identifier(); @@ -202,8 +200,8 @@ static void AddPostgresSetofColumnAlias(BindContext &bind_context, TableIndex bi bind_context.AddColumnAlias(bind_index, original_name, 0); } -BoundStatement Binder::BindTableFunctionInternal(TableFunction &table_function, const TableFunctionRef &ref, - vector parameters, named_parameter_map_t named_parameters, +BoundStatement Binder::BindTableFunctionInternal(BoundTableFunction &table_function, const TableFunctionRef &ref, + vector parameters, named_argument_map_t named_parameters, vector input_table_types, vector input_table_names, optional_ptr> input_plan) { @@ -217,6 +215,9 @@ BoundStatement Binder::BindTableFunctionInternal(TableFunction &table_function, auto constexpr ordinality_name = "ordinality"; string ordinality_column_name = ordinality_name; optional_idx ordinality_column_id; + // the function binder has placed them already, but not for a table in-out call or a direct bind + table_function.GetSignature().FillNamedDefaults(context, named_parameters); + table_function.SetCallArguments(parameters, named_parameters); if (table_function.bind || table_function.bind_replace || table_function.bind_operator) { TableFunctionBindInput bind_input(parameters, named_parameters, input_table_types, input_table_names, table_function.function_info.get(), this, table_function, ref, input_plan); @@ -226,13 +227,13 @@ BoundStatement Binder::BindTableFunctionInternal(TableFunction &table_function, new_plan->ResolveOperatorTypes(); if (new_plan->types.size() != return_names.size()) { throw InternalException("Failed to bind \"%s\": return_types/names must have same size", - table_function.name); + table_function.GetName()); } for (auto &binding : new_plan->GetColumnBindings()) { if (binding.table_index != bind_index) { throw InternalException( "Failed to bind \"%s\": root bind index must be the passed in bind index", - table_function.name); + table_function.GetName()); } } auto setof_column_name = ApplyPostgresSetofAliasCompatibility(table_function, ref, return_names); @@ -259,7 +260,7 @@ BoundStatement Binder::BindTableFunctionInternal(TableFunction &table_function, } if (!table_function.bind) { throw BinderException("Failed to bind \"%s\": nullptr returned from bind_replace without bind function", - table_function.name); + table_function.GetName()); } bind_data = table_function.bind(context, bind_input, return_types, return_names); if (ref.with_ordinality == OrdinalityType::WITH_ORDINALITY) { @@ -285,17 +286,18 @@ BoundStatement Binder::BindTableFunctionInternal(TableFunction &table_function, } } else { throw InvalidInputException("Cannot call function \"%s\" directly - it has no bind function", - table_function.name); + table_function.GetName()); } if (bind_data && !bind_data->SupportStatementCache()) { SetAlwaysRequireRebind(); } if (return_types.size() != return_names.size()) { - throw InternalException("Failed to bind \"%s\": return_types/names must have same size", table_function.name); + throw InternalException("Failed to bind \"%s\": return_types/names must have same size", + table_function.GetName()); } if (return_types.empty()) { throw InternalException("Failed to bind \"%s\": Table function must return at least one column", - table_function.name); + table_function.GetName()); } auto setof_column_name = ApplyPostgresSetofAliasCompatibility(table_function, ref, return_names); // overwrite the names with any supplied aliases @@ -372,14 +374,15 @@ BoundStatement Binder::BindTableFunctionInternal(TableFunction &table_function, } BoundStatement Binder::BindTableFunction(TableFunction &function, vector parameters) { - named_parameter_map_t named_parameters; + named_argument_map_t named_parameters; vector input_table_types; vector input_table_names; TableFunctionRef ref; ref.alias = function.name; D_ASSERT(!ref.alias.empty()); - return BindTableFunctionInternal(function, ref, std::move(parameters), std::move(named_parameters), + BoundTableFunction bound_function(function); + return BindTableFunctionInternal(bound_function, ref, std::move(parameters), std::move(named_parameters), std::move(input_table_types), std::move(input_table_names), nullptr); } @@ -428,11 +431,11 @@ BoundStatement Binder::Bind(TableFunctionRef &ref) { D_ASSERT(func_catalog.type == CatalogType::TABLE_FUNCTION_ENTRY); auto &function = func_catalog.Cast(); - // evaluate the input parameters to the function - vector arguments; - vector parameters; - named_parameter_map_t named_parameters; + // bind the input parameters to the function - they are folded to constants after the overload is chosen + vector> positional_arguments; + vector>> named_arguments; BoundStatement subquery; + bool table_in_out = false; ErrorData error; vector> children; @@ -440,23 +443,26 @@ BoundStatement Binder::Bind(TableFunctionRef &ref) { children.push_back(std::move(child.GetExpressionMutable())); } - if (!BindTableFunctionParameters(function, children, arguments, parameters, named_parameters, subquery, error)) { + if (!BindTableFunctionParameters(function, children, positional_arguments, named_arguments, subquery, table_in_out, + error)) { error.AddQueryLocation(ref); error.Throw(); } - // select the function based on the input parameters + // selection, named-argument checking, folding and casting all happen in the function binder FunctionBinder function_binder(*this); - auto best_function_idx = function_binder.BindFunction(function.name, function.functions, arguments, error); + vector parameters; + named_argument_map_t named_parameters; + auto best_function_idx = + table_in_out ? function_binder.BindTableInOutFunction(function.name, function.functions, subquery.types, error) + : function_binder.BindFunction(function.name, function.functions, positional_arguments, + named_arguments, parameters, named_parameters, error); if (!best_function_idx.IsValid()) { error.AddQueryLocation(ref); error.Throw(); } - // copied out of the set: BindTableFunctionInternal fills in the bound arguments/return types - auto table_function = *function.functions.GetFunctionByOffset(best_function_idx.GetIndex()); - - // now check the named parameters - BindNamedParameters(table_function.named_parameters, named_parameters, error_context, table_function.name); + // copied out of the set: BindTableFunctionInternal fills in the bound return types + BoundTableFunction table_function(function.functions.GetFunctionByOffset(best_function_idx.GetIndex())); vector input_table_types; vector input_table_names; @@ -470,22 +476,17 @@ BoundStatement Binder::Bind(TableFunctionRef &ref) { input_table_names.push_back(Identifier()); } } - if (!parameters.empty()) { - // cast the parameters to the type of the function - for (idx_t i = 0; i < arguments.size(); i++) { - auto target_type = i < table_function.GetArguments().size() ? table_function.GetArguments()[i] - : table_function.GetVarArgs(); - - if (target_type != LogicalType::ANY && target_type != LogicalType::POINTER && - target_type.id() != LogicalTypeId::LIST && target_type != LogicalType::TABLE) { - parameters[i] = parameters[i].CastAs(context, target_type); + if (parameters.empty() && subquery.plan) { + // the arguments are the columns of a subquery, so the declared types apply to those instead - the function + // binder casts the folded constants of every other call shape + const auto &signature = table_function.GetSignature(); + auto args = signature.GetArgs(); + for (idx_t i = 0; i < input_table_types.size(); i++) { + if (i >= signature.GetPositionalParameterCount() && !args) { + break; } - } - } else if (subquery.plan) { - for (idx_t i = 0; i < arguments.size(); i++) { - auto target_type = i < table_function.GetArguments().size() ? table_function.GetArguments()[i] - : table_function.GetVarArgs(); - + auto target_type = + i < signature.GetPositionalParameterCount() ? signature.GetParameter(i).GetType() : args->GetType(); if (target_type != LogicalType::ANY && target_type != LogicalType::POINTER && target_type.id() != LogicalTypeId::LIST) { input_table_types[i] = target_type; diff --git a/src/duckdb/src/planner/operator/logical_get.cpp b/src/duckdb/src/planner/operator/logical_get.cpp index 6715034f9..19ae5dc1d 100644 --- a/src/duckdb/src/planner/operator/logical_get.cpp +++ b/src/duckdb/src/planner/operator/logical_get.cpp @@ -68,7 +68,7 @@ static void MapLegacyTableFilterKeys(LogicalGet &get) { LogicalGet::LogicalGet() : LogicalOperator(LogicalOperatorType::LOGICAL_GET) { } -LogicalGet::LogicalGet(TableIndex table_index, TableFunction function, unique_ptr bind_data, +LogicalGet::LogicalGet(TableIndex table_index, BoundTableFunction function, unique_ptr bind_data, vector returned_types, vector returned_names, virtual_column_map_t virtual_columns_p) : LogicalOperator(LogicalOperatorType::LOGICAL_GET), table_index(table_index), function(std::move(function)), @@ -376,8 +376,7 @@ unique_ptr LogicalGet::Deserialize(Deserializer &deserializer) deserializer.ReadPropertyWithDefault(203, "column_ids", legacy_column_ids); deserializer.ReadProperty(204, "projection_ids", result->projection_ids); deserializer.ReadProperty(205, "table_filters", result->table_filters); - auto entry = FunctionSerializer::DeserializeBase( - deserializer, CatalogType::TABLE_FUNCTION_ENTRY); + auto entry = FunctionSerializer::DeserializeTableFunction(deserializer); result->function = entry.first; auto &function = result->function; auto has_serialize = entry.second; @@ -387,6 +386,8 @@ unique_ptr LogicalGet::Deserialize(Deserializer &deserializer) } deserializer.ReadPropertyWithDefault(206, "parameters", result->parameters); deserializer.ReadPropertyWithDefault(207, "named_parameters", result->named_parameters); + // a plan written by an older version holds only the arguments the call passed + function.GetSignature().FillNamedDefaults(deserializer.Get(), result->named_parameters); deserializer.ReadPropertyWithDefault(208, "input_table_types", result->input_table_types); deserializer.ReadPropertyWithDefault(209, "input_table_names", result->input_table_names); deserializer.ReadProperty(210, "projected_input", result->projected_input); @@ -427,7 +428,7 @@ unique_ptr LogicalGet::Deserialize(Deserializer &deserializer) vector bind_return_types; vector bind_names; if (!function.bind) { - throw InternalException("Table function \"%s\" has neither bind nor (de)serialize", function.name); + throw InternalException("Table function \"%s\" has neither bind nor (de)serialize", function.GetName()); } bind_data = function.bind(context, input, bind_return_types, bind_names); if (result->ordinality_idx.IsValid()) { @@ -452,7 +453,7 @@ unique_ptr LogicalGet::Deserialize(Deserializer &deserializer) if (bind_return_types[idx] != ret_type) { throw SerializationException("Table function deserialization failure in function %s - column with " "name %s was serialized with type %s, but now has type %s", - function.name, col_name, ret_type, bind_return_types[idx]); + function.GetName(), col_name, ret_type, bind_return_types[idx]); } } } @@ -479,10 +480,11 @@ vector LogicalGet::GetTableIndex() const { string LogicalGet::GetName() const { #ifdef DEBUG if (DBConfigOptions::debug_print_bindings) { - return StringUtil::Upper(function.name.GetIdentifierName()) + StringUtil::Format(" #%llu", table_index.index); + return StringUtil::Upper(function.GetName().GetIdentifierName()) + + StringUtil::Format(" #%llu", table_index.index); } #endif - return StringUtil::Upper(function.name.GetIdentifierName()); + return StringUtil::Upper(function.GetName().GetIdentifierName()); } } // namespace duckdb diff --git a/src/duckdb/src/planner/sql_export/sql_export_functions.cpp b/src/duckdb/src/planner/sql_export/sql_export_functions.cpp index 2218de9c7..90cf8cec9 100644 --- a/src/duckdb/src/planner/sql_export/sql_export_functions.cpp +++ b/src/duckdb/src/planner/sql_export/sql_export_functions.cpp @@ -164,7 +164,8 @@ BoundExpressionSQLExportState::ExportScalarFunction(const BoundFunctionExpressio } const auto logical_argument_count = function.GetLogicalArguments().size(); const auto child_count = expression.GetChildren().size(); - const bool retained_variadic_arguments = definition->HasVarArgs() && child_count >= logical_argument_count; + const bool retained_variadic_arguments = + definition->GetSignature().GetArgs() && child_count >= logical_argument_count; const bool has_scalar_arguments = child_count == logical_argument_count || retained_variadic_arguments || definition->HasUnbindCallback(); const bool has_expected_arguments = diff --git a/src/duckdb/src/planner/sql_export/table_function_sql_export.cpp b/src/duckdb/src/planner/sql_export/table_function_sql_export.cpp index e032ebfac..df15f5ac3 100644 --- a/src/duckdb/src/planner/sql_export/table_function_sql_export.cpp +++ b/src/duckdb/src/planner/sql_export/table_function_sql_export.cpp @@ -23,9 +23,10 @@ namespace duckdb { static string SQLFunctionCallGuard(const LogicalGet &get, bool has_input) { - const auto argument_count = get.function.GetArguments().size(); + const auto &signature = get.function.GetSignature(); + const auto argument_count = signature.GetPositionalParameterCount(); const bool has_expected_parameters = - get.function.HasVarArgs() ? get.parameters.size() >= argument_count : get.parameters.size() == argument_count; + signature.GetArgs() ? get.parameters.size() >= argument_count : get.parameters.size() == argument_count; if (!has_input && !has_expected_parameters) { return "positional_parameters"; } diff --git a/src/duckdb/ub_src_planner_binder_tableref.cpp b/src/duckdb/ub_src_planner_binder_tableref.cpp index efcc04519..f26b22800 100644 --- a/src/duckdb/ub_src_planner_binder_tableref.cpp +++ b/src/duckdb/ub_src_planner_binder_tableref.cpp @@ -12,8 +12,6 @@ #include "src/planner/binder/tableref/bind_joinref.cpp" -#include "src/planner/binder/tableref/bind_named_parameters.cpp" - #include "src/planner/binder/tableref/bind_pivot.cpp" #include "src/planner/binder/tableref/bind_showref.cpp"