static VALUE rb_tinytds_result_fetch_row(VALUE self, ID timezone, int symbolize_keys, int as_array) { VALUE row; /* Storing Values */ unsigned int i; /* Wrapper And Local Vars */ GET_RESULT_WRAPPER(self); /* Create Empty Row */ row = as_array ? rb_ary_new2(rwrap->number_of_fields) : rb_hash_new(); 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); DBINT data_len = dbdatlen(rwrap->client, col); int null_val = ((data == NULL) && (data_len == 0)); if (!null_val) { switch(coltype) { case SYBINT1: val = INT2FIX(*(DBTINYINT *)data); break; case SYBINT2: val = INT2FIX(*(DBSMALLINT *)data); break; case SYBINT4: val = INT2NUM(*(DBINT *)data); break; case SYBINT8: val = LL2NUM(*(DBBIGINT *)data); break; case SYBBIT: val = *(int *)data ? Qtrue : Qfalse; break; case SYBNUMERIC: case SYBDECIMAL: { DBTYPEINFO *data_info = dbcoltypeinfo(rwrap->client, col); int data_slength = (int)data_info->precision + (int)data_info->scale + 1; char converted_decimal[data_slength]; dbconvert(rwrap->client, coltype, data, data_len, SYBVARCHAR, (BYTE *)converted_decimal, -1); val = rb_funcall(cBigDecimal, intern_new, 1, rb_str_new2((char *)converted_decimal)); break; } case SYBFLT8: { double col_to_double = *(double *)data; val = (col_to_double == 0.000000) ? opt_float_zero : rb_float_new(col_to_double); break; } case SYBREAL: { float col_to_float = *(float *)data; val = (col_to_float == 0.0) ? opt_float_zero : rb_float_new(col_to_float); break; } case SYBMONEY: { DBMONEY *money = (DBMONEY *)data; char converted_money[25]; long long money_value = ((long long)money->mnyhigh << 32) | money->mnylow; sprintf(converted_money, "%" LONG_LONG_FORMAT, money_value); val = rb_funcall(cBigDecimal, intern_new, 2, rb_str_new2(converted_money), opt_four); val = rb_funcall(val, intern_divide, 1, opt_tenk); break; } case SYBMONEY4: { DBMONEY4 *money = (DBMONEY4 *)data; char converted_money[20]; sprintf(converted_money, "%f", money->mny4 / 10000.0); val = rb_funcall(cBigDecimal, intern_new, 1, rb_str_new2(converted_money)); break; } case SYBBINARY: case SYBIMAGE: val = rb_str_new((char *)data, (long)data_len); #ifdef HAVE_RUBY_ENCODING_H rb_enc_associate(val, binaryEncoding); #endif break; case 36: { // SYBUNIQUE char converted_unique[37]; dbconvert(rwrap->client, coltype, data, 37, SYBVARCHAR, (BYTE *)converted_unique, -1); val = ENCODED_STR_NEW2(converted_unique); break; } 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 dr; dbdatecrack(rwrap->client, &dr, (DBDATETIME *)data); if (dr.year + dr.month + dr.day + dr.hour + dr.minute + dr.second + dr.millisecond != 0) { val = rb_funcall(rb_cTime, timezone, 7, INT2NUM(dr.year), INT2NUM(dr.month), INT2NUM(dr.day), INT2NUM(dr.hour), INT2NUM(dr.minute), INT2NUM(dr.second), INT2NUM(dr.millisecond*1000)); } break; } case 40: // SYBMSDATE case 41: // SYBMSTIME case 42: // SYBMSDATETIME2 case 43: { // SYBMSDATETIMEOFFSET #ifdef DBVERSION_73 if (dbtds(rwrap->client) >= DBTDS_7_3) { DBDATEREC2 dr2; dbanydatecrack(rwrap->client, &dr2, coltype, data); switch(coltype) { case 40: { // SYBMSDATE val = rb_funcall(cDate, intern_new, 3, INT2NUM(dr2.year), INT2NUM(dr2.month), INT2NUM(dr2.day)); break; } case 41: { // SYBMSTIME VALUE rational_nsec = rb_Rational(INT2NUM(dr2.nanosecond), opt_onek); val = rb_funcall(rb_cTime, timezone, 7, INT2NUM(1900), INT2NUM(1), INT2NUM(1), INT2NUM(dr2.hour), INT2NUM(dr2.minute), INT2NUM(dr2.second), rational_nsec); break; } case 42: { // SYBMSDATETIME2 VALUE rational_nsec = rb_Rational(INT2NUM(dr2.nanosecond), opt_onek); val = rb_funcall(rb_cTime, timezone, 7, INT2NUM(dr2.year), INT2NUM(dr2.month), INT2NUM(dr2.day), INT2NUM(dr2.hour), INT2NUM(dr2.minute), INT2NUM(dr2.second), rational_nsec); break; } case 43: { // SYBMSDATETIMEOFFSET long long numerator = ((long)dr2.second * (long long)1000000000) + (long long)dr2.nanosecond; VALUE rational_sec = rb_Rational(LL2NUM(numerator), opt_onebil); val = rb_funcall(rb_cTime, intern_new, 7, INT2NUM(dr2.year), INT2NUM(dr2.month), INT2NUM(dr2.day), INT2NUM(dr2.hour), INT2NUM(dr2.minute), rational_sec, INT2NUM(dr2.tzone*60)); break; } } } else { val = ENCODED_STR_NEW(data, data_len); } #else val = ENCODED_STR_NEW(data, data_len); #endif break; } case SYBCHAR: case SYBTEXT: val = ENCODED_STR_NEW(data, data_len); break; default: val = ENCODED_STR_NEW(data, data_len); break; } } if (as_array) { rb_ary_store(row, i, val); } else { 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; }
/* This procedure is called for every parsed field */ void end_of_field_callback(void * field, size_t field_size, void * data) { const char * field_str = (char *)field; struct rcsv_metadata * meta = (struct rcsv_metadata *) data; char row_conversion = 0; VALUE parsed_field; /* No need to parse anything until the end of the line if skip_current_row is set */ if (meta->skip_current_row) { return; } /* Skip the row if its position is less than specifed offset */ if (meta->current_row < meta->offset_rows) { meta->skip_current_row = true; return; } /* Get row conversion char specifier */ if (meta->current_col < meta->num_row_conversions) { row_conversion = (char)meta->row_conversions[meta->current_col]; } /* Convert the field from string into Ruby type specified by row_conversion */ if (row_conversion != ' ') { /* spacebar skips the column */ if (field_size == 0) { /* Assigning appropriate default value if applicable. */ if (meta->current_col < meta->num_row_defaults) { parsed_field = meta->row_defaults[meta->current_col]; } else { /* It depends on empty_field_is_nil if we convert empty strings to nils */ if (meta->empty_field_is_nil || field_str == NULL) { parsed_field = Qnil; } else { parsed_field = ENCODED_STR_NEW("", 0, meta->encoding_index); } } } else { if (meta->current_col < meta->num_row_conversions) { switch (row_conversion){ case 's': /* String */ parsed_field = ENCODED_STR_NEW(field_str, field_size, meta->encoding_index); break; case 'i': /* Integer */ parsed_field = LL2NUM(atoll(field_str)); break; case 'f': /* Float */ parsed_field = rb_float_new(atof(field_str)); break; case 'b': /* TrueClass/FalseClass */ switch (field_str[0]) { case 't': case 'T': case '1': parsed_field = Qtrue; break; case 'f': case 'F': case '0': parsed_field = Qfalse; break; default: RAISE_WITH_LOCATION( meta->current_row, meta->current_col, field_str, "Bad Boolean value. Valid values are strings where the first character is T/t/1 for true or F/f/0 for false." ); } break; default: RAISE_WITH_LOCATION( meta->current_row, meta->current_col, field_str, "Unknown deserializer '%c'.", row_conversion ); } } else { /* No conversion happens */ parsed_field = ENCODED_STR_NEW(field_str, field_size, meta->encoding_index); /* field */ } } /* Filter by row values listed in meta->only_rows */ if ((meta->only_rows != NULL) && (meta->current_col < meta->num_only_rows) && (meta->only_rows[meta->current_col] != Qnil) && (!rb_ary_includes(meta->only_rows[meta->current_col], parsed_field))) { meta->skip_current_row = true; return; } /* Filter out by row values listed in meta->except_rows */ if ((meta->except_rows != NULL) && (meta->current_col < meta->num_except_rows) && (meta->except_rows[meta->current_col] != Qnil) && (rb_ary_includes(meta->except_rows[meta->current_col], parsed_field))) { meta->skip_current_row = true; return; } /* Assign the value to appropriate hash key if parsing into Hash */ if (meta->row_as_hash) { if (meta->current_col >= meta->num_columns) { RAISE_WITH_LOCATION( meta->current_row, meta->current_col, field_str, "There are at least %d columns in a row, which is beyond the number of provided column names (%d).", (int)meta->current_col + 1, (int)meta->num_columns ); } else { rb_hash_aset(meta->last_entry, meta->column_names[meta->current_col], parsed_field); /* last_entry[column_names[current_col]] = field */ } } else { /* Parse into Array */ rb_ary_push(meta->last_entry, parsed_field); /* last_entry << field */ } } /* Increment column counter */ meta->current_col++; return; }