Class: DuckDB::PreparedStatement

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

Overview

The DuckDB::PreparedStatement encapsulates connection with DuckDB prepared statement.

require 'duckdb'
db = DuckDB::Database.open('duckdb_database')
con = db.connect
sql ='SELECT name, email FROM users WHERE email = ?'
stmt = PreparedStatement.new(con, sql)
stmt.bind(1, 'email@example.com')
stmt.execute

Constant Summary

Constants included from Converter

Converter::EPOCH, Converter::EPOCH_UTC, Converter::HALF_HUGEINT, Converter::HALF_HUGEINT_BIT, Converter::LOWER_HUGEINT_MASK, Converter::RANGE_DECIMAL_WIDTH, Converter::RANGE_HUGEINT, Converter::RANGE_INT16, Converter::RANGE_INT32, Converter::RANGE_INT64, Converter::RANGE_INT8, Converter::RANGE_UHUGEINT, Converter::RANGE_UINT16, Converter::RANGE_UINT32, Converter::RANGE_UINT64, Converter::RANGE_UINT8

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Converter

_decimal_to_unscaled, _decimal_width, _hugeint_lower, _hugeint_upper, _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_ns, _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, decimal_to_hugeint, default_timezone_utc?, format_timestamp_with_micro, format_timezone_offset, integer_to_hugeint

Constructor Details

#initialize(con, query) ⇒ Object



94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'ext/duckdb/prepared_statement.c', line 94

static VALUE prepared_statement_initialize(VALUE self, VALUE con, VALUE query) {
    rubyDuckDBConnection *ctxcon;
    rubyDuckDBPreparedStatement *ctx;

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

    TypedData_Get_Struct(self, rubyDuckDBPreparedStatement, &prepared_statement_data_type, ctx);
    ctxcon = rbduckdb_get_struct_connection(con);

    if (duckdb_prepare(ctxcon->con, StringValuePtr(query), &(ctx->prepared_statement)) == DuckDBError) {
        const char *error = duckdb_prepare_error(ctx->prepared_statement);
        rb_raise(eDuckDBError, "%s", error ? error : "Failed to prepare statement(Database connection closed?).");
    }
    return self;
}

Class Method Details

.prepare(con, sql) ⇒ Object

return DuckDB::PreparedStatement object. The first argument is DuckDB::Connection object. The second argument is SQL string. If block is given, the block is executed and the statement is destroyed.

require 'duckdb' db = DuckDB::Database.open('duckdb_database') con = db.connection DuckDB::PreparedStatement.prepare(con, 'SELECT * FROM users WHERE id = ?') do |stmt| stmt.bind(1, 1) stmt.execute end



34
35
36
37
38
39
40
41
42
43
# File 'lib/duckdb/prepared_statement.rb', line 34

def prepare(con, sql)
  stmt = new(con, sql)
  return stmt unless block_given?

  begin
    yield stmt
  ensure
    stmt.destroy
  end
end

Instance Method Details

#bind(index, value) ⇒ Object

binds i-th parameter with SQL prepared statement. The first argument is index of parameter. The index of first parameter is 1 not 0. The second argument value is the value of prepared statement parameter.

require 'duckdb'
db = DuckDB::Database.open('duckdb_database')
con = db.connect
sql ='SELECT name, email FROM users WHERE email = ?'
stmt = PreparedStatement.new(con, sql)
stmt.bind(1, 'email@example.com')


367
368
369
370
371
372
373
374
375
376
377
378
# File 'lib/duckdb/prepared_statement.rb', line 367

def bind(index, value)
  case index
  when Integer
    bind_with_index(index, value)
  when String
    bind_with_name(index, value)
  when Symbol
    bind_with_name(index.to_s, value)
  else
    raise(ArgumentError, "1st argument `#{index}` must be Integer or String or Symbol.")
  end
end

#bind_args(*args, **kwargs) ⇒ Object

binds all parameters with SQL prepared statement.

require 'duckdb'
db = DuckDB::Database.open('duckdb_database')
con = db.connect
sql ='SELECT name FROM users WHERE id = ?'
# or
# sql ='SELECT name FROM users WHERE id = $id'
stmt = PreparedStatement.new(con, sql)
stmt.bind_args([1])
# or
# stmt.bind_args(id: 1)


