From cee05c5d2c0733d84dfb448d173a62ddb57ed5a5 Mon Sep 17 00:00:00 2001 From: robertburrowes Date: Sat, 28 May 2022 18:12:22 +1200 Subject: [PATCH 1/5] Added accessor methods for MYSQL_FIELD char * table and char *db --- ext/mysql2/result.c | 116 +++++++++++++++++++++++++++++++++++++++++++- ext/mysql2/result.h | 2 + 2 files changed, 116 insertions(+), 2 deletions(-) diff --git a/ext/mysql2/result.c b/ext/mysql2/result.c index 314cecdaa..760fe514d 100644 --- a/ext/mysql2/result.c +++ b/ext/mysql2/result.c @@ -62,6 +62,8 @@ static void rb_mysql_result_mark(void * wrapper) { mysql2_result_wrapper * w = wrapper; if (w) { rb_gc_mark(w->fields); + rb_gc_mark(w->tables); + rb_gc_mark(w->dbs); rb_gc_mark(w->rows); rb_gc_mark(w->encoding); rb_gc_mark(w->client); @@ -190,6 +192,74 @@ static VALUE rb_mysql_result_fetch_field(VALUE self, unsigned int idx, int symbo return rb_field; } +static VALUE rb_mysql_result_fetch_table(VALUE self, unsigned int idx) { + VALUE rb_table; + GET_RESULT(self); + + if (wrapper->tables == Qnil) { + wrapper->numberOfFields = mysql_num_fields(wrapper->result); + wrapper->tables = rb_ary_new2(wrapper->numberOfFields); + } + + rb_table = rb_ary_entry(wrapper->tables, idx); + if (rb_table == Qnil) { + MYSQL_FIELD *field = NULL; + rb_encoding *default_internal_enc = rb_default_internal_encoding(); + rb_encoding *conn_enc = rb_to_encoding(wrapper->encoding); + + field = mysql_fetch_field_direct(wrapper->result, idx); +#ifdef HAVE_RB_ENC_INTERNED_STR + rb_table = rb_enc_interned_str(field->table, field->table_length, conn_enc); + if (default_internal_enc && default_internal_enc != conn_enc) { + rb_table = rb_str_to_interned_str(rb_str_export_to_enc(rb_table, default_internal_enc)); + } +#else + rb_table = rb_enc_str_new(field->table, field->table_length, conn_enc); + if (default_internal_enc && default_internal_enc != conn_enc) { + rb_table = rb_str_export_to_enc(rb_table, default_internal_enc); + } + rb_obj_freeze(rb_table); +#endif + rb_ary_store(wrapper->tables, idx, rb_table); + } + + return rb_table; +} + +static VALUE rb_mysql_result_fetch_db(VALUE self, unsigned int idx) { + VALUE rb_db; + GET_RESULT(self); + + if (wrapper->dbs == Qnil) { + wrapper->numberOfFields = mysql_num_fields(wrapper->result); + wrapper->dbs = rb_ary_new2(wrapper->numberOfFields); + } + + rb_db = rb_ary_entry(wrapper->dbs, idx); + if (rb_db == Qnil) { + MYSQL_FIELD *field = NULL; + rb_encoding *default_internal_enc = rb_default_internal_encoding(); + rb_encoding *conn_enc = rb_to_encoding(wrapper->encoding); + + field = mysql_fetch_field_direct(wrapper->result, idx); +#ifdef HAVE_RB_ENC_INTERNED_STR + rb_db = rb_enc_interned_str(field->db, field->db_length, conn_enc); + if (default_internal_enc && default_internal_enc != conn_enc) { + rb_db = rb_str_to_interned_str(rb_str_export_to_enc(rb_db, default_internal_enc)); + } +#else + rb_db = rb_enc_str_new(field->db, field->db_length, conn_enc); + if (default_internal_enc && default_internal_enc != conn_enc) { + rb_db = rb_str_export_to_enc(rb_db, default_internal_enc); + } + rb_obj_freeze(rb_db); +#endif + rb_ary_store(wrapper->dbs, idx, rb_db); + } + + return rb_db; +} + static VALUE rb_mysql_result_fetch_field_type(VALUE self, unsigned int idx) { VALUE rb_field_type; GET_RESULT(self); @@ -365,7 +435,7 @@ static VALUE mysql2_set_field_string_encoding(VALUE val, MYSQL_FIELD field, rb_e int enc_index; enc_name = (field.charsetnr-1 < MYSQL2_CHARSETNR_SIZE) ? mysql2_mysql_enc_to_rb[field.charsetnr-1] : NULL; - + if (enc_name != NULL) { /* use the field encoding we were able to match */ enc_index = rb_enc_find_index(enc_name); @@ -899,6 +969,44 @@ static VALUE rb_mysql_result_fetch_fields(VALUE self) { return wrapper->fields; } +static VALUE rb_mysql_result_fetch_tables(VALUE self) { + unsigned int i = 0; + + GET_RESULT(self); + + if (wrapper->tables == Qnil) { + wrapper->numberOfFields = mysql_num_fields(wrapper->result); + wrapper->tables = rb_ary_new2(wrapper->numberOfFields); + } + + if ((my_ulonglong)RARRAY_LEN(wrapper->tables) != wrapper->numberOfFields) { + for (i=0; inumberOfFields; i++) { + rb_mysql_result_fetch_table(self, i); + } + } + + return wrapper->tables; +} + +static VALUE rb_mysql_result_fetch_dbs(VALUE self) { + unsigned int i = 0; + + GET_RESULT(self); + + if (wrapper->dbs == Qnil) { + wrapper->numberOfFields = mysql_num_fields(wrapper->result); + wrapper->dbs = rb_ary_new2(wrapper->numberOfFields); + } + + if ((my_ulonglong)RARRAY_LEN(wrapper->dbs) != wrapper->numberOfFields) { + for (i=0; inumberOfFields; i++) { + rb_mysql_result_fetch_db(self, i); + } + } + + return wrapper->dbs; +} + static VALUE rb_mysql_result_fetch_field_types(VALUE self) { unsigned int i = 0; @@ -1137,6 +1245,8 @@ VALUE rb_mysql_result_to_obj(VALUE client, VALUE encoding, VALUE options, MYSQL_ wrapper->result = r; wrapper->fields = Qnil; wrapper->fieldTypes = Qnil; + wrapper->tables = Qnil; + wrapper->dbs = Qnil; wrapper->rows = Qnil; wrapper->encoding = encoding; wrapper->streamingComplete = 0; @@ -1176,9 +1286,11 @@ void init_mysql2_result() { cMysql2Result = rb_define_class_under(mMysql2, "Result", rb_cObject); rb_undef_alloc_func(cMysql2Result); rb_global_variable(&cMysql2Result); - + rb_define_method(cMysql2Result, "each", rb_mysql_result_each, -1); rb_define_method(cMysql2Result, "fields", rb_mysql_result_fetch_fields, 0); + rb_define_method(cMysql2Result, "tables", rb_mysql_result_fetch_tables, 0); + rb_define_method(cMysql2Result, "dbs", rb_mysql_result_fetch_dbs, 0); rb_define_method(cMysql2Result, "field_types", rb_mysql_result_fetch_field_types, 0); rb_define_method(cMysql2Result, "free", rb_mysql_result_free_, 0); rb_define_method(cMysql2Result, "count", rb_mysql_result_count, 0); diff --git a/ext/mysql2/result.h b/ext/mysql2/result.h index 3f58b1005..d5a19642f 100644 --- a/ext/mysql2/result.h +++ b/ext/mysql2/result.h @@ -7,6 +7,8 @@ VALUE rb_mysql_result_to_obj(VALUE client, VALUE encoding, VALUE options, MYSQL_ typedef struct { VALUE fields; VALUE fieldTypes; + VALUE tables; + VALUE dbs; VALUE rows; VALUE client; VALUE encoding; From a7295eea01e99832ec9a4cb001dcb30dca1022d3 Mon Sep 17 00:00:00 2001 From: Rob Burrowes Date: Wed, 15 Jun 2022 14:24:59 +1200 Subject: [PATCH 2/5] Tests for attribute accessors result.tables and result.dbs --- spec/mysql2/result_spec.rb | 41 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/spec/mysql2/result_spec.rb b/spec/mysql2/result_spec.rb index ed3e9d262..c80c817f3 100644 --- a/spec/mysql2/result_spec.rb +++ b/spec/mysql2/result_spec.rb @@ -207,6 +207,47 @@ end end + context "#tables" do + let(:test_result) { @client.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1") } + + it "method should exist" do + expect(test_result).to respond_to(:tables) + end + + it "should return an array of table names in proper order" do + result = @client.query("SELECT id, bit_test, single_bit_test FROM mysql2_test ORDER BY id DESC LIMIT 1") + expect(result.tables).to eql(%w[mysql2_test mysql2_test mysql2_test]) + end + + it "should return an array of frozen strings" do + result = @client.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1") + result.tables.each do |f| + expect(f).to be_frozen + end + end + end + + context "#dbs" do + let(:test_result) { @client.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1") } + + it "method should exist" do + expect(test_result).to respond_to(:dbs) + end + + it "should return an array of database names in proper order" do + db = DatabaseCredentials['root']['database'] + result = @client.query( "SELECT id, bit_test, single_bit_test FROM mysql2_test ORDER BY id DESC LIMIT 1" ) + expect(result.dbs).to eql([db,db,db]) + end + + it "should return an array of frozen strings" do + result = @client.query ""SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1"" + result.dbs.each do |f| + expect(f).to be_frozen + end + end + end + context "streaming" do it "should maintain a count while streaming" do result = @client.query('SELECT 1', stream: true, cache_rows: false) From e3b74f34f7490aad88f6edaaf9438fba84c08a81 Mon Sep 17 00:00:00 2001 From: robertburrowes Date: Thu, 16 Jun 2022 19:45:12 +1200 Subject: [PATCH 3/5] Pasted quotes inside quotes --- spec/mysql2/result_spec.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/spec/mysql2/result_spec.rb b/spec/mysql2/result_spec.rb index c80c817f3..d07d84956 100644 --- a/spec/mysql2/result_spec.rb +++ b/spec/mysql2/result_spec.rb @@ -220,8 +220,8 @@ end it "should return an array of frozen strings" do - result = @client.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1") - result.tables.each do |f| + result = @client.query "SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1" + result.fields.each do |f| expect(f).to be_frozen end end @@ -241,7 +241,7 @@ end it "should return an array of frozen strings" do - result = @client.query ""SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1"" + result = @client.query "SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1" result.dbs.each do |f| expect(f).to be_frozen end From 1cc348421f6856baa3d3ec03ff25ea2b1f0608e2 Mon Sep 17 00:00:00 2001 From: robertburrowes Date: Thu, 16 Jun 2022 20:00:14 +1200 Subject: [PATCH 4/5] rubocop cleanup --- spec/mysql2/result_spec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/mysql2/result_spec.rb b/spec/mysql2/result_spec.rb index d07d84956..9ad138985 100644 --- a/spec/mysql2/result_spec.rb +++ b/spec/mysql2/result_spec.rb @@ -236,8 +236,8 @@ it "should return an array of database names in proper order" do db = DatabaseCredentials['root']['database'] - result = @client.query( "SELECT id, bit_test, single_bit_test FROM mysql2_test ORDER BY id DESC LIMIT 1" ) - expect(result.dbs).to eql([db,db,db]) + result = @client.query("SELECT id, bit_test, single_bit_test FROM mysql2_test ORDER BY id DESC LIMIT 1") + expect(result.dbs).to eql([db, db, db]) end it "should return an array of frozen strings" do From 254b00edb9929650bc7b0823efc714b9adcce1a5 Mon Sep 17 00:00:00 2001 From: robertburrowes Date: Thu, 16 Jun 2022 20:20:03 +1200 Subject: [PATCH 5/5] fields should have been tables. It was, then I broke it. --- spec/mysql2/result_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/mysql2/result_spec.rb b/spec/mysql2/result_spec.rb index 9ad138985..b9964ff6c 100644 --- a/spec/mysql2/result_spec.rb +++ b/spec/mysql2/result_spec.rb @@ -221,7 +221,7 @@ it "should return an array of frozen strings" do result = @client.query "SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1" - result.fields.each do |f| + result.tables.each do |f| expect(f).to be_frozen end end