ext/duckdb/result.c in duckdb-0.3.4.0 vs ext/duckdb/result.c in duckdb-0.5.0

- old
+ new

@@ -2,46 +2,81 @@ static VALUE cDuckDBResult; static void deallocate(void *ctx); static VALUE allocate(VALUE klass); +static size_t memsize(const void *p); static VALUE to_ruby_obj_boolean(duckdb_result *result, idx_t col_idx, idx_t row_idx); static VALUE to_ruby_obj_smallint(duckdb_result *result, idx_t col_idx, idx_t row_idx); +static VALUE to_ruby_obj_utinyint(duckdb_result *result, idx_t col_idx, idx_t row_idx); static VALUE to_ruby_obj_integer(duckdb_result *result, idx_t col_idx, idx_t row_idx); static VALUE to_ruby_obj_bigint(duckdb_result *result, idx_t col_idx, idx_t row_idx); static VALUE to_ruby_obj_float(duckdb_result *result, idx_t col_idx, idx_t row_idx); static VALUE to_ruby_obj_double(duckdb_result *result, idx_t col_idx, idx_t row_idx); -static VALUE to_ruby_obj_string_from_blob(duckdb_result *result, idx_t col_idx, idx_t row_idx); -static VALUE to_ruby_obj(duckdb_result *result, idx_t col_idx, idx_t row_idx); -static VALUE row_array(rubyDuckDBResult *ctx, idx_t row_idx); -static VALUE duckdb_result_row_size(VALUE oDuckDBResult, VALUE args, VALUE obj); -static VALUE duckdb_result_each(VALUE oDuckDBResult); +static VALUE to_ruby_obj_blob(duckdb_result *result, idx_t col_idx, idx_t row_idx); +static VALUE duckdb_result_column_count(VALUE oDuckDBResult); +static VALUE duckdb_result_row_count(VALUE oDuckDBResult); static VALUE duckdb_result_rows_changed(VALUE oDuckDBResult); static VALUE duckdb_result_columns(VALUE oDuckDBResult); +static VALUE duckdb_result__column_type(VALUE oDuckDBResult, VALUE col_idx); +static VALUE duckdb_result__is_null(VALUE oDuckDBResult, VALUE row_idx, VALUE col_idx); +static VALUE duckdb_result__to_boolean(VALUE oDuckDBResult, VALUE row_idx, VALUE col_idx); +static VALUE duckdb_result__to_smallint(VALUE oDuckDBResult, VALUE row_idx, VALUE col_idx); +static VALUE duckdb_result__to_utinyint(VALUE oDuckDBResult, VALUE row_idx, VALUE col_idx); +static VALUE duckdb_result__to_integer(VALUE oDuckDBResult, VALUE row_idx, VALUE col_idx); +static VALUE duckdb_result__to_bigint(VALUE oDuckDBResult, VALUE row_idx, VALUE col_idx); +static VALUE duckdb_result__to_float(VALUE oDuckDBResult, VALUE row_idx, VALUE col_idx); +static VALUE duckdb_result__to_double(VALUE oDuckDBResult, VALUE row_idx, VALUE col_idx); +static VALUE duckdb_result__to_string(VALUE oDuckDBResult, VALUE row_idx, VALUE col_idx); +static VALUE duckdb_result__to_blob(VALUE oDuckDBResult, VALUE row_idx, VALUE col_idx); +static VALUE duckdb_result__enum_internal_type(VALUE oDuckDBResult, VALUE col_idx); +static VALUE duckdb_result__enum_dictionary_size(VALUE oDuckDBResult, VALUE col_idx); +static VALUE duckdb_result__enum_dictionary_value(VALUE oDuckDBResult, VALUE col_idx, VALUE idx); +static const rb_data_type_t result_data_type = { + "DuckDB/Result", + {NULL, deallocate, memsize,}, + 0, 0, RUBY_TYPED_FREE_IMMEDIATELY +}; + static void deallocate(void *ctx) { rubyDuckDBResult *p = (rubyDuckDBResult *)ctx; duckdb_destroy_result(&(p->result)); xfree(p); } static VALUE allocate(VALUE klass) { rubyDuckDBResult *ctx = xcalloc((size_t)1, sizeof(rubyDuckDBResult)); - return Data_Wrap_Struct(klass, NULL, deallocate, ctx); + return TypedData_Wrap_Struct(klass, &result_data_type, ctx); } +static size_t memsize(const void *p) { + return sizeof(rubyDuckDBResult); +} + +rubyDuckDBResult *get_struct_result(VALUE obj) { + rubyDuckDBResult *ctx; + TypedData_Get_Struct(obj, rubyDuckDBResult, &result_data_type, ctx); + return ctx; +} + static VALUE to_ruby_obj_boolean(duckdb_result *result, idx_t col_idx, idx_t row_idx) { bool bval = duckdb_value_boolean(result, col_idx, row_idx); return bval ? Qtrue : Qnil; } static VALUE to_ruby_obj_smallint(duckdb_result *result, idx_t col_idx, idx_t row_idx) { int16_t i16val = duckdb_value_int16(result, col_idx, row_idx); return INT2FIX(i16val); } +static VALUE to_ruby_obj_utinyint(duckdb_result *result, idx_t col_idx, idx_t row_idx) { + uint8_t ui8val = duckdb_value_uint8(result, col_idx, row_idx); + return UINT2NUM(ui8val); +} + static VALUE to_ruby_obj_integer(duckdb_result *result, idx_t col_idx, idx_t row_idx) { int32_t i32val = duckdb_value_int32(result, col_idx, row_idx); return INT2NUM(i32val); } @@ -58,11 +93,11 @@ static VALUE to_ruby_obj_double(duckdb_result *result, idx_t col_idx, idx_t row_idx) { double dval = duckdb_value_double(result, col_idx, row_idx); return DBL2NUM(dval); } -static VALUE to_ruby_obj_string_from_blob(duckdb_result *result, idx_t col_idx, idx_t row_idx) { +static VALUE to_ruby_obj_blob(duckdb_result *result, idx_t col_idx, idx_t row_idx) { VALUE str; duckdb_blob bval = duckdb_value_blob(result, col_idx, row_idx); str = rb_str_new(bval.data, bval.size); if (bval.data) { @@ -70,77 +105,10 @@ } return str; } -static VALUE to_ruby_obj(duckdb_result *result, idx_t col_idx, idx_t row_idx) { - char *p; - VALUE obj = Qnil; - if (duckdb_value_is_null(result, col_idx, row_idx)) { - return obj; - } - switch(duckdb_column_type(result, col_idx)) { - case DUCKDB_TYPE_BOOLEAN: - return to_ruby_obj_boolean(result, col_idx, row_idx); - case DUCKDB_TYPE_SMALLINT: - return to_ruby_obj_smallint(result, col_idx, row_idx); - case DUCKDB_TYPE_INTEGER: - return to_ruby_obj_integer(result, col_idx, row_idx); - case DUCKDB_TYPE_BIGINT: - return to_ruby_obj_bigint(result, col_idx, row_idx); - case DUCKDB_TYPE_FLOAT: - return to_ruby_obj_float(result, col_idx, row_idx); - case DUCKDB_TYPE_DOUBLE: - return to_ruby_obj_double(result, col_idx, row_idx); - case DUCKDB_TYPE_BLOB: - return to_ruby_obj_string_from_blob(result, col_idx, row_idx); - default: - p = duckdb_value_varchar(result, col_idx, row_idx); - if (p) { - obj = rb_str_new2(p); - duckdb_free(p); - if (duckdb_column_type(result, col_idx) == DUCKDB_TYPE_HUGEINT) { - obj = rb_funcall(obj, rb_intern("to_i"), 0); - } - } - } - return obj; -} - -static VALUE row_array(rubyDuckDBResult *ctx, idx_t row_idx) { - idx_t col_idx; - idx_t column_count = duckdb_column_count(&(ctx->result)); - - VALUE ary = rb_ary_new2(column_count); - for(col_idx = 0; col_idx < column_count; col_idx++) { - rb_ary_store(ary, col_idx, to_ruby_obj(&(ctx->result), col_idx, row_idx)); - } - return ary; -} - -static VALUE duckdb_result_row_size(VALUE oDuckDBResult, VALUE args, VALUE obj) { - rubyDuckDBResult *ctx; - Data_Get_Struct(oDuckDBResult, rubyDuckDBResult, ctx); - - return LONG2FIX(duckdb_row_count(&(ctx->result))); -} - -static VALUE duckdb_result_each(VALUE oDuckDBResult) { - rubyDuckDBResult *ctx; - idx_t row_idx = 0; - idx_t row_count = 0; - - RETURN_SIZED_ENUMERATOR(oDuckDBResult, 0, 0, duckdb_result_row_size); - - Data_Get_Struct(oDuckDBResult, rubyDuckDBResult, ctx); - row_count = duckdb_row_count(&(ctx->result)); - for (row_idx = 0; row_idx < row_count; row_idx++) { - rb_yield(row_array(ctx, row_idx)); - } - return oDuckDBResult; -} - /* * call-seq: * result.rows_changed -> integer * * Returns the count of rows changed. @@ -161,24 +129,72 @@ * end * */ static VALUE duckdb_result_rows_changed(VALUE oDuckDBResult) { rubyDuckDBResult *ctx; - Data_Get_Struct(oDuckDBResult, rubyDuckDBResult, ctx); + TypedData_Get_Struct(oDuckDBResult, rubyDuckDBResult, &result_data_type, ctx); return LL2NUM(duckdb_rows_changed(&(ctx->result))); } /* * call-seq: + * result.column_count -> Integer + * + * Returns the column size of the result. + * + * DuckDB::Database.open do |db| + * db.connect do |con| + * r = con.query('CREATE TABLE t2 (id INT, name VARCHAR(128))') + * r = con.query("INSERT INTO t2 VALUES (1, 'Alice'), (2, 'Bob'), (3, 'Catherine')") + * r = con.query('SELECT id FROM t2') + * r.column_count # => 1 + * r = con.query('SELECT id, name FROM t2') + * r.column_count # => 2 + * end + * end + * + */ +static VALUE duckdb_result_column_count(VALUE oDuckDBResult) { + rubyDuckDBResult *ctx; + TypedData_Get_Struct(oDuckDBResult, rubyDuckDBResult, &result_data_type, ctx); + return LL2NUM(duckdb_column_count(&(ctx->result))); +} + +/* + * call-seq: + * result.row_count -> Integer + * + * Returns the column size of the result. + * + * DuckDB::Database.open do |db| + * db.connect do |con| + * r = con.query('CREATE TABLE t2 (id INT, name VARCHAR(128))') + * r = con.query("INSERT INTO t2 VALUES (1, 'Alice'), (2, 'Bob'), (3, 'Catherine')") + * r = con.query('SELECT * FROM t2') + * r.row_count # => 3 + * r = con.query('SELECT * FROM t2 where id = 1') + * r.row_count # => 1 + * end + * end + * + */ +static VALUE duckdb_result_row_count(VALUE oDuckDBResult) { + rubyDuckDBResult *ctx; + TypedData_Get_Struct(oDuckDBResult, rubyDuckDBResult, &result_data_type, ctx); + return LL2NUM(duckdb_row_count(&(ctx->result))); +} + +/* + * call-seq: * result.columns -> DuckDB::Column[] * * Returns the column class Lists. * */ static VALUE duckdb_result_columns(VALUE oDuckDBResult) { rubyDuckDBResult *ctx; - Data_Get_Struct(oDuckDBResult, rubyDuckDBResult, ctx); + TypedData_Get_Struct(oDuckDBResult, rubyDuckDBResult, &result_data_type, ctx); idx_t col_idx; idx_t column_count = duckdb_column_count(&(ctx->result)); VALUE ary = rb_ary_new2(column_count); @@ -187,17 +203,162 @@ rb_ary_store(ary, col_idx, column); } return ary; } +static VALUE duckdb_result__column_type(VALUE oDuckDBResult, VALUE col_idx) { + rubyDuckDBResult *ctx; + TypedData_Get_Struct(oDuckDBResult, rubyDuckDBResult, &result_data_type, ctx); + return LL2NUM(duckdb_column_type(&(ctx->result), NUM2LL(col_idx))); +} + +static VALUE duckdb_result__is_null(VALUE oDuckDBResult, VALUE row_idx, VALUE col_idx) { + rubyDuckDBResult *ctx; + bool is_null; + TypedData_Get_Struct(oDuckDBResult, rubyDuckDBResult, &result_data_type, ctx); + + is_null = duckdb_value_is_null(&(ctx->result), NUM2LL(col_idx), NUM2LL(row_idx)); + return is_null ? Qtrue : Qfalse; +} + +static VALUE duckdb_result__to_boolean(VALUE oDuckDBResult, VALUE row_idx, VALUE col_idx) { + rubyDuckDBResult *ctx; + TypedData_Get_Struct(oDuckDBResult, rubyDuckDBResult, &result_data_type, ctx); + + return to_ruby_obj_boolean(&(ctx->result), NUM2LL(col_idx), NUM2LL(row_idx)) ? Qtrue : Qfalse; +} + +static VALUE duckdb_result__to_smallint(VALUE oDuckDBResult, VALUE row_idx, VALUE col_idx) { + rubyDuckDBResult *ctx; + TypedData_Get_Struct(oDuckDBResult, rubyDuckDBResult, &result_data_type, ctx); + + return to_ruby_obj_smallint(&(ctx->result), NUM2LL(col_idx), NUM2LL(row_idx)); +} + +static VALUE duckdb_result__to_utinyint(VALUE oDuckDBResult, VALUE row_idx, VALUE col_idx) { + rubyDuckDBResult *ctx; + TypedData_Get_Struct(oDuckDBResult, rubyDuckDBResult, &result_data_type, ctx); + + return to_ruby_obj_utinyint(&(ctx->result), NUM2LL(col_idx), NUM2LL(row_idx)); +} + +static VALUE duckdb_result__to_integer(VALUE oDuckDBResult, VALUE row_idx, VALUE col_idx) { + rubyDuckDBResult *ctx; + TypedData_Get_Struct(oDuckDBResult, rubyDuckDBResult, &result_data_type, ctx); + + return to_ruby_obj_integer(&(ctx->result), NUM2LL(col_idx), NUM2LL(row_idx)); +} + +static VALUE duckdb_result__to_bigint(VALUE oDuckDBResult, VALUE row_idx, VALUE col_idx) { + rubyDuckDBResult *ctx; + TypedData_Get_Struct(oDuckDBResult, rubyDuckDBResult, &result_data_type, ctx); + + return to_ruby_obj_bigint(&(ctx->result), NUM2LL(col_idx), NUM2LL(row_idx)); +} + +static VALUE duckdb_result__to_float(VALUE oDuckDBResult, VALUE row_idx, VALUE col_idx) { + rubyDuckDBResult *ctx; + TypedData_Get_Struct(oDuckDBResult, rubyDuckDBResult, &result_data_type, ctx); + + return to_ruby_obj_float(&(ctx->result), NUM2LL(col_idx), NUM2LL(row_idx)); +} + +static VALUE duckdb_result__to_double(VALUE oDuckDBResult, VALUE row_idx, VALUE col_idx) { + rubyDuckDBResult *ctx; + TypedData_Get_Struct(oDuckDBResult, rubyDuckDBResult, &result_data_type, ctx); + + return to_ruby_obj_double(&(ctx->result), NUM2LL(col_idx), NUM2LL(row_idx)); +} + +static VALUE duckdb_result__to_string(VALUE oDuckDBResult, VALUE row_idx, VALUE col_idx) { + rubyDuckDBResult *ctx; + char *p; + VALUE obj; + TypedData_Get_Struct(oDuckDBResult, rubyDuckDBResult, &result_data_type, ctx); + + p = duckdb_value_varchar(&(ctx->result), NUM2LL(col_idx), NUM2LL(row_idx)); + if (p) { + obj = rb_utf8_str_new_cstr(p); + duckdb_free(p); + return obj; + } + return Qnil; +} + +static VALUE duckdb_result__to_blob(VALUE oDuckDBResult, VALUE row_idx, VALUE col_idx) { + rubyDuckDBResult *ctx; + TypedData_Get_Struct(oDuckDBResult, rubyDuckDBResult, &result_data_type, ctx); + + return to_ruby_obj_blob(&(ctx->result), NUM2LL(col_idx), NUM2LL(row_idx)); +} + +static VALUE duckdb_result__enum_internal_type(VALUE oDuckDBResult, VALUE col_idx) { + rubyDuckDBResult *ctx; + VALUE type = Qnil; + duckdb_logical_type logical_type; + + TypedData_Get_Struct(oDuckDBResult, rubyDuckDBResult, &result_data_type, ctx); + logical_type = duckdb_column_logical_type(&(ctx->result), NUM2LL(col_idx)); + if (logical_type) { + type = LL2NUM(duckdb_enum_internal_type(logical_type)); + } + return type; +} + +static VALUE duckdb_result__enum_dictionary_size(VALUE oDuckDBResult, VALUE col_idx) { + rubyDuckDBResult *ctx; + VALUE size = Qnil; + duckdb_logical_type logical_type; + + TypedData_Get_Struct(oDuckDBResult, rubyDuckDBResult, &result_data_type, ctx); + logical_type = duckdb_column_logical_type(&(ctx->result), NUM2LL(col_idx)); + if (logical_type) { + size = UINT2NUM(duckdb_enum_dictionary_size(logical_type)); + } + return size; +} + +static VALUE duckdb_result__enum_dictionary_value(VALUE oDuckDBResult, VALUE col_idx, VALUE idx) { + rubyDuckDBResult *ctx; + VALUE value = Qnil; + duckdb_logical_type logical_type; + char *p; + + TypedData_Get_Struct(oDuckDBResult, rubyDuckDBResult, &result_data_type, ctx); + logical_type = duckdb_column_logical_type(&(ctx->result), NUM2LL(col_idx)); + if (logical_type) { + p = duckdb_enum_dictionary_value(logical_type, NUM2LL(idx)); + if (p) { + value = rb_utf8_str_new_cstr(p); + duckdb_free(p); + } + } + return value; +} + VALUE create_result(void) { return allocate(cDuckDBResult); } void init_duckdb_result(void) { cDuckDBResult = rb_define_class_under(mDuckDB, "Result", rb_cObject); rb_define_alloc_func(cDuckDBResult, allocate); - rb_define_method(cDuckDBResult, "each", duckdb_result_each, 0); + rb_define_method(cDuckDBResult, "column_count", duckdb_result_column_count, 0); + rb_define_method(cDuckDBResult, "row_count", duckdb_result_row_count, 0); rb_define_method(cDuckDBResult, "rows_changed", duckdb_result_rows_changed, 0); rb_define_method(cDuckDBResult, "columns", duckdb_result_columns, 0); + rb_define_private_method(cDuckDBResult, "_column_type", duckdb_result__column_type, 1); + rb_define_private_method(cDuckDBResult, "_null?", duckdb_result__is_null, 2); + rb_define_private_method(cDuckDBResult, "_to_boolean", duckdb_result__to_boolean, 2); + rb_define_private_method(cDuckDBResult, "_to_smallint", duckdb_result__to_smallint, 2); + rb_define_private_method(cDuckDBResult, "_to_utinyint", duckdb_result__to_utinyint, 2); + rb_define_private_method(cDuckDBResult, "_to_integer", duckdb_result__to_integer, 2); + rb_define_private_method(cDuckDBResult, "_to_bigint", duckdb_result__to_bigint, 2); + rb_define_private_method(cDuckDBResult, "_to_float", duckdb_result__to_float, 2); + rb_define_private_method(cDuckDBResult, "_to_double", duckdb_result__to_double, 2); + rb_define_private_method(cDuckDBResult, "_to_string", duckdb_result__to_string, 2); + rb_define_private_method(cDuckDBResult, "_to_blob", duckdb_result__to_blob, 2); + rb_define_private_method(cDuckDBResult, "_enum_internal_type", duckdb_result__enum_internal_type, 1); + rb_define_private_method(cDuckDBResult, "_enum_dictionary_size", duckdb_result__enum_dictionary_size, 1); + rb_define_private_method(cDuckDBResult, "_enum_dictionary_value", duckdb_result__enum_dictionary_value, 2); }