106
107
108
109
110
111
112
113
# File 'lib/duckdb/prepared_statement.rb', line 106

def bind_args(*args, **kwargs)
  args.each.with_index(1) do |arg, i|
    bind(i, arg)
  end
  kwargs.each do |key, value|
    bind(key, value)
  end
end

#bind_blob(vidx, blob) ⇒ Object



357
358
359
360
361
362
363
364
365
366
367
# File 'ext/duckdb/prepared_statement.c', line 357

static VALUE prepared_statement_bind_blob(VALUE self, VALUE vidx, VALUE blob) {
    rubyDuckDBPreparedStatement *ctx;
    idx_t idx = check_index(vidx);

    TypedData_Get_Struct(self, rubyDuckDBPreparedStatement, &prepared_statement_data_type, ctx);

    if (duckdb_bind_blob(ctx->prepared_statement, idx, (const void *)StringValuePtr(blob), (idx_t)RSTRING_LEN(blob)) == DuckDBError) {
        rb_raise(eDuckDBError, "fail to bind %llu parameter", (unsigned long long)idx);
    }
    return self;
}

#bind_bool(vidx, val) ⇒ Object



251
252
253
254
255
256
257
258
259
260
261
262
263
264
# File 'ext/duckdb/prepared_statement.c', line 251

static VALUE prepared_statement_bind_bool(VALUE self, VALUE vidx, VALUE val) {
    rubyDuckDBPreparedStatement *ctx;
    idx_t idx = check_index(vidx);

    TypedData_Get_Struct(self, rubyDuckDBPreparedStatement, &prepared_statement_data_type, ctx);
    if (val != Qtrue && val != Qfalse) {
        rb_raise(rb_eArgError, "binding value must be boolean");
    }

    if (duckdb_bind_boolean(ctx->prepared_statement, idx, (val == Qtrue)) == DuckDBError) {
        rb_raise(eDuckDBError, "fail to bind %llu parameter", (unsigned long long)idx);
    }
    return self;
}

#bind_date(index, value) ⇒ Object

binds i-th parameter with SQL prepared statement. The first argument is index of parameter. The index of first parameter is 1 not 0. The second argument value is to expected date.

require 'duckdb'
db = DuckDB::Database.open('duckdb_database')
con = db.connect
sql ='SELECT name FROM users WHERE birth_day = ?'
stmt = PreparedStatement.new(con, sql)
stmt.bind(1, Date.today)
#  or you can specify date string.
# stmt.bind(1, '2021-02-23')


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

def bind_date(index, value)
  date = _parse_date(value)

  _bind_date(index, date.year, date.month, date.day)
end

#bind_decimal(index, value) ⇒ Object

binds i-th parameter with SQL prepared statement. The first argument is index of parameter. The index of first parameter is 1 not 0. The second argument value is to expected BigDecimal value or any value that can be parsed into a BigDecimal.

require 'duckdb'
db = DuckDB::Database.open('duckdb_database')
con = db.connect
sql ='SELECT value FROM decimals WHERE decimal = ?'
stmt = PreparedStatement.new(con, sql)
stmt.bind_decimal(1, BigDecimal('987654.321'))


331
332
333
334
335
336
# File 'lib/duckdb/prepared_statement.rb', line 331

def bind_decimal(index, value)
  decimal = _parse_deciaml(value)
  lower, upper = decimal_to_hugeint(decimal)
  width = _decimal_width(decimal)
  _bind_decimal(index, lower, upper, width, decimal.scale)
end

#bind_double(vidx, val) ⇒ Object



332
333
334
335
336
337
338
339
340
341
342
343
# File 'ext/duckdb/prepared_statement.c', line 332

static VALUE prepared_statement_bind_double(VALUE self, VALUE vidx, VALUE val) {
    rubyDuckDBPreparedStatement *ctx;
    idx_t idx = check_index(vidx);
    double dbl = NUM2DBL(val);

    TypedData_Get_Struct(self, rubyDuckDBPreparedStatement, &prepared_statement_data_type, ctx);

    if (duckdb_bind_double(ctx->prepared_statement, idx, dbl) == DuckDBError) {
        rb_raise(eDuckDBError, "fail to bind %llu parameter", (unsigned long long)idx);
    }
    return self;
}

