build and use a cache of field names for results

This commit is contained in:
Brian Lopez 2010-04-22 11:56:18 -07:00
parent aa9f435141
commit c05138e328
2 changed files with 35 additions and 26 deletions

View File

@ -273,7 +273,7 @@ static VALUE rb_mysql_result_to_obj(MYSQL_RES * r) {
obj = Data_Make_Struct(cMysql2Result, mysql2_result_wrapper, rb_mysql_result_mark, rb_mysql_result_free, wrapper); obj = Data_Make_Struct(cMysql2Result, mysql2_result_wrapper, rb_mysql_result_mark, rb_mysql_result_free, wrapper);
wrapper->numberOfFields = 0; wrapper->numberOfFields = 0;
wrapper->numberOfRows = 0; wrapper->numberOfRows = 0;
wrapper->lastRow = 0; wrapper->lastRowProcessed = 0;
wrapper->resultFreed = 0; wrapper->resultFreed = 0;
wrapper->result = r; wrapper->result = r;
rb_obj_call_init(obj, 0, NULL); rb_obj_call_init(obj, 0, NULL);
@ -291,7 +291,7 @@ void rb_mysql_result_free(void * wrapper) {
void rb_mysql_result_mark(void * wrapper) { void rb_mysql_result_mark(void * wrapper) {
mysql2_result_wrapper * w = wrapper; mysql2_result_wrapper * w = wrapper;
if (w) { if (w) {
rb_gc_mark(w->fieldList); rb_gc_mark(w->fields);
rb_gc_mark(w->rows); rb_gc_mark(w->rows);
} }
} }
@ -300,9 +300,9 @@ static VALUE rb_mysql_result_fetch_row(int argc, VALUE * argv, VALUE self) {
VALUE rowHash, opts, block; VALUE rowHash, opts, block;
mysql2_result_wrapper * wrapper; mysql2_result_wrapper * wrapper;
MYSQL_ROW row; MYSQL_ROW row;
MYSQL_FIELD * fields; MYSQL_FIELD * fields = NULL;
struct tm parsedTime; struct tm parsedTime;
unsigned int i = 0, numFields = 0, symbolizeKeys = 0; unsigned int i = 0, symbolizeKeys = 0;
unsigned long * fieldLengths; unsigned long * fieldLengths;
GetMysql2Result(self, wrapper); GetMysql2Result(self, wrapper);
@ -319,24 +319,34 @@ static VALUE rb_mysql_result_fetch_row(int argc, VALUE * argv, VALUE self) {
return Qnil; return Qnil;
} }
numFields = mysql_num_fields(wrapper->result); if (wrapper->numberOfFields == 0) {
fieldLengths = mysql_fetch_lengths(wrapper->result); wrapper->numberOfFields = mysql_num_fields(wrapper->result);
fields = mysql_fetch_fields(wrapper->result); wrapper->fields = rb_ary_new2(wrapper->numberOfFields);
}
rowHash = rb_hash_new(); rowHash = rb_hash_new();
for (i = 0; i < numFields; i++) { fields = mysql_fetch_fields(wrapper->result);
VALUE key; fieldLengths = mysql_fetch_lengths(wrapper->result);
if (symbolizeKeys) { for (i = 0; i < wrapper->numberOfFields; i++) {
char buf[fields[i].name_length+1];
memcpy(buf, fields[i].name, fields[i].name_length); // lazily create fields, but only once
buf[fields[i].name_length] = 0; // we'll use cached versions from here on out
key = ID2SYM(rb_intern(buf)); VALUE field = rb_ary_entry(wrapper->fields, i);
} else { if (field == Qnil) {
key = rb_str_new(fields[i].name, fields[i].name_length); if (symbolizeKeys) {
char buf[fields[i].name_length+1];
memcpy(buf, fields[i].name, fields[i].name_length);
buf[fields[i].name_length] = 0;
field = ID2SYM(rb_intern(buf));
} else {
field = rb_str_new(fields[i].name, fields[i].name_length);
#ifdef HAVE_RUBY_ENCODING_H #ifdef HAVE_RUBY_ENCODING_H
rb_enc_associate_index(key, utf8Encoding); rb_enc_associate_index(field, utf8Encoding);
#endif #endif
}
rb_ary_store(wrapper->fields, i, field);
} }
if (row[i]) { if (row[i]) {
VALUE val; VALUE val;
switch(fields[i].type) { switch(fields[i].type) {
@ -408,9 +418,9 @@ static VALUE rb_mysql_result_fetch_row(int argc, VALUE * argv, VALUE self) {
#endif #endif
break; break;
} }
rb_hash_aset(rowHash, key, val); rb_hash_aset(rowHash, field, val);
} else { } else {
rb_hash_aset(rowHash, key, Qnil); rb_hash_aset(rowHash, field, Qnil);
} }
} }
return rowHash; return rowHash;
@ -425,7 +435,7 @@ static VALUE rb_mysql_result_each(int argc, VALUE * argv, VALUE self) {
rb_scan_args(argc, argv, "01&", &opts, &block); rb_scan_args(argc, argv, "01&", &opts, &block);
if (wrapper->lastRow == 0) { if (wrapper->lastRowProcessed == 0) {
wrapper->numberOfRows = mysql_num_rows(wrapper->result); wrapper->numberOfRows = mysql_num_rows(wrapper->result);
if (wrapper->numberOfRows == 0) { if (wrapper->numberOfRows == 0) {
return Qnil; return Qnil;
@ -433,7 +443,7 @@ static VALUE rb_mysql_result_each(int argc, VALUE * argv, VALUE self) {
wrapper->rows = rb_ary_new2(wrapper->numberOfRows); wrapper->rows = rb_ary_new2(wrapper->numberOfRows);
} }
if (wrapper->lastRow == wrapper->numberOfRows) { if (wrapper->lastRowProcessed == wrapper->numberOfRows) {
// we've already read the entire dataset from the C result into our // we've already read the entire dataset from the C result into our
// internal array. Lets hand that over to the user since it's ready to go // internal array. Lets hand that over to the user since it's ready to go
for (i = 0; i < wrapper->numberOfRows; i++) { for (i = 0; i < wrapper->numberOfRows; i++) {
@ -449,7 +459,7 @@ static VALUE rb_mysql_result_each(int argc, VALUE * argv, VALUE self) {
} else { } else {
row = rb_mysql_result_fetch_row(argc, argv, self); row = rb_mysql_result_fetch_row(argc, argv, self);
rb_ary_store(wrapper->rows, i, row); rb_ary_store(wrapper->rows, i, row);
wrapper->lastRow++; wrapper->lastRowProcessed++;
} }
if (row == Qnil) { if (row == Qnil) {
@ -462,7 +472,7 @@ static VALUE rb_mysql_result_each(int argc, VALUE * argv, VALUE self) {
rb_yield(row); rb_yield(row);
} }
} }
if (wrapper->lastRow == wrapper->numberOfRows) { if (wrapper->lastRowProcessed == wrapper->numberOfRows) {
// we don't need the mysql C dataset around anymore, peace it // we don't need the mysql C dataset around anymore, peace it
rb_mysql_result_free(wrapper); rb_mysql_result_free(wrapper);
} }

View File

@ -44,12 +44,11 @@ void rb_mysql_client_free(void * client);
/* Mysql2::Result */ /* Mysql2::Result */
typedef struct { typedef struct {
VALUE fieldList; VALUE fields;
VALUE rows; VALUE rows;
unsigned long numberOfFields; unsigned long numberOfFields;
int *types;
unsigned long numberOfRows; unsigned long numberOfRows;
unsigned long lastRow; unsigned long lastRowProcessed;
int resultFreed; int resultFreed;
MYSQL_RES *result; MYSQL_RES *result;
} mysql2_result_wrapper; } mysql2_result_wrapper;