do_postgres 0.10.3 → 0.10.4.rc1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,170 @@
1
+ #ifndef _DO_COMMON_H_
2
+ #define _DO_COMMON_H_
3
+
4
+ #include <ruby.h>
5
+
6
+ #ifdef _WIN32
7
+ #define cCommand_execute cCommand_execute_sync
8
+ typedef signed __int64 do_int64;
9
+ #else
10
+ #define cCommand_execute cCommand_execute_async
11
+ typedef signed long long int do_int64;
12
+ #endif
13
+
14
+ #ifdef HAVE_RUBY_ENCODING_H
15
+ #include <ruby/encoding.h>
16
+
17
+ #define DO_STR_NEW2(str, encoding, internal_encoding) \
18
+ ({ \
19
+ VALUE _string = rb_str_new2((const char *)str); \
20
+ if(encoding != -1) { \
21
+ rb_enc_associate_index(_string, encoding); \
22
+ } \
23
+ if(internal_encoding) { \
24
+ _string = rb_str_export_to_enc(_string, internal_encoding); \
25
+ } \
26
+ _string; \
27
+ })
28
+
29
+ #define DO_STR_NEW(str, len, encoding, internal_encoding) \
30
+ ({ \
31
+ VALUE _string = rb_str_new((const char *)str, (long)len); \
32
+ if(encoding != -1) { \
33
+ rb_enc_associate_index(_string, encoding); \
34
+ } \
35
+ if(internal_encoding) { \
36
+ _string = rb_str_export_to_enc(_string, internal_encoding); \
37
+ } \
38
+ _string; \
39
+ })
40
+
41
+ # else
42
+
43
+ #define DO_STR_NEW2(str, encoding, internal_encoding) \
44
+ rb_str_new2((const char *)str)
45
+
46
+ #define DO_STR_NEW(str, len, encoding, internal_encoding) \
47
+ rb_str_new((const char *)str, (long)len)
48
+ #endif
49
+
50
+ // Needed for defining error.h
51
+ struct errcodes {
52
+ int error_no;
53
+ const char *error_name;
54
+ const char *exception;
55
+ };
56
+
57
+ #define ERRCODE(name,message) {name, #name, message}
58
+
59
+ // To store rb_intern values
60
+ extern ID ID_NEW;
61
+ extern ID ID_NEW_DATE;
62
+ extern ID ID_CONST_GET;
63
+ extern ID ID_RATIONAL;
64
+ extern ID ID_ESCAPE;
65
+ extern ID ID_STRFTIME;
66
+ extern ID ID_LOG;
67
+
68
+ // Reference to Extlib module
69
+ extern VALUE mExtlib;
70
+ extern VALUE rb_cByteArray;
71
+
72
+ // References to DataObjects base classes
73
+ extern VALUE mDO;
74
+ extern VALUE mEncoding;
75
+ extern VALUE cDO_Quoting;
76
+ extern VALUE cDO_Connection;
77
+ extern VALUE cDO_Command;
78
+ extern VALUE cDO_Result;
79
+ extern VALUE cDO_Reader;
80
+ extern VALUE cDO_Logger;
81
+ extern VALUE cDO_Logger_Message;
82
+ extern VALUE cDO_Extension;
83
+ extern VALUE eConnectionError;
84
+ extern VALUE eDataError;
85
+
86
+ // References to Ruby classes that we'll need
87
+ extern VALUE rb_cDate;
88
+ extern VALUE rb_cDateTime;
89
+ extern VALUE rb_cBigDecimal;
90
+
91
+ extern void data_objects_debug(VALUE connection, VALUE string, struct timeval *start);
92
+ extern char *get_uri_option(VALUE query_hash, const char *key);
93
+ extern void assert_file_exists(char *file, const char *message);
94
+ extern VALUE build_query_from_args(VALUE klass, int count, VALUE *args);
95
+
96
+ extern void reduce(do_int64 *numerator, do_int64 *denominator);
97
+ extern int jd_from_date(int year, int month, int day);
98
+ extern VALUE seconds_to_offset(long seconds_offset);
99
+ extern VALUE timezone_to_offset(int hour_offset, int minute_offset);
100
+
101
+ extern VALUE parse_date(const char *date);
102
+ extern VALUE parse_time(const char *date);
103
+ extern VALUE parse_date_time(const char *date);
104
+
105
+ extern VALUE cConnection_character_set(VALUE self);
106
+ extern VALUE cConnection_is_using_socket(VALUE self);
107
+ extern VALUE cConnection_ssl_cipher(VALUE self);
108
+ extern VALUE cConnection_quote_time(VALUE self, VALUE value);
109
+ extern VALUE cConnection_quote_date_time(VALUE self, VALUE value);
110
+ extern VALUE cConnection_quote_date(VALUE self, VALUE value);
111
+
112
+ extern VALUE cCommand_set_types(int argc, VALUE *argv, VALUE self);
113
+
114
+ extern VALUE cReader_values(VALUE self);
115
+ extern VALUE cReader_fields(VALUE self);
116
+ extern VALUE cReader_field_count(VALUE self);
117
+
118
+ extern void common_init(void);
119
+
120
+ static inline VALUE do_const_get(VALUE scope, const char *constant) {
121
+ return rb_funcall(scope, ID_CONST_GET, 1, rb_str_new2(constant));
122
+ }
123
+
124
+ static inline VALUE do_str_new(const void *string, long length, int encoding, void *internal_encoding) {
125
+ VALUE new_string = rb_str_new(string, length);
126
+
127
+ #ifdef HAVE_RUBY_ENCODING_H
128
+ if(encoding != -1) {
129
+ rb_enc_associate_index(new_string, encoding);
130
+ }
131
+
132
+ if(internal_encoding) {
133
+ new_string = rb_str_export_to_enc(new_string, internal_encoding);
134
+ }
135
+ #endif
136
+
137
+ return new_string;
138
+ }
139
+
140
+ static inline VALUE do_str_new2(const void *string, int encoding, void *internal_encoding) {
141
+ VALUE new_string = rb_str_new2(string);
142
+
143
+ #ifdef HAVE_RUBY_ENCODING_H
144
+ if(encoding != -1) {
145
+ rb_enc_associate_index(new_string, encoding);
146
+ }
147
+
148
+ if(internal_encoding) {
149
+ new_string = rb_str_export_to_enc(new_string, internal_encoding);
150
+ }
151
+ #endif
152
+
153
+ return new_string;
154
+ }
155
+
156
+ static inline void do_define_errors(VALUE scope, const struct errcodes *errors) {
157
+ const struct errcodes *e;
158
+
159
+ for (e = errors; e->error_name; e++) {
160
+ rb_const_set(scope, rb_intern(e->error_name), INT2NUM(e->error_no));
161
+ }
162
+ }
163
+
164
+ extern void do_raise_error(VALUE self, const struct errcodes *errors, int errnum, const char *message, VALUE query, VALUE state);
165
+
166
+ extern VALUE do_typecast(const char *value, long length, const VALUE type, int encoding);
167
+
168
+ #define RSTRING_NOT_MODIFIED
169
+
170
+ #endif
@@ -23,11 +23,6 @@
23
23
  #undef snprintf
24
24
  #undef sprintf
25
25
  #undef printf
26
- #define cCommand_execute cCommand_execute_sync
27
- #define do_int64 signed __int64
28
- #else
29
- #define cCommand_execute cCommand_execute_async
30
- #define do_int64 signed long long int
31
26
  #endif
32
27
 
33
28
  #include <ruby.h>
@@ -38,308 +33,20 @@
38
33
  #include "error.h"
39
34
  #include "compat.h"
40
35
 