#bind_float(vidx, val) ⇒ Object



319
320
321
322
323
324
325
326
327
328
329
330
# File 'ext/duckdb/prepared_statement.c', line 319

static VALUE prepared_statement_bind_float(VALUE self, VALUE vidx, VALUE val) {
    rubyDuckDBPreparedStatement *ctx;
    idx_t idx = check_index(vidx);
    double dbl = NUM2DBL(val);

    TypedData_Get_Struct(self, rubyDuckDBPreparedStatement, &prepared_statement_data_type, ctx);

    if (duckdb_bind_float(ctx->prepared_statement, idx, (float)dbl) == DuckDBError) {
        rb_raise(eDuckDBError, "fail to bind %llu parameter", (unsigned long long)idx);
    }
    return self;
}

#bind_hugeint(index, value) ⇒ Object

binds i-th parameter with SQL prepared statement. The first argument is index of parameter. The index of first parameter is 1 not 0. The second argument value is to expected Integer value. This method uses bind_varchar internally.

require 'duckdb'
db = DuckDB::Database.open('duckdb_database')
con = db.connect
sql ='SELECT name FROM users WHERE bigint_col = ?'
stmt = PreparedStatement.new(con, sql)
stmt.bind_hugeint(1, 1_234_567_890_123_456_789_012_345)


168
169
170
171
172
173
174
175
# File 'lib/duckdb/prepared_statement.rb', line 168

def bind_hugeint(index, value)
  case value
  when Integer
    bind_varchar(index, value.to_s)
  else
    raise(ArgumentError, "2nd argument `#{value}` must be Integer.")
  end
end

#bind_hugeint_internal(index, value) ⇒ Object

binds i-th parameter with SQL prepared statement. The first argument is index of parameter. The index of first parameter is 1 not 0. The second argument value must be Integer value. This method uses duckdb_bind_hugeint internally.

require 'duckdb'
db = DuckDB::Database.open('duckdb_database')
con = db.connect
sql ='SELECT name FROM users WHERE hugeint_col = ?'
stmt = PreparedStatement.new(con, sql)
stmt.bind_hugeint_internal(1, 1_234_567_890_123_456_789_012_345)


189
190
191
192
# File 'lib/duckdb/prepared_statement.rb', line 189

def bind_hugeint_internal(index, value)
  lower, upper = integer_to_hugeint(value)
  _bind_hugeint(index, lower, upper)
end

#bind_int16(vidx, val) ⇒ Object



280
281
282
283
284
285
286
287
288
289
290
291
# File 'ext/duckdb/prepared_statement.c', line 280

static VALUE prepared_statement_bind_int16(VALUE self, VALUE vidx, VALUE val) {
    rubyDuckDBPreparedStatement *ctx;
    idx_t idx = check_index(vidx);
    int16_t i16val = NUM2INT(val);

    TypedData_Get_Struct(self, rubyDuckDBPreparedStatement, &prepared_statement_data_type, ctx);

    if (duckdb_bind_int16(ctx->prepared_statement, idx, i16val) == DuckDBError) {
        rb_raise(eDuckDBError, "fail to bind %llu parameter", (unsigned long long)idx);
    }
    return self;
}

#bind_int32(vidx, val) ⇒ Object



293
294
295
296
297
298
299
300
301
302
303
304
# File 'ext/duckdb/prepared_statement.c', line 293

static VALUE prepared_statement_bind_int32(VALUE self, VALUE vidx, VALUE val) {
    rubyDuckDBPreparedStatement *ctx;
    idx_t idx = check_index(vidx);
    int32_t i32val = NUM2INT(val);

    TypedData_Get_Struct(self, rubyDuckDBPreparedStatement, &prepared_statement_data_type, ctx);

    if (duckdb_bind_int32(ctx->prepared_statement, idx, i32val) == DuckDBError) {
        rb_raise(eDuckDBError, "fail to bind %llu parameter", (unsigned long long)idx);
    }
    return self;
}

#bind_int64(vidx, val) ⇒ Object



306
307
308
309
310
311
312
313
314
315
316
317
# File 'ext/duckdb/prepared_statement.c', line 306

