Class: DuckDB::TableFunction
- Inherits:
-
Object
- Object
- DuckDB::TableFunction
- Defined in:
- lib/duckdb/table_function.rb,
lib/duckdb/table_function/bind_info.rb,
lib/duckdb/table_function/init_info.rb,
lib/duckdb/table_function/function_info.rb,
ext/duckdb/table_function.c
Overview
The DuckDB::TableFunction encapsulates a DuckDB table function.
NOTE: DuckDB::TableFunction is experimental now.
require 'duckdb'
db = DuckDB::Database.new
conn = db.connect
# Low-level API:
tf = DuckDB::TableFunction.new
tf.name = 'my_function'
tf.add_parameter(DuckDB::LogicalType::BIGINT)
tf.bind do |bind_info|
bind_info.add_result_column('value', DuckDB::LogicalType::BIGINT)
end
tf.execute do |func_info, output|
# Fill output data...
0 # Return 0 to signal done
end
conn.register_table_function(tf)
# High-level API (recommended):
tf = DuckDB::TableFunction.create(
name: 'my_function',
parameters: [DuckDB::LogicalType::BIGINT],
columns: { 'value' => DuckDB::LogicalType::BIGINT }
) do |func_info, output|
# Fill output data...
0 # Return row count (0 when done)
end
Defined Under Namespace
Classes: BindInfo, FunctionInfo, InitInfo
Class Method Summary collapse
-
.add_table_adapter(klass, adapter) ⇒ void
Registers a table adapter for a Ruby class.
-
.create(name:, columns:, parameters: nil) {|func_info, output| ... } ⇒ TableFunction
Creates a new table function with a declarative API.
-
.table_adapter_for(klass) ⇒ #call?
Returns the table adapter registered for the given class, or
nilif none.
Instance Method Summary collapse
- #add_named_parameter(name, logical_type) ⇒ Object
- #add_parameter(logical_type) ⇒ Object
- #bind ⇒ Object
- #execute ⇒ Object
- #init ⇒ Object
- #initialize ⇒ Object constructor
- #name=(name) ⇒ Object
- #set_name(name) ⇒ Object
Constructor Details
#initialize ⇒ Object
92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 |
# File 'ext/duckdb/table_function.c', line 92
static VALUE table_function_initialize(VALUE self) {
rubyDuckDBTableFunction *ctx;
TypedData_Get_Struct(self, rubyDuckDBTableFunction, &table_function_data_type, ctx);
ctx->table_function = duckdb_create_table_function();
if (!ctx->table_function) {
rb_raise(eDuckDBError, "Failed to create table function");
}
ctx->bind_proc = Qnil;
ctx->init_proc = Qnil;
ctx->execute_proc = Qnil;
// Set extra_info to the C struct pointer (safe with GC compaction)
// Store ctx instead of self - ctx is xmalloc'd and won't move during GC
duckdb_table_function_set_extra_info(ctx->table_function, ctx, NULL);
return self;
}
|
Class Method Details
.add_table_adapter(klass, adapter) ⇒ void
This method returns an undefined value.
Registers a table adapter for a Ruby class.
The adapter is used by DuckDB::Connection#expose_as_table to convert
instances of klass into a DuckDB table function. The adapter must respond
to call(object, name, columns: nil) and return a DuckDB::TableFunction.
Implementing a Table Adapter
An adapter is any object that responds to call(object, name, columns: nil).
The columns: keyword argument allows callers to override the column schema;
the adapter should fall back to its own schema detection when it is nil.
The execute block passed to DuckDB::TableFunction.create must:
- Write one batch of rows into
outputper call - Return the number of rows written as an
Integer - Return
0to signal that all data has been exhausted
172 173 174 |
# File 'lib/duckdb/table_function.rb', line 172 def add_table_adapter(klass, adapter) @table_adapters[klass] = adapter end |
.create(name:, columns:, parameters: nil) {|func_info, output| ... } ⇒ TableFunction
Creates a new table function with a declarative API.
rubocop:disable-next Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 |
# File 'lib/duckdb/table_function.rb', line 79 def create(name:, columns:, parameters: nil, &) raise ArgumentError, 'name is required' unless name raise ArgumentError, 'columns are required' unless columns raise ArgumentError, 'block is required' unless block_given? tf = new tf.name = name # Add parameters (positional or named) if parameters case parameters when Array parameters.each { |type| tf.add_parameter(type) } when Hash parameters.each { |param_name, type| tf.add_named_parameter(param_name, type) } else raise ArgumentError, 'parameters must be Array or Hash' end end # Set bind callback to add result columns tf.bind do |bind_info| columns.each do |col_name, col_type| bind_info.add_result_column(col_name, col_type) end end # Set init callback (required by DuckDB) tf.init do |_init_info| # No-op end # Set execute callback - user's block returns row count tf.execute do |func_info, output| size = yield(func_info, output) output.size = Integer(size) end tf end |
.table_adapter_for(klass) ⇒ #call?
Returns the table adapter registered for the given class, or nil if none.
184 185 186 |
# File 'lib/duckdb/table_function.rb', line 184 def table_adapter_for(klass) @table_adapters[klass] end |
Instance Method Details
#add_named_parameter(name, logical_type) ⇒ Object
170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 |
# File 'ext/duckdb/table_function.c', line 170
static VALUE table_function_add_named_parameter(VALUE self, VALUE name, VALUE logical_type) {
rubyDuckDBTableFunction *ctx;
rubyDuckDBLogicalType *ctx_logical_type;
const char *param_name;
TypedData_Get_Struct(self, rubyDuckDBTableFunction, &table_function_data_type, ctx);
if (!ctx->table_function) {
rb_raise(eDuckDBError, "Table function is destroyed");
}
param_name = StringValueCStr(name);
ctx_logical_type = rbduckdb_get_struct_logical_type(logical_type);
duckdb_table_function_add_named_parameter(ctx->table_function, param_name, ctx_logical_type->logical_type);
return self;
}
|
#add_parameter(logical_type) ⇒ Object
146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 |
# File 'ext/duckdb/table_function.c', line 146
static VALUE table_function_add_parameter(VALUE self, VALUE logical_type) {
rubyDuckDBTableFunction *ctx;
rubyDuckDBLogicalType *ctx_logical_type;
TypedData_Get_Struct(self, rubyDuckDBTableFunction, &table_function_data_type, ctx);
if (!ctx->table_function) {
rb_raise(eDuckDBError, "Table function is destroyed");
}
ctx_logical_type = rbduckdb_get_struct_logical_type(logical_type);
duckdb_table_function_add_parameter(ctx->table_function, ctx_logical_type->logical_type);
return self;
}
|
#bind ⇒ Object
200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 |
# File 'ext/duckdb/table_function.c', line 200
static VALUE table_function_bind(VALUE self) {
rubyDuckDBTableFunction *ctx;
if (!rb_block_given_p()) {
rb_raise(rb_eArgError, "block is required");
}
TypedData_Get_Struct(self, rubyDuckDBTableFunction, &table_function_data_type, ctx);
if (!ctx->table_function) {
rb_raise(eDuckDBError, "Table function is destroyed");
}
ctx->bind_proc = rb_block_proc();
duckdb_table_function_set_bind(ctx->table_function, table_function_bind_callback);
rbduckdb_function_executor_ensure_started();
return self;
}
|
#execute ⇒ Object
353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 |
# File 'ext/duckdb/table_function.c', line 353
static VALUE table_function_execute(VALUE self) {
rubyDuckDBTableFunction *ctx;
if (!rb_block_given_p()) {
rb_raise(rb_eArgError, "block is required for execute");
}
TypedData_Get_Struct(self, rubyDuckDBTableFunction, &table_function_data_type, ctx);
ctx->execute_proc = rb_block_proc();
duckdb_table_function_set_function(ctx->table_function, table_function_execute_callback);
#ifdef HAVE_DUCKDB_H_GE_V1_5_0
/* Per-worker proxy threads for the execute path (DuckDB >= 1.5.0). */
duckdb_table_function_set_local_init(ctx->table_function, table_function_local_init_callback);
#endif
rbduckdb_function_executor_ensure_started();
return self;
}
|
#init ⇒ Object
276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 |
# File 'ext/duckdb/table_function.c', line 276
static VALUE table_function_init(VALUE self) {
rubyDuckDBTableFunction *ctx;
if (!rb_block_given_p()) {
rb_raise(rb_eArgError, "block is required for init");
}
TypedData_Get_Struct(self, rubyDuckDBTableFunction, &table_function_data_type, ctx);
if (!ctx->table_function) {
rb_raise(eDuckDBError, "Table function is destroyed");
}
ctx->init_proc = rb_block_proc();
duckdb_table_function_set_init(ctx->table_function, table_function_init_callback);
rbduckdb_function_executor_ensure_started();
return self;
}
|
#name=(name) ⇒ Object
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 |
# File 'ext/duckdb/table_function.c', line 121
static VALUE table_function_set_name(VALUE self, VALUE name) {
rubyDuckDBTableFunction *ctx;
const char *func_name;
TypedData_Get_Struct(self, rubyDuckDBTableFunction, &table_function_data_type, ctx);
if (!ctx->table_function) {
rb_raise(eDuckDBError, "Table function is destroyed");
}
func_name = StringValueCStr(name);
duckdb_table_function_set_name(ctx->table_function, func_name);
return name;
}
|
#set_name(name) ⇒ Object
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 |
# File 'ext/duckdb/table_function.c', line 121
static VALUE table_function_set_name(VALUE self, VALUE name) {
rubyDuckDBTableFunction *ctx;
const char *func_name;
TypedData_Get_Struct(self, rubyDuckDBTableFunction, &table_function_data_type, ctx);
if (!ctx->table_function) {
rb_raise(eDuckDBError, "Table function is destroyed");
}
func_name = StringValueCStr(name);
duckdb_table_function_set_name(ctx->table_function, func_name);
return name;
}
|