41
- #define CONST_GET(scope, constant) (rb_funcall(scope, ID_CONST_GET, 1, rb_str_new2(constant)))
42
- #define DRIVER_CLASS(klass, parent) (rb_define_class_under(mPostgres, klass, parent))
43
-
44
- #ifdef HAVE_RUBY_ENCODING_H
45
- #include <ruby/encoding.h>
46
-
47
- #define DO_STR_NEW2(str, encoding, internal_encoding) \
48
- ({ \
49
- VALUE _string = rb_str_new2((const char *)str); \
50
- if(encoding != -1) { \
51
- rb_enc_associate_index(_string, encoding); \
52
- } \
53
- if(internal_encoding) { \
54
- _string = rb_str_export_to_enc(_string, internal_encoding); \
55
- } \
56
- _string; \
57
- })
58
-
59
- #define DO_STR_NEW(str, len, encoding, internal_encoding) \
60
- ({ \
61
- VALUE _string = rb_str_new((const char *)str, (long)len); \
62
- if(encoding != -1) { \
63
- rb_enc_associate_index(_string, encoding); \
64
- } \
65
- if(internal_encoding) { \
66
- _string = rb_str_export_to_enc(_string, internal_encoding); \
67
- } \
68
- _string; \
69
- })
70
-
71
- #else
72
-
73
- #define DO_STR_NEW2(str, encoding, internal_encoding) \
74
- rb_str_new2((const char *)str)
75
-
76
- #define DO_STR_NEW(str, len, encoding, internal_encoding) \
77
- rb_str_new((const char *)str, (long)len)
78
- #endif
79
-
80
- // To store rb_intern values
81
- static ID ID_NEW_DATE;
82
- static ID ID_RATIONAL;
83
- static ID ID_CONST_GET;
84
- static ID ID_NEW;
85
- static ID ID_ESCAPE;
86
- static ID ID_LOG;
87
-
88
- static VALUE mExtlib;
89
- static VALUE mDO;
90
- static VALUE mEncoding;
91
- static VALUE cDO_Quoting;
92
- static VALUE cDO_Connection;
93
- static VALUE cDO_Command;
94
- static VALUE cDO_Result;
95
- static VALUE cDO_Reader;
96
- static VALUE cDO_Logger;
97
- static VALUE cDO_Logger_Message;
98
-
99
- static VALUE rb_cDate;
100
- static VALUE rb_cDateTime;
101
- static VALUE rb_cBigDecimal;
102
- static VALUE rb_cByteArray;
103
-
104
- static VALUE mPostgres;
105
- static VALUE cConnection;
106
- static VALUE cCommand;
107
- static VALUE cResult;
108
- static VALUE cReader;
109
-
110
- static VALUE eConnectionError;
111
- static VALUE eDataError;
112
-
113
- static void data_objects_debug(VALUE connection, VALUE string, struct timeval* start) {
114
- struct timeval stop;
115
- VALUE message;
116
-
117
- gettimeofday(&stop, NULL);
118
- do_int64 duration = (stop.tv_sec - start->tv_sec) * 1000000 + stop.tv_usec - start->tv_usec;
119
-
120
- message = rb_funcall(cDO_Logger_Message, ID_NEW, 3, string, rb_time_new(start->tv_sec, start->tv_usec), INT2NUM(duration));
121
-
122
- rb_funcall(connection, ID_LOG, 1, message);
123
- }
124
-
125
- static const char * get_uri_option(VALUE query_hash, const char * key) {
126
- VALUE query_value;
127
- const char * value = NULL;
128
-
129
- if(!rb_obj_is_kind_of(query_hash, rb_cHash)) { return NULL; }
130
-
131
- query_value = rb_hash_aref(query_hash, rb_str_new2(key));
132
-
133
- if (Qnil != query_value) {
134
- value = StringValuePtr(query_value);
135
- }
136
-
137
- return value;
138
- }
139
-
140
- /* ====== Time/Date Parsing Helper Functions ====== */
141
- static void reduce( do_int64 *numerator, do_int64 *denominator ) {
142
- do_int64 a, b, c;
143
- a = *numerator;
144
- b = *denominator;
145
- while ( a != 0 ) {
146
- c = a; a = b % a; b = c;
147
- }
148
- *numerator = *numerator / b;
149
- *denominator = *denominator / b;
150
- }
151
-
152
- // Generate the date integer which Date.civil_to_jd returns
153
- static int jd_from_date(int year, int month, int day) {
154
- int a, b;
155
- if ( month <= 2 ) {
156
- year -= 1;
157
- month += 12;
158
- }
159
- a = year / 100;
160
- b = 2 - a + (a / 4);
161
- return (int) (floor(365.25 * (year + 4716)) + floor(30.6001 * (month + 1)) + day + b - 1524);
162
- }
163
-
164
- static VALUE parse_date(const char *date) {
165
- int year, month, day;
166
- int jd, ajd;
167
- VALUE rational;
168
-
169
- sscanf(date, "%4d-%2d-%2d", &year, &month, &day);
170
-
171
- jd = jd_from_date(year, month, day);
172
-
173
- // Math from Date.jd_to_ajd
174
- ajd = jd * 2 - 1;
175
- rational = rb_funcall(rb_mKernel, ID_RATIONAL, 2, INT2NUM(ajd), INT2NUM(2));
176
-
177
- return rb_funcall(rb_cDate, ID_NEW_DATE, 3, rational, INT2NUM(0), INT2NUM(2299161));
178
- }
179
-
180
- // Creates a Rational for use as a Timezone offset to be passed to DateTime.new!
181
- static VALUE seconds_to_offset(do_int64 num) {
182
- do_int64 den = 86400;
183
- reduce(&num, &den);
184
- return rb_funcall(rb_mKernel, ID_RATIONAL, 2, rb_ll2inum(num), rb_ll2inum(den));
185
- }
186
-
187
- static VALUE timezone_to_offset(int hour_offset, int minute_offset) {
188
- do_int64 seconds = 0;
189
-
190
- seconds += hour_offset * 3600;
191
- seconds += minute_offset * 60;
192
-
193
- return seconds_to_offset(seconds);
194
- }
195
-
196
- static VALUE parse_date_time(const char *date) {
197
- VALUE ajd, offset;
198
-
199
- int year, month, day, hour, min, sec, usec, hour_offset, minute_offset;
200
- int jd;
201
- do_int64 num, den;
202
-
203
- long int gmt_offset;
204
- int dst_adjustment;
205
-
206
- time_t rawtime;
207
- struct tm timeinfo;
208
-
209
- int tokens_read, max_tokens;
210
-
211
- if (0 != strchr(date, '.')) {
212
- // This is a datetime with sub-second precision
213
- tokens_read = sscanf(date, "%4d-%2d-%2d %2d:%2d:%2d.%d%3d:%2d", &year, &month, &day, &hour, &min, &sec, &usec, &hour_offset, &minute_offset);
214
- max_tokens = 9;
215
- } else {
216
- // This is a datetime second precision
217
- tokens_read = sscanf(date, "%4d-%2d-%2d %2d:%2d:%2d%3d:%2d", &year, &month, &day, &hour, &min, &sec, &hour_offset, &minute_offset);
218
- max_tokens = 8;
219
- }
220
-
221
- if (max_tokens == tokens_read) {
222
- // We read the Date, Time, and Timezone info
223
- minute_offset *= hour_offset < 0 ? -1 : 1;
224
- } else if ((max_tokens - 1) == tokens_read) {
225
- // We read the Date and Time, but no Minute Offset
226
- minute_offset = 0;
227
- } else if (tokens_read == 3 || tokens_read >= (max_tokens - 3)) {
228
- if (tokens_read == 3) {
229
- hour = 0;
230
- min = 0;
231
- hour_offset = 0;
232
- minute_offset = 0;
233
- sec = 0;
234
- }
235
- // We read the Date and Time, default to the current locale's offset
236
-
237
- tzset();
238
-
239
- // Get localtime
240
- time(&rawtime);
241
- #ifdef HAVE_LOCALTIME_R
242
- localtime_r(&rawtime, &timeinfo);
243
- #else
244
- // Thread unsafe, this is used on Windows...
245
- timeinfo = *localtime(&rawtime);
246
- #endif
247
-
248
- timeinfo.tm_sec = sec;
249
- timeinfo.tm_min = min;
250
- timeinfo.tm_hour = hour;
251
- timeinfo.tm_mday = day;
252
- timeinfo.tm_mon = month;
253
- timeinfo.tm_year = year - 1900;
254
- timeinfo.tm_isdst = -1;
255
-
256
- // Update tm_isdst
257
- mktime(&timeinfo);
258
-
259
- if (timeinfo.tm_isdst) {
260
- dst_adjustment = 3600;
261
- } else {
262
- dst_adjustment = 0;
263
- }
264
-
265
- #ifdef HAVE_GMTIME_R
266
- // Reset to GM Time
267
- gmtime_r(&rawtime, &timeinfo);
268
- #else
269
- // Same as for localtime_r above
270
- timeinfo = *gmtime(&rawtime);
271
- #endif
272
-
273
- gmt_offset = rawtime - mktime(&timeinfo);
274
-
275
- if (dst_adjustment) {
276
- gmt_offset += dst_adjustment;
277
- }
278
-
279
- hour_offset = ((int)gmt_offset / 3600);
280
- minute_offset = ((int)gmt_offset % 3600 / 60);
281
-
282
- } else {
283
- // Something went terribly wrong
284
- rb_raise(eDataError, "Couldn't parse date: %s", date);
285
- }
286
-
287
- jd = jd_from_date(year, month, day);
288
-
289
- // Generate ajd with fractional days for the time
290
- // Extracted from Date#jd_to_ajd, Date#day_fraction_to_time, and Rational#+ and #-
291
- num = (hour * 1440) + (min * 24);
292
-
293
- // Modify the numerator so when we apply the timezone everything works out
294
- num -= (hour_offset * 1440) + (minute_offset * 24);
295
-
296
- den = (24 * 1440);
297
- reduce(&num, &den);
298
-
299
- num = (num * 86400) + (sec * den);
300
- den = den * 86400;
301
- reduce(&num, &den);
302
-
303
- num = (jd * den) + num;
304
-
305
- num = num * 2;
306
- num = num - den;
307
- den = den * 2;
308
-
309
- reduce(&num, &den);
310
-
311
- ajd = rb_funcall(rb_mKernel, ID_RATIONAL, 2, rb_ull2inum(num), rb_ull2inum(den));
312
- offset = timezone_to_offset(hour_offset, minute_offset);
313
-
314
- return rb_funcall(rb_cDateTime, ID_NEW_DATE, 3, ajd, offset, INT2NUM(2299161));
315
- }
36
+ #include "do_common.h"
316
37
 
