class DuckDB::Appender
The DuckDB::Appender encapsulates DuckDB Appender.
The table argument (2nd positional argument) supports dot-notation and quoting:
-
'schema.table'— interpreted as schema-qualified (deprecated; useschema:instead) -
'"schema.table"'or"'schema.table'"— treated as a literal table name containing a dotrequire ‘duckdb’ db =
DuckDB::Database.opencon = db.connect con.query(‘CREATE TABLE users (id INTEGER, name VARCHAR)’) appender = con.appender(‘users’) appender.append_row(1, ‘Alice’)
Public Class Methods
Source
static VALUE appender_s_create_query(VALUE klass, VALUE con, VALUE query, VALUE types, VALUE table, VALUE columns) {
rubyDuckDBConnection *ctxcon;
rubyDuckDBAppender *ctx;
char *query_str = StringValuePtr(query);
char *table_name = NULL;
const char **column_names = NULL;
idx_t column_count = 0;
duckdb_logical_type *type_array = NULL;
VALUE appender = Qnil;
if (!rb_obj_is_kind_of(con, cDuckDBConnection)) {
rb_raise(rb_eTypeError, "1st argument should be instance of DackDB::Connection");
}
if (rb_obj_is_kind_of(types, rb_cArray) == Qfalse) {
rb_raise(rb_eTypeError, "2nd argument should be an Array");
}
column_count = RARRAY_LEN(types);
type_array = ALLOCA_N(duckdb_logical_type, (size_t)column_count);
for (idx_t i = 0; i < column_count; i++) {
VALUE type_val = rb_ary_entry(types, i);
rubyDuckDBLogicalType *type_ctx = rbduckdb_get_struct_logical_type(type_val);
type_array[i] = type_ctx->logical_type;
}
if (table != Qnil) {
table_name = StringValuePtr(table);
}
if (columns != Qnil) {
if (rb_obj_is_kind_of(columns, rb_cArray) == Qfalse) {
rb_raise(rb_eTypeError, "4th argument should be an Array or nil");
}
idx_t col_count = RARRAY_LEN(columns);
column_names = ALLOCA_N(const char *, (size_t)col_count);
for (idx_t i = 0; i < col_count; i++) {
VALUE col_name_val = rb_ary_entry(columns, i);
column_names[i] = StringValuePtr(col_name_val);
}
}
ctxcon = rbduckdb_get_struct_connection(con);
appender = allocate(klass);
TypedData_Get_Struct(appender, rubyDuckDBAppender, &appender_data_type, ctx);
if (duckdb_appender_create_query(ctxcon->con, query_str, column_count, type_array, table_name, column_names, &ctx->appender) == DuckDBError) {
rb_raise(eDuckDBError, "failed to create appender from query");
}
return appender;
}
Returns a new Appender instance created from a query.
require 'duckdb' db = DuckDB::Database.open con = db.connect con.query('CREATE TABLE users (id INTEGER, name VARCHAR)') query = 'INSERT OR REPLACE INTO users SELECT i, val FROM my_appended_data' types = [DuckDB::LogicalType::INTEGER, DuckDB::LogicalType::VARCHAR] appender = DuckDB::Appender.create_query(con, query, types, 'my_appended_data', %w[i val])
Source
# File lib/duckdb/appender.rb, line 29 def initialize(con, table_or_schema, table = nil, schema: nil, catalog: nil) if table warn_deprecated_3arg _initialize(con, table_or_schema, table) else initialize_with_parsed_table(con, table_or_schema, schema: schema, catalog: catalog) end end
Public Instance Methods
Source
# File lib/duckdb/appender.rb, line 129 def add_column(column) return self if _add_column(column) raise_appender_error('failed to add_column') end
Specifies a column to append to, allowing selective column insertion. Columns not added will use their default values or be computed from generated column expressions. Raises DuckDB::Error if the column does not exist in the table.
require 'duckdb' db = DuckDB::Database.open con = db.connect con.query('CREATE TABLE t (id UUID PRIMARY KEY DEFAULT uuidv4(), name VARCHAR)') appender = con.appender('t') appender.add_column('name') appender .append_varchar('Alice') .end_row .flush
Source
# File lib/duckdb/appender.rb, line 740 def append(value) case value when NilClass append_null when Float append_double(value) when Integer append_integer_value(value) when String append_string_value(value) when TrueClass, FalseClass append_bool(value) when Time append_timestamp(value) when Date append_date(value) when DuckDB::Interval append_interval(value) else raise(DuckDB::Error, "not supported type #{value} (#{value.class})") end end
appends value.
require 'duckdb' db = DuckDB::Database.open con = db.connect con.query('CREATE TABLE users (id INTEGER, name VARCHAR)') appender = con.appender('users') appender.append(1) appender.append('Alice') appender.end_row
rubocop:disable Metrics/CyclomaticComplexity, Metrics/MethodLength
Source
# File lib/duckdb/appender.rb, line 469 def append_blob(value) return self if _append_blob(value) raise_appender_error('failed to append_blob') end
Appends a varchar value to the current row in the appender.
require 'duckdb' db = DuckDB::Database.open con = db.connect con.query('CREATE TABLE values (value BLOB)') appender = con.appender('values') appender .append('\0\1\2\3\4\5'.encode(Encoding::BINARY)) .end_row .flush
Source
# File lib/duckdb/appender.rb, line 200 def append_bool(value) return self if _append_bool(value) raise_appender_error('failed to append_bool') end
Appends a boolean value to the current row in the appender.
require 'duckdb' db = DuckDB::Database.open con = db.connect con.query('CREATE TABLE users (id INTEGER, active BOOLEAN)') appender = con.appender('users') appender .append_int32(1) .append_bool(true) .end_row .flush
Source
# File lib/duckdb/appender.rb, line 693 def append_data_chunk(chunk) raise ArgumentError, "expected DuckDB::DataChunk, got #{chunk.class}" unless chunk.is_a?(DuckDB::DataChunk) return self if _append_data_chunk(chunk) raise_appender_error('failed to append_data_chunk') end
Appends a pre-filled DuckDB::DataChunk to the appender.
require 'duckdb' db = DuckDB::Database.open con = db.connect con.query('CREATE TABLE users (id INTEGER, name VARCHAR)') appender = con.appender('users') chunk = DuckDB::DataChunk.new([DuckDB::LogicalType::INTEGER, DuckDB::LogicalType::VARCHAR]) chunk.set_value(0, 0, 1) chunk.set_value(1, 0, 'Alice') chunk.size = 1 appender.append_data_chunk(chunk) appender.flush
Source
# File lib/duckdb/appender.rb, line 577 def append_date(value) date = _parse_date(value) return self if _append_date(date.year, date.month, date.day) raise_appender_error('failed to append_date') end
Appends a date value to the current row in the appender.
require 'duckdb' db = DuckDB::Database.open con = db.connect con.query('CREATE TABLE dates (date_value DATE)') appender = con.appender('dates') appender.append_date(Date.today) # or # appender.append_date(Time.now) # appender.append_date('2021-10-10') appender.end_row appender.flush
Source
# File lib/duckdb/appender.rb, line 511 def append_default return self if _append_default raise_appender_error('failed to append_default') end
Appends a default value to the current row in the appender. If the column does not have a default value, this method appends a NULL value.
require 'duckdb' db = DuckDB::Database.open con = db.connect con.query('CREATE TABLE values (value INTEGER DEFAULT 1)') appender = con.appender('values') appender .append_default .end_row .flush
Source
# File lib/duckdb/appender.rb, line 721 def append_default_to_chunk(chunk, col, row) raise ArgumentError, "expected DuckDB::DataChunk, got #{chunk.class}" unless chunk.is_a?(DuckDB::DataChunk) return self if _append_default_to_chunk(chunk, col, row) raise_appender_error('failed to append_default_to_chunk') end
Appends the DEFAULT value for the column at col and row in chunk. If no DEFAULT is defined for the column, NULL is used. Call this before appending the chunk via append_data_chunk.
require 'duckdb' db = DuckDB::Database.open con = db.connect con.query('CREATE TABLE users (name VARCHAR, enabled BOOLEAN DEFAULT TRUE)') appender = con.appender('users') chunk = DuckDB::DataChunk.new([DuckDB::LogicalType::VARCHAR, DuckDB::LogicalType::BOOLEAN]) appender.append_default_to_chunk(chunk, 1, 0) # enabled DEFAULT for row 0 appender.append_default_to_chunk(chunk, 1, 1) # enabled DEFAULT for row 1 chunk.set_value(0, 0, 'Alice') chunk.set_value(0, 1, 'Bob') chunk.size = 2 appender.append_data_chunk(chunk) appender.flush
Source
# File lib/duckdb/appender.rb, line 409 def append_double(value) return self if _append_double(value) raise_appender_error('failed to append_double') end
Appends a double value to the current row in the appender.
require 'duckdb' db = DuckDB::Database.open con = db.connect con.query('CREATE TABLE numbers (num DOUBLE)') appender = con.appender('numbers') appender .append_double(1.23) .end_row .flush
Source
# File lib/duckdb/appender.rb, line 389 def append_float(value) return self if _append_float(value) raise_appender_error('failed to append_float') end
Appends a float value to the current row in the appender.
require 'duckdb' db = DuckDB::Database.open con = db.connect con.query('CREATE TABLE numbers (num FLOAT)') appender = con.appender('numbers') appender .append_float(1.23) .end_row .flush
Source
# File lib/duckdb/appender.rb, line 531 def append_hugeint(value) lower, upper = integer_to_hugeint(value) return self if _append_hugeint(lower, upper) raise_appender_error('failed to append_hugeint') end
Appends a huge int value to the current row in the appender.
require 'duckdb' db = DuckDB::Database.open con = db.connect con.query('CREATE TABLE numbers (num HUGEINT)') appender = con.appender('numbers') appender .append_hugeint(-170_141_183_460_469_231_731_687_303_715_884_105_727) .end_row .flush
Source
# File lib/duckdb/appender.rb, line 243 def append_int16(value) return self if _append_int16(value) raise_appender_error('failed to append_int16') end
Appends an int16(SMALLINT) value to the current row in the appender.
require 'duckdb' db = DuckDB::Database.open con = db.connect con.query('CREATE TABLE users (id INTEGER, age SMALLINT)') appender = con.appender('users') appender .append_int32(1) .append_int16(20) .end_row .flush
Source
# File lib/duckdb/appender.rb, line 264 def append_int32(value) return self if _append_int32(value) raise_appender_error('failed to append_int32') end
Appends an int32(INTEGER) value to the current row in the appender.
require 'duckdb' db = DuckDB::Database.open con = db.connect con.query('CREATE TABLE users (id INTEGER, age INTEGER)') appender = con.appender('users') appender .append_int32(1) .append_int32(20) .end_row .flush
Source
# File lib/duckdb/appender.rb, line 285 def append_int64(value) return self if _append_int64(value) raise_appender_error('failed to append_int64') end
Appends an int64(BIGINT) value to the current row in the appender.
require 'duckdb' db = DuckDB::Database.open con = db.connect con.query('CREATE TABLE users (id INTEGER, age BIGINT)') appender = con.appender('users') appender .append_int32(1) .append_int64(20) .end_row .flush
Source
# File lib/duckdb/appender.rb, line 222 def append_int8(value) return self if _append_int8(value) raise_appender_error('failed to append_int8') end
Appends an int8(TINYINT) value to the current row in the appender.
require 'duckdb' db = DuckDB::Database.open con = db.connect con.query('CREATE TABLE users (id INTEGER, age TINYINT)') appender = con.appender('users') appender .append_int32(1) .append_int8(20) .end_row .flush
Source
# File lib/duckdb/appender.rb, line 647 def append_interval(value) value = Interval.to_interval(value) return self if _append_interval(value.interval_months, value.interval_days, value.interval_micros) raise_appender_error('failed to append_interval') end
Appends an interval value to the current row in the appender. The argument must be ISO8601 duration format.
require 'duckdb' db = DuckDB::Database.open con = db.connect con.query('CREATE TABLE intervals (interval_value INTERVAL)') appender = con.appender('intervals') appender .append_interval('P1Y2D') # => append 1 year 2 days interval. .end_row .flush
Source
# File lib/duckdb/appender.rb, line 489 def append_null return self if _append_null raise_appender_error('failed to append_null') end
Appends a NULL value to the current row in the appender.
require 'duckdb' db = DuckDB::Database.open con = db.connect con.query('CREATE TABLE values (value INTEGER)') appender = con.appender('values') appender .append_null .end_row .flush
Source
# File lib/duckdb/appender.rb, line 773 def append_row(*args) args.each do |arg| append(arg) end end_row end
append a row.
appender.append_row(1, 'Alice')
is same as:
appender.append(2) appender.append('Alice') appender.end_row
Source
# File lib/duckdb/appender.rb, line 600 def append_time(value) time = _parse_time(value) return self if _append_time(time.hour, time.min, time.sec, time.usec) raise_appender_error('failed to append_time') end
Appends a time value to the current row in the appender.
require 'duckdb' db = DuckDB::Database.open con = db.connect con.query('CREATE TABLE times (time_value TIME)') appender = con.appender('times') appender.append_time(Time.now) # or # appender.append_time('01:01:01') appender.end_row appender.flush
Source
# File lib/duckdb/appender.rb, line 624 def append_timestamp(value) time = to_time(value) return self if _append_timestamp(time.year, time.month, time.day, time.hour, time.min, time.sec, time.nsec / 1000) raise_appender_error('failed to append_timestamp') end
Appends a timestamp value to the current row in the appender.
require 'duckdb' db = DuckDB::Database.open con = db.connect con.query('CREATE TABLE timestamps (timestamp_value TIMESTAMP)') appender = con.appender('timestamps') appender.append_time(Time.now) # or # appender.append_time(Date.today) # appender.append_time('2021-08-01 01:01:01') appender.end_row appender.flush
Source
# File lib/duckdb/appender.rb, line 553 def append_uhugeint(value) lower, upper = integer_to_hugeint(value) return self if _append_uhugeint(lower, upper) raise_appender_error('failed to append_uhugeint') end
Appends an unsigned huge int value to the current row in the appender.
require 'duckdb' db = DuckDB::Database.open con = db.connect con.query('CREATE TABLE numbers (num UHUGEINT)') appender = con.appender('numbers') appender .append_hugeint(340_282_366_920_938_463_463_374_607_431_768_211_455) .end_row .flush
Source
# File lib/duckdb/appender.rb, line 327 def append_uint16(value) return self if _append_uint16(value) raise_appender_error('failed to append_uint16') end
Appends an uint16 value to the current row in the appender.
require 'duckdb' db = DuckDB::Database.open con = db.connect con.query('CREATE TABLE users (id INTEGER, age USMALLINT)') appender = con.appender('users') appender .append_int32(1) .append_uint16(20) .end_row .flush
Source
# File lib/duckdb/appender.rb, line 348 def append_uint32(value) return self if _append_uint32(value) raise_appender_error('failed to append_uint32') end
Appends an uint32 value to the current row in the appender.
require 'duckdb' db = DuckDB::Database.open con = db.connect con.query('CREATE TABLE users (id INTEGER, age UINTEGER)') appender = con.appender('users') appender .append_int32(1) .append_uint32(20) .end_row .flush
Source
# File lib/duckdb/appender.rb, line 369 def append_uint64(value) return self if _append_uint64(value) raise_appender_error('failed to append_uint64') end
Appends an uint64 value to the current row in the appender.
require 'duckdb' db = DuckDB::Database.open con = db.connect con.query('CREATE TABLE users (id INTEGER, age UBIGINT)') appender = con.appender('users') Appender .append_int32(1) .append_uint64(20) .end_row .flush
Source
# File lib/duckdb/appender.rb, line 306 def append_uint8(value) return self if _append_uint8(value) raise_appender_error('failed to append_uint8') end
Appends an uint8 value to the current row in the appender.
require 'duckdb' db = DuckDB::Database.open con = db.connect con.query('CREATE TABLE users (id INTEGER, age UTINYINT)') appender = con.appender('users') appender .append_int32(1) .append_uint8(20) .end_row .flush
Source
# File lib/duckdb/appender.rb, line 669 def append_value(value) raise ArgumentError, "expected DuckDB::Value, got #{value.class}" unless value.is_a?(DuckDB::Value) return self if _append_value(value) raise_appender_error('failed to append_value') end
Appends a DuckDB::Value to the current row in the appender.
require 'duckdb' db = DuckDB::Database.open con = db.connect con.query('CREATE TABLE numbers (num INTEGER)') appender = con.appender('numbers') appender .append_value(DuckDB::Value.create_int32(42)) .end_row .flush
Source
# File lib/duckdb/appender.rb, line 429 def append_varchar(value) return self if _append_varchar(value) raise_appender_error('failed to append_varchar') end
Appends a varchar value to the current row in the appender.
require 'duckdb' db = DuckDB::Database.open con = db.connect con.query('CREATE TABLE names (name VARCHAR)') appender = con.appender('names') appender .append_varchar('Alice') .end_row .flush
Source
# File lib/duckdb/appender.rb, line 449 def append_varchar_length(value, length) return self if _append_varchar_length(value, length) raise_appender_error('failed to append_varchar_length') end
Appends a varchar value to the current row in the appender.
require 'duckdb' db = DuckDB::Database.open con = db.connect con.query('CREATE TABLE names (name VARCHAR)') appender = con.appender('names') appender .append_varchar_length('Alice', 5) .end_row .flush
Source
# File lib/duckdb/appender.rb, line 42 def begin_row self end
Source
# File lib/duckdb/appender.rb, line 178 def clear return self if _clear raise_appender_error('failed to clear') end
Clears all unflushed data from the appender, discarding any appended rows that have not yet been flushed to the table.
require 'duckdb' db = DuckDB::Database.open con = db.connect con.query('CREATE TABLE users (id INTEGER, name VARCHAR)') appender = con.appender('users') appender .append_int32(1) .append_varchar('Alice') .end_row .clear # discards the row above without flushing to the table
Source
# File lib/duckdb/appender.rb, line 155 def clear_columns return self if _clear_columns raise_appender_error('failed to clear_columns') end
Clears the list of columns previously set by add_column, so that all columns of the table become active again. Any previously appended rows are flushed before the column list is reset; if the flush fails (e.g. a constraint violation), this method raises DuckDB::Error.
require 'duckdb' db = DuckDB::Database.open con = db.connect con.query('CREATE TABLE t (id UUID PRIMARY KEY DEFAULT uuidv4(), name VARCHAR)') appender = con.appender('t') appender.add_column('name') appender .append_varchar('Alice') .end_row .flush appender.clear_columns # all table columns are active again
Source
# File lib/duckdb/appender.rb, line 105 def close return self if _close raise_appender_error('failed to close') end
Closes the appender by flushing all intermediate states and closing it for further appends. If flushing the data triggers a constraint violation or any other error, then all data is invalidated, and this method raises DuckDB::Error.
require 'duckdb' db = DuckDB::Database.open con = db.connect con.query('CREATE TABLE users (id INTEGER, name VARCHAR)') appender = con.appender('users') appender .append_int32(1) .append_varchar('Alice') .end_row .close
Source
# File lib/duckdb/appender.rb, line 59 def end_row return self if _end_row raise_appender_error('failed to end_row') end
Finish the current row of appends. After end_row is called, the next row can be appended.
require 'duckdb' db = DuckDB::Database.open con = db.connect con.query('CREATE TABLE users (id INTEGER, name VARCHAR)') appender = con.appender('users') appender .append_int32(1) .append_varchar('Alice') .end_row
Source
static VALUE appender_error_message(VALUE self) {
rubyDuckDBAppender *ctx;
duckdb_error_data error_data;
const char *msg = NULL;
VALUE rb_msg = Qnil;
TypedData_Get_Struct(self, rubyDuckDBAppender, &appender_data_type, ctx);
error_data = duckdb_appender_error_data(ctx->appender);
if (duckdb_error_data_has_error(error_data)) {
msg = duckdb_error_data_message(error_data);
rb_msg = rb_str_new2(msg);
}
duckdb_destroy_error_data(&error_data);
return rb_msg;
}
Returns the error message of the appender. If there is no error, then it returns nil.
require 'duckdb' db = DuckDB::Database.open con = db.connect con.query('CREATE TABLE users (id INTEGER, name VARCHAR)') appender = con.appender('users') appender.error_message # => nil
Source
# File lib/duckdb/appender.rb, line 82 def flush return self if _flush raise_appender_error('failed to flush') end
Flushes the appender to the table, forcing the cache of the appender to be cleared. If flushing the data triggers a constraint violation or any other error, then all data is invalidated, and this method raises DuckDB::Error.
require 'duckdb' db = DuckDB::Database.open con = db.connect con.query('CREATE TABLE users (id INTEGER, name VARCHAR)') appender = con.appender('users') appender .append_int32(1) .append_varchar('Alice') .end_row .flush