static VALUE prepared_statement_bind_int64(VALUE self, VALUE vidx, VALUE val) {
    rubyDuckDBPreparedStatement *ctx;
    idx_t idx = check_index(vidx);
    int64_t i64val = NUM2LL(val);

    TypedData_Get_Struct(self, rubyDuckDBPreparedStatement, &prepared_statement_data_type, ctx);

    if (duckdb_bind_int64(ctx->prepared_statement, idx, i64val) == DuckDBError) {
        rb_raise(eDuckDBError, "fail to bind %llu parameter", (unsigned long long)idx);
    }
    return self;
}

#bind_int8(vidx, val) ⇒ Object



266
267
268
269
270
271
272
273
274
275
276
277
# File 'ext/duckdb/prepared_statement.c', line 266

static VALUE prepared_statement_bind_int8(VALUE self, VALUE vidx, VALUE val) {
    rubyDuckDBPreparedStatement *ctx;
    idx_t idx = check_index(vidx);
    int8_t i8val = (int8_t)NUM2INT(val);

    TypedData_Get_Struct(self, rubyDuckDBPreparedStatement, &prepared_statement_data_type, ctx);

    if (duckdb_bind_int8(ctx->prepared_statement, idx, i8val) == DuckDBError) {
        rb_raise(eDuckDBError, "fail to bind %llu parameter", (unsigned long long)idx);
    }
    return self;
}

#bind_interval(index, value) ⇒ Object

binds i-th parameter with SQL prepared statement. The first argument is index of parameter. The index of first parameter is 1 not 0. The second argument value is to expected ISO8601 time interval string.

require 'duckdb'
db = DuckDB::Database.open('duckdb_database')
con = db.connect
sql ='SELECT value FROM intervals WHERE interval = ?'
stmt = PreparedStatement.new(con, sql)
stmt.bind(1, 'P1Y2D')


314
315
316
317
# File 'lib/duckdb/prepared_statement.rb', line 314

def bind_interval(index, value)
  value = Interval.to_interval(value)
  _bind_interval(index, value.interval_months, value.interval_days, value.interval_micros)
end

#bind_null(vidx) ⇒ Object



369
370
371
372
373
374
375
376
377
378
379
# File 'ext/duckdb/prepared_statement.c', line 369

static VALUE prepared_statement_bind_null(VALUE self, VALUE vidx) {
    rubyDuckDBPreparedStatement *ctx;
    idx_t idx = check_index(vidx);

    TypedData_Get_Struct(self, rubyDuckDBPreparedStatement, &prepared_statement_data_type, ctx);

    if (duckdb_bind_null(ctx->prepared_statement, idx) == DuckDBError) {
        rb_raise(eDuckDBError, "fail to bind %llu parameter", (unsigned long long)idx);
    }
    return self;
}

#bind_parameter_index(name) ⇒ Object



183
184
185
186
187
188
189
190
191
192
193
# File 'ext/duckdb/prepared_statement.c', line 183

static VALUE prepared_statement_bind_parameter_index(VALUE self, VALUE name) {
    rubyDuckDBPreparedStatement *ctx;
    idx_t idx;

    TypedData_Get_Struct(self, rubyDuckDBPreparedStatement, &prepared_statement_data_type, ctx);

    if (duckdb_bind_parameter_index(ctx->prepared_statement, &idx, StringValuePtr(name)) == DuckDBError) {;
        rb_raise(rb_eArgError, "parameter '%s' not found", StringValuePtr(name));
    }
    return ULL2NUM(idx);
}

#bind_time(index, value) ⇒ Object

binds i-th parameter with SQL prepared statement. The first argument is index of parameter. The index of first parameter is 1 not 0. The second argument value is to expected time value.

require 'duckdb'
db = DuckDB::Database.open('duckdb_database')
con = db.connect
sql ='SELECT name FROM users WHERE birth_time = ?'
stmt = PreparedStatement.new(con, sql)
stmt.bind(1, Time.now)
#  or you can specify time string.
# stmt.bind(1, '07:39:45')


260
261
262
263
264
# File 'lib/duckdb/prepared_statement.rb', line 260

def bind_time(index, value)
  time = _parse_time(value)

  _bind_time(index, time.hour, time.min, time.sec, time.usec)
end

#bind_timestamp(index, value) ⇒ Object

