Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 0 additions & 33 deletions contrib/ruby/Gemfile.lock

This file was deleted.

15 changes: 10 additions & 5 deletions contrib/ruby/ext/trilogy-ruby/cast.c
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,8 @@ rb_trilogy_cast_value(const trilogy_value_t *value, const struct column_info *co
if (column->decimals == 0 && !options->cast_decimals_to_bigdecimals) {
return rb_funcall(rb_mKernel, id_Integer, 1, str);
} else {
return rb_funcall(rb_mKernel, id_BigDecimal, 1, str);
VALUE bigdecimal = rb_funcall(rb_mKernel, id_BigDecimal, 1, str);
return rb_trilogy_shareable(bigdecimal, options);
}
}
case TRILOGY_TYPE_FLOAT:
Expand Down Expand Up @@ -311,8 +312,9 @@ rb_trilogy_cast_value(const trilogy_value_t *value, const struct column_info *co
rb_raise(Trilogy_CastError, "Invalid date: %.*s", (int)value->data_len, (char *)value->data);
}

return trilogy_make_time(year, month, day, hour, min, sec, usec,
VALUE time = trilogy_make_time(year, month, day, hour, min, sec, usec,
options->database_local_time);
return rb_trilogy_shareable(time, options);
}
case TRILOGY_TYPE_DATE: {
const char *p = (const char *)value->data;
Expand Down Expand Up @@ -343,7 +345,8 @@ rb_trilogy_cast_value(const trilogy_value_t *value, const struct column_info *co
rb_raise(Trilogy_CastError, "Invalid date: %.*s", (int)value->data_len, (char *)value->data);
}

return rb_funcall(Date, id_new, 3, INT2NUM(year), INT2NUM(month), INT2NUM(day));
VALUE date = rb_funcall(Date, id_new, 3, INT2NUM(year), INT2NUM(month), INT2NUM(day));
return rb_trilogy_shareable(date, options);
}
case TRILOGY_TYPE_TIME: {
const char *p = (const char *)value->data;
Expand Down Expand Up @@ -375,16 +378,18 @@ rb_trilogy_cast_value(const trilogy_value_t *value, const struct column_info *co
return Qnil;
}

return trilogy_make_time(2000, 1, 1, hour, min, sec, usec,
VALUE time = trilogy_make_time(2000, 1, 1, hour, min, sec, usec,
options->database_local_time);
return rb_trilogy_shareable(time, options);
}
default:
break;
}
}

// for all other types, just return a string
return rb_enc_str_new(value->data, value->data_len, encoding_for_charset(column->charset));
VALUE string = rb_enc_str_new(value->data, value->data_len, encoding_for_charset(column->charset));
return rb_trilogy_shareable(string, options);
}

void rb_trilogy_cast_init(void)
Expand Down
19 changes: 16 additions & 3 deletions contrib/ruby/ext/trilogy-ruby/cext.c
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ static ID id_socket, id_host, id_port, id_username, id_password, id_found_rows,
id_password, id_database, id_enable_cleartext_plugin,
id_ssl_ca, id_ssl_capath, id_ssl_cert, id_ssl_cipher, id_ssl_crl, id_ssl_crlpath, id_ssl_key,
id_ssl_mode, id_tls_ciphersuites, id_tls_min_version, id_tls_max_version, id_multi_statement, id_multi_result,
id_from_code, id_from_errno, id_max_allowed_packet;
id_from_code, id_from_errno, id_max_allowed_packet, id_shareable;

