Class: DuckDB::Appender

Inherits:
Object
  • Object
show all
Includes:
Converter
Defined in:
lib/duckdb/appender.rb,
ext/duckdb/appender.c

Overview

The DuckDB::Appender encapsulates DuckDB Appender.

require 'duckdb'
db = DuckDB::Database.open
con = db.connect
con.query('CREATE TABLE users (id INTEGER, name VARCHAR)')
appender = con.appender('users')
appender.append_row(1, 'Alice')

Constant Summary

Constants included from Converter

Converter::EPOCH, Converter::EPOCH_UTC, Converter::FLIP_HUGEINT, Converter::HALF_HUGEINT, Converter::HALF_HUGEINT_BIT

Instance Method Summary collapse

Methods included from Converter

_parse_date, _parse_deciaml, _parse_time, _to_date, _to_decimal_from_hugeint, _to_decimal_from_value, _to_hugeint_from_vector, _to_infinity, _to_interval_from_vector, _to_query_progress, _to_time, _to_time_from_duckdb_time, _to_time_from_duckdb_time_tz, _to_time_from_duckdb_timestamp_ms, _to_time_from_duckdb_timestamp_ns, _to_time_from_duckdb_timestamp_s, _to_time_from_duckdb_timestamp_tz, _to_uuid_from_vector

Constructor Details

#initialize(con, schema, table) ⇒ Object



59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# File 'ext/duckdb/appender.c', line 59

static VALUE appender_initialize(VALUE self, VALUE con, VALUE schema, VALUE table) {

    rubyDuckDBConnection *ctxcon;
    rubyDuckDBAppender *ctx;
    char *pschema = 0;

    if (!rb_obj_is_kind_of(con, cDuckDBConnection)) {
        rb_raise(rb_eTypeError, "1st argument should be instance of DackDB::Connection");
    }

    TypedData_Get_Struct(self, rubyDuckDBAppender, &appender_data_type, ctx);
    ctxcon = get_struct_connection(con);

    if (schema != Qnil) {
        pschema = StringValuePtr(schema);
    }

    if (duckdb_appender_create(ctxcon->con, pschema, StringValuePtr(table), &(ctx->appender)) == DuckDBError) {
        rb_raise(eDuckDBError, "failed to create appender");
    }
    return self;
}

Instance Method Details

#append(value) ⇒ Object

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


579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
# File 'lib/duckdb/appender.rb', line 579