binds i-th parameter with SQL prepared statement. The first argument is index of parameter. The index of first parameter is 1 not 0. The second argument value is to expected time value.

require 'duckdb'
db = DuckDB::Database.open('duckdb_database')
con = db.connect
sql ='SELECT name FROM users WHERE created_at = ?'
stmt = PreparedStatement.new(con, sql)
stmt.bind(1, Time.now)
#  or you can specify timestamp string.
# stmt.bind(1, '2022-02-23 07:39:45')


279
280
281
282
283
# File 'lib/duckdb/prepared_statement.rb', line 279

def bind_timestamp(index, value)
  time = _parse_time(value)

  _bind_timestamp(index, time.year, time.month, time.day, time.hour, time.min, time.sec, time.usec)
end

#bind_timestamp_tz(index, value) ⇒ Object

binds i-th parameter of TIMESTAMP WITH TIME ZONE (TIMESTAMPTZ) type with SQL prepared statement. The first argument is index of parameter. The index of first parameter is 1 not 0. The second argument value is to expected time value.

require 'duckdb'
db = DuckDB::Database.open('duckdb_database')
con = db.connect
sql ='SELECT name FROM users WHERE created_at = ?'
stmt = PreparedStatement.new(con, sql)
stmt.bind_timestamp_tz(1, Time.now)
#  or you can specify timestamp string.
# stmt.bind_timestamp_tz(1, '2022-02-23 07:39:45+00')


298
299
300
301
# File 'lib/duckdb/prepared_statement.rb', line 298

def bind_timestamp_tz(index, value)
  time = _parse_time(value).utc
  _bind_timestamp_tz(index, time.year, time.month, time.day, time.hour, time.min, time.sec, time.usec)
end

#bind_uhugeint(index, value) ⇒ Object

binds i-th parameter with SQL prepared statement. The first argument is index of parameter. The index of first parameter is 1 not 0. The second argument value must be Integer value. This method uses duckdb_bind_uhugeint internally.

require 'duckdb'
db = DuckDB::Database.open('duckdb_database')
con = db.connect
sql ='SELECT name FROM users WHERE uhugeint_col = ?'
stmt = PreparedStatement.new(con, sql)
stmt.bind_uhugeint(1, (2**128) - 1)


206
207
208
209
# File 'lib/duckdb/prepared_statement.rb', line 206

def bind_uhugeint(index, value)
  lower, upper = integer_to_hugeint(value)
  _bind_uhugeint(index, lower, upper)
end

#bind_uint16(index, val) ⇒ Object

binds i-th parameter with SQL prepared statement. The first argument is index of parameter. The index of first parameter is 1 not 0. The second argument value is to expected Integer value between 0 to 65535.

Raises:



129
130
131
132
133
# File 'lib/duckdb/prepared_statement.rb', line 129

def bind_uint16(index, val)
  return _bind_uint16(index, val) if val.between?(0, 65_535)

  raise DuckDB::Error, "can't bind uint16(bind_uint16) to `#{val}`. The `#{val}` is out of range 0..65535."
end

#bind_uint32(index, val) ⇒ Object

binds i-th parameter with SQL prepared statement. The first argument is index of parameter. The index of first parameter is 1 not 0. The second argument value is to expected Integer value between 0 to 4294967295.

Raises:



139
140
141
142
143
# File 'lib/duckdb/prepared_statement.rb', line 139

def bind_uint32(index, val)
  return _bind_uint32(index, val) if val.between?(0, 4_294_967_295)

  raise DuckDB::Error, "can't bind uint32(bind_uint32) to `#{val}`. The `#{val}` is out of range 0..4294967295."
end

#bind_uint64(index, val) ⇒ Object

binds i-th parameter with SQL prepared statement. The first argument is index of parameter. The index of first parameter is 1 not 0. The second argument value is to expected Integer value between 0 to 18446744073709551615.

Raises:



149
150
151
152
153
154
# File 'lib/duckdb/prepared_statement.rb', line 149

def bind_uint64(index, val)
  return _bind_uint64(index, val) if val.between?(0, 18_446_744_073_709_551_615)

  raise DuckDB::Error,
        "can't bind uint64(bind_uint64) to `#{val}`. The `#{val}` is out of range 0..18446744073709551615."
