ext/tiny_tds/result.c in tiny_tds-0.1.0 vs ext/tiny_tds/result.c in tiny_tds-0.2.0

- old
+ new

@@ -21,24 +21,24 @@ rb_enc_associate(_val, rwrap->encoding); \ _val; \ }) #else #define ENCODED_STR_NEW(_data, _len) \ - rb_str_new((char *)_data, (long)_len); + rb_str_new((char *)_data, (long)_len) #define ENCODED_STR_NEW2(_data2) \ - rb_str_new2((char *)_data2); + rb_str_new2((char *)_data2) #endif // Lib Backend (Memory Management) static void rb_tinytds_result_mark(void *ptr) { tinytds_result_wrapper *rwrap = (tinytds_result_wrapper *)ptr; if (rwrap) { rb_gc_mark(rwrap->local_offset); rb_gc_mark(rwrap->fields); - rb_gc_mark(rwrap->rows); + rb_gc_mark(rwrap->results); } } static void rb_tinytds_result_free(void *ptr) { tinytds_result_wrapper *rwrap = (tinytds_result_wrapper *)ptr; @@ -48,14 +48,14 @@ VALUE rb_tinytds_new_result_obj(DBPROCESS *c) { VALUE obj; tinytds_result_wrapper *rwrap; obj = Data_Make_Struct(cTinyTdsResult, tinytds_result_wrapper, rb_tinytds_result_mark, rb_tinytds_result_free, rwrap); rwrap->client = c; - rwrap->return_code = 0; rwrap->local_offset = Qnil; rwrap->fields = Qnil; - rwrap->rows = Qnil; + rwrap->results = Qnil; + rwrap->number_of_results = 0; rwrap->number_of_fields = 0; rwrap->number_of_rows = 0; rb_obj_call_init(obj, 0, NULL); return obj; } @@ -64,29 +64,14 @@ // Lib Backend (Helpers) static VALUE rb_tinytds_result_fetch_row(VALUE self, ID timezone, int symbolize_keys, int as_array) { /* Wrapper And Local Vars */ GET_RESULT_WRAPPER(self); - VALUE row; - unsigned int i = 0; - /* One-Time Fields Info & Container */ - if (NIL_P(rwrap->fields)) { - rwrap->number_of_fields = dbnumcols(rwrap->client); - rwrap->fields = rb_ary_new2(rwrap->number_of_fields); - for (i = 0; i < rwrap->number_of_fields; i++) { - char *colname = dbcolname(rwrap->client, i+1); - VALUE field = symbolize_keys ? ID2SYM(rb_intern(colname)) : rb_obj_freeze(rb_str_new2(colname)); - rb_ary_store(rwrap->fields, i, field); - } - } /* Create Empty Row */ - if (as_array) { - row = rb_ary_new2(rwrap->number_of_fields); - } else { - row = rb_hash_new(); - } + VALUE row = as_array ? rb_ary_new2(rwrap->number_of_fields) : rb_hash_new(); /* Storing Values */ + unsigned int i = 0; for (i = 0; i < rwrap->number_of_fields; i++) { VALUE val = Qnil; int col = i+1; int coltype = dbcoltype(rwrap->client, col); BYTE *data = dbdata(rwrap->client, col); @@ -150,17 +135,21 @@ #ifdef HAVE_RUBY_ENCODING_H rb_enc_associate(val, binaryEncoding); #endif break; case 36: { // SYBUNIQUE - char converted_unique[32]; - dbconvert(rwrap->client, coltype, data, 32, SYBVARCHAR, (BYTE *)converted_unique, -1); + char converted_unique[36]; + dbconvert(rwrap->client, coltype, data, data_len, SYBVARCHAR, (BYTE *)converted_unique, sizeof(converted_unique)); val = ENCODED_STR_NEW2(converted_unique); break; } - case SYBDATETIME4: - dbconvert(rwrap->client, coltype, data, data_len, SYBDATETIME, data, data_len); + case SYBDATETIME4: { + DBDATETIME new_data; + dbconvert(rwrap->client, coltype, data, data_len, SYBDATETIME, (BYTE *)&new_data, sizeof(new_data)); + data = (BYTE *)&new_data; + data_len = sizeof(new_data); + } case SYBDATETIME: { DBDATEREC date_rec; dbdatecrack(rwrap->client, &date_rec, (DBDATETIME *)data); int year = date_rec.year, month = date_rec.month, @@ -201,11 +190,17 @@ } } if (as_array) { rb_ary_store(row, i, val); } else { - rb_hash_aset(row, rb_ary_entry(rwrap->fields, i), val); + VALUE key; + if (rwrap->number_of_results == 0) { + key = rb_ary_entry(rwrap->fields, i); + } else { + key = rb_ary_entry(rb_ary_entry(rwrap->fields, rwrap->number_of_results), i); + } + rb_hash_aset(row, key, val); } } return row; } @@ -240,47 +235,80 @@ timezone = intern_utc; } else { rb_warn(":timezone option must be :utc or :local - defaulting to :local"); timezone = intern_local; } - /* Make The Rows Or Yield Existing */ - if (NIL_P(rwrap->rows)) { - rwrap->rows = rb_ary_new(); - RETCODE return_code; - while (return_code != NO_MORE_RESULTS) { - return_code = dbresults(rwrap->client); - if (return_code != FAIL) { - /* If no actual rows, return the empty array. */ - if (DBROWS(rwrap->client) != SUCCEED) - return rwrap->rows; + /* Make The Results Or Yield Existing */ + if (NIL_P(rwrap->results)) { + rwrap->results = rb_ary_new(); + RETCODE dbresults_rc = 0; + dbresults_rc = dbresults(rwrap->client); + while (dbresults_rc == SUCCEED) { + /* Only do field and row work if there are rows in this result set. */ + int has_rows = (DBROWS(rwrap->client) == SUCCEED) ? 1 : 0; + int number_of_fields = has_rows ? dbnumcols(rwrap->client) : 0; + if (has_rows && (number_of_fields > 0)) { + /* Create fields for this result set. */ + unsigned int fldi = 0; + rwrap->number_of_fields = number_of_fields; + VALUE fields = rb_ary_new2(rwrap->number_of_fields); + for (fldi = 0; fldi < rwrap->number_of_fields; fldi++) { + char *colname = dbcolname(rwrap->client, fldi+1); + VALUE field = symbolize_keys ? ID2SYM(rb_intern(colname)) : rb_obj_freeze(ENCODED_STR_NEW2(colname)); + rb_ary_store(fields, fldi, field); + } + /* Store the fields. */ + if (rwrap->number_of_results == 0) { + rwrap->fields = fields; + } else if (rwrap->number_of_results == 1) { + VALUE multi_rs_fields = rb_ary_new(); + rb_ary_store(multi_rs_fields, 0, rwrap->fields); + rb_ary_store(multi_rs_fields, 1, fields); + rwrap->fields = multi_rs_fields; + } else { + rb_ary_store(rwrap->fields, rwrap->number_of_results, fields); + } + /* Create rows for this result set. */ unsigned long rowi = 0; + VALUE result = rb_ary_new(); while (dbnextrow(rwrap->client) != NO_MORE_ROWS) { VALUE row = rb_tinytds_result_fetch_row(self, timezone, symbolize_keys, as_array); if (cache_rows) - rb_ary_store(rwrap->rows, rowi, row); + rb_ary_store(result, rowi, row); if (!NIL_P(block)) rb_yield(row); if (first) dbcanquery(rwrap->client); rowi++; } rwrap->number_of_rows = rowi; - } else { - // TODO: Account for failed dbresults() must have returned FAIL. - rb_warn("TinyTds: dbresults() must have returned FAIL.\n"); + /* Store the result. */ + if (rwrap->number_of_results == 0) { + rwrap->results = result; + } else if (rwrap->number_of_results == 1) { + VALUE multi_resultsets = rb_ary_new(); + rb_ary_store(multi_resultsets, 0, rwrap->results); + rb_ary_store(multi_resultsets, 1, result); + rwrap->results = multi_resultsets; + } else { + rb_ary_store(rwrap->results, rwrap->number_of_results, result); + } + /* Record the result set */ + rwrap->number_of_results = rwrap->number_of_results + 1; } + dbresults_rc = dbresults(rwrap->client); } - if (return_code == FAIL) { + if (dbresults_rc == FAIL) { // TODO: Account for something in the dbresults() while loop set the return code to FAIL. rb_warn("TinyTds: Something in the dbresults() while loop set the return code to FAIL.\n"); } } else if (!NIL_P(block)) { unsigned long i; for (i = 0; i < rwrap->number_of_rows; i++) { - rb_yield(rb_ary_entry(rwrap->rows, i)); + rb_yield(rb_ary_entry(rwrap->results, i)); } } - return rwrap->rows; + return rwrap->results; } static VALUE rb_tinytds_result_fields(VALUE self) { GET_RESULT_WRAPPER(self); return rwrap->fields;