Skip to content

Commit 76fb84a

Browse files
committed
scalar func: main extra info
1 parent 55bcc4d commit 76fb84a

File tree

3 files changed

+64
-10
lines changed

3 files changed

+64
-10
lines changed

bindings/pkgs/@duckdb/node-bindings/duckdb.d.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1039,17 +1039,21 @@ export function scalar_function_set_name(scalar_function: ScalarFunction, name:
10391039
export function scalar_function_set_return_type(scalar_function: ScalarFunction, logical_type: LogicalType): void;
10401040

10411041
// DUCKDB_C_API void duckdb_scalar_function_set_extra_info(duckdb_scalar_function scalar_function, void *extra_info, duckdb_delete_callback_t destroy);
1042+
// not exposed: combined with scalar_function_set_function
1043+
10421044
// DUCKDB_C_API void duckdb_scalar_function_set_bind(duckdb_scalar_function scalar_function, duckdb_scalar_function_bind_t bind);
10431045
// DUCKDB_C_API void duckdb_scalar_function_set_bind_data(duckdb_bind_info info, void *bind_data, duckdb_delete_callback_t destroy);
10441046
// DUCKDB_C_API void duckdb_scalar_function_bind_set_error(duckdb_bind_info info, const char *error);
10451047

10461048
// DUCKDB_C_API void duckdb_scalar_function_set_function(duckdb_scalar_function scalar_function, duckdb_scalar_function_t function);
1047-
export function scalar_function_set_function(scalar_function: ScalarFunction, func: ScalarFunctionMainFunction): void;
1049+
export function scalar_function_set_function(scalar_function: ScalarFunction, func: ScalarFunctionMainFunction, extra_info?: object): void;
10481050

10491051
// DUCKDB_C_API duckdb_state duckdb_register_scalar_function(duckdb_connection con, duckdb_scalar_function scalar_function);
10501052
export function register_scalar_function(connection: Connection, scalar_function: ScalarFunction): void;
10511053

10521054
// DUCKDB_C_API void *duckdb_scalar_function_get_extra_info(duckdb_function_info info);
1055+
export function scalar_function_get_extra_info(function_info: FunctionInfo): object | undefined;
1056+
10531057
// DUCKDB_C_API void *duckdb_scalar_function_get_bind_data(duckdb_function_info info);
10541058
// DUCKDB_C_API void duckdb_scalar_function_get_client_context(duckdb_bind_info info, duckdb_client_context *out_context);
10551059

bindings/src/duckdb_node_bindings.cpp

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -712,22 +712,28 @@ using ScalarFunctionMainTSFN = Napi::TypedThreadSafeFunction<ScalarFunctionMainC
712712

713713
struct ScalarFunctionMainExtraInfo {
714714
ScalarFunctionMainTSFN tsfn;
715-
// TODO: user extra info
715+
Napi::ObjectReference user_extra_info_ref;
716716
};
717717

718-
ScalarFunctionMainExtraInfo *CreateScalarFunctionMainExtraInfo(Napi::Env env, Napi::Function func) {
718+
ScalarFunctionMainExtraInfo *CreateScalarFunctionMainExtraInfo(Napi::Env env, Napi::Function func, Napi::Object user_extra_info) {
719719
auto extra_info = reinterpret_cast<ScalarFunctionMainExtraInfo*>(duckdb_malloc(sizeof(ScalarFunctionMainExtraInfo)));
720720
extra_info->tsfn = ScalarFunctionMainTSFN::New(env, func, "ScalarFunctionMain", 0, 1);
721+
extra_info->user_extra_info_ref = user_extra_info.IsUndefined() ? Napi::ObjectReference() : Napi::Persistent(user_extra_info);
721722
return extra_info;
722723
}
723724

725+
ScalarFunctionMainExtraInfo *GetScalarFunctionMainExtraInfo(duckdb_function_info function_info) {
726+
return reinterpret_cast<ScalarFunctionMainExtraInfo*>(duckdb_scalar_function_get_extra_info(function_info));
727+
}
728+
724729
void DeleteScalarFunctionMainExtraInfo(ScalarFunctionMainExtraInfo *extra_info) {
725730
extra_info->tsfn.Release();
731+
extra_info->user_extra_info_ref.Reset();
726732
duckdb_free(extra_info);
727733
}
728734

729735
void ScalarFunctionMainFunction(duckdb_function_info info, duckdb_data_chunk input, duckdb_vector output) {
730-
auto extra_info = reinterpret_cast<ScalarFunctionMainExtraInfo*>(duckdb_scalar_function_get_extra_info(info));
736+
auto extra_info = GetScalarFunctionMainExtraInfo(info);
731737
auto data = reinterpret_cast<ScalarFunctionMainData*>(duckdb_malloc(sizeof(ScalarFunctionMainData)));
732738
data->info = info;
733739
data->input = input;
@@ -1553,6 +1559,7 @@ class DuckDBNodeAddon : public Napi::Addon<DuckDBNodeAddon> {
15531559
InstanceMethod("scalar_function_set_return_type", &DuckDBNodeAddon::scalar_function_set_return_type),
15541560
InstanceMethod("scalar_function_set_function", &DuckDBNodeAddon::scalar_function_set_function),
15551561
InstanceMethod("register_scalar_function", &DuckDBNodeAddon::register_scalar_function),
1562+
InstanceMethod("scalar_function_get_extra_info", &DuckDBNodeAddon::scalar_function_get_extra_info),
15561563
InstanceMethod("scalar_function_set_error", &DuckDBNodeAddon::scalar_function_set_error),
15571564

15581565
InstanceMethod("appender_create", &DuckDBNodeAddon::appender_create),
@@ -4055,17 +4062,20 @@ class DuckDBNodeAddon : public Napi::Addon<DuckDBNodeAddon> {
40554062
}
40564063

40574064
// DUCKDB_C_API void duckdb_scalar_function_set_extra_info(duckdb_scalar_function scalar_function, void *extra_info, duckdb_delete_callback_t destroy);
4065+
// not exposed: combined with scalar_function_set_function
4066+
40584067
// DUCKDB_C_API void duckdb_scalar_function_set_bind(duckdb_scalar_function scalar_function, duckdb_scalar_function_bind_t bind);
40594068
// DUCKDB_C_API void duckdb_scalar_function_set_bind_data(duckdb_bind_info info, void *bind_data, duckdb_delete_callback_t destroy);
40604069
// DUCKDB_C_API void duckdb_scalar_function_bind_set_error(duckdb_bind_info info, const char *error);
40614070

40624071
// DUCKDB_C_API void duckdb_scalar_function_set_function(duckdb_scalar_function scalar_function, duckdb_scalar_function_t function);
4063-
// function scalar_function_set_function(scalar_function: ScalarFunction, func: ScalarFunctionMainFunction): void
4072+
// function scalar_function_set_function(scalar_function: ScalarFunction, func: ScalarFunctionMainFunction, extra_info?: object): void
40644073
Napi::Value scalar_function_set_function(const Napi::CallbackInfo& info) {
40654074
auto env = info.Env();
40664075
auto scalar_function = GetScalarFunctionFromExternal(env, info[0]);
40674076
auto func = info[1].As<Napi::Function>();
4068-
auto extra_info = CreateScalarFunctionMainExtraInfo(env, func);
4077+
auto user_extra_info = info[2].As<Napi::Object>();
4078+
auto extra_info = CreateScalarFunctionMainExtraInfo(env, func, user_extra_info);
40694079
duckdb_scalar_function_set_extra_info(scalar_function, extra_info, reinterpret_cast<duckdb_delete_callback_t>(DeleteScalarFunctionMainExtraInfo));
40704080
duckdb_scalar_function_set_function(scalar_function, &ScalarFunctionMainFunction);
40714081
return env.Undefined();
@@ -4084,6 +4094,17 @@ class DuckDBNodeAddon : public Napi::Addon<DuckDBNodeAddon> {
40844094
}
40854095

40864096
// DUCKDB_C_API void *duckdb_scalar_function_get_extra_info(duckdb_function_info info);
4097+
// function scalar_function_get_extra_info(function_info: FunctionInfo): object | undefined
4098+
Napi::Value scalar_function_get_extra_info(const Napi::CallbackInfo& info) {
4099+
auto env = info.Env();
4100+
auto function_info = GetFunctionInfoFromExternal(env, info[0]);
4101+
auto extra_info = GetScalarFunctionMainExtraInfo(function_info);
4102+
if (extra_info->user_extra_info_ref.IsEmpty()) {
4103+
return env.Undefined();
4104+
}
4105+
return extra_info->user_extra_info_ref.Value();
4106+
}
4107+
40874108
// DUCKDB_C_API void *duckdb_scalar_function_get_bind_data(duckdb_function_info info);
40884109
// DUCKDB_C_API void duckdb_scalar_function_get_client_context(duckdb_bind_info info, duckdb_client_context *out_context);
40894110

@@ -4691,14 +4712,14 @@ NODE_API_ADDON(DuckDBNodeAddon)
46914712
---
46924713
431 total functions
46934714
4694-
252 instance methods
4715+
253 instance methods
46954716
3 unimplemented client context functions
46964717
1 unimplemented table names function
46974718
1 unimplemented value to string function
46984719
1 unimplemented logical type function
46994720
2 unimplemented vector creation functions
47004721
3 unimplemented vector manipulation functions
4701-
11 unimplemented scalar function functions
4722+
10 unimplemented scalar function functions
47024723
4 unimplemented scalar function set functions
47034724
3 unimplemented selection vector functions
47044725
12 unimplemented aggregate function functions
@@ -4713,7 +4734,7 @@ NODE_API_ADDON(DuckDBNodeAddon)
47134734
6 unimplemented table description functions
47144735
8 unimplemented tasks functions
47154736
12 unimplemented cast function functions
4716-
23 functions not exposed
4737+
24 functions not exposed
47174738
+ 41 unimplemented deprecated functions (of 47)
47184739
---
47194740
431 functions accounted for

bindings/test/scalar_functions.test.ts

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ suite('scalar functions', () => {
1818
const int_type = duckdb.create_logical_type(duckdb.Type.INTEGER);
1919
duckdb.scalar_function_set_return_type(scalar_function, int_type);
2020
});
21-
test('register & run', async () => {
21+
test('register & run (no extra info)', async () => {
2222
await withConnection(async (connection) => {
2323
const scalar_function = duckdb.create_scalar_function();
2424
duckdb.scalar_function_set_name(scalar_function, 'my_func');
@@ -46,4 +46,33 @@ suite('scalar functions', () => {
4646
duckdb.destroy_scalar_function_sync(scalar_function);
4747
});
4848
});
49+
test('register & run (extra info)', async () => {
50+
await withConnection(async (connection) => {
51+
const scalar_function = duckdb.create_scalar_function();
52+
duckdb.scalar_function_set_name(scalar_function, 'my_func');
53+
const int_type = duckdb.create_logical_type(duckdb.Type.VARCHAR);
54+
duckdb.scalar_function_set_return_type(scalar_function, int_type);
55+
duckdb.scalar_function_set_function(scalar_function, (info, input, output) => {
56+
const extra_info = duckdb.scalar_function_get_extra_info(info);
57+
const inputSize = duckdb.data_chunk_get_size(input);
58+
for (let i = 0; i < inputSize; i++) {
59+
duckdb.vector_assign_string_element(output, i, `output_${i}_${JSON.stringify(extra_info)}`);
60+
}
61+
}, { 'my_extra_info_key': 'my_extra_info_value' });
62+
duckdb.register_scalar_function(connection, scalar_function);
63+
64+
const result = await duckdb.query(connection, "select my_func()");
65+
await expectResult(result, {
66+
chunkCount: 1,
67+
rowCount: 1,
68+
columns: [
69+
{ name: 'my_func()', logicalType: { typeId: duckdb.Type.VARCHAR } }
70+
],
71+
chunks: [
72+
{ rowCount: 1, vectors: [data(16, [true], ['output_0_{"my_extra_info_key":"my_extra_info_value"}'])]}
73+
],
74+
});
75+
duckdb.destroy_scalar_function_sync(scalar_function);
76+
});
77+
});
4978
});

0 commit comments

Comments
 (0)