end

#bind_uint8(index, val) ⇒ Object

binds i-th parameter with SQL prepared statement. The first argument is index of parameter. The index of first parameter is 1 not 0. The second argument value is to expected Integer value between 0 to 255.

Raises:



119
120
121
122
123
# File 'lib/duckdb/prepared_statement.rb', line 119

def bind_uint8(index, val)
  return _bind_uint8(index, val) if val.between?(0, 255)

  raise DuckDB::Error, "can't bind uint8(bind_uint8) to `#{val}`. The `#{val}` is out of range 0..255."
end

#bind_uuid(index, value) ⇒ Object

binds i-th parameter with a UUID value. The first argument is the index of the parameter (1-based). The second argument must be a String in canonical UUID format (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx). Raises ArgumentError if the value is not a valid UUID string.

require 'duckdb'
db = DuckDB::Database.open
con = db.connect
con.query('CREATE TABLE uuids (id UUID)')
stmt = DuckDB::PreparedStatement.new(con, 'INSERT INTO uuids(id) VALUES ($1)')
stmt.bind_uuid(1, '550e8400-e29b-41d4-a716-446655440000')
stmt.execute


224
225
226
# File 'lib/duckdb/prepared_statement.rb', line 224

def bind_uuid(index, value)
  _bind_uuid(index, value)
end

#bind_value(index, value) ⇒ Object

binds i-th parameter with SQL prepared statement. The first argument is index of parameter. The index of first parameter is 1 not 0. The second argument value must be a DuckDB::Value instance.

require 'duckdb'
db = DuckDB::Database.open('duckdb_database')
con = db.connect
sql ='SELECT col_boolean FROM booleans WHERE col_boolean = ?'
stmt = PreparedStatement.new(con, sql)
stmt.bind_value(1, DuckDB::Value.create_bool(true))

Raises:

  • (ArgumentError)


349
350
351
352
353
354
# File 'lib/duckdb/prepared_statement.rb', line 349

def bind_value(index, value)
  raise ArgumentError, '2nd argument must be DuckDB::Value' unless value.is_a?(DuckDB::Value)

  _bind_value(index, value)
  self
end

#bind_varchar(vidx, str) ⇒ Object



345
346
347
348
349
350
351
352
353
354
355
# File 'ext/duckdb/prepared_statement.c', line 345

static VALUE prepared_statement_bind_varchar(VALUE self, VALUE vidx, VALUE str) {
    rubyDuckDBPreparedStatement *ctx;
    idx_t idx = check_index(vidx);

    TypedData_Get_Struct(self, rubyDuckDBPreparedStatement, &prepared_statement_data_type, ctx);

    if (duckdb_bind_varchar(ctx->prepared_statement, idx, StringValuePtr(str)) == DuckDBError) {
        rb_raise(eDuckDBError, "fail to bind %llu parameter", (unsigned long long)idx);
    }
    return self;
}

#clear_bindingsDuckDB::PreparedStatement

clear all bindings of prepared statement.



240
241
242
243
244
245
246
247
248
249
# File 'ext/duckdb/prepared_statement.c', line 240

static VALUE prepared_statement_clear_bindings(VALUE self) {
    rubyDuckDBPreparedStatement *ctx;
    TypedData_Get_Struct(self, rubyDuckDBPreparedStatement, &prepared_statement_data_type, ctx);

    if (duckdb_clear_bindings(ctx->prepared_statement) == DuckDBError) {
        const char *error = duckdb_prepare_error(ctx->prepared_statement);
        rb_raise(eDuckDBError, "fail to clear bindings. %s", error);
    }
    return self;
}

#column_countInteger

Returns the number of columns in the result set of the prepared statement without executing it.

require 'duckdb'
db = DuckDB::Database.open
con = db.connect
stmt = con.prepared_statement('SELECT 1 AS a, 2 AS b')
stmt.column_count # => 2

Returns:

  • (Integer)


401
402
403
404
405
# File 'ext/duckdb/prepared_statement.c', line 401

static VALUE prepared_statement_column_count(VALUE self) {
    rubyDuckDBPreparedStatement *ctx;
    TypedData_Get_Struct(self, rubyDuckDBPreparedStatement, &prepared_statement_data_type, ctx);
    return ULL2NUM(duckdb_prepared_statement_column_count(ctx->prepared_statement));
}