def append(value)
  case value
  when NilClass
    append_null
  when Float
    append_double(value)
  when Integer
    case value
    when RANGE_INT16
      append_int16(value)
    when RANGE_INT32
      append_int32(value)
    when RANGE_INT64
      append_int64(value)
    else
      append_hugeint(value)
    end
  when String
    blob?(value) ? append_blob(value) : append_varchar(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

#append_blob(value) ⇒ Object

call-seq:

appender.append_blob(val) -> self

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


383
384
385
386
387
# File 'lib/duckdb/appender.rb', line 383

def append_blob(value)
  return self if _append_blob(value)

  raise_appender_error('failed to append_blob')
end

#append_bool(value) ⇒ Object

call-seq:

appender.append_bool(val) -> self

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


114
115
116
117
118
# File 'lib/duckdb/appender.rb', line 114

def append_bool(value)
  return self if _append_bool(value)

  raise_appender_error('failed to append_bool')
end

#append_date(value) ⇒ Object

call-seq:

appender.append_date(val) -> self

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


491
492
493
494
495
496
497
# File 'lib/duckdb/appender.rb', line 491

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

#append_defaultObject

call-seq:

appender.append_default -> self

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


425
426
427
428
429
# File 'lib/duckdb/appender.rb', line 425

def append_default
  return self if _append_default

  raise_appender_error('failed to append_default')
end

#append_double(value) ⇒ Object

call-seq:

appender.append_double(val) -> self

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


323
324
325
326
327
# File 'lib/duckdb/appender.rb', line 323

def append_double(value)
  return self if _append_double(value)

  raise_appender_error('failed to append_double')
end

#append_float(value) ⇒ Object

call-seq:

appender.append_float(val) -> self

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


303
304
305
306
307
# File 'lib/duckdb/appender.rb', line 303

def append_float(value)
  return self if _append_float(value)

  raise_appender_error('failed to append_float')
end

#append_hugeint(value) ⇒ Object

call-seq:

appender.append_hugeint(val) -> self

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


445
446
447
448
449
450
451
# File 'lib/duckdb/appender.rb', line 445

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

#append_int16(value) ⇒ Object

call-seq:

appender.append_int16(val) -> self

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


157
158
159
160
161
# File 'lib/duckdb/appender.rb', line 157

def append_int16(value)
  return self if _append_int16(value)

  raise_appender_error('failed to append_int16')
end

#append_int32(value) ⇒ Object

call-seq:

appender.append_int32(val) -> self

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


178
179
180
181
182
# File 'lib/duckdb/appender.rb', line 178

def append_int32(value)
  return self if _append_int32(value)

  raise_appender_error('failed to append_int32')
end

#append_int64(value) ⇒ Object

call-seq:

appender.append_int64(val) -> self

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


199
200
201
202
203
# File 'lib/duckdb/appender.rb', line 199

def append_int64(value)
  return self if _append_int64(value)

  raise_appender_error('failed to append_int64')
end

#append_int8(value) ⇒ Object

call-seq:

appender.append_int8(val) -> self

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


136
137
138
139
140
# File 'lib/duckdb/appender.rb', line 136

def append_int8(value)
  return self if _append_int8(value)

  raise_appender_error('failed to append_int8')
end

#append_interval(value) ⇒ Object

call-seq:

appender.append_interval(val) -> self

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


561
562
563
564
565
566
567
# File 'lib/duckdb/appender.rb', line 561

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

#append_nullObject

call-seq:

appender.append_null -> self

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


403
404
405
406
407
# File 'lib/duckdb/appender.rb', line 403

def append_null
  return self if _append_null

  raise_appender_error('failed to append_null')
end

#append_row(*args) ⇒ Object

append a row.

appender.append_row(1, 'Alice')

is same as:

appender.append(2)
appender.append('Alice')
appender.end_row


620
621
622
623
624
625
# File 'lib/duckdb/appender.rb', line 620

def append_row(*args)
  args.each do |arg|
    append(arg)
  end
  end_row
end

#append_time(value) ⇒ Object

call-seq:

appender.append_time(val) -> self

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


514
515
516
517
518
519
520
# File 'lib/duckdb/appender.rb', line 514

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

#append_timestamp(value) ⇒ Object

call-seq:

appender.append_timestamp(val) -> self

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


538
539
540
541
542
543
544
# File 'lib/duckdb/appender.rb', line 538

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

#append_uhugeint(value) ⇒ Object

call-seq:

appender.append_uhugeint(val) -> self

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


467
468
469
470
471
472
473
# File 'lib/duckdb/appender.rb', line 467

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

#append_uint16(value) ⇒ Object

call-seq:

appender.append_uint16(val) -> self

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


241
242
243
244
245
# File 'lib/duckdb/appender.rb', line 241

def append_uint16(value)
  return self if _append_uint16(value)

  raise_appender_error('failed to append_uint16')
end

#append_uint32(value) ⇒ Object

call-seq:

appender.append_uint32(val) -> self

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


262
263
264
265
266
# File 'lib/duckdb/appender.rb', line 262

def append_uint32(value)
  return self if _append_uint32(value)

  raise_appender_error('failed to append_uint32')
end

#append_uint64(value) ⇒ Object

call-seq:

appender.append_uint64(val) -> self

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


283
284
285
286
287
# File 'lib/duckdb/appender.rb', line 283

def append_uint64(value)
  return self if _append_uint64(value)

  raise_appender_error('failed to append_uint64')
end

#append_uint8(value) ⇒ Object

call-seq:

appender.append_uint8(val) -> self

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


220
221
222
223
224
# File 'lib/duckdb/appender.rb', line 220

def append_uint8(value)
  return self if _append_uint8(value)

  raise_appender_error('failed to append_uint8')
end

#append_varchar(value) ⇒ Object

call-seq:

appender.append_varchar(val) -> self

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


343
344
345
346
347
# File 'lib/duckdb/appender.rb', line 343

def append_varchar(value)
  return self if _append_varchar(value)

  raise_appender_error('failed to append_varchar')
end

#append_varchar_length(value, length) ⇒ Object

call-seq:

appender.append_varchar_length(val, len) -> self

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


363
364
365
366
367
# File 'lib/duckdb/appender.rb', line 363

def append_varchar_length(value, length)
  return self if _append_varchar_length(value, length)

  raise_appender_error('failed to append_varchar_length')
end

#begin_rowObject

:call-seq:

appender.begin_row -> self

A nop method, provided for backwards compatibility reasons. Does nothing. Only ‘end_row` is required.



30
31
32
# File 'lib/duckdb/appender.rb', line 30

def begin_row
  self
end

#closeObject

:call-seq:

appender.close -> self

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


93
94
95
96
97
# File 'lib/duckdb/appender.rb', line 93

def close
  return self if _close

  raise_appender_error('failed to close')
end

#end_rowObject

call-seq:

appender.end_row -> self

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


47
48
49
50
51
# File 'lib/duckdb/appender.rb', line 47

def end_row
  return self if _end_row

  raise_appender_error('failed to end_row')
end

#error_messageString

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


94
95
96
97
98
99
100
101
102
103
104
# File 'ext/duckdb/appender.c', line 94

static VALUE appender_error_message(VALUE self) {
    rubyDuckDBAppender *ctx;
    const char *msg;
    TypedData_Get_Struct(self, rubyDuckDBAppender, &appender_data_type, ctx);

    msg = duckdb_appender_error(ctx->appender);
    if (msg == NULL) {
        return Qnil;
    }
    return rb_str_new2(msg);
}

#flushObject

:call-seq:

appender.flush -> self

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


70
71
72
73
74
# File 'lib/duckdb/appender.rb', line 70

def flush
  return self if _flush

  raise_appender_error('failed to flush')
end