317
- static VALUE parse_time(const char *date) {
318
-
319
- int year, month, day, hour, min, sec, usec, tokens;
320
- char subsec[7];
321
-
322
- if (0 != strchr(date, '.')) {
323
- // right padding usec with 0. e.g. '012' will become 12000 microsecond, since Time#local use microsecond
324
- sscanf(date, "%4d-%2d-%2d %2d:%2d:%2d.%s", &year, &month, &day, &hour, &min, &sec, subsec);
325
- usec = atoi(subsec);
326
- usec *= (int) pow(10, (6 - strlen(subsec)));
327
- } else {
328
- tokens = sscanf(date, "%4d-%2d-%2d %2d:%2d:%2d", &year, &month, &day, &hour, &min, &sec);
329
- if (tokens == 3) {
330
- hour = 0;
331
- min = 0;
332
- sec = 0;
333
- }
334
- usec = 0;
335
- }
38
+ VALUE mPostgres;
39
+ VALUE mEncoding;
40
+ VALUE cConnection;
41
+ VALUE cCommand;
42
+ VALUE cResult;
43
+ VALUE cReader;
336
44
 
337
- return rb_funcall(rb_cTime, rb_intern("local"), 7, INT2NUM(year), INT2NUM(month), INT2NUM(day), INT2NUM(hour), INT2NUM(min), INT2NUM(sec), INT2NUM(usec));
338
- }
45
+ void full_connect(VALUE self, PGconn *db);
339
46
 
340
47
  /* ===== Typecasting Functions ===== */
341
48
 