#column_logical_type(col_index) ⇒ DuckDB::LogicalType

Returns the logical type of the column at the specified index (0-based) of the result set of the prepared statement without executing it. Raises DuckDB::Error if the column index is out of range.

require 'duckdb'
db = DuckDB::Database.open
con = db.connect
stmt = con.prepared_statement('SELECT 1.5::DECIMAL(9, 4) AS a')
stmt.column_logical_type(0).type # => :decimal

Returns:



459
460
461
462
463
464
465
466
467
468
469
470
471
# File 'ext/duckdb/prepared_statement.c', line 459

static VALUE prepared_statement_column_logical_type(VALUE self, VALUE vidx) {
    rubyDuckDBPreparedStatement *ctx;
    duckdb_logical_type logical_type;
    idx_t idx = NUM2ULL(vidx);

    TypedData_Get_Struct(self, rubyDuckDBPreparedStatement, &prepared_statement_data_type, ctx);

    logical_type = duckdb_prepared_statement_column_logical_type(ctx->prepared_statement, idx);
    if (logical_type == NULL) {
        rb_raise(eDuckDBError, "fail to get column logical type at %llu. column index is out of range.", (unsigned long long)idx);
    }
    return rbduckdb_create_logical_type(logical_type);
}

#column_name(col_index) ⇒ String

Returns the name of the column at the specified index (0-based) of the result set of the prepared statement without executing it. Raises DuckDB::Error if the column index is out of range.

require 'duckdb'
db = DuckDB::Database.open
con = db.connect
stmt = con.prepared_statement('SELECT 1 AS a, 2 AS b')
stmt.column_name(1) # => 'b'

Returns:

  • (String)


421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
# File 'ext/duckdb/prepared_statement.c', line 421

static VALUE prepared_statement_column_name(VALUE self, VALUE vidx) {
    rubyDuckDBPreparedStatement *ctx;
    VALUE vname;
    const char *name;
    idx_t idx = NUM2ULL(vidx);

    TypedData_Get_Struct(self, rubyDuckDBPreparedStatement, &prepared_statement_data_type, ctx);

    name = duckdb_prepared_statement_column_name(ctx->prepared_statement, idx);
    if (name == NULL) {
        rb_raise(eDuckDBError, "fail to get column name at %llu. column index is out of range.", (unsigned long long)idx);
    }
    vname = rb_str_new2(name);
    duckdb_free((void *)name);
    return vname;
}

#column_type(index) ⇒ Object

returns the column type of the result set of the prepared statement without executing it. The argument is the column index (0-based). Returns :invalid if the column index is out of range.

require 'duckdb'
db = DuckDB::Database.open
con = db.connect
con.execute('CREATE TABLE users (id INTEGER, name VARCHAR(255))')
stmt = con.prepared_statement('SELECT * FROM users')
stmt.column_type(0) # => :integer


89
90
91
92
# File 'lib/duckdb/prepared_statement.rb', line 89

def column_type(index)
  i = _column_type(index)
  Converter::IntToSym.type_to_sym(i)
end

#destroyObject

:nodoc:



165
166
167
168
169
170
171
172
173
# File 'ext/duckdb/prepared_statement.c', line 165

static VALUE prepared_statement_destroy(VALUE self) {
    rubyDuckDBPreparedStatement *ctx;
    TypedData_Get_Struct(self, rubyDuckDBPreparedStatement, &prepared_statement_data_type, ctx);
    destroy_prepared_statement(ctx);
    /*
    ctx->prepared_statement = NULL;
    */
    return Qnil;
}

#executeObject



132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
# File 'ext/duckdb/prepared_statement.c', line 132