struct trilogy_ctx {
trilogy_conn_t conn;
Expand Down Expand Up @@ -764,6 +764,10 @@ static VALUE rb_trilogy_connect(VALUE self, VALUE raw_socket, VALUE encoding, VA
connopt.tls_max_version = NUM2INT(val);
}

if (RTEST(rb_hash_aref(opts, ID2SYM(id_shareable)))) {
ctx->query_flags |= TRILOGY_FLAGS_CAST_SHAREABLE;
}

VALUE io = rb_io_get_io(raw_socket);

rb_io_t *fptr;
Expand Down Expand Up @@ -880,6 +884,7 @@ static void load_query_options(unsigned int query_flags, struct rb_trilogy_cast_
cast_options->cast_decimals_to_bigdecimals = (query_flags & TRILOGY_FLAGS_CAST_ALL_DECIMALS_TO_BIGDECIMALS) != 0;
cast_options->database_local_time = (query_flags & TRILOGY_FLAGS_LOCAL_TIMEZONE) != 0;
cast_options->flatten_rows = (query_flags & TRILOGY_FLAGS_FLATTEN_ROWS) != 0;
cast_options->shareable = (query_flags & TRILOGY_FLAGS_CAST_SHAREABLE) != 0;
}

struct read_query_response_state {
Expand Down Expand Up @@ -990,6 +995,7 @@ static VALUE read_query_response(VALUE vargs)
row_ruby_values[i] = rb_enc_str_new(column.name, column.name_len, ctx->encoding);
OBJ_FREEZE(row_ruby_values[i]);
#endif
rb_trilogy_shareable(row_ruby_values[i], args->cast_options);

column_info[i].type = column.type;
column_info[i].flags = column.flags;
Expand All @@ -999,6 +1005,7 @@ static VALUE read_query_response(VALUE vargs)
}

column_names = rb_ary_new_from_values(column_count, row_ruby_values);
rb_trilogy_shareable(column_names, args->cast_options);

VALUE rb_trilogy_values;
trilogy_value_t *row_trilogy_values = ALLOCV_N(trilogy_value_t, rb_trilogy_values, column_count);
Expand Down Expand Up @@ -1029,16 +1036,19 @@ static VALUE read_query_response(VALUE vargs)
if (args->cast_options->flatten_rows) {
rb_ary_cat(rows, row_ruby_values, column_count);
} else {
rb_ary_push(rows, rb_ary_new_from_values(column_count, row_ruby_values));
VALUE row = rb_ary_new_from_values(column_count, row_ruby_values);
rb_ary_push(rows, rb_trilogy_shareable(row, args->cast_options));
}
}

rb_trilogy_shareable(rows, args->cast_options);

ALLOCV_END(rb_column_info);
ALLOCV_END(rb_trilogy_values);
ALLOCV_END(rb_ruby_values);
}

return rb_class_new_instance(
VALUE result = rb_class_new_instance(
6,
(VALUE []){
column_names,
Expand All @@ -1050,6 +1060,7 @@ static VALUE read_query_response(VALUE vargs)
},
Trilogy_Result
);
return rb_trilogy_shareable(result, args->cast_options);
}

static VALUE execute_read_query_response(struct trilogy_ctx *ctx)
Expand Down Expand Up @@ -1415,6 +1426,7 @@ RUBY_FUNC_EXPORTED void Init_cext(void)
rb_define_const(Trilogy, "QUERY_FLAGS_CAST", INT2NUM(TRILOGY_FLAGS_CAST));
rb_define_const(Trilogy, "QUERY_FLAGS_CAST_BOOLEANS", INT2NUM(TRILOGY_FLAGS_CAST_BOOLEANS));
rb_define_const(Trilogy, "QUERY_FLAGS_CAST_ALL_DECIMALS_TO_BIGDECIMALS", INT2NUM(TRILOGY_FLAGS_CAST_ALL_DECIMALS_TO_BIGDECIMALS));
rb_define_const(Trilogy, "QUERY_FLAGS_CAST_SHAREABLE", INT2NUM(TRILOGY_FLAGS_CAST_SHAREABLE));
rb_define_const(Trilogy, "QUERY_FLAGS_LOCAL_TIMEZONE", INT2NUM(TRILOGY_FLAGS_LOCAL_TIMEZONE));
rb_define_const(Trilogy, "QUERY_FLAGS_FLATTEN_ROWS", INT2NUM(TRILOGY_FLAGS_FLATTEN_ROWS));
rb_define_const(Trilogy, "QUERY_FLAGS_DEFAULT", INT2NUM(TRILOGY_FLAGS_DEFAULT));
Expand Down Expand Up @@ -1483,6 +1495,7 @@ RUBY_FUNC_EXPORTED void Init_cext(void)
id_multi_result = rb_intern("multi_result");
id_from_code = rb_intern("from_code");
id_from_errno = rb_intern("from_errno");
id_shareable = rb_intern("shareable");

