duckdb 1.5.3.0 → 1.5.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +47 -0
  3. data/CLAUDE.md +4 -0
  4. data/README.md +52 -0
  5. data/duckdb.gemspec +1 -1
  6. data/ext/duckdb/aggregate_function.c +0 -1
  7. data/ext/duckdb/appender.c +17 -0
  8. data/ext/duckdb/arrow_array_stream.c +226 -0
  9. data/ext/duckdb/arrow_array_stream.h +61 -0
  10. data/ext/duckdb/arrow_import.c +165 -0
  11. data/ext/duckdb/arrow_import.h +6 -0
  12. data/ext/duckdb/blob.c +1 -1
  13. data/ext/duckdb/blob.h +1 -2
  14. data/ext/duckdb/config.c +1 -1
  15. data/ext/duckdb/config.h +1 -1
  16. data/ext/duckdb/connection.c +26 -4
  17. data/ext/duckdb/converter.h +1 -0
  18. data/ext/duckdb/conveter.c +39 -9
  19. data/ext/duckdb/data_chunk.c +10 -0
  20. data/ext/duckdb/data_chunk.h +1 -0
  21. data/ext/duckdb/duckdb.c +13 -11
  22. data/ext/duckdb/error.c +13 -1
  23. data/ext/duckdb/error.h +2 -3
  24. data/ext/duckdb/function_executor.c +308 -2
  25. data/ext/duckdb/function_executor.h +44 -0
  26. data/ext/duckdb/function_vector.c +14 -0
  27. data/ext/duckdb/prepared_statement.c +141 -5
  28. data/ext/duckdb/result.c +49 -3
  29. data/ext/duckdb/result.h +11 -0
  30. data/ext/duckdb/ruby-duckdb.h +3 -0
  31. data/ext/duckdb/scalar_function.c +97 -29
  32. data/ext/duckdb/scalar_function.h +2 -4
  33. data/ext/duckdb/scalar_function_bind_info.c +13 -13
  34. data/ext/duckdb/scalar_function_bind_info.h +1 -1
  35. data/ext/duckdb/scalar_function_set.c +9 -9
  36. data/ext/duckdb/scalar_function_set.h +2 -2
  37. data/ext/duckdb/table_description.c +19 -19
  38. data/ext/duckdb/table_description.h +1 -1
  39. data/ext/duckdb/table_function.c +94 -28
  40. data/ext/duckdb/table_function.h +2 -2
  41. data/ext/duckdb/table_function_bind_info.c +20 -20
  42. data/ext/duckdb/table_function_bind_info.h +2 -2
  43. data/ext/duckdb/table_function_function_info.c +5 -5
  44. data/ext/duckdb/table_function_function_info.h +2 -2
  45. data/ext/duckdb/table_function_init_info.c +70 -5
  46. data/ext/duckdb/table_function_init_info.h +2 -2
  47. data/ext/duckdb/util.c +8 -0
  48. data/ext/duckdb/util.h +1 -0
  49. data/ext/duckdb/value.c +526 -1
  50. data/lib/duckdb/appender.rb +23 -0
  51. data/lib/duckdb/arrow_array_stream.rb +33 -0
  52. data/lib/duckdb/connection.rb +73 -0
  53. data/lib/duckdb/converter/int_to_sym.rb +54 -1
  54. data/lib/duckdb/converter.rb +7 -7
  55. data/lib/duckdb/error.rb +26 -0
  56. data/lib/duckdb/function_type_validation.rb +1 -0
  57. data/lib/duckdb/logical_type.rb +6 -3
  58. data/lib/duckdb/prepared_statement.rb +32 -0
  59. data/lib/duckdb/scalar_function.rb +6 -6
  60. data/lib/duckdb/value.rb +400 -0
  61. data/lib/duckdb/version.rb +1 -1
  62. data/lib/duckdb.rb +2 -0
  63. metadata +10 -3
@@ -5,10 +5,10 @@ VALUE cDuckDBScalarFunctionBindInfo;
5
5
  static void deallocate(void *ctx);
6
6
  static VALUE allocate(VALUE klass);
7
7
  static size_t memsize(const void *p);
8
- static VALUE rbduckdb_scalar_function_bind_info_argument_count(VALUE self);
9
- static VALUE rbduckdb_scalar_function_bind_info_set_error(VALUE self, VALUE error);
10
- static VALUE rbduckdb_scalar_function_bind_info_get_argument(VALUE self, VALUE index);
11
- static VALUE rbduckdb_scalar_function_bind_info_client_context(VALUE self);
8
+ static VALUE scalar_function_bind_info_argument_count(VALUE self);
9
+ static VALUE scalar_function_bind_info_set_error(VALUE self, VALUE error);
10
+ static VALUE scalar_function_bind_info__get_argument(VALUE self, VALUE index);
11
+ static VALUE scalar_function_bind_info_client_context(VALUE self);
12
12
 