static VALUE prepared_statement_execute(VALUE self) {
    rubyDuckDBPreparedStatement *ctx;
    rubyDuckDBResult *ctxr;
    const char *error;
    VALUE result = rbduckdb_create_result();

    TypedData_Get_Struct(self, rubyDuckDBPreparedStatement, &prepared_statement_data_type, ctx);
    ctxr = rbduckdb_get_struct_result(result);

    prepared_statement_execute_nogvl_args args = {
        .prepared_statement = ctx->prepared_statement,
        .out_result = &(ctxr->result),
        .retval = DuckDBError,
    };

    rb_thread_call_without_gvl((void *)prepared_statement_execute_nogvl, &args, RUBY_UBF_IO, 0);
    duckdb_state state = args.retval;

    if (state == DuckDBError) {
        error = duckdb_prepare_error(args.prepared_statement);
        if (error == NULL) {
            /* error originates from the result, which carries an error type */
            rbduckdb_raise_result_error(args.out_result);
        }
        rb_raise(eDuckDBError, "%s", error);
    }

    return result;
}

#nparamsObject



112
113
114
115
116
# File 'ext/duckdb/prepared_statement.c', line 112

static VALUE prepared_statement_nparams(VALUE self) {
    rubyDuckDBPreparedStatement *ctx;
    TypedData_Get_Struct(self, rubyDuckDBPreparedStatement, &prepared_statement_data_type, ctx);
    return ULL2NUM(duckdb_nparams(ctx->prepared_statement));
}

#param_logical_type(param_index) ⇒ DuckDB::LogicalType

Returns the logical type of the parameter at the given (1-based) index. This provides richer type information than #param_type, e.g. decimal width/scale, nested types.

Returns:



220
221
222
223
224
225
226
227
228
229
230
231
232
# File 'ext/duckdb/prepared_statement.c', line 220

static VALUE prepared_statement_param_logical_type(VALUE self, VALUE vidx) {
    rubyDuckDBPreparedStatement *ctx;
    duckdb_logical_type logical_type;
    idx_t idx = check_index(vidx);

    TypedData_Get_Struct(self, rubyDuckDBPreparedStatement, &prepared_statement_data_type, ctx);

    logical_type = duckdb_param_logical_type(ctx->prepared_statement, idx);
    if (logical_type == NULL) {
        rb_raise(eDuckDBError, "fail to get logical type of the parameter at %llu. parameter index is out of range.", (unsigned long long)idx);
    }
    return rbduckdb_create_logical_type(logical_type);
}

#param_type(index) ⇒ Object

returns parameter type. The argument must be index of parameter.

require 'duckdb'
db = DuckDB::Database.open
con = db.connect
con.execute('CREATE TABLE users (id INTEGER, name VARCHAR(255))')
stmt = con.prepared_statement('SELECT * FROM users WHERE id = ?')
stmt.param_type(1) # => :integer


74
75
76
77
# File 'lib/duckdb/prepared_statement.rb', line 74

def param_type(index)
  i = _param_type(index)
  Converter::IntToSym.type_to_sym(i)
end

#parameter_name(vidx) ⇒ Object



195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
# File 'ext/duckdb/prepared_statement.c', line 195

static VALUE prepared_statement_parameter_name(VALUE self, VALUE vidx) {
    rubyDuckDBPreparedStatement *ctx;
    VALUE vname;
    const char *name;
    idx_t idx = check_index(vidx);

    TypedData_Get_Struct(self, rubyDuckDBPreparedStatement, &prepared_statement_data_type, ctx);

    name = duckdb_parameter_name(ctx->prepared_statement, idx);
    if (name == NULL) {
        rb_raise(eDuckDBError, "fail to get name of %llu parameter", (unsigned long long)idx);
    }
    vname = rb_str_new2(name);
    duckdb_free((void *)name);
    return vname;
}

#pending_preparedObject



46
47
48
# File 'lib/duckdb/prepared_statement.rb', line 46

def pending_prepared
  PendingResult.new(self)
end

#statement_typeObject

returns statement type. The return value is one of the following symbols: :invalid, :select, :insert, :update, :explain, :delete, :prepare, :create, :execute, :alter, :transaction, :copy, :analyze, :variable_set, :create_func, :drop, :export, :pragma, :vacuum, :call, :set, :load, :relation, :extension, :logical_plan, :attach, :detach, :multi

require 'duckdb'
db = DuckDB::Database.open('duckdb_database')
con = db.connect
stmt = con.prepared_statement('SELECT * FROM users')
stmt.statement_type # => :select


61
62
63
64
# File 'lib/duckdb/prepared_statement.rb', line 61

def statement_type
  i = _statement_type
  Converter::IntToSym.statement_type_to_sym(i)
end