ext/result.cc in swift-0.13.0 vs ext/result.cc in swift-0.14.0
- old
+ new
@@ -1,13 +1,13 @@
#include "result.h"
+#include "datetime.h"
#include <math.h>
-VALUE cBigDecimal;
-VALUE cStringIO;
-VALUE cSwiftResult;
+#define date_parse(klass, data,len) rb_funcall(datetime_parse(klass, data, len), fto_date, 0)
-ID fnew, fto_date, fload;
+VALUE cBigDecimal, cStringIO, cSwiftResult;
+ID fnew, fload, fto_date;
void result_mark(ResultWrapper *handle) {
if (handle)
rb_gc_mark(handle->adapter);
}
@@ -55,18 +55,15 @@
rb_raise(eSwiftRuntimeError, "dup is not allowed.");
}
VALUE result_each(VALUE self) {
uint64_t length;
- const char *data, *tzstring;
+ const char *data;
dbi::AbstractResult *result = result_handle(self);
VALUE scheme = rb_iv_get(self, "@scheme");
- VALUE timezone = rb_iv_get(self, "@timezone");
- tzstring = NIL_P(timezone) ? 0 : CSTRING(timezone);
-
try {
std::vector<string> result_fields = result->fields();
std::vector<int> result_types = result->types();
std::vector<VALUE> fields;
for (uint32_t i = 0; i < result_fields.size(); i++)
@@ -79,11 +76,11 @@
data = (const char*)result->read(row, column, &length);
if (data) {
rb_hash_aset(
tuple,
fields[column],
- typecast_field(result_types[column], data, length, tzstring)
+ typecast_field(result_types[column], data, length)
);
}
else {
rb_hash_aset(tuple, fields[column], Qnil);
}
@@ -94,149 +91,22 @@
CATCH_DBI_EXCEPTIONS();
return Qnil;
}
-// Calculates local offset at a given time, including dst.
-int64_t client_tzoffset(int64_t local, int isdst) {
- struct tm tm;
- gmtime_r((const time_t*)&local, &tm);
- // TODO: This won't work in Lord Howe Island, Australia which uses half hour shift.
- return (int64_t)(local + (isdst ? 3600 : 0) - mktime(&tm));
-}
-
-// Calculates server offset at a given time, including dst.
-int64_t server_tzoffset(struct tm* tm, const char *zone) {
- uint64_t local;
- int64_t offset;
- char buffer[512];
- char *old, saved[512];
- struct tm tm_copy;
-
- // save current zone setting.
- if ((old = getenv("TZ"))) {
- strncpy(saved, old, 512);
- saved[511] = 0;
- }
-
- // setup.
- snprintf(buffer, 512, ":%s", zone);
- setenv("TZ", buffer, 1);
- tzset();
-
- // pretend we're on server timezone and calculate offset.
- memcpy(&tm_copy, tm, sizeof(struct tm));
- tm_copy.tm_isdst = -1;
- local = mktime(&tm_copy);
- offset = client_tzoffset(local, tm_copy.tm_isdst);
-
- // reset timezone to what it was before.
- old ? setenv("TZ", saved, 1) : unsetenv("TZ");
- tzset();
-
- return offset;
-}
-
-VALUE typecast_timestamp(const char *data, uint64_t len, const char *zone) {
- struct tm tm;
- uint64_t usec = 0;
- int64_t epoch, adjust, offset;
- char tzsign = 0, subsec[32];
- int tzhour = 0, tzmin = 0, lastmatch = -1;
-
- memset(&tm, 0, sizeof(struct tm));
- sscanf(data, "%04d-%02d-%02d %02d:%02d:%02d%n",
- &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &tm.tm_hour, &tm.tm_min, &tm.tm_sec, &lastmatch);
-
- // parse millisecs if any
- if (lastmatch > 0 && lastmatch < len && *(data+lastmatch) == '.') {
- lastmatch++;
- int idx = 0;
- const char *ptr = data + lastmatch;
- while (*ptr && *ptr >= '0' && *ptr <= '9' && idx < 31) {
- subsec[idx++] = *ptr;
- ptr++;
- lastmatch++;
- }
- subsec[idx] = 0;
- usec = round(atoll(subsec) * (1000000 / pow(10, idx)));
- }
-
- tm.tm_year -= 1900;
- tm.tm_mon -= 1;
- tm.tm_isdst = -1;
- if (tm.tm_mday > 0) {
- epoch = mktime(&tm);
- adjust = client_tzoffset(epoch, tm.tm_isdst);
- offset = adjust;
-
- // parse timezone offsets if any - matches +HH:MM +HH MM +HHMM
- if (lastmatch > 0 && lastmatch < len) {
- const char *ptr = data + lastmatch;
- while(*ptr && *ptr != '+' && *ptr != '-') ptr++;
- tzsign = *ptr++;
- if (*ptr && *ptr >= '0' && *ptr <= '9') {
- tzhour = *ptr++ - '0';
- if (*ptr && *ptr >= '0' && *ptr <= '9') tzhour = tzhour*10 + *ptr++ - '0';
- while(*ptr && (*ptr < '0' || *ptr > '9')) ptr++;
- if (*ptr && *ptr >= '0' && *ptr <= '9') {
- tzmin = *ptr++ - '0';
- if (*ptr && *ptr >= '0' && *ptr <= '9') tzmin = tzmin*10 + *ptr++ - '0';
- }
- }
- }
-
- if (tzsign) {
- offset = tzsign == '+'
- ? (time_t)tzhour * 3600 + (time_t)tzmin * 60
- : (time_t)tzhour * -3600 + (time_t)tzmin * -60;
- }
- else if (zone) {
- if (strncasecmp(zone, "UTC", 3) == 0 || strncasecmp(zone, "GMT", 3) == 0)
- offset = 0;
- else if (strcmp(zone, "+00:00") == 0 || strcmp(zone, "+0000") == 0)
- offset = 0;
- else if (sscanf(zone, "%c%02d%02d", &tzsign, &tzhour, &tzmin) == 3)
- offset = tzsign == '+'
- ? (time_t)tzhour * 3600 + (time_t)tzmin * 60
- : (time_t)tzhour * -3600 + (time_t)tzmin * -60;
- else if (sscanf(zone, "%c%02d:%02d", &tzsign, &tzhour, &tzmin) >= 2)
- offset = tzsign == '+'
- ? (time_t)tzhour * 3600 + (time_t)tzmin * 60
- : (time_t)tzhour * -3600 + (time_t)tzmin * -60;
- else
- offset = server_tzoffset(&tm, zone);
- }
-
- return rb_time_new(epoch+adjust-offset, usec);
- }
-
- printf("WARNING: Unable to parse timestamp value '%s'\n", data);
- return rb_str_new(data, len);
-}
-
-#define typecast_date(data,len,tz) rb_funcall(typecast_timestamp(data,len,tz), fto_date, 0)
-
-/*
- This is my wish list below for rubycore - to be built into core ruby.
- 1. Time class represents time - time zone invariant
- 2. Date class represents a date - time zone invariant
- 3. DateTime class represents a timestamp with full zoneinfo support.
-*/
-
-VALUE typecast_field(int type, const char *data, uint64_t length, const char* timezone) {
+VALUE typecast_field(int type, const char *data, uint64_t length) {
switch(type) {
case DBI_TYPE_BOOLEAN:
return (data && (data[0] =='t' || data[0] == '1')) ? Qtrue : Qfalse;
case DBI_TYPE_INT:
return rb_cstr2inum(data, 10);
case DBI_TYPE_BLOB:
return rb_funcall(cStringIO, fnew, 1, rb_str_new(data, length));
case DBI_TYPE_TIMESTAMP:
- return typecast_timestamp(data, length, timezone);
+ return datetime_parse(cSwiftDateTime, data, length);
case DBI_TYPE_DATE:
- return typecast_date(data, length, timezone);
+ return date_parse(cSwiftDateTime, data, length);
case DBI_TYPE_NUMERIC:
return rb_funcall(cBigDecimal, fnew, 1, rb_str_new2(data));
case DBI_TYPE_FLOAT:
return rb_float_new(atof(data));
@@ -282,31 +152,78 @@
return fields;
}
CATCH_DBI_EXCEPTIONS();
}
+VALUE result_field_types(VALUE self) {
+ dbi::AbstractResult *result = result_handle(self);
+ std::vector<int> result_types = result->types();
+
+ VALUE types = rb_ary_new();
+ for (std::vector<int>::iterator it = result_types.begin(); it != result_types.end(); it++) {
+ switch(*it) {
+ case DBI_TYPE_BOOLEAN:
+ rb_ary_push(types, rb_str_new2("boolean"));
+ break;
+ case DBI_TYPE_INT:
+ rb_ary_push(types, rb_str_new2("integer"));
+ break;
+ case DBI_TYPE_BLOB:
+ rb_ary_push(types, rb_str_new2("blob"));
+ break;
+ case DBI_TYPE_TIMESTAMP:
+ rb_ary_push(types, rb_str_new2("timestamp"));
+ break;
+ case DBI_TYPE_DATE:
+ rb_ary_push(types, rb_str_new2("date"));
+ break;
+ case DBI_TYPE_NUMERIC:
+ rb_ary_push(types, rb_str_new2("numeric"));
+ break;
+ case DBI_TYPE_FLOAT:
+ rb_ary_push(types, rb_str_new2("float"));
+ break;
+ case DBI_TYPE_TIME:
+ rb_ary_push(types, rb_str_new2("time"));
+ break;
+ default:
+ rb_ary_push(types, rb_str_new2("text"));
+ }
+ }
+
+ return types;
+}
+
+VALUE result_retrieve(VALUE self) {
+ dbi::AbstractResult *result = result_handle(self);
+ while (result->consumeResult());
+ result->prepareResult();
+ return true;
+}
+
void init_swift_result() {
rb_require("bigdecimal");
rb_require("stringio");
- rb_require("date");
VALUE mSwift = rb_define_module("Swift");
cSwiftResult = rb_define_class_under(mSwift, "Result", rb_cObject);
cStringIO = CONST_GET(rb_mKernel, "StringIO");
cBigDecimal = CONST_GET(rb_mKernel, "BigDecimal");
- fnew = rb_intern("new");
fto_date = rb_intern("to_date");
+ fnew = rb_intern("new");
fload = rb_intern("load");
rb_define_alloc_func(cSwiftResult, result_alloc);
rb_include_module(cSwiftResult, CONST_GET(rb_mKernel, "Enumerable"));
- rb_define_method(cSwiftResult, "clone", RUBY_METHOD_FUNC(result_clone), 0);
- rb_define_method(cSwiftResult, "dup", RUBY_METHOD_FUNC(result_dup), 0);
- rb_define_method(cSwiftResult, "each", RUBY_METHOD_FUNC(result_each), 0);
- rb_define_method(cSwiftResult, "insert_id", RUBY_METHOD_FUNC(result_insert_id), 0);
- rb_define_method(cSwiftResult, "rows", RUBY_METHOD_FUNC(result_rows), 0);
- rb_define_method(cSwiftResult, "columns", RUBY_METHOD_FUNC(result_columns), 0);
- rb_define_method(cSwiftResult, "fields", RUBY_METHOD_FUNC(result_fields), 0);
+ rb_define_method(cSwiftResult, "retrieve", RUBY_METHOD_FUNC(result_retrieve), 0);
+ rb_define_method(cSwiftResult, "clone", RUBY_METHOD_FUNC(result_clone), 0);
+ rb_define_method(cSwiftResult, "dup", RUBY_METHOD_FUNC(result_dup), 0);
+ rb_define_method(cSwiftResult, "each", RUBY_METHOD_FUNC(result_each), 0);
+ rb_define_method(cSwiftResult, "insert_id", RUBY_METHOD_FUNC(result_insert_id), 0);
+ rb_define_method(cSwiftResult, "rows", RUBY_METHOD_FUNC(result_rows), 0);
+ rb_define_method(cSwiftResult, "columns", RUBY_METHOD_FUNC(result_columns), 0);
+ rb_define_method(cSwiftResult, "fields", RUBY_METHOD_FUNC(result_fields), 0);
+ rb_define_method(cSwiftResult, "field_types", RUBY_METHOD_FUNC(result_field_types), 0);
}