mysql2
mysql2 copied to clipboard
I can't see a way to get the field table names
Is there a way to get the field table names from a query. I have a lot of multi table queries, where different tables have the same field names. When I do a query with :as => :hash, I lose fields. I can get all the row results with :as=>:array, but the fields array doesn't have the table names, so I can't tell an id from an id, or a site_name from a site_name.
The table names are in the c structure MYSQL_FIELD, both as *tables (might be an alias), and as *org_table. I just don't see a way to get to them from ruby. An rb_mysql_result_tables equivalent to rb_mysql_result_fields would help. Otherwise I need to rewrite a lot of queries adding 'as name' in the SELECT statements.
Tried it myself, and this works
Added to the typedef for struct mysql2_result_wrapper in result.h
VALUE tables;
Added to result.c
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_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; i<wrapper->numberOfFields; i++) {
rb_mysql_result_fetch_table(self, i);
}
}
return wrapper->tables;
}
In rb_mysql_result_to_obj() added
wrapper->tables = Qnil;
In init_mysql2_result() added
rb_define_method(cMysql2Result, "tables", rb_mysql_result_fetch_tables, 0);
Not sure if I should have added to rb_mysql_result_mark()
rb_gc_mark(w->tables);
That looks like an interesting addition if you would consider opening a PR?
How do I open a PR?
I think I have created a proposal. It shows up as pull request 1267
It created a fork [email protected]:rbur004/mysql2.git, which I cloned and made the changes to added access to the array of MYSQL_FIELD char * table entries, as a Ruby Array of Strings.
Great! Next step is to click this button Open Pull Request ->
I think I went through that step successfully. It is awaiting approval
I just added a couple of simple tests to specs/mysql2/result_spec.rb
They are clones of the 'fields' test, and only cover the very simple case of one table and one database. To get a better test, a second table would need to be added to the test database, and a second test database created.