13
13
  static const rb_data_type_t scalar_function_bind_info_data_type = {
14
14
  "DuckDB/ScalarFunction/BindInfo",
@@ -46,7 +46,7 @@ VALUE rbduckdb_scalar_function_bind_info_new(duckdb_bind_info bind_info) {
46
46
  *
47
47
  * bind_info.argument_count # => 2
48
48
  */
49
- static VALUE rbduckdb_scalar_function_bind_info_argument_count(VALUE self) {
49
+ static VALUE scalar_function_bind_info_argument_count(VALUE self) {
50
50
  rubyDuckDBScalarFunctionBindInfo *ctx;
51
51
  TypedData_Get_Struct(self, rubyDuckDBScalarFunctionBindInfo, &scalar_function_bind_info_data_type, ctx);
52
52
  return ULL2NUM(duckdb_scalar_function_bind_get_argument_count(ctx->bind_info));
@@ -61,7 +61,7 @@ static VALUE rbduckdb_scalar_function_bind_info_argument_count(VALUE self) {
61
61
  *
62
62
  * bind_info.set_error('invalid argument')
63
63
  */
64
- static VALUE rbduckdb_scalar_function_bind_info_set_error(VALUE self, VALUE error) {
64
+ static VALUE scalar_function_bind_info_set_error(VALUE self, VALUE error) {
65
65
  rubyDuckDBScalarFunctionBindInfo *ctx;
66
66
  TypedData_Get_Struct(self, rubyDuckDBScalarFunctionBindInfo, &scalar_function_bind_info_data_type, ctx);
67
67
  duckdb_scalar_function_bind_set_error(ctx->bind_info, StringValueCStr(error));
@@ -75,7 +75,7 @@ static VALUE rbduckdb_scalar_function_bind_info_set_error(VALUE self, VALUE erro
75
75
  * Returns the expression at the given argument index.
76
76
  * Called internally by +get_argument+ after index validation.
77
77
  */
78
- static VALUE rbduckdb_scalar_function_bind_info_get_argument(VALUE self, VALUE index) {
78
+ static VALUE scalar_function_bind_info__get_argument(VALUE self, VALUE index) {
79
79
  rubyDuckDBScalarFunctionBindInfo *ctx;
80
80
  TypedData_Get_Struct(self, rubyDuckDBScalarFunctionBindInfo, &scalar_function_bind_info_data_type, ctx);
81
81
  duckdb_expression expr = duckdb_scalar_function_bind_get_argument(ctx->bind_info, (idx_t)NUM2ULL(index));
@@ -88,7 +88,7 @@ static VALUE rbduckdb_scalar_function_bind_info_get_argument(VALUE self, VALUE i
88
88
  *
89
89
  * Returns the client context associated with the bind phase of the scalar function.
90
90
  */
91
- static VALUE rbduckdb_scalar_function_bind_info_client_context(VALUE self) {
91
+ static VALUE scalar_function_bind_info_client_context(VALUE self) {
92
92
  rubyDuckDBScalarFunctionBindInfo *ctx;
93
93
  duckdb_client_context client_context;
94
94
  TypedData_Get_Struct(self, rubyDuckDBScalarFunctionBindInfo, &scalar_function_bind_info_data_type, ctx);
@@ -96,14 +96,14 @@ static VALUE rbduckdb_scalar_function_bind_info_client_context(VALUE self) {
96
96
  return rbduckdb_client_context_new(client_context);
97
97
  }
98
98
 
99
- void rbduckdb_init_duckdb_scalar_function_bind_info(void) {
99
+ void rbduckdb_init_scalar_function_bind_info(void) {
100
100
  #if 0
101
101
  VALUE mDuckDB = rb_define_module("DuckDB");
102
102
  #endif
103
103
  cDuckDBScalarFunctionBindInfo = rb_define_class_under(cDuckDBScalarFunction, "BindInfo", rb_cObject);
104
104
  rb_define_alloc_func(cDuckDBScalarFunctionBindInfo, allocate);
105
- rb_define_method(cDuckDBScalarFunctionBindInfo, "argument_count", rbduckdb_scalar_function_bind_info_argument_count, 0);
106
- rb_define_method(cDuckDBScalarFunctionBindInfo, "set_error", rbduckdb_scalar_function_bind_info_set_error, 1);
107
- rb_define_private_method(cDuckDBScalarFunctionBindInfo, "_get_argument", rbduckdb_scalar_function_bind_info_get_argument, 1);
108
- rb_define_method(cDuckDBScalarFunctionBindInfo, "client_context", rbduckdb_scalar_function_bind_info_client_context, 0);
105
+ rb_define_method(cDuckDBScalarFunctionBindInfo, "argument_count", scalar_function_bind_info_argument_count, 0);
106
+ rb_define_method(cDuckDBScalarFunctionBindInfo, "set_error", scalar_function_bind_info_set_error, 1);
107
+ rb_define_private_method(cDuckDBScalarFunctionBindInfo, "_get_argument", scalar_function_bind_info__get_argument, 1);
108
+ rb_define_method(cDuckDBScalarFunctionBindInfo, "client_context", scalar_function_bind_info_client_context, 0);
109
109
  }
@@ -7,7 +7,7 @@ struct _rubyDuckDBScalarFunctionBindInfo {
7
7
 
8
8
  typedef struct _rubyDuckDBScalarFunctionBindInfo rubyDuckDBScalarFunctionBindInfo;
9
9
 
10
- void rbduckdb_init_duckdb_scalar_function_bind_info(void);
10
+ void rbduckdb_init_scalar_function_bind_info(void);
11
11
  VALUE rbduckdb_scalar_function_bind_info_new(duckdb_bind_info bind_info);
12
12
 
13
13
  #endif
@@ -7,8 +7,8 @@ static void deallocate(void *);
7
7
  static VALUE allocate(VALUE klass);
8
8
  static size_t memsize(const void *p);
9
9
  static void compact(void *);
10
- static VALUE rbduckdb_scalar_function_set__initialize(VALUE self, VALUE name);
11
- static VALUE rbduckdb_scalar_function_set__add(VALUE self, VALUE scalar_function);
10
+ static VALUE scalar_function_set__initialize(VALUE self, VALUE name);
11
+ static VALUE scalar_function_set__add(VALUE self, VALUE scalar_function);
12
12
 
13
13
  static const rb_data_type_t scalar_function_set_data_type = {
14
14
  "DuckDB/ScalarFunctionSet",
@@ -44,14 +44,14 @@ static size_t memsize(const void *p) {
44
44
  return sizeof(rubyDuckDBScalarFunctionSet);
45
45
  }
46
46
 
47
- rubyDuckDBScalarFunctionSet *get_struct_scalar_function_set(VALUE obj) {
47
+ rubyDuckDBScalarFunctionSet *rbduckdb_get_struct_scalar_function_set(VALUE obj) {
48
48
  rubyDuckDBScalarFunctionSet *ctx;
49
49
  TypedData_Get_Struct(obj, rubyDuckDBScalarFunctionSet, &scalar_function_set_data_type, ctx);
50
50
  return ctx;
51
51
  }
52
52
 
53
53
  /* :nodoc: */
54
- static VALUE rbduckdb_scalar_function_set__initialize(VALUE self, VALUE name) {
54
+ static VALUE scalar_function_set__initialize(VALUE self, VALUE name) {
55
55
  rubyDuckDBScalarFunctionSet *p;
56
56
 
57
57
  TypedData_Get_Struct(self, rubyDuckDBScalarFunctionSet, &scalar_function_set_data_type, p);
@@ -60,12 +60,12 @@ static VALUE rbduckdb_scalar_function_set__initialize(VALUE self, VALUE name) {
60
60
  }
61
61
 
62
62
  /* :nodoc: */
63
- static VALUE rbduckdb_scalar_function_set__add(VALUE self, VALUE scalar_function) {
63
+ static VALUE scalar_function_set__add(VALUE self, VALUE scalar_function) {
64
64
  rubyDuckDBScalarFunctionSet *p;
65
65
  rubyDuckDBScalarFunction *sf;
66
66
 
67
67
  TypedData_Get_Struct(self, rubyDuckDBScalarFunctionSet, &scalar_function_set_data_type, p);
68
- sf = get_struct_scalar_function(scalar_function);
68
+ sf = rbduckdb_get_struct_scalar_function(scalar_function);
69
69
 
70
70
  if (duckdb_add_scalar_function_to_set(p->scalar_function_set, sf->scalar_function) == DuckDBError) {
71
71
  rb_raise(eDuckDBError, "failed to add scalar function to set (duplicate overload?)");
@@ -75,12 +75,12 @@ static VALUE rbduckdb_scalar_function_set__add(VALUE self, VALUE scalar_function
75
75
  return self;
76
76
  }
77
77
 
78
- void rbduckdb_init_duckdb_scalar_function_set(void) {
78
+ void rbduckdb_init_scalar_function_set(void) {
79
79
  #if 0
80
80
  VALUE mDuckDB = rb_define_module("DuckDB");
81
81
  #endif
82
82
  cDuckDBScalarFunctionSet = rb_define_class_under(mDuckDB, "ScalarFunctionSet", rb_cObject);
83
83
  rb_define_alloc_func(cDuckDBScalarFunctionSet, allocate);
84
- rb_define_private_method(cDuckDBScalarFunctionSet, "_initialize", rbduckdb_scalar_function_set__initialize, 1);
85
- rb_define_private_method(cDuckDBScalarFunctionSet, "_add", rbduckdb_scalar_function_set__add, 1);
84
+ rb_define_private_method(cDuckDBScalarFunctionSet, "_initialize", scalar_function_set__initialize, 1);
85
+ rb_define_private_method(cDuckDBScalarFunctionSet, "_add", scalar_function_set__add, 1);
86
86
  }
@@ -8,7 +8,7 @@ struct _rubyDuckDBScalarFunctionSet {
8
8
 
9
9
  typedef struct _rubyDuckDBScalarFunctionSet rubyDuckDBScalarFunctionSet;
10
10
 
11
- void rbduckdb_init_duckdb_scalar_function_set(void);
12
- rubyDuckDBScalarFunctionSet *get_struct_scalar_function_set(VALUE obj);
11
+ void rbduckdb_init_scalar_function_set(void);
12
+ rubyDuckDBScalarFunctionSet *rbduckdb_get_struct_scalar_function_set(VALUE obj);
13
13
 
14
14
  #endif
@@ -8,13 +8,13 @@ static void deallocate(void *ctx);
8
8
  static VALUE allocate(VALUE klass);
9
9
  static size_t memsize(const void *p);
10
10
  static rubyDuckDBTableDescription *get_struct_table_description(VALUE obj);
11
- static VALUE rbduckdb_table_description_error_message(VALUE self);
12
- static VALUE duckdb_table_description__initialize(VALUE self, VALUE conn, VALUE catalog, VALUE schema, VALUE table);
11
+ static VALUE table_description_error_message(VALUE self);
12
+ static VALUE table_description__initialize(VALUE self, VALUE conn, VALUE catalog, VALUE schema, VALUE table);
13
13
 
14
- static VALUE duckdb_table_description__column_count(VALUE self);
15
- static VALUE duckdb_table_description__column_name(VALUE self, VALUE idx);
16
- static VALUE duckdb_table_description__column_logical_type(VALUE self, VALUE idx);
17
- static VALUE duckdb_table_description__column_has_default(VALUE self, VALUE idx);
14
+ static VALUE table_description__column_count(VALUE self);
15
+ static VALUE table_description__column_name(VALUE self, VALUE idx);
16
+ static VALUE table_description__column_logical_type(VALUE self, VALUE idx);
17
+ static VALUE table_description__column_has_default(VALUE self, VALUE idx);
18
18
 
19
19
  static const rb_data_type_t table_description_data_type = {
20
20
  "DuckDB/TableDescription",
@@ -46,14 +46,14 @@ static rubyDuckDBTableDescription *get_struct_table_description(VALUE obj) {
46
46
  return ctx;
47
47
  }
48
48
 
49
- static VALUE rbduckdb_table_description_error_message(VALUE self) {
49
+ static VALUE table_description_error_message(VALUE self) {
50
50
  rubyDuckDBTableDescription *ctx = get_struct_table_description(self);
51
51
  const char *p = duckdb_table_description_error(ctx->table_description);
52
52
  return p ? rb_str_new2(p) : Qnil;
53
53
  }
54
54
 
55
55
  /* nodoc */
56
- static VALUE duckdb_table_description__initialize(VALUE self, VALUE con, VALUE catalog, VALUE schema, VALUE table) {
56
+ static VALUE table_description__initialize(VALUE self, VALUE con, VALUE catalog, VALUE schema, VALUE table) {
57
57
  char *pcatalog = NULL;
58
58
  char *pschema = NULL;
59
59
  char *ptable = NULL;
@@ -89,14 +89,14 @@ static VALUE duckdb_table_description__initialize(VALUE self, VALUE con, VALUE c
89
89
  }
90
90
 
91
91
  /* nodoc */
92
- static VALUE duckdb_table_description__column_count(VALUE self) {
92
+ static VALUE table_description__column_count(VALUE self) {
93
93
  rubyDuckDBTableDescription *ctx;
94
94
  ctx = get_struct_table_description(self);
95
95
  return ULL2NUM(duckdb_table_description_get_column_count(ctx->table_description));
96
96
  }
97
97
 
98
98
  /* nodoc */
99
- static VALUE duckdb_table_description__column_name(VALUE self, VALUE idx) {
99
+ static VALUE table_description__column_name(VALUE self, VALUE idx) {
100
100
  VALUE name = Qnil;
101
101
  rubyDuckDBTableDescription *ctx;
102
102
  ctx = get_struct_table_description(self);
@@ -109,7 +109,7 @@ static VALUE duckdb_table_description__column_name(VALUE self, VALUE idx) {
109
109
  }
110
110
 
111
111
  /* nodoc */
112
- static VALUE duckdb_table_description__column_logical_type(VALUE self, VALUE idx) {
112
+ static VALUE table_description__column_logical_type(VALUE self, VALUE idx) {
113
113
  rubyDuckDBTableDescription *ctx;
114
114
  duckdb_logical_type lt;
115
115
  ctx = get_struct_table_description(self);
@@ -117,7 +117,7 @@ static VALUE duckdb_table_description__column_logical_type(VALUE self, VALUE idx
117
117
  return rbduckdb_create_logical_type(lt);
118
118
  }
119
119
 
120
- static VALUE duckdb_table_description__column_has_default(VALUE self, VALUE idx) {
120
+ static VALUE table_description__column_has_default(VALUE self, VALUE idx) {
121
121
  rubyDuckDBTableDescription *ctx;
122
122
  bool has_default;
123
123
  ctx = get_struct_table_description(self);
@@ -128,17 +128,17 @@ static VALUE duckdb_table_description__column_has_default(VALUE self, VALUE idx)
128
128
  return has_default ? Qtrue : Qfalse;
129
129
  }
130
130
 
131
- void rbduckdb_init_duckdb_table_description(void) {
131
+ void rbduckdb_init_table_description(void) {
132
132
  #if 0
133
133
  VALUE mDuckDB = rb_define_module("DuckDB");
134
134
  #endif
135
135
  cDuckDBTableDescription = rb_define_class_under(mDuckDB, "TableDescription", rb_cObject);
136
136
  rb_define_alloc_func(cDuckDBTableDescription, allocate);
137
- rb_define_method(cDuckDBTableDescription, "error_message", rbduckdb_table_description_error_message, 0);
138
- rb_define_private_method(cDuckDBTableDescription, "_initialize", duckdb_table_description__initialize, 4);
139
- rb_define_private_method(cDuckDBTableDescription, "_column_count", duckdb_table_description__column_count, 0);
140
- rb_define_private_method(cDuckDBTableDescription, "_column_name", duckdb_table_description__column_name, 1);
141
- rb_define_private_method(cDuckDBTableDescription, "_column_logical_type", duckdb_table_description__column_logical_type, 1);
142
- rb_define_private_method(cDuckDBTableDescription, "_column_has_default", duckdb_table_description__column_has_default, 1);
137
+ rb_define_method(cDuckDBTableDescription, "error_message", table_description_error_message, 0);
138
+ rb_define_private_method(cDuckDBTableDescription, "_initialize", table_description__initialize, 4);
139
+ rb_define_private_method(cDuckDBTableDescription, "_column_count", table_description__column_count, 0);
140
+ rb_define_private_method(cDuckDBTableDescription, "_column_name", table_description__column_name, 1);
141
+ rb_define_private_method(cDuckDBTableDescription, "_column_logical_type", table_description__column_logical_type, 1);
142
+ rb_define_private_method(cDuckDBTableDescription, "_column_has_default", table_description__column_has_default, 1);
143
143
  }
144
144
  #endif
@@ -9,7 +9,7 @@ struct _rubyDuckDBTableDescription {
9
9
 
10
10
  typedef struct _rubyDuckDBTableDescription rubyDuckDBTableDescription;
11
11
 
12
- void rbduckdb_init_duckdb_table_description(void);
12
+ void rbduckdb_init_table_description(void);
13
13
 
14
14
  #endif /* HAVE_DUCKDB_H_GE_V1_5_0 */
15
15
 
@@ -11,16 +11,21 @@ static void deallocate(void *ctx);
11
11
  static VALUE allocate(VALUE klass);
12
12
  static size_t memsize(const void *p);
13
13
  static void compact(void *ctx);
14
- static VALUE duckdb_table_function_initialize(VALUE self);
15
- static VALUE rbduckdb_table_function_set_name(VALUE self, VALUE name);
16
- static VALUE rbduckdb_table_function_add_parameter(VALUE self, VALUE logical_type);
17
- static VALUE rbduckdb_table_function_add_named_parameter(VALUE self, VALUE name, VALUE logical_type);
18
- static VALUE rbduckdb_table_function_set_bind(VALUE self);
14
+ static VALUE table_function_initialize(VALUE self);
15
+ static VALUE table_function_set_name(VALUE self, VALUE name);
16
+ static VALUE table_function_add_parameter(VALUE self, VALUE logical_type);
17
+ static VALUE table_function_add_named_parameter(VALUE self, VALUE name, VALUE logical_type);
18
+ static VALUE table_function_bind(VALUE self);
19
19
  static void table_function_bind_callback(duckdb_bind_info info);
20
- static VALUE rbduckdb_table_function_set_init(VALUE self);
20
+ static VALUE table_function_init(VALUE self);
21
21
  static void table_function_init_callback(duckdb_init_info info);
22
- static VALUE rbduckdb_table_function_set_execute(VALUE self);
22
+ static VALUE table_function_execute(VALUE self);
23
23
  static void table_function_execute_callback(duckdb_function_info info, duckdb_data_chunk output);
24
+ #ifdef HAVE_DUCKDB_H_GE_V1_5_0
25
+ /* Thread detection (declared in function_executor.c); used to skip the proxy on Ruby threads. */
26
+ extern int ruby_native_thread_p(void);
27
+ static void table_function_local_init_callback(duckdb_init_info info);
28
+ #endif
24
29
 
25
30
  static const rb_data_type_t table_function_data_type = {
26
31
  "DuckDB/TableFunction",
@@ -84,7 +89,7 @@ static size_t memsize(const void *p) {
84
89
  * tf.name = "my_function"
85
90
  * # ... configure tf ...
86
91
  */
87
- static VALUE duckdb_table_function_initialize(VALUE self) {
92
+ static VALUE table_function_initialize(VALUE self) {
88
93
  rubyDuckDBTableFunction *ctx;
89
94
 
90
95
  TypedData_Get_Struct(self, rubyDuckDBTableFunction, &table_function_data_type, ctx);
@@ -113,7 +118,7 @@ static VALUE duckdb_table_function_initialize(VALUE self) {
113
118
  *
114
119
  * tf.name = "my_function"
115
120
  */
116
- static VALUE rbduckdb_table_function_set_name(VALUE self, VALUE name) {
121
+ static VALUE table_function_set_name(VALUE self, VALUE name) {
117
122
  rubyDuckDBTableFunction *ctx;
118
123
  const char *func_name;
119
124
 
@@ -138,7 +143,7 @@ static VALUE rbduckdb_table_function_set_name(VALUE self, VALUE name) {
138
143
  * tf.add_parameter(DuckDB::LogicalType::BIGINT)
139
144
  * tf.add_parameter(DuckDB::LogicalType::VARCHAR)
140
145
  */
141
- static VALUE rbduckdb_table_function_add_parameter(VALUE self, VALUE logical_type) {
146
+ static VALUE table_function_add_parameter(VALUE self, VALUE logical_type) {
142
147
  rubyDuckDBTableFunction *ctx;
143
148
  rubyDuckDBLogicalType *ctx_logical_type;
144
149
 
@@ -162,7 +167,7 @@ static VALUE rbduckdb_table_function_add_parameter(VALUE self, VALUE logical_typ
162
167
  *
163
168
  * tf.add_named_parameter("limit", DuckDB::LogicalType::BIGINT)
164
169
  */
165
- static VALUE rbduckdb_table_function_add_named_parameter(VALUE self, VALUE name, VALUE logical_type) {
170
+ static VALUE table_function_add_named_parameter(VALUE self, VALUE name, VALUE logical_type) {
166
171
  rubyDuckDBTableFunction *ctx;
167
172
  rubyDuckDBLogicalType *ctx_logical_type;
168
173
  const char *param_name;
@@ -192,7 +197,7 @@ static VALUE rbduckdb_table_function_add_named_parameter(VALUE self, VALUE name,
192
197
  * bind_info.add_result_column('name', DuckDB::LogicalType::VARCHAR)
193
198
  * end
194
199
  */
195
- static VALUE rbduckdb_table_function_set_bind(VALUE self) {
200
+ static VALUE table_function_bind(VALUE self) {
196
201
  rubyDuckDBTableFunction *ctx;
197
202
 
198
203
  if (!rb_block_given_p()) {
@@ -231,7 +236,7 @@ static void execute_bind_callback_protected(void *user_data) {
231
236
  int state = 0;
232
237
 
233
238
  bind_info_obj = rb_class_new_instance(0, NULL, cDuckDBTableFunctionBindInfo);
234
- bind_info_ctx = get_struct_bind_info(bind_info_obj);
239
+ bind_info_ctx = rbduckdb_get_struct_bind_info(bind_info_obj);
235
240
  bind_info_ctx->bind_info = darg->info;
236
241
 
237
242
  VALUE call_args[2] = { darg->ctx->bind_proc, bind_info_obj };
@@ -269,7 +274,7 @@ static void table_function_bind_callback(duckdb_bind_info info) {
269
274
  * # Initialize execution state
270
275
  * end
271
276
  */
272
- static VALUE rbduckdb_table_function_set_init(VALUE self) {
277
+ static VALUE table_function_init(VALUE self) {
273
278
  rubyDuckDBTableFunction *ctx;
274
279
 
275
280
  if (!rb_block_given_p()) {
@@ -307,7 +312,7 @@ static void execute_init_callback_protected(void *user_data) {
307
312
  int state = 0;
308
313
 
309
314
  init_info_obj = rb_class_new_instance(0, NULL, cDuckDBTableFunctionInitInfo);
310
- init_info_ctx = get_struct_init_info(init_info_obj);
315
+ init_info_ctx = rbduckdb_get_struct_init_info(init_info_obj);
311
316
  init_info_ctx->info = darg->info;
312
317
 
313
318
  VALUE call_args[2] = { darg->ctx->init_proc, init_info_obj };
@@ -347,7 +352,7 @@ static void table_function_init_callback(duckdb_init_info info) {
347
352
  * # Write data...
348
353
  * end
349
354
  */
350
- static VALUE rbduckdb_table_function_set_execute(VALUE self) {
355
+ static VALUE table_function_execute(VALUE self) {
351
356
  rubyDuckDBTableFunction *ctx;
352
357
 
353
358
  if (!rb_block_given_p()) {
@@ -358,6 +363,10 @@ static VALUE rbduckdb_table_function_set_execute(VALUE self) {
358
363
 
359
364
  ctx->execute_proc = rb_block_proc();
360
365
  duckdb_table_function_set_function(ctx->table_function, table_function_execute_callback);
366
+ #ifdef HAVE_DUCKDB_H_GE_V1_5_0
367
+ /* Per-worker proxy threads for the execute path (DuckDB >= 1.5.0). */
368
+ duckdb_table_function_set_local_init(ctx->table_function, table_function_local_init_callback);
369
+ #endif
361
370
 
362
371
  rbduckdb_function_executor_ensure_started();
363
372
 
@@ -384,7 +393,7 @@ static void execute_execute_callback_protected(void *user_data) {
384
393
  int state = 0;
385
394
 
386
395
  func_info_obj = rb_class_new_instance(0, NULL, cDuckDBTableFunctionFunctionInfo);
387
- func_info_ctx = get_struct_function_info(func_info_obj);
396
+ func_info_ctx = rbduckdb_get_struct_function_info(func_info_obj);
388
397
  func_info_ctx->info = darg->info;
389
398
 
390
399
  data_chunk_obj = rb_class_new_instance(0, NULL, cDuckDBDataChunk);
@@ -405,6 +414,7 @@ static void execute_execute_callback_protected(void *user_data) {
405
414
  static void table_function_execute_callback(duckdb_function_info info, duckdb_data_chunk output) {
406
415
  rubyDuckDBTableFunction *ctx;
407
416
  struct execute_dispatch_arg darg;
417
+ struct worker_proxy *proxy = NULL;
408
418
 
409
419
  ctx = (rubyDuckDBTableFunction *)duckdb_function_get_extra_info(info);
410
420
  if (!ctx || ctx->execute_proc == Qnil) return;
@@ -413,28 +423,84 @@ static void table_function_execute_callback(duckdb_function_info info, duckdb_da
413
423
  darg.info = info;
414
424
  darg.output = output;
415
425
 
416
- rbduckdb_function_executor_dispatch(execute_execute_callback_protected, &darg);
426
+ #ifdef HAVE_DUCKDB_H_GE_V1_5_0
427
+ /* On DuckDB >= 1.5.0 each worker thread carries its own proxy (see local_init). */
428
+ proxy = (struct worker_proxy *)duckdb_function_get_local_init_data(info);
429
+ #endif
430
+ rbduckdb_function_executor_dispatch_via_proxy(execute_execute_callback_protected, &darg, proxy);
431
+ }
432
+
433
+ #ifdef HAVE_DUCKDB_H_GE_V1_5_0
434
+ /*
435
+ * Per-worker init for the execute path (DuckDB >= 1.5.0).
436
+ *
437
+ * DuckDB calls this once on each worker thread that will run the execute
438
+ * callback. We create a per-worker proxy (allocating its Ruby thread under the
439
+ * GVL via the global executor, since this runs on a non-Ruby thread) and store
440
+ * it as thread-local init data. The execute callback then dispatches through it
441
+ * instead of the shared global executor, so workers run callbacks concurrently.
442
+ * DuckDB invokes rbduckdb_worker_proxy_destroy when the local state is freed.
443
+ */
444
+ struct create_proxy_callback_arg {
445
+ struct worker_proxy *proxy;
446
+ };
447
+
448
+ static VALUE create_proxy_callback(VALUE varg) {
449
+ struct create_proxy_callback_arg *arg = (struct create_proxy_callback_arg *)varg;
450
+ arg->proxy = rbduckdb_worker_proxy_create();
451
+ return Qnil;
452
+ }
453
+
454
+ /*
455
+ * rbduckdb_worker_proxy_create may raise (NoMemError, Thread.new failure),
456
+ * and the executor runs callbacks unprotected — a raise would longjmp past
457
+ * its done-signaling and block the waiting DuckDB worker forever. Swallow
458
+ * the exception instead: the proxy stays NULL, local_init sets no state, and
459
+ * the execute callback falls back to the global executor.
460
+ */
461
+ static void create_proxy_callback_protected(void *user_data) {
462
+ int exception_state;
463
+
464
+ rb_protect(create_proxy_callback, (VALUE)user_data, &exception_state);
465
+ if (exception_state) {
466
+ rb_set_errinfo(Qnil);
467
+ }
468
+ }
469
+
470
+ static void table_function_local_init_callback(duckdb_init_info info) {
471
+ struct create_proxy_callback_arg arg;
472
+
473
+ /* A Ruby calling thread runs the callback inline (Case 1/2); no proxy needed. */
474
+ if (ruby_native_thread_p()) return;
475
+
476
+ arg.proxy = NULL;
477
+ rbduckdb_function_executor_dispatch(create_proxy_callback_protected, &arg);
478
+
479
+ if (arg.proxy != NULL) {
480
+ duckdb_init_set_init_data(info, arg.proxy, rbduckdb_worker_proxy_destroy);
481
+ }
417
482
  }
483
+ #endif
418
484
 
419
- rubyDuckDBTableFunction *get_struct_table_function(VALUE self) {
485
+ rubyDuckDBTableFunction *rbduckdb_get_struct_table_function(VALUE self) {
420
486
  rubyDuckDBTableFunction *ctx;
421
487
  TypedData_Get_Struct(self, rubyDuckDBTableFunction, &table_function_data_type, ctx);
422
488
  return ctx;
423
489
  }
424
490
 
425
- void rbduckdb_init_duckdb_table_function(void) {
491
+ void rbduckdb_init_table_function(void) {
426
492
  #if 0
427
493
  VALUE mDuckDB = rb_define_module("DuckDB");
428
494
  #endif
429
495
  cDuckDBTableFunction = rb_define_class_under(mDuckDB, "TableFunction", rb_cObject);
430
496
  rb_define_alloc_func(cDuckDBTableFunction, allocate);
431
497
 
432
- rb_define_method(cDuckDBTableFunction, "initialize", duckdb_table_function_initialize, 0);
433
- rb_define_method(cDuckDBTableFunction, "set_name", rbduckdb_table_function_set_name, 1);
434
- rb_define_method(cDuckDBTableFunction, "name=", rbduckdb_table_function_set_name, 1);
435
- rb_define_method(cDuckDBTableFunction, "add_parameter", rbduckdb_table_function_add_parameter, 1);
436
- rb_define_method(cDuckDBTableFunction, "add_named_parameter", rbduckdb_table_function_add_named_parameter, 2);
437
- rb_define_method(cDuckDBTableFunction, "bind", rbduckdb_table_function_set_bind, 0);
438
- rb_define_method(cDuckDBTableFunction, "init", rbduckdb_table_function_set_init, 0);
439
- rb_define_method(cDuckDBTableFunction, "execute", rbduckdb_table_function_set_execute, 0);
498
+ rb_define_method(cDuckDBTableFunction, "initialize", table_function_initialize, 0);
499
+ rb_define_method(cDuckDBTableFunction, "set_name", table_function_set_name, 1);
500
+ rb_define_method(cDuckDBTableFunction, "name=", table_function_set_name, 1);
501
+ rb_define_method(cDuckDBTableFunction, "add_parameter", table_function_add_parameter, 1);
502
+ rb_define_method(cDuckDBTableFunction, "add_named_parameter", table_function_add_named_parameter, 2);
503
+ rb_define_method(cDuckDBTableFunction, "bind", table_function_bind, 0);
504
+ rb_define_method(cDuckDBTableFunction, "init", table_function_init, 0);
505
+ rb_define_method(cDuckDBTableFunction, "execute", table_function_execute, 0);
440
506
  }
@@ -11,7 +11,7 @@ struct _rubyDuckDBTableFunction {
11
11
  typedef struct _rubyDuckDBTableFunction rubyDuckDBTableFunction;
12
12
 
13
13
  extern VALUE cDuckDBTableFunction;
14
- rubyDuckDBTableFunction *get_struct_table_function(VALUE self);
15
- void rbduckdb_init_duckdb_table_function(void);
14
+ rubyDuckDBTableFunction *rbduckdb_get_struct_table_function(VALUE self);
15
+ void rbduckdb_init_table_function(void);
16
16
 
17
17
  #endif
@@ -5,12 +5,12 @@ VALUE cDuckDBTableFunctionBindInfo;
5
5
  static void deallocate(void *ctx);
6
6
  static VALUE allocate(VALUE klass);
7
7
  static size_t memsize(const void *p);
8
- static VALUE rbduckdb_bind_info_parameter_count(VALUE self);
9
- static VALUE rbduckdb_bind_info_get_parameter(VALUE self, VALUE index);
10
- static VALUE rbduckdb_bind_info_get_named_parameter(VALUE self, VALUE name);
11
- static VALUE rbduckdb_bind_info__add_result_column(VALUE self, VALUE column_name, VALUE logical_type);
12
- static VALUE rbduckdb_bind_info_set_cardinality(VALUE self, VALUE cardinality, VALUE is_exact);
13
- static VALUE rbduckdb_bind_info_set_error(VALUE self, VALUE error);
8
+ static VALUE table_function_bind_info_parameter_count(VALUE self);
9
+ static VALUE table_function_bind_info_get_parameter(VALUE self, VALUE index);
10
+ static VALUE table_function_bind_info_get_named_parameter(VALUE self, VALUE name);
11
+ static VALUE table_function_bind_info__add_result_column(VALUE self, VALUE column_name, VALUE logical_type);
12
+ static VALUE table_function_bind_info_set_cardinality(VALUE self, VALUE cardinality, VALUE is_exact);
13
+ static VALUE table_function_bind_info_set_error(VALUE self, VALUE error);
14
14
 
15
15
  static const rb_data_type_t bind_info_data_type = {
16
16
  "DuckDB/TableFunctionBindInfo",
@@ -32,7 +32,7 @@ static size_t memsize(const void *p) {
32
32
  return sizeof(rubyDuckDBBindInfo);
33
33
  }
34
34
 
35
- rubyDuckDBBindInfo *get_struct_bind_info(VALUE obj) {
35
+ rubyDuckDBBindInfo *rbduckdb_get_struct_bind_info(VALUE obj) {
36
36
  rubyDuckDBBindInfo *ctx;
37
37
  TypedData_Get_Struct(obj, rubyDuckDBBindInfo, &bind_info_data_type, ctx);
38
38
  return ctx;
@@ -52,7 +52,7 @@ rubyDuckDBBindInfo *get_struct_bind_info(VALUE obj) {
52
52
  *
53
53
  * bind_info.parameter_count # => 2
54
54
  */
55
- static VALUE rbduckdb_bind_info_parameter_count(VALUE self) {
55
+ static VALUE table_function_bind_info_parameter_count(VALUE self) {
56
56
  rubyDuckDBBindInfo *ctx;
57
57
  idx_t count;
58
58
 
@@ -71,7 +71,7 @@ static VALUE rbduckdb_bind_info_parameter_count(VALUE self) {
71
71
  *
72
72
  * param = bind_info.get_parameter(0)
73
73
  */
74
- static VALUE rbduckdb_bind_info_get_parameter(VALUE self, VALUE index) {
74
+ static VALUE table_function_bind_info_get_parameter(VALUE self, VALUE index) {
75
75
  rubyDuckDBBindInfo *ctx;
76
76
  idx_t idx;
77
77
  duckdb_value param_value;
@@ -97,7 +97,7 @@ static VALUE rbduckdb_bind_info_get_parameter(VALUE self, VALUE index) {
97
97
  *
98
98
  * param = bind_info.get_named_parameter('limit')
99
99
  */
100
- static VALUE rbduckdb_bind_info_get_named_parameter(VALUE self, VALUE name) {
100
+ static VALUE table_function_bind_info_get_named_parameter(VALUE self, VALUE name) {
101
101
  rubyDuckDBBindInfo *ctx;
102
102
  const char *param_name;
103
103
  duckdb_value param_value;
@@ -129,7 +129,7 @@ static VALUE rbduckdb_bind_info_get_named_parameter(VALUE self, VALUE name) {
129
129
  * bind_info.add_result_column('id', DuckDB::LogicalType::BIGINT)
130
130
  * bind_info.add_result_column('name', DuckDB::LogicalType::VARCHAR)
131
131
  */
132
- static VALUE rbduckdb_bind_info__add_result_column(VALUE self, VALUE column_name, VALUE logical_type) {
132
+ static VALUE table_function_bind_info__add_result_column(VALUE self, VALUE column_name, VALUE logical_type) {
133
133
  rubyDuckDBBindInfo *ctx;
134
134
  rubyDuckDBLogicalType *ctx_logical_type;
135
135
  const char *col_name;
@@ -152,7 +152,7 @@ static VALUE rbduckdb_bind_info__add_result_column(VALUE self, VALUE column_name
152
152
  * bind_info.set_cardinality(100, true) # Exactly 100 rows
153
153
  * bind_info.set_cardinality(1000, false) # Approximately 1000 rows
154
154
  */
155
- static VALUE rbduckdb_bind_info_set_cardinality(VALUE self, VALUE cardinality, VALUE is_exact) {
155
+ static VALUE table_function_bind_info_set_cardinality(VALUE self, VALUE cardinality, VALUE is_exact) {
156
156
  rubyDuckDBBindInfo *ctx;
157
157
  idx_t card;
158
158
  bool exact;
@@ -175,7 +175,7 @@ static VALUE rbduckdb_bind_info_set_cardinality(VALUE self, VALUE cardinality, V
175
175
  *
176
176
  * bind_info.set_error('Invalid parameter value')
177
177
  */
178
- static VALUE rbduckdb_bind_info_set_error(VALUE self, VALUE error) {
178
+ static VALUE table_function_bind_info_set_error(VALUE self, VALUE error) {
179
179
  rubyDuckDBBindInfo *ctx;
180
180
  const char *error_msg;
181
181
 
@@ -187,18 +187,18 @@ static VALUE rbduckdb_bind_info_set_error(VALUE self, VALUE error) {
187
187
  return self;
188
188
  }
189
189
 
190
- void rbduckdb_init_duckdb_table_function_bind_info(void) {
190
+ void rbduckdb_init_table_function_bind_info(void) {
191
191
  #if 0
192
192
  VALUE mDuckDB = rb_define_module("DuckDB");
193
193
  #endif
194
194
  cDuckDBTableFunctionBindInfo = rb_define_class_under(cDuckDBTableFunction, "BindInfo", rb_cObject);
195
195
  rb_define_alloc_func(cDuckDBTableFunctionBindInfo, allocate);
196
196
 
197
- rb_define_method(cDuckDBTableFunctionBindInfo, "parameter_count", rbduckdb_bind_info_parameter_count, 0);
198
- rb_define_method(cDuckDBTableFunctionBindInfo, "get_parameter", rbduckdb_bind_info_get_parameter, 1);
199
- rb_define_method(cDuckDBTableFunctionBindInfo, "get_named_parameter", rbduckdb_bind_info_get_named_parameter, 1);
200
- rb_define_method(cDuckDBTableFunctionBindInfo, "set_cardinality", rbduckdb_bind_info_set_cardinality, 2);
201
- rb_define_method(cDuckDBTableFunctionBindInfo, "set_error", rbduckdb_bind_info_set_error, 1);
197
+ rb_define_method(cDuckDBTableFunctionBindInfo, "parameter_count", table_function_bind_info_parameter_count, 0);
198
+ rb_define_method(cDuckDBTableFunctionBindInfo, "get_parameter", table_function_bind_info_get_parameter, 1);
199
+ rb_define_method(cDuckDBTableFunctionBindInfo, "get_named_parameter", table_function_bind_info_get_named_parameter, 1);
200
+ rb_define_method(cDuckDBTableFunctionBindInfo, "set_cardinality", table_function_bind_info_set_cardinality, 2);
201
+ rb_define_method(cDuckDBTableFunctionBindInfo, "set_error", table_function_bind_info_set_error, 1);
202
202
 
203
- rb_define_private_method(cDuckDBTableFunctionBindInfo, "_add_result_column", rbduckdb_bind_info__add_result_column, 2);
203
+ rb_define_private_method(cDuckDBTableFunctionBindInfo, "_add_result_column", table_function_bind_info__add_result_column, 2);
204
204
  }
@@ -8,7 +8,7 @@ struct _rubyDuckDBBindInfo {
8
8
  typedef struct _rubyDuckDBBindInfo rubyDuckDBBindInfo;
9
9
 
10
10
  extern VALUE cDuckDBTableFunctionBindInfo;
11
- rubyDuckDBBindInfo *get_struct_bind_info(VALUE obj);
12
- void rbduckdb_init_duckdb_table_function_bind_info(void);
11
+ rubyDuckDBBindInfo *rbduckdb_get_struct_bind_info(VALUE obj);
12
+ void rbduckdb_init_table_function_bind_info(void);
13
13
 
14
14
  #endif
@@ -5,7 +5,7 @@ VALUE cDuckDBTableFunctionFunctionInfo;
5
5
  static void deallocate(void *ctx);
6
6
  static VALUE allocate(VALUE klass);
7
7
  static size_t memsize(const void *p);
8
- static VALUE rbduckdb_function_info_set_error(VALUE self, VALUE error);
8
+ static VALUE table_function_function_info_set_error(VALUE self, VALUE error);
9
9
 
10
10
  static const rb_data_type_t function_info_data_type = {
11
11
  "DuckDB/TableFunctionFunctionInfo",
@@ -27,7 +27,7 @@ static size_t memsize(const void *p) {
27
27
  return sizeof(rubyDuckDBFunctionInfo);
28
28
  }
29
29
 
30
- rubyDuckDBFunctionInfo *get_struct_function_info(VALUE obj) {
30
+ rubyDuckDBFunctionInfo *rbduckdb_get_struct_function_info(VALUE obj) {
31
31
  rubyDuckDBFunctionInfo *ctx;
32
32
  TypedData_Get_Struct(obj, rubyDuckDBFunctionInfo, &function_info_data_type, ctx);
33
33
  return ctx;
@@ -42,7 +42,7 @@ rubyDuckDBFunctionInfo *get_struct_function_info(VALUE obj) {
42
42
  *
43
43
  * function_info.set_error('Invalid parameter value')
44
44
  */
45
- static VALUE rbduckdb_function_info_set_error(VALUE self, VALUE error) {
45
+ static VALUE table_function_function_info_set_error(VALUE self, VALUE error) {
46
46
  rubyDuckDBFunctionInfo *ctx;
47
47
  const char *error_msg;
48
48
 
@@ -54,12 +54,12 @@ static VALUE rbduckdb_function_info_set_error(VALUE self, VALUE error) {
54
54
  return self;
55
55
  }
56
56
 
57
- void rbduckdb_init_duckdb_table_function_function_info(void) {
57
+ void rbduckdb_init_table_function_function_info(void) {
58
58
  #if 0
59
59
  VALUE mDuckDB = rb_define_module("DuckDB");
60
60
  #endif
61
61
  cDuckDBTableFunctionFunctionInfo = rb_define_class_under(cDuckDBTableFunction, "FunctionInfo", rb_cObject);
62
62
  rb_define_alloc_func(cDuckDBTableFunctionFunctionInfo, allocate);
63
63
 
64
- rb_define_method(cDuckDBTableFunctionFunctionInfo, "set_error", rbduckdb_function_info_set_error, 1);
64
+ rb_define_method(cDuckDBTableFunctionFunctionInfo, "set_error", table_function_function_info_set_error, 1);
65
65
  }