rb_trilogy_cast_init();

Expand Down
1 change: 1 addition & 0 deletions contrib/ruby/ext/trilogy-ruby/extconf.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,6 @@
have_func("rb_ractor_local_storage_value_newkey", "ruby.h")
have_func("rb_enc_interned_str", "ruby.h")
have_func("rb_io_descriptor", "ruby.h") # Ruby 3.1+
# have_func("rb_obj_set_shareable", "ruby/ractor.h")

create_makefile "trilogy/cext"
16 changes: 16 additions & 0 deletions contrib/ruby/ext/trilogy-ruby/trilogy-ruby.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#define TRILOGY_RUBY_H

#include <ruby.h>
#include <ruby/ractor.h>
#include <trilogy_xallocator.h>
#include <trilogy.h>

Expand All @@ -12,6 +13,7 @@
#define TRILOGY_FLAGS_LOCAL_TIMEZONE 4
#define TRILOGY_FLAGS_FLATTEN_ROWS 8
#define TRILOGY_FLAGS_CAST_ALL_DECIMALS_TO_BIGDECIMALS 16
#define TRILOGY_FLAGS_CAST_SHAREABLE 32
#define TRILOGY_FLAGS_DEFAULT (TRILOGY_FLAGS_CAST)

struct rb_trilogy_cast_options {
Expand All @@ -20,6 +22,7 @@ struct rb_trilogy_cast_options {
bool database_local_time;
bool flatten_rows;
bool cast_decimals_to_bigdecimals;
bool shareable;
};

struct column_info {
Expand All @@ -32,6 +35,19 @@ struct column_info {

extern VALUE Trilogy_CastError;

static inline VALUE rb_trilogy_shareable(VALUE obj, const struct rb_trilogy_cast_options *cast_options)
{
if (cast_options->shareable) {
RB_OBJ_SET_FROZEN_SHAREABLE(obj);
// OBJ_FREEZE(obj);
// #ifdef RB_OBJ_SET_SHAREABLE
// VALUE rb_obj_set_shareable(VALUE);
// rb_obj_set_shareable(obj);
// #endif
}
return obj;
}

VALUE
rb_trilogy_cast_value(const trilogy_value_t *value, const struct column_info *column,
const struct rb_trilogy_cast_options *options);
Expand Down
10 changes: 10 additions & 0 deletions contrib/ruby/script/benchmark
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,16 @@ Benchmark.ips do |x|
x.compare!
end

baseline = Trilogy.new(connect_options)
shareable = Trilogy.new(connect_options.merge(shareable: true))

Benchmark.ips do |x|
x.report("baseline") { Ractor.make_shareable(baseline.query("SELECT * FROM trilogy_test")) }
x.report("shareable") { Ractor.make_shareable(shareable.query("SELECT * FROM trilogy_test")) }
x.compare!(order: :baseline)
end


QUERY = "SELECT 1"

Benchmark.ips do |x|
Expand Down
6 changes: 6 additions & 0 deletions contrib/ruby/test/client_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1268,6 +1268,12 @@ def test_is_ractor_compatible
end
assert_equal [[1]], ractor.value.to_a
end

def test_shareable_result
client = new_tcp_client(shareable: true)
result = client.query("SELECT * FROM test.trilogy_test")
assert_predicate result, :frozen?
end
end

if defined?(Process.fork)
Expand Down
Loading