342
- static VALUE infer_ruby_type(Oid type) {
49
+ VALUE infer_ruby_type(Oid type) {
343
50
  switch(type) {
344
51
  case BITOID:
345
52
  case VARBITOID:
@@ -367,165 +74,85 @@ static VALUE infer_ruby_type(Oid type) {
367
74
  }
368
75
  }
369
76
 
370
- static VALUE typecast(const char *value, long length, const VALUE type, int encoding) {
371
-
372
- #ifdef HAVE_RUBY_ENCODING_H
373
- rb_encoding * internal_encoding = rb_default_internal_encoding();
374
- #else
375
- void * internal_encoding = NULL;
376
- #endif
377
-
378
- if (type == rb_cInteger) {
379
- return rb_cstr2inum(value, 10);
380
- } else if (type == rb_cString) {
381
- return DO_STR_NEW(value, length, encoding, internal_encoding);
382
- } else if (type == rb_cFloat) {
383
- return rb_float_new(rb_cstr_to_dbl(value, Qfalse));
384
- } else if (type == rb_cBigDecimal) {
385
- return rb_funcall(rb_cBigDecimal, ID_NEW, 1, rb_str_new(value, length));
386
- } else if (type == rb_cDate) {
387
- return parse_date(value);
388
- } else if (type == rb_cDateTime) {
389
- return parse_date_time(value);
390
- } else if (type == rb_cTime) {
391
- return parse_time(value);
392
- } else if (type == rb_cTrueClass) {
77
+ VALUE typecast(const char *value, long length, const VALUE type, int encoding) {
78
+ if (type == rb_cTrueClass) {
393
79
  return *value == 't' ? Qtrue : Qfalse;
394
- } else if (type == rb_cByteArray) {
80
+ }
81
+ else if (type == rb_cByteArray) {
395
82
  size_t new_length = 0;
396
- char* unescaped = (char *)PQunescapeBytea((unsigned char*)value, &new_length);
83
+ char *unescaped = (char *)PQunescapeBytea((unsigned char*)value, &new_length);
397
84
  VALUE byte_array = rb_funcall(rb_cByteArray, ID_NEW, 1, rb_str_new(unescaped, new_length));
85
+
398
86
  PQfreemem(unescaped);
399
87
  return byte_array;
400
- } else if (type == rb_cClass) {
401
- return rb_funcall(mDO, rb_intern("full_const_get"), 1, rb_str_new(value, length));
402
- } else if (type == rb_cNilClass) {
403
- return Qnil;
404
- } else {
405
- return DO_STR_NEW(value, length, encoding, internal_encoding);
406
88
  }
407
-
89
+ else {
90
+ return do_typecast(value, length, type, encoding);
91
+ }
408
92
  }
409
93
 
410
- static void raise_error(VALUE self, PGresult *result, VALUE query) {
411
- VALUE exception;
412
- char *message;
413
- char *sqlstate;
414
- int postgres_errno;
94
+ void raise_error(VALUE self, PGresult *result, VALUE query) {
95
+ const char *message = PQresultErrorMessage(result);
96
+ char *sql_state = PQresultErrorField(result, PG_DIAG_SQLSTATE);
97
+ int postgres_errno = MAKE_SQLSTATE(sql_state[0], sql_state[1], sql_state[2], sql_state[3], sql_state[4]);
415
98
 
416
- message = PQresultErrorMessage(result);
417
- sqlstate = PQresultErrorField(result, PG_DIAG_SQLSTATE);
418
- postgres_errno = MAKE_SQLSTATE(sqlstate[0], sqlstate[1], sqlstate[2], sqlstate[3], sqlstate[4]);
419
99
  PQclear(result);
420
100
 
421
- const char *exception_type = "SQLError";
422
-
423
- struct errcodes *errs;
424
-
425
- for (errs = errors; errs->error_name; errs++) {
426
- if(errs->error_no == postgres_errno) {
427
- exception_type = errs->exception;
428
- break;
429
- }
430
- }
431
-
432
- VALUE uri = rb_funcall(rb_iv_get(self, "@connection"), rb_intern("to_s"), 0);
433
-
434
- exception = rb_funcall(CONST_GET(mDO, exception_type), ID_NEW, 5,
435
- rb_str_new2(message),
436
- INT2NUM(postgres_errno),
437
- rb_str_new2(sqlstate),
438
- query,
439
- uri);
440
- rb_exc_raise(exception);
101
+ do_raise_error(self, errors, postgres_errno, message, query, rb_str_new2(sql_state));
441
102
  }
442
103
 
443
-
444
104
  /* ====== Public API ======= */
445
- static VALUE cConnection_dispose(VALUE self) {
446
- VALUE connection_container = rb_iv_get(self, "@connection");
447
105
 
448
- PGconn *db;
106
+ VALUE cConnection_dispose(VALUE self) {
107
+ VALUE connection_container = rb_iv_get(self, "@connection");
449
108
 
450
- if (Qnil == connection_container)
109
+ if (connection_container == Qnil) {
451
110
  return Qfalse;
111
+ }
452
112
 
453
- db = DATA_PTR(connection_container);
113
+ PGconn *db = DATA_PTR(connection_container);
454
114
 
455
- if (NULL == db)
115
+ if (!db) {
456
116
  return Qfalse;
117
+ }
457
118
 
458
119
  PQfinish(db);
459
120
  rb_iv_set(self, "@connection", Qnil);
460
-
461
121
  return Qtrue;
462
122
  }
463
123
 
464
- static VALUE cCommand_set_types(int argc, VALUE *argv, VALUE self) {
465
- VALUE type_strings = rb_ary_new();
466
- VALUE array = rb_ary_new();
467
-
468
- int i, j;
469
-
470
- for ( i = 0; i < argc; i++) {
471
- rb_ary_push(array, argv[i]);
472
- }
473
-
474
- for (i = 0; i < RARRAY_LEN(array); i++) {
475
- VALUE entry = rb_ary_entry(array, i);
476
- if(TYPE(entry) == T_CLASS) {
477
- rb_ary_push(type_strings, entry);
478
- } else if (TYPE(entry) == T_ARRAY) {
479
- for (j = 0; j < RARRAY_LEN(entry); j++) {
480
- VALUE sub_entry = rb_ary_entry(entry, j);
481
- if(TYPE(sub_entry) == T_CLASS) {
482
- rb_ary_push(type_strings, sub_entry);
483
- } else {
484
- rb_raise(rb_eArgError, "Invalid type given");
485
- }
486
- }
487
- } else {
488
- rb_raise(rb_eArgError, "Invalid type given");
489
- }
490
- }
491
-
492
- rb_iv_set(self, "@field_types", type_strings);
493
-
494
- return array;
495
- }
496
-
497
- static VALUE build_query_from_args(VALUE klass, int count, VALUE *args[]) {
498
- VALUE query = rb_iv_get(klass, "@text");
499
-
500
- int i;
501
- VALUE array = rb_ary_new();
502
- for ( i = 0; i < count; i++) {
503
- rb_ary_push(array, (VALUE)args[i]);
504
- }
505
- query = rb_funcall(klass, ID_ESCAPE, 1, array);
506
-
507
- return query;
508
- }
509
-
510
- static VALUE cConnection_quote_string(VALUE self, VALUE string) {
124
+ VALUE cConnection_quote_string(VALUE self, VALUE string) {
511
125
  PGconn *db = DATA_PTR(rb_iv_get(self, "@connection"));
512
-
513
126
  const char *source = rb_str_ptr_readonly(string);
514
- size_t source_len = rb_str_len(string);
127
+ int error = 0;
128
+ long source_len = rb_str_len(string);
129
+ long buffer_len = source_len * 2 + 3;
130
+
131
+ // Overflow check
132
+ if(buffer_len <= source_len) {
133
+ rb_raise(rb_eArgError, "Input string is too large to be safely quoted");
134
+ }
515
135
 
516
136
  char *escaped;
517
- size_t quoted_length = 0;
518
- VALUE result;
519
137
 
520
138
  // Allocate space for the escaped version of 'string'
521
139
  // http://www.postgresql.org/docs/8.3/static/libpq-exec.html#LIBPQ-EXEC-ESCAPE-STRING
522
- escaped = (char *)calloc(source_len * 2 + 3, sizeof(char));
140
+ if (!(escaped = calloc(buffer_len, sizeof(char)))) {
141
+ rb_memerror();
142
+ }
143
+
144
+ long quoted_length;
145
+ VALUE result;
523
146
 
524
147
  // Escape 'source' using the current charset in use on the conection 'db'
525
- quoted_length = PQescapeStringConn(db, escaped + 1, source, source_len, NULL);
148
+ quoted_length = PQescapeStringConn(db, escaped + 1, source, source_len, &error);
149
+
150
+ if(error) {
151
+ rb_raise(eDataError, "%s", PQerrorMessage(db));
152
+ }
526
153
 
527
154
  // Wrap the escaped string in single-quotes, this is DO's convention
528
- escaped[quoted_length + 1] = escaped[0] = '\'';
155
+ escaped[0] = escaped[quoted_length + 1] = '\'';
529
156
 
530
157
  result = DO_STR_NEW(escaped, quoted_length + 2, FIX2INT(rb_iv_get(self, "@encoding_id")), NULL);
531
158
 
@@ -533,11 +160,10 @@ static VALUE cConnection_quote_string(VALUE self, VALUE string) {
533
160
  return result;
534
161
  }
535
162
 
536
- static VALUE cConnection_quote_byte_array(VALUE self, VALUE string) {
163
+ VALUE cConnection_quote_byte_array(VALUE self, VALUE string) {
537
164
  PGconn *db = DATA_PTR(rb_iv_get(self, "@connection"));
538
-
539
- const unsigned char *source = (unsigned char*) rb_str_ptr_readonly(string);
540
- size_t source_len = rb_str_len(string);
165
+ const unsigned char *source = (unsigned char *)rb_str_ptr_readonly(string);
166
+ size_t source_len = rb_str_len(string);
541
167
 
542
168
  unsigned char *escaped;
543
169
  unsigned char *escaped_quotes;
@@ -547,11 +173,19 @@ static VALUE cConnection_quote_byte_array(VALUE self, VALUE string) {
547
173
  // Allocate space for the escaped version of 'string'
548
174
  // http://www.postgresql.org/docs/8.3/static/libpq-exec.html#LIBPQ-EXEC-ESCAPE-STRING
549
175
  escaped = PQescapeByteaConn(db, source, source_len, &quoted_length);
550
- escaped_quotes = (unsigned char *)calloc(quoted_length + 1, sizeof(unsigned char));
551
- memcpy(escaped_quotes + 1, escaped, quoted_length);
176
+
177
+ if(!escaped) {
178
+ rb_memerror();
179
+ }
180
+
181
+ if (!(escaped_quotes = calloc(quoted_length + 1, sizeof(unsigned char)))) {
182
+ rb_memerror();
183
+ }
184
+
185
+ memcpy(escaped_quotes + 1, escaped, quoted_length * sizeof(unsigned char));
552
186
 
553
187
  // Wrap the escaped string in single-quotes, this is DO's convention (replace trailing \0)
554
- escaped_quotes[quoted_length] = escaped_quotes[0] = '\'';
188
+ escaped_quotes[0] = escaped_quotes[quoted_length] = '\'';
555
189
 
556
190
  result = rb_str_new((const char *)escaped_quotes, quoted_length + 1);
557
191
  PQfreemem(escaped);
@@ -559,195 +193,206 @@ static VALUE cConnection_quote_byte_array(VALUE self, VALUE string) {
559
193
  return result;
560
194
  }
561
195
 
562
- static void full_connect(VALUE self, PGconn *db);
563
-
564
196
  #ifdef _WIN32
565
- static PGresult* cCommand_execute_sync(VALUE self, VALUE connection, PGconn *db, VALUE query) {
197
+ PGresult * cCommand_execute_sync(VALUE self, VALUE connection, PGconn *db, VALUE query) {
198
+ char *str = StringValuePtr(query);
566
199
  PGresult *response;
567
- struct timeval start;
568
- char* str = StringValuePtr(query);
569
200
 
570
- while ((response = PQgetResult(db)) != NULL) {
201
+ while ((response = PQgetResult(db))) {
571
202
  PQclear(response);
572
203
  }
573
204
 
574
- gettimeofday(&start, NULL);
205
+ struct timeval start;
575
206
 
207
+ gettimeofday(&start, NULL);
576
208
  response = PQexec(db, str);
577
209
 
578
- if (response == NULL) {
579
- if(PQstatus(db) != CONNECTION_OK) {
210
+ if (!response) {
211
+ if (PQstatus(db) != CONNECTION_OK) {
580
212
  PQreset(db);
213
+
581
214
  if (PQstatus(db) == CONNECTION_OK) {
582
215
  response = PQexec(db, str);
583
- } else {
216
+ }
217
+ else {
584
218
  full_connect(connection, db);
585
219
  response = PQexec(db, str);
586
220
  }
587
221
  }
588
222
 
589
- if(response == NULL) {
223
+ if(!response) {
590
224
  rb_raise(eConnectionError, PQerrorMessage(db));
591
225
  }
592
226
  }
593
227
 
594
228
  data_objects_debug(connection, query, &start);
595
-
596
229
  return response;
597
230
  }
598
231
  #else
599
- static PGresult* cCommand_execute_async(VALUE self, VALUE connection, PGconn *db, VALUE query) {
600
- int socket_fd;
601
- int retval;
602
- fd_set rset;
232
+ PGresult * cCommand_execute_async(VALUE self, VALUE connection, PGconn *db, VALUE query) {
603
233
  PGresult *response;
604
- struct timeval start;
605
234
  char* str = StringValuePtr(query);
606
235
 
607
- while ((response = PQgetResult(db)) != NULL) {
236
+ while ((response = PQgetResult(db))) {
608
237
  PQclear(response);
609
238
  }
610
239
 
611
- gettimeofday(&start, NULL);
240
+ struct timeval start;
241
+ int retval;
612
242
 
243
+ gettimeofday(&start, NULL);
613
244
  retval = PQsendQuery(db, str);
614
245
 
615
246
  if (!retval) {
616
- if(PQstatus(db) != CONNECTION_OK) {
247
+ if (PQstatus(db) != CONNECTION_OK) {
617
248
  PQreset(db);
249
+
618
250
  if (PQstatus(db) == CONNECTION_OK) {
619
251
  retval = PQsendQuery(db, str);
620
- } else {
252
+ }
253
+ else {
621
254
  full_connect(connection, db);
622
255
  retval = PQsendQuery(db, str);
623
256
  }
624
257
  }
625
258
 
626
- if(!retval) {
259
+ if (!retval) {
627
260
  rb_raise(eConnectionError, "%s", PQerrorMessage(db));
628
261
  }
629
262
  }
630
263
 
631
- socket_fd = PQsocket(db);
264
+ int socket_fd = PQsocket(db);
265
+ fd_set rset;
632
266
 
633
- for(;;) {
634
- FD_ZERO(&rset);
635
- FD_SET(socket_fd, &rset);
636
- retval = rb_thread_select(socket_fd + 1, &rset, NULL, NULL, NULL);
637
- if (retval < 0) {
638
- rb_sys_fail(0);
639
- }
267
+ while (1) {
268
+ FD_ZERO(&rset);
269
+ FD_SET(socket_fd, &rset);
270
+ retval = rb_thread_select(socket_fd + 1, &rset, NULL, NULL, NULL);
640
271
 
641
- if (retval == 0) {
642
- continue;
643
- }
272
+ if (retval < 0) {
273
+ rb_sys_fail(0);
274
+ }
644
275
 
645
- if (PQconsumeInput(db) == 0) {
646
- rb_raise(eConnectionError, "%s", PQerrorMessage(db));
647
- }
276
+ if (retval == 0) {
277
+ continue;
278
+ }
648
279
 
649
- if (PQisBusy(db) == 0) {
650
- break;
651
- }
280
+ if (PQconsumeInput(db) == 0) {
281
+ rb_raise(eConnectionError, "%s", PQerrorMessage(db));
282
+ }
283
+
284
+ if (PQisBusy(db) == 0) {
285
+ break;
286
+ }
652
287
  }
653
288
 
654
289
  data_objects_debug(connection, query, &start);
655
-
656
290
  return PQgetResult(db);
657
291
  }
658
292
  #endif
659
293
 
660
- static VALUE cConnection_initialize(VALUE self, VALUE uri) {
661
- VALUE r_host, r_user, r_password, r_path, r_query, r_port;
662
-
663
- PGconn *db = NULL;
664
-
294
+ VALUE cConnection_initialize(VALUE self, VALUE uri) {
665
295
  rb_iv_set(self, "@using_socket", Qfalse);
666
296
 
667
- r_host = rb_funcall(uri, rb_intern("host"), 0);
668
- if (Qnil != r_host) {
297
+ VALUE r_host = rb_funcall(uri, rb_intern("host"), 0);
298
+
299
+ if (r_host != Qnil) {
669
300
  rb_iv_set(self, "@host", r_host);
670
301
  }
671
302
 
672
- r_user = rb_funcall(uri, rb_intern("user"), 0);
673
- if (Qnil != r_user) {
303
+ VALUE r_user = rb_funcall(uri, rb_intern("user"), 0);
304
+
305
+ if (r_user != Qnil) {
674
306
  rb_iv_set(self, "@user", r_user);
675
307
  }
676
308
 
677
- r_password = rb_funcall(uri, rb_intern("password"), 0);
678
- if (Qnil != r_password) {
309
+ VALUE r_password = rb_funcall(uri, rb_intern("password"), 0);
310
+
311
+ if (r_password != Qnil) {
679
312
  rb_iv_set(self, "@password", r_password);
680
313
  }
681
314
 
682
- r_path = rb_funcall(uri, rb_intern("path"), 0);
683
- if (Qnil != r_path) {
315
+ VALUE r_path = rb_funcall(uri, rb_intern("path"), 0);
316
+
317
+ if (r_path != Qnil) {
684
318
  rb_iv_set(self, "@path", r_path);
685
319
  }
686
320
 
687
- r_port = rb_funcall(uri, rb_intern("port"), 0);
688
- if (Qnil != r_port) {
321
+ VALUE r_port = rb_funcall(uri, rb_intern("port"), 0);
322
+
323
+ if (r_port != Qnil) {
689
324
  r_port = rb_funcall(r_port, rb_intern("to_s"), 0);
690
325
  rb_iv_set(self, "@port", r_port);
691
326
  }
692
327
 
693
328
  // Pull the querystring off the URI
694
- r_query = rb_funcall(uri, rb_intern("query"), 0);
329
+ VALUE r_query = rb_funcall(uri, rb_intern("query"), 0);
330
+
695
331
  rb_iv_set(self, "@query", r_query);
696
332
 
697
- const char* encoding = get_uri_option(r_query, "encoding");
698
- if (!encoding) { encoding = get_uri_option(r_query, "charset"); }
699
- if (!encoding) { encoding = "UTF-8"; }
333
+ const char *encoding = get_uri_option(r_query, "encoding");
334
+
335
+ if (!encoding) {
336
+ encoding = get_uri_option(r_query, "charset");
337
+
338
+ if (!encoding) {
339
+ encoding = "UTF-8";
340
+ }
341
+ }
700
342
 
701
343
  rb_iv_set(self, "@encoding", rb_str_new2(encoding));
702
344
 
703
- full_connect(self, db);
345
+ PGconn *db = NULL;
704
346
 
347
+ full_connect(self, db);
705
348
  rb_iv_set(self, "@uri", uri);
706
-
707
349
  return Qtrue;
708
350
  }
709
351
 
710
- static void full_connect(VALUE self, PGconn *db) {
352
+ void full_connect(VALUE self, PGconn *db) {
353
+ VALUE r_host;
354
+ char *host = NULL;
711
355
 
712
- PGresult *result = NULL;
713
- VALUE r_host, r_user, r_password, r_path, r_port, r_query, r_options;
714
- char *host = NULL, *user = NULL, *password = NULL, *path = NULL, *database = NULL;
715
- const char *port = "5432";
716
- VALUE encoding = Qnil;
717
- const char *search_path = NULL;
718
- char *search_path_query = NULL;
719
- const char *backslash_off = "SET backslash_quote = off";
720
- const char *standard_strings_on = "SET standard_conforming_strings = on";
721
- const char *warning_messages = "SET client_min_messages = warning";
722
-
723
- if((r_host = rb_iv_get(self, "@host")) != Qnil) {
724
- host = StringValuePtr(r_host);
356
+ if ((r_host = rb_iv_get(self, "@host")) != Qnil) {
357
+ host = StringValuePtr(r_host);
725
358
  }
726
359
 
727
- if((r_user = rb_iv_get(self, "@user")) != Qnil) {
728
- user = StringValuePtr(r_user);
360
+ VALUE r_user;
361
+ char *user = NULL;
362
+
363
+ if ((r_user = rb_iv_get(self, "@user")) != Qnil) {
364
+ user = StringValuePtr(r_user);
729
365
  }
730
366
 
731
- if((r_password = rb_iv_get(self, "@password")) != Qnil) {
367
+ VALUE r_password;
368
+ char *password = NULL;
369
+
370
+ if ((r_password = rb_iv_get(self, "@password")) != Qnil) {
732
371
  password = StringValuePtr(r_password);
733
372
  }
734
373
 
735
- if((r_port = rb_iv_get(self, "@port")) != Qnil) {
374
+ VALUE r_port;
375
+ const char *port = "5432";
376
+
377
+ if ((r_port = rb_iv_get(self, "@port")) != Qnil) {
736
378
  port = StringValuePtr(r_port);
737
379
  }
738
380
 
739
- if((r_path = rb_iv_get(self, "@path")) != Qnil) {
381
+ VALUE r_path;
382
+ char *path = NULL;
383
+ char *database = NULL;
384
+
385
+ if ((r_path = rb_iv_get(self, "@path")) != Qnil) {
740
386
  path = StringValuePtr(r_path);
741
387
  database = strtok(path, "/");
742
388
  }
743
389
 
744
- if (NULL == database || 0 == strlen(database)) {
390
+ if (!database || !*database) {
745
391
  rb_raise(eConnectionError, "Database must be specified");
746
392
  }
747
393
 
748
- r_query = rb_iv_get(self, "@query");
749
-
750
- search_path = get_uri_option(r_query, "search_path");
394
+ VALUE r_query = rb_iv_get(self, "@query");
395
+ const char *search_path = get_uri_option(r_query, "search_path");
751
396
 
752
397
  db = PQsetdbLogin(
753
398
  host,
@@ -759,24 +404,37 @@ static void full_connect(VALUE self, PGconn *db) {
759
404
  password
760
405
  );
761
406
 
762
- if ( PQstatus(db) == CONNECTION_BAD ) {
407
+ if (PQstatus(db) == CONNECTION_BAD) {
763
408
  rb_raise(eConnectionError, "%s", PQerrorMessage(db));
764
409
  }
765
410
 
766
- if (search_path != NULL) {
767
- search_path_query = (char *)calloc(256, sizeof(char));
411
+ PGresult *result;
412
+
413
+ if (search_path) {
414
+ char *search_path_query;
415
+
416
+ if (!(search_path_query = calloc(256, sizeof(char)))) {
417
+ rb_memerror();
418
+ }
419
+
768
420
  snprintf(search_path_query, 256, "set search_path to %s;", search_path);
421
+
769
422
  r_query = rb_str_new2(search_path_query);
770
423
  result = cCommand_execute(Qnil, self, db, r_query);
771
424
 
772
425
  if (PQresultStatus(result) != PGRES_COMMAND_OK) {
773
- free((void *)search_path_query);
426
+ free(search_path_query);
774
427
  raise_error(self, result, r_query);
775
428
  }
776
429
 
777
- free((void *)search_path_query);
430
+ free(search_path_query);
778
431
  }
779
432
 
433
+ const char *backslash_off = "SET backslash_quote = off";
434
+ const char *standard_strings_on = "SET standard_conforming_strings = on";
435
+ const char *warning_messages = "SET client_min_messages = warning";
436
+ VALUE r_options;
437
+
780
438
  r_options = rb_str_new2(backslash_off);
781
439
  result = cCommand_execute(Qnil, self, db, r_options);
782
440
 
@@ -798,21 +456,24 @@ static void full_connect(VALUE self, PGconn *db) {
798
456
  rb_warn("%s", PQresultErrorMessage(result));
799
457
  }
800
458
 
801
- encoding = rb_iv_get(self, "@encoding");
802
-
459
+ VALUE encoding = rb_iv_get(self, "@encoding");
803
460
  #ifdef HAVE_PQSETCLIENTENCODING
804
- VALUE pg_encoding = rb_hash_aref(CONST_GET(mEncoding, "MAP"), encoding);
805
- if(pg_encoding != Qnil) {
806
- if(PQsetClientEncoding(db, rb_str_ptr_readonly(pg_encoding))) {
461
+ VALUE pg_encoding = rb_hash_aref(do_const_get(mEncoding, "MAP"), encoding);
462
+
463
+ if (pg_encoding != Qnil) {
464
+ if (PQsetClientEncoding(db, rb_str_ptr_readonly(pg_encoding))) {
807
465
  rb_raise(eConnectionError, "Couldn't set encoding: %s", rb_str_ptr_readonly(encoding));
808
- } else {
466
+ }
467
+ else {
809
468
  #ifdef HAVE_RUBY_ENCODING_H
810
469
  rb_iv_set(self, "@encoding_id", INT2FIX(rb_enc_find_index(rb_str_ptr_readonly(encoding))));
811
470
  #endif
812
471
  rb_iv_set(self, "@pg_encoding", pg_encoding);
813
472
  }
814
- } else {
473
+ }
474
+ else {
815
475
  rb_warn("Encoding %s is not a known Ruby encoding for PostgreSQL\n", rb_str_ptr_readonly(encoding));
476
+
816
477
  rb_iv_set(self, "@encoding", rb_str_new2("UTF-8"));
817
478
  #ifdef HAVE_RUBY_ENCODING_H
818
479
  rb_iv_set(self, "@encoding_id", INT2FIX(rb_enc_find_index("UTF-8")));
@@ -820,42 +481,40 @@ static void full_connect(VALUE self, PGconn *db) {
820
481
  rb_iv_set(self, "@pg_encoding", rb_str_new2("UTF8"));
821
482
  }
822
483
  #endif
823
- rb_iv_set(self, "@connection", Data_Wrap_Struct(rb_cObject, 0, 0, db));
824
- }
825
484
 
826
- static VALUE cConnection_character_set(VALUE self) {
827
- return rb_iv_get(self, "@encoding");
485
+ rb_iv_set(self, "@connection", Data_Wrap_Struct(rb_cObject, 0, 0, db));
828
486
  }
829
487
 
830
- static VALUE cCommand_execute_non_query(int argc, VALUE *argv[], VALUE self) {
488
+ VALUE cCommand_execute_non_query(int argc, VALUE *argv, VALUE self) {
831
489
  VALUE connection = rb_iv_get(self, "@connection");
832
490
  VALUE postgres_connection = rb_iv_get(connection, "@connection");
833
- if (Qnil == postgres_connection) {
491
+
492
+ if (postgres_connection == Qnil) {
834
493
  rb_raise(eConnectionError, "This connection has already been closed.");
835
494
  }
836
495
 
496
+ VALUE query = build_query_from_args(self, argc, argv);
837
497
  PGconn *db = DATA_PTR(postgres_connection);
838
498
  PGresult *response;
839
499
  int status;
840
500
 
841
- VALUE affected_rows = Qnil;
842
- VALUE insert_id = Qnil;
843
-
844
- VALUE query = build_query_from_args(self, argc, argv);
845
-
846
501
  response = cCommand_execute(self, connection, db, query);
847
-
848
502
  status = PQresultStatus(response);
849
503
 
850
- if ( status == PGRES_TUPLES_OK ) {
851
- if (PQgetlength(response, 0, 0) == 0) {
504
+ VALUE affected_rows = Qnil;
505
+ VALUE insert_id = Qnil;
506
+
507
+ if (status == PGRES_TUPLES_OK) {
508
+ if (PQgetlength(response, 0, 0) == 0) {
852
509
  insert_id = Qnil;
853
- } else {
510
+ }
511
+ else {
854
512
  insert_id = INT2NUM(atoi(PQgetvalue(response, 0, 0)));
855
513
  }
514
+
856
515
  affected_rows = INT2NUM(atoi(PQcmdTuples(response)));
857
516
  }
858
- else if ( status == PGRES_COMMAND_OK ) {
517
+ else if (status == PGRES_COMMAND_OK) {
859
518
  insert_id = Qnil;
860
519
  affected_rows = INT2NUM(atoi(PQcmdTuples(response)));
861
520
  }
@@ -864,59 +523,55 @@ static VALUE cCommand_execute_non_query(int argc, VALUE *argv[], VALUE self) {
864
523
  }
865
524
 
866
525
  PQclear(response);
867
-
868
526
  return rb_funcall(cResult, ID_NEW, 3, self, affected_rows, insert_id);
869
527
  }
870
528
 
871
- static VALUE cCommand_execute_reader(int argc, VALUE *argv[], VALUE self) {
872
- VALUE reader, query;
873
- VALUE field_names, field_types;
874
-
875
- int i;
876
- int field_count;
877
- int infer_types = 0;
878
-
529
+ VALUE cCommand_execute_reader(int argc, VALUE *argv, VALUE self) {
879
530
  VALUE connection = rb_iv_get(self, "@connection");
880
531
  VALUE postgres_connection = rb_iv_get(connection, "@connection");
881
- if (Qnil == postgres_connection) {
532
+
533
+ if (postgres_connection == Qnil) {
882
534
  rb_raise(eConnectionError, "This connection has already been closed.");
883
535
  }
884
536
 
537
+ VALUE query = build_query_from_args(self, argc, argv);
885
538
  PGconn *db = DATA_PTR(postgres_connection);
886
- PGresult *response;
539
+ PGresult *response = cCommand_execute(self, connection, db, query);
887
540
 
888
- query = build_query_from_args(self, argc, argv);
889
-
890
- response = cCommand_execute(self, connection, db, query);
891
-
892
- if ( PQresultStatus(response) != PGRES_TUPLES_OK ) {
541
+ if (PQresultStatus(response) != PGRES_TUPLES_OK) {
893
542
  raise_error(self, response, query);
894
543
  }
895
544
 
896
- field_count = PQnfields(response);
545
+ int field_count = PQnfields(response);
546
+ VALUE reader = rb_funcall(cReader, ID_NEW, 0);
897
547
 
898
- reader = rb_funcall(cReader, ID_NEW, 0);
899
548
  rb_iv_set(reader, "@connection", connection);
900
549
  rb_iv_set(reader, "@reader", Data_Wrap_Struct(rb_cObject, 0, 0, response));
550
+ rb_iv_set(reader, "@opened", Qfalse);
901
551
  rb_iv_set(reader, "@field_count", INT2NUM(field_count));
902
552
  rb_iv_set(reader, "@row_count", INT2NUM(PQntuples(response)));
903
553
 
904
- field_names = rb_ary_new();
905
- field_types = rb_iv_get(self, "@field_types");
554
+ VALUE field_names = rb_ary_new();
555
+ VALUE field_types = rb_iv_get(self, "@field_types");
556
+ int infer_types = 0;
906
557
 
907
- if ( field_types == Qnil || 0 == RARRAY_LEN(field_types) ) {
558
+ if (field_types == Qnil || 0 == RARRAY_LEN(field_types)) {
908
559
  field_types = rb_ary_new();
909
560
  infer_types = 1;
910
- } else if (RARRAY_LEN(field_types) != field_count) {
561
+ }
562
+ else if (RARRAY_LEN(field_types) != field_count) {
911
563
  // Whoops... wrong number of types passed to set_types. Close the reader and raise
912
564
  // and error
913
565
  rb_funcall(reader, rb_intern("close"), 0);
914
566
  rb_raise(rb_eArgError, "Field-count mismatch. Expected %ld fields, but the query yielded %d", RARRAY_LEN(field_types), field_count);
915
567
  }
916
568
 
917
- for ( i = 0; i < field_count; i++ ) {
569
+ int i;
570
+
571
+ for (i = 0; i < field_count; i++) {
918
572
  rb_ary_push(field_names, rb_str_new2(PQfname(response, i)));
919
- if ( infer_types == 1 ) {
573
+
574
+ if (infer_types == 1) {
920
575
  rb_ary_push(field_types, infer_ruby_type(PQftype(response, i)));
921
576
  }
922
577
  }
@@ -924,65 +579,66 @@ static VALUE cCommand_execute_reader(int argc, VALUE *argv[], VALUE self) {
924
579
  rb_iv_set(reader, "@position", INT2NUM(0));
925
580
  rb_iv_set(reader, "@fields", field_names);
926
581
  rb_iv_set(reader, "@field_types", field_types);
927
-
928
582
  return reader;
929
583
  }
930
584
 
931
- static VALUE cReader_close(VALUE self) {
585
+ VALUE cReader_close(VALUE self) {
932
586
  VALUE reader_container = rb_iv_get(self, "@reader");
933
587
 
934
- PGresult *reader;
935
-
936
- if (Qnil == reader_container)
588
+ if (reader_container == Qnil) {
937
589
  return Qfalse;
590
+ }
938
591
 
939
- reader = DATA_PTR(reader_container);
592
+ PGresult *reader = DATA_PTR(reader_container);
940
593
 
941
- if (NULL == reader)
594
+ if (!reader) {
942
595
  return Qfalse;
596
+ }
943
597
 
944
598
  PQclear(reader);
599
+
945
600
  rb_iv_set(self, "@reader", Qnil);
601
+ rb_iv_set(self, "@opened", Qfalse);
946
602
  return Qtrue;
947
603
  }
948
604
 
949
- static VALUE cReader_next(VALUE self) {
605
+ VALUE cReader_next(VALUE self) {
950
606
  PGresult *reader = DATA_PTR(rb_iv_get(self, "@reader"));
951
607
 
952
- int field_count;
953
- int row_count;
954
- int i;
955
- int position;
956
-
957
- VALUE array = rb_ary_new();
958
- VALUE field_types, field_type;
959
- VALUE value;
608
+ int row_count = NUM2INT(rb_iv_get(self, "@row_count"));
609
+ int field_count = NUM2INT(rb_iv_get(self, "@field_count"));
610
+ VALUE field_types = rb_iv_get(self, "@field_types");
611
+ int position = NUM2INT(rb_iv_get(self, "@position"));
960
612
 
961
- row_count = NUM2INT(rb_iv_get(self, "@row_count"));
962
- field_count = NUM2INT(rb_iv_get(self, "@field_count"));
963
- field_types = rb_iv_get(self, "@field_types");
964
- position = NUM2INT(rb_iv_get(self, "@position"));
965
-
966
- if ( position > (row_count - 1) ) {
613
+ if (position > (row_count - 1)) {
967
614
  rb_iv_set(self, "@values", Qnil);
968
615
  return Qfalse;
969
616
  }
970
617
 
618
+ rb_iv_set(self, "@opened", Qtrue);
619
+
971
620
  int enc = -1;
972
621
  #ifdef HAVE_RUBY_ENCODING_H
973
622
  VALUE encoding_id = rb_iv_get(rb_iv_get(self, "@connection"), "@encoding_id");
623
+
974
624
  if (encoding_id != Qnil) {
975
625
  enc = FIX2INT(encoding_id);
976
626
  }
977
627
  #endif
978
628
 
979
- for ( i = 0; i < field_count; i++ ) {
629
+ VALUE array = rb_ary_new();
630
+ VALUE field_type;
631
+ VALUE value;
632
+ int i;
633
+
634
+ for (i = 0; i < field_count; i++) {
980
635
  field_type = rb_ary_entry(field_types, i);
981
636
 
982
637
  // Always return nil if the value returned from Postgres is null
983
638
  if (!PQgetisnull(reader, position, i)) {
984
639
  value = typecast(PQgetvalue(reader, position, i), PQgetlength(reader, position, i), field_type, enc);
985
- } else {
640
+ }
641
+ else {
986
642
  value = Qnil;
987
643
  }
988
644
 
@@ -991,117 +647,38 @@ static VALUE cReader_next(VALUE self) {
991
647
 
992
648
  rb_iv_set(self, "@values", array);
993
649
  rb_iv_set(self, "@position", INT2NUM(position+1));
994
-
995
650
  return Qtrue;
996
651
  }
997
652
 
998
- static VALUE cReader_values(VALUE self) {
999
-
1000
- VALUE values = rb_iv_get(self, "@values");
1001
- if(values == Qnil) {
1002
- rb_raise(eDataError, "Reader not initialized");
1003
- return Qnil;
1004
- } else {
1005
- return values;
1006
- }
1007
- }
1008
-
1009
- static VALUE cReader_fields(VALUE self) {
1010
- return rb_iv_get(self, "@fields");
1011
- }
1012
-
1013
- static VALUE cReader_field_count(VALUE self) {
1014
- return rb_iv_get(self, "@field_count");
1015
- }
1016
-
1017
653
  void Init_do_postgres() {
1018
- rb_require("date");
1019
- rb_require("rational");
1020
- rb_require("bigdecimal");
1021
- rb_require("data_objects");
1022
-
1023
- ID_CONST_GET = rb_intern("const_get");
1024
-
1025
- // Get references classes needed for Date/Time parsing
1026
- rb_cDate = CONST_GET(rb_mKernel, "Date");
1027
- rb_cDateTime = CONST_GET(rb_mKernel, "DateTime");
1028
- rb_cBigDecimal = CONST_GET(rb_mKernel, "BigDecimal");
1029
-
1030
- #ifdef RUBY_LESS_THAN_186
1031
- ID_NEW_DATE = rb_intern("new0");
1032
- #else
1033
- ID_NEW_DATE = rb_intern("new!");
1034
- #endif
1035
- ID_RATIONAL = rb_intern("Rational");
1036
- ID_NEW = rb_intern("new");
1037
- ID_ESCAPE = rb_intern("escape_sql");
1038
- ID_LOG = rb_intern("log");
1039
-
1040
- // Get references to the Extlib module
1041
- mExtlib = CONST_GET(rb_mKernel, "Extlib");
1042
- rb_cByteArray = CONST_GET(mExtlib, "ByteArray");
1043
-
1044
- // Get references to the DataObjects module and its classes
1045
- mDO = CONST_GET(rb_mKernel, "DataObjects");
1046
- cDO_Quoting = CONST_GET(mDO, "Quoting");
1047
- cDO_Connection = CONST_GET(mDO, "Connection");
1048
- cDO_Command = CONST_GET(mDO, "Command");
1049
- cDO_Result = CONST_GET(mDO, "Result");
1050
- cDO_Reader = CONST_GET(mDO, "Reader");
1051
- cDO_Logger = CONST_GET(mDO, "Logger");
1052
- cDO_Logger_Message = CONST_GET(cDO_Logger, "Message");
654
+ common_init();
1053
655
 
1054
656
  mPostgres = rb_define_module_under(mDO, "Postgres");
1055
- eConnectionError = CONST_GET(mDO, "ConnectionError");
1056
- eDataError = CONST_GET(mDO, "DataError");
1057
657
  mEncoding = rb_define_module_under(mPostgres, "Encoding");
1058
658
 
1059
- cConnection = DRIVER_CLASS("Connection", cDO_Connection);
659
+ cConnection = rb_define_class_under(mPostgres, "Connection", cDO_Connection);
1060
660
  rb_define_method(cConnection, "initialize", cConnection_initialize, 1);
1061
661
  rb_define_method(cConnection, "dispose", cConnection_dispose, 0);
1062
662
  rb_define_method(cConnection, "character_set", cConnection_character_set , 0);
1063
663
  rb_define_method(cConnection, "quote_string", cConnection_quote_string, 1);
1064
664
  rb_define_method(cConnection, "quote_byte_array", cConnection_quote_byte_array, 1);
1065
665
 
1066
- cCommand = DRIVER_CLASS("Command", cDO_Command);
666
+ cCommand = rb_define_class_under(mPostgres, "Command", cDO_Command);
1067
667
  rb_define_method(cCommand, "set_types", cCommand_set_types, -1);
1068
668
  rb_define_method(cCommand, "execute_non_query", cCommand_execute_non_query, -1);
1069
669
  rb_define_method(cCommand, "execute_reader", cCommand_execute_reader, -1);
1070
670
 
1071
- cResult = DRIVER_CLASS("Result", cDO_Result);
671
+ cResult = rb_define_class_under(mPostgres, "Result", cDO_Result);
1072
672
 
1073
- cReader = DRIVER_CLASS("Reader", cDO_Reader);
673
+ cReader = rb_define_class_under(mPostgres, "Reader", cDO_Reader);
1074
674
  rb_define_method(cReader, "close", cReader_close, 0);
1075
675
  rb_define_method(cReader, "next!", cReader_next, 0);
1076
676
  rb_define_method(cReader, "values", cReader_values, 0);
1077
677
  rb_define_method(cReader, "fields", cReader_fields, 0);
1078
678
  rb_define_method(cReader, "field_count", cReader_field_count, 0);
1079
679
 
1080
- rb_global_variable(&ID_NEW_DATE);
1081
- rb_global_variable(&ID_RATIONAL);
1082
- rb_global_variable(&ID_CONST_GET);
1083
- rb_global_variable(&ID_ESCAPE);
1084
- rb_global_variable(&ID_LOG);
1085
- rb_global_variable(&ID_NEW);
1086
-
1087
- rb_global_variable(&rb_cDate);
1088
- rb_global_variable(&rb_cDateTime);
1089
- rb_global_variable(&rb_cBigDecimal);
1090
- rb_global_variable(&rb_cByteArray);
1091
-
1092
- rb_global_variable(&mDO);
1093
- rb_global_variable(&cDO_Logger_Message);
1094
-
1095
680
  rb_global_variable(&cResult);
1096
681
  rb_global_variable(&cReader);
1097
682
 
1098
- rb_global_variable(&eConnectionError);
1099
- rb_global_variable(&eDataError);
1100
-
1101
- struct errcodes *errs;
1102
-
1103
- for (errs = errors; errs->error_name; errs++) {
1104
- rb_const_set(mPostgres, rb_intern(errs->error_name), INT2NUM(errs->error_no));
1105
- }
1106
-
683
+ do_define_errors(mPostgres, errors);
1107
684
  }