pg 1.1.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (77) hide show
  1. checksums.yaml +7 -0
  2. checksums.yaml.gz.sig +3 -0
  3. data.tar.gz.sig +0 -0
  4. data/.gemtest +0 -0
  5. data/BSDL +22 -0
  6. data/ChangeLog +6595 -0
  7. data/Contributors.rdoc +46 -0
  8. data/History.rdoc +492 -0
  9. data/LICENSE +56 -0
  10. data/Manifest.txt +72 -0
  11. data/POSTGRES +23 -0
  12. data/README-OS_X.rdoc +68 -0
  13. data/README-Windows.rdoc +56 -0
  14. data/README.ja.rdoc +14 -0
  15. data/README.rdoc +178 -0
  16. data/Rakefile +215 -0
  17. data/Rakefile.cross +298 -0
  18. data/ext/errorcodes.def +968 -0
  19. data/ext/errorcodes.rb +45 -0
  20. data/ext/errorcodes.txt +478 -0
  21. data/ext/extconf.rb +94 -0
  22. data/ext/gvl_wrappers.c +17 -0
  23. data/ext/gvl_wrappers.h +241 -0
  24. data/ext/pg.c +640 -0
  25. data/ext/pg.h +365 -0
  26. data/ext/pg_binary_decoder.c +229 -0
  27. data/ext/pg_binary_encoder.c +162 -0
  28. data/ext/pg_coder.c +549 -0
  29. data/ext/pg_connection.c +4252 -0
  30. data/ext/pg_copy_coder.c +596 -0
  31. data/ext/pg_errors.c +95 -0
  32. data/ext/pg_result.c +1501 -0
  33. data/ext/pg_text_decoder.c +981 -0
  34. data/ext/pg_text_encoder.c +682 -0
  35. data/ext/pg_tuple.c +541 -0
  36. data/ext/pg_type_map.c +166 -0
  37. data/ext/pg_type_map_all_strings.c +116 -0
  38. data/ext/pg_type_map_by_class.c +239 -0
  39. data/ext/pg_type_map_by_column.c +312 -0
  40. data/ext/pg_type_map_by_mri_type.c +284 -0
  41. data/ext/pg_type_map_by_oid.c +355 -0
  42. data/ext/pg_type_map_in_ruby.c +299 -0
  43. data/ext/util.c +149 -0
  44. data/ext/util.h +65 -0
  45. data/ext/vc/pg.sln +26 -0
  46. data/ext/vc/pg_18/pg.vcproj +216 -0
  47. data/ext/vc/pg_19/pg_19.vcproj +209 -0
  48. data/lib/pg.rb +74 -0
  49. data/lib/pg/basic_type_mapping.rb +459 -0
  50. data/lib/pg/binary_decoder.rb +22 -0
  51. data/lib/pg/coder.rb +83 -0
  52. data/lib/pg/connection.rb +291 -0
  53. data/lib/pg/constants.rb +11 -0
  54. data/lib/pg/exceptions.rb +11 -0
  55. data/lib/pg/result.rb +31 -0
  56. data/lib/pg/text_decoder.rb +47 -0
  57. data/lib/pg/text_encoder.rb +69 -0
  58. data/lib/pg/tuple.rb +30 -0
  59. data/lib/pg/type_map_by_column.rb +15 -0
  60. data/spec/data/expected_trace.out +26 -0
  61. data/spec/data/random_binary_data +0 -0
  62. data/spec/helpers.rb +380 -0
  63. data/spec/pg/basic_type_mapping_spec.rb +508 -0
  64. data/spec/pg/connection_spec.rb +1872 -0
  65. data/spec/pg/connection_sync_spec.rb +41 -0
  66. data/spec/pg/result_spec.rb +491 -0
  67. data/spec/pg/tuple_spec.rb +280 -0
  68. data/spec/pg/type_map_by_class_spec.rb +138 -0
  69. data/spec/pg/type_map_by_column_spec.rb +222 -0
  70. data/spec/pg/type_map_by_mri_type_spec.rb +136 -0
  71. data/spec/pg/type_map_by_oid_spec.rb +149 -0
  72. data/spec/pg/type_map_in_ruby_spec.rb +164 -0
  73. data/spec/pg/type_map_spec.rb +22 -0
  74. data/spec/pg/type_spec.rb +949 -0
  75. data/spec/pg_spec.rb +50 -0
  76. metadata +322 -0
  77. metadata.gz.sig +0 -0
@@ -0,0 +1,95 @@
1
+ /*
2
+ * pg_errors.c - Definition and lookup of error classes.
3
+ *
4
+ */
5
+
6
+ #include "pg.h"
7
+
8
+ VALUE rb_hErrors;
9
+ VALUE rb_ePGerror;
10
+ VALUE rb_eServerError;
11
+ VALUE rb_eUnableToSend;
12
+ VALUE rb_eConnectionBad;
13
+ VALUE rb_eInvalidResultStatus;
14
+ VALUE rb_eNoResultError;
15
+ VALUE rb_eInvalidChangeOfResultFields;
16
+
17
+ static VALUE
18
+ define_error_class(const char *name, const char *baseclass_code)
19
+ {
20
+ VALUE baseclass = rb_eServerError;
21
+ if(baseclass_code)
22
+ {
23
+ baseclass = rb_hash_aref( rb_hErrors, rb_str_new2(baseclass_code) );
24
+ }
25
+ return rb_define_class_under( rb_mPG, name, baseclass );
26
+ }
27
+
28
+ static void
29
+ register_error_class(const char *code, VALUE klass)
30
+ {
31
+ rb_hash_aset( rb_hErrors, rb_str_new2(code), klass );
32
+ }
33
+
34
+ /* Find a proper error class for the given SQLSTATE string
35
+ */
36
+ VALUE
37
+ lookup_error_class(const char *sqlstate)
38
+ {
39
+ VALUE klass;
40
+
41
+ if(sqlstate)
42
+ {
43
+ /* Find the proper error class by the 5-characters SQLSTATE. */
44
+ klass = rb_hash_aref( rb_hErrors, rb_str_new2(sqlstate) );
45
+ if(NIL_P(klass))
46
+ {
47
+ /* The given SQLSTATE couldn't be found. This might happen, if
48
+ * the server side uses a newer version than the client.
49
+ * Try to find a error class by using the 2-characters SQLSTATE.
50
+ */
51
+ klass = rb_hash_aref( rb_hErrors, rb_str_new(sqlstate, 2) );
52
+ if(NIL_P(klass))
53
+ {
54
+ /* Also the 2-characters SQLSTATE is unknown.
55
+ * Use the generic server error instead.
56
+ */
57
+ klass = rb_eServerError;
58
+ }
59
+ }
60
+ }
61
+ else
62
+ {
63
+ /* Unable to retrieve the PG_DIAG_SQLSTATE.
64
+ * Use the generic error instead.
65
+ */
66
+ klass = rb_eUnableToSend;
67
+ }
68
+
69
+ return klass;
70
+ }
71
+
72
+ void
73
+ init_pg_errors()
74
+ {
75
+ rb_hErrors = rb_hash_new();
76
+ rb_define_const( rb_mPG, "ERROR_CLASSES", rb_hErrors );
77
+
78
+ rb_ePGerror = rb_define_class_under( rb_mPG, "Error", rb_eStandardError );
79
+
80
+ /*************************
81
+ * PG::Error
82
+ *************************/
83
+ rb_define_alias( rb_ePGerror, "error", "message" );
84
+ rb_define_attr( rb_ePGerror, "connection", 1, 0 );
85
+ rb_define_attr( rb_ePGerror, "result", 1, 0 );
86
+
87
+ rb_eServerError = rb_define_class_under( rb_mPG, "ServerError", rb_ePGerror );
88
+ rb_eUnableToSend = rb_define_class_under( rb_mPG, "UnableToSend", rb_ePGerror );
89
+ rb_eConnectionBad = rb_define_class_under( rb_mPG, "ConnectionBad", rb_ePGerror );
90
+ rb_eInvalidResultStatus = rb_define_class_under( rb_mPG, "InvalidResultStatus", rb_ePGerror );
91
+ rb_eNoResultError = rb_define_class_under( rb_mPG, "NoResultError", rb_ePGerror );
92
+ rb_eInvalidChangeOfResultFields = rb_define_class_under( rb_mPG, "InvalidChangeOfResultFields", rb_ePGerror );
93
+
94
+ #include "errorcodes.def"
95
+ }
@@ -0,0 +1,1501 @@
1
+ /*
2
+ * pg_result.c - PG::Result class extension
3
+ * $Id$
4
+ *
5
+ */
6
+
7
+ #include "pg.h"
8
+
9
+
10
+ VALUE rb_cPGresult;
11
+
12
+ static void pgresult_gc_free( t_pg_result * );
13
+ static VALUE pgresult_type_map_set( VALUE, VALUE );
14
+ static VALUE pgresult_s_allocate( VALUE );
15
+ static t_pg_result *pgresult_get_this( VALUE );
16
+ static t_pg_result *pgresult_get_this_safe( VALUE );
17
+
18
+
19
+ #define PGRESULT_DATA_BLOCKSIZE 2048
20
+ typedef struct pgresAttValue
21
+ {
22
+ int len; /* length in bytes of the value */
23
+ char *value; /* actual value, plus terminating zero byte */
24
+ } PGresAttValue;
25
+
26
+
27
+ static int
28
+ count_leading_zero_bits(unsigned int x)
29
+ {
30
+ #if defined(__GNUC__) || defined(__clang__)
31
+ return __builtin_clz(x);
32
+ #elif defined(_MSC_VER)
33
+ DWORD r = 0;
34
+ _BitScanForward(&r, x);
35
+ return (int)r;
36
+ #else
37
+ unsigned int a;
38
+ for(a=0; a < sizeof(unsigned int) * 8; a++){
39
+ if( x & (1 << (sizeof(unsigned int) * 8 - 1))) return a;
40
+ x <<= 1;
41
+ }
42
+ return a;
43
+ #endif
44
+ }
45
+
46
+ static ssize_t
47
+ pgresult_approx_size(PGresult *result)
48
+ {
49
+ int num_fields = PQnfields(result);
50
+ ssize_t size = 0;
51
+
52
+ if( num_fields > 0 ){
53
+ int num_tuples = PQntuples(result);
54
+
55
+ if( num_tuples > 0 ){
56
+ int pos;
57
+
58
+ /* This is a simple heuristic to determine the number of sample fields and subsequently to approximate the memory size taken by all field values of the result set.
59
+ * Since scanning of all field values is would have a severe performance impact, only a small subset of fields is retrieved and the result is extrapolated to the whole result set.
60
+ * The given algorithm has no real scientific background, but is made for speed and typical table layouts.
61
+ */
62
+ int num_samples =
63
+ (num_fields < 9 ? num_fields : 39 - count_leading_zero_bits(num_fields-8)) *
64
+ (num_tuples < 8 ? 1 : 30 - count_leading_zero_bits(num_tuples));
65
+
66
+ /* start with scanning very last fields, since they are most probably in the cache */
67
+ for( pos = 0; pos < (num_samples+1)/2; pos++ ){
68
+ size += PQgetlength(result, num_tuples - 1 - (pos / num_fields), num_fields - 1 - (pos % num_fields));
69
+ }
70
+ /* scan the very first fields */
71
+ for( pos = 0; pos < num_samples/2; pos++ ){
72
+ size += PQgetlength(result, pos / num_fields, pos % num_fields);
73
+ }
74
+ /* extrapolate sample size to whole result set */
75
+ size = size * num_tuples * num_fields / num_samples;
76
+ }
77
+
78
+ /* count metadata */
79
+ size += num_fields * (
80
+ sizeof(PGresAttDesc) + /* column description */
81
+ num_tuples * (
82
+ sizeof(PGresAttValue) + 1 /* ptr, len and zero termination of each value */
83
+ )
84
+ );
85
+
86
+ /* Account free space due to libpq's default block size */
87
+ size = (size + PGRESULT_DATA_BLOCKSIZE - 1) / PGRESULT_DATA_BLOCKSIZE * PGRESULT_DATA_BLOCKSIZE;
88
+
89
+ /* count tuple pointers */
90
+ size += sizeof(void*) * ((num_tuples + 128 - 1) / 128 * 128);
91
+ }
92
+
93
+ size += 216; /* add PGresult size */
94
+
95
+ return size;
96
+ }
97
+
98
+ static void
99
+ pgresult_clear( t_pg_result *this )
100
+ {
101
+ if( this->pgresult && !this->autoclear ){
102
+ PQclear(this->pgresult);
103
+ #ifdef HAVE_RB_GC_ADJUST_MEMORY_USAGE
104
+ rb_gc_adjust_memory_usage(-this->result_size);
105
+ #endif
106
+ }
107
+ this->pgresult = NULL;
108
+ }
109
+
110
+ static size_t
111
+ pgresult_memsize( t_pg_result *this )
112
+ {
113
+ return this->result_size;
114
+ }
115
+
116
+ /*
117
+ * Global functions
118
+ */
119
+
120
+ /*
121
+ * Result constructor
122
+ */
123
+ static VALUE
124
+ pg_new_result2(PGresult *result, VALUE rb_pgconn)
125
+ {
126
+ int nfields = result ? PQnfields(result) : 0;
127
+ VALUE self = pgresult_s_allocate( rb_cPGresult );
128
+ t_pg_result *this;
129
+
130
+ this = (t_pg_result *)xmalloc(sizeof(*this) + sizeof(*this->fnames) * nfields);
131
+ RTYPEDDATA_DATA(self) = this;
132
+
133
+ this->pgresult = result;
134
+ this->connection = rb_pgconn;
135
+ this->typemap = pg_typemap_all_strings;
136
+ this->p_typemap = DATA_PTR( this->typemap );
137
+ this->nfields = -1;
138
+ this->tuple_hash = Qnil;
139
+ this->field_map = Qnil;
140
+
141
+ PG_ENCODING_SET_NOCHECK(self, ENCODING_GET(rb_pgconn));
142
+
143
+ if( result ){
144
+ t_pg_connection *p_conn = pg_get_connection(rb_pgconn);
145
+ VALUE typemap = p_conn->type_map_for_results;
146
+
147
+ /* Type check is done when assigned to PG::Connection. */
148
+ t_typemap *p_typemap = DATA_PTR(typemap);
149
+
150
+ this->typemap = p_typemap->funcs.fit_to_result( typemap, self );
151
+ this->p_typemap = DATA_PTR( this->typemap );
152
+ }
153
+
154
+ return self;
155
+ }
156
+
157
+ VALUE
158
+ pg_new_result(PGresult *result, VALUE rb_pgconn)
159
+ {
160
+ VALUE self = pg_new_result2(result, rb_pgconn);
161
+ t_pg_result *this = pgresult_get_this(self);
162
+ t_pg_connection *p_conn = pg_get_connection(rb_pgconn);
163
+
164
+ this->autoclear = 0;
165
+
166
+ if( p_conn->guess_result_memsize ){
167
+ /* Approximate size of underlying pgresult memory storage and account to ruby GC */
168
+ this->result_size = pgresult_approx_size(result);
169
+
170
+ #ifdef HAVE_RB_GC_ADJUST_MEMORY_USAGE
171
+ rb_gc_adjust_memory_usage(this->result_size);
172
+ #endif
173
+ }
174
+
175
+ return self;
176
+ }
177
+
178
+ VALUE
179
+ pg_new_result_autoclear(PGresult *result, VALUE rb_pgconn)
180
+ {
181
+ VALUE self = pg_new_result2(result, rb_pgconn);
182
+ t_pg_result *this = pgresult_get_this(self);
183
+
184
+ /* Autocleared results are freed implicit instead of by PQclear().
185
+ * So it's not very useful to be accounted by ruby GC.
186
+ */
187
+ this->result_size = 0;
188
+ this->autoclear = 1;
189
+ return self;
190
+ }
191
+
192
+ /*
193
+ * call-seq:
194
+ * res.check -> nil
195
+ *
196
+ * Raises appropriate exception if PG::Result is in a bad state.
197
+ */
198
+ VALUE
199
+ pg_result_check( VALUE self )
200
+ {
201
+ t_pg_result *this = pgresult_get_this(self);
202
+ VALUE error, exception, klass;
203
+ char * sqlstate;
204
+
205
+ if(this->pgresult == NULL)
206
+ {
207
+ PGconn *conn = pg_get_pgconn(this->connection);
208
+ error = rb_str_new2( PQerrorMessage(conn) );
209
+ }
210
+ else
211
+ {
212
+ switch (PQresultStatus(this->pgresult))
213
+ {
214
+ case PGRES_TUPLES_OK:
215
+ case PGRES_COPY_OUT:
216
+ case PGRES_COPY_IN:
217
+ case PGRES_COPY_BOTH:
218
+ case PGRES_SINGLE_TUPLE:
219
+ case PGRES_EMPTY_QUERY:
220
+ case PGRES_COMMAND_OK:
221
+ return self;
222
+ case PGRES_BAD_RESPONSE:
223
+ case PGRES_FATAL_ERROR:
224
+ case PGRES_NONFATAL_ERROR:
225
+ error = rb_str_new2( PQresultErrorMessage(this->pgresult) );
226
+ break;
227
+ default:
228
+ error = rb_str_new2( "internal error : unknown result status." );
229
+ }
230
+ }
231
+
232
+ PG_ENCODING_SET_NOCHECK( error, ENCODING_GET(self) );
233
+
234
+ sqlstate = PQresultErrorField( this->pgresult, PG_DIAG_SQLSTATE );
235
+ klass = lookup_error_class( sqlstate );
236
+ exception = rb_exc_new3( klass, error );
237
+ rb_iv_set( exception, "@connection", this->connection );
238
+ rb_iv_set( exception, "@result", this->pgresult ? self : Qnil );
239
+ rb_exc_raise( exception );
240
+
241
+ /* Not reached */
242
+ return self;
243
+ }
244
+
245
+
246
+ /*
247
+ * :TODO: This shouldn't be a global function, but it needs to be as long as pg_new_result
248
+ * doesn't handle blocks, check results, etc. Once connection and result are disentangled
249
+ * a bit more, I can make this a static pgresult_clear() again.
250
+ */
251
+
252
+ /*
253
+ * call-seq:
254
+ * res.clear() -> nil
255
+ *
256
+ * Clears the PG::Result object as the result of a query.
257
+ * This frees all underlying memory consumed by the result object.
258
+ * Afterwards access to result methods raises PG::Error "result has been cleared".
259
+ *
260
+ * Explicit calling #clear can lead to better memory performance, but is not generally necessary.
261
+ * Special care must be taken when PG::Tuple objects are used.
262
+ * In this case #clear must not be called unless all PG::Tuple objects of this result are fully materialized.
263
+ *
264
+ * If PG::Result#autoclear? is true then the result is marked as cleared
265
+ * and the underlying C struct will be cleared automatically by libpq.
266
+ *
267
+ */
268
+ VALUE
269
+ pg_result_clear(VALUE self)
270
+ {
271
+ t_pg_result *this = pgresult_get_this(self);
272
+ pgresult_clear( this );
273
+ return Qnil;
274
+ }
275
+
276
+ /*
277
+ * call-seq:
278
+ * res.cleared? -> boolean
279
+ *
280
+ * Returns +true+ if the backend result memory has been free'd.
281
+ */
282
+ VALUE
283
+ pgresult_cleared_p( VALUE self )
284
+ {
285
+ t_pg_result *this = pgresult_get_this(self);
286
+ return this->pgresult ? Qfalse : Qtrue;
287
+ }
288
+
289
+ /*
290
+ * call-seq:
291
+ * res.autoclear? -> boolean
292
+ *
293
+ * Returns +true+ if the underlying C struct will be cleared automatically by libpq.
294
+ * Elsewise the result is cleared by PG::Result#clear or by the GC when it's no longer in use.
295
+ *
296
+ */
297
+ VALUE
298
+ pgresult_autoclear_p( VALUE self )
299
+ {
300
+ t_pg_result *this = pgresult_get_this(self);
301
+ return this->autoclear ? Qtrue : Qfalse;
302
+ }
303
+
304
+ /*
305
+ * DATA pointer functions
306
+ */
307
+
308
+ /*
309
+ * GC Mark function
310
+ */
311
+ static void
312
+ pgresult_gc_mark( t_pg_result *this )
313
+ {
314
+ int i;
315
+
316
+ if( !this ) return;
317
+ rb_gc_mark( this->connection );
318
+ rb_gc_mark( this->typemap );
319
+ rb_gc_mark( this->tuple_hash );
320
+ rb_gc_mark( this->field_map );
321
+
322
+ for( i=0; i < this->nfields; i++ ){
323
+ rb_gc_mark( this->fnames[i] );
324
+ }
325
+ }
326
+
327
+ /*
328
+ * GC Free function
329
+ */
330
+ static void
331
+ pgresult_gc_free( t_pg_result *this )
332
+ {
333
+ if( !this ) return;
334
+ pgresult_clear( this );
335
+
336
+ xfree(this);
337
+ }
338
+
339
+ /*
340
+ * Fetch the PG::Result object data pointer and check it's
341
+ * PGresult data pointer for sanity.
342
+ */
343
+ static t_pg_result *
344
+ pgresult_get_this_safe( VALUE self )
345
+ {
346
+ t_pg_result *this = pgresult_get_this(self);
347
+
348
+ if (this->pgresult == NULL) rb_raise(rb_ePGerror, "result has been cleared");
349
+ return this;
350
+ }
351
+
352
+ /*
353
+ * Fetch the PGresult pointer for the result object and check validity
354
+ *
355
+ * Note: This function is used externally by the sequel_pg gem,
356
+ * so do changes carefully.
357
+ *
358
+ */
359
+ PGresult*
360
+ pgresult_get(VALUE self)
361
+ {
362
+ t_pg_result *this = pgresult_get_this(self);
363
+
364
+ if (this->pgresult == NULL) rb_raise(rb_ePGerror, "result has been cleared");
365
+ return this->pgresult;
366
+ }
367
+
368
+
369
+ static const rb_data_type_t pgresult_type = {
370
+ "pg",
371
+ {
372
+ (void (*)(void*))pgresult_gc_mark,
373
+ (void (*)(void*))pgresult_gc_free,
374
+ (size_t (*)(const void *))pgresult_memsize,
375
+ },
376
+ 0, 0,
377
+ #ifdef RUBY_TYPED_FREE_IMMEDIATELY
378
+ RUBY_TYPED_FREE_IMMEDIATELY,
379
+ #endif
380
+ };
381
+
382
+ /*
383
+ * Document-method: allocate
384
+ *
385
+ * call-seq:
386
+ * PG::Result.allocate -> result
387
+ */
388
+ static VALUE
389
+ pgresult_s_allocate( VALUE klass )
390
+ {
391
+ VALUE self = TypedData_Wrap_Struct( klass, &pgresult_type, NULL );
392
+
393
+ return self;
394
+ }
395
+
396
+ static void pgresult_init_fnames(VALUE self)
397
+ {
398
+ t_pg_result *this = pgresult_get_this_safe(self);
399
+
400
+ if( this->nfields == -1 ){
401
+ int i;
402
+ int nfields = PQnfields(this->pgresult);
403
+
404
+ for( i=0; i<nfields; i++ ){
405
+ VALUE fname = rb_tainted_str_new2(PQfname(this->pgresult, i));
406
+ PG_ENCODING_SET_NOCHECK(fname, ENCODING_GET(self));
407
+ this->fnames[i] = rb_obj_freeze(fname);
408
+ this->nfields = i + 1;
409
+
410
+ RB_GC_GUARD(fname);
411
+ }
412
+ this->nfields = nfields;
413
+ }
414
+ }
415
+
416
+ /********************************************************************
417
+ *
418
+ * Document-class: PG::Result
419
+ *
420
+ * The class to represent the query result tuples (rows).
421
+ * An instance of this class is created as the result of every query.
422
+ * All result rows and columns are stored in a memory block attached to the PG::Result object.
423
+ * Whenever a value is accessed it is casted to a Ruby object by the assigned #type_map .
424
+ *
425
+ * Since pg-1.1 the amount of memory in use by a PG::Result object is estimated and passed to ruby's garbage collector.
426
+ * You can invoke the #clear method to force deallocation of memory of the instance when finished with the result for better memory performance.
427
+ *
428
+ * Example:
429
+ * require 'pg'
430
+ * conn = PG.connect(:dbname => 'test')
431
+ * res = conn.exec('SELECT 1 AS a, 2 AS b, NULL AS c')
432
+ * res.getvalue(0,0) # '1'
433
+ * res[0]['b'] # '2'
434
+ * res[0]['c'] # nil
435
+ *
436
+ */
437
+
438
+ /**************************************************************************
439
+ * PG::Result INSTANCE METHODS
440
+ **************************************************************************/
441
+
442
+ /*
443
+ * call-seq:
444
+ * res.result_status() -> Integer
445
+ *
446
+ * Returns the status of the query. The status value is one of:
447
+ * * +PGRES_EMPTY_QUERY+
448
+ * * +PGRES_COMMAND_OK+
449
+ * * +PGRES_TUPLES_OK+
450
+ * * +PGRES_COPY_OUT+
451
+ * * +PGRES_COPY_IN+
452
+ * * +PGRES_BAD_RESPONSE+
453
+ * * +PGRES_NONFATAL_ERROR+
454
+ * * +PGRES_FATAL_ERROR+
455
+ * * +PGRES_COPY_BOTH+
456
+ */
457
+ static VALUE
458
+ pgresult_result_status(VALUE self)
459
+ {
460
+ return INT2FIX(PQresultStatus(pgresult_get(self)));
461
+ }
462
+
463
+ /*
464
+ * call-seq:
465
+ * res.res_status( status ) -> String
466
+ *
467
+ * Returns the string representation of status +status+.
468
+ *
469
+ */
470
+ static VALUE
471
+ pgresult_res_status(VALUE self, VALUE status)
472
+ {
473
+ VALUE ret = rb_tainted_str_new2(PQresStatus(NUM2INT(status)));
474
+ PG_ENCODING_SET_NOCHECK(ret, ENCODING_GET(self));
475
+ return ret;
476
+ }
477
+
478
+ /*
479
+ * call-seq:
480
+ * res.error_message() -> String
481
+ *
482
+ * Returns the error message of the command as a string.
483
+ */
484
+ static VALUE
485
+ pgresult_error_message(VALUE self)
486
+ {
487
+ VALUE ret = rb_tainted_str_new2(PQresultErrorMessage(pgresult_get(self)));
488
+ PG_ENCODING_SET_NOCHECK(ret, ENCODING_GET(self));
489
+ return ret;
490
+ }
491
+
492
+ /*
493
+ * call-seq:
494
+ * res.error_field(fieldcode) -> String
495
+ *
496
+ * Returns the individual field of an error.
497
+ *
498
+ * +fieldcode+ is one of:
499
+ * * +PG_DIAG_SEVERITY+
500
+ * * +PG_DIAG_SQLSTATE+
501
+ * * +PG_DIAG_MESSAGE_PRIMARY+
502
+ * * +PG_DIAG_MESSAGE_DETAIL+
503
+ * * +PG_DIAG_MESSAGE_HINT+
504
+ * * +PG_DIAG_STATEMENT_POSITION+
505
+ * * +PG_DIAG_INTERNAL_POSITION+
506
+ * * +PG_DIAG_INTERNAL_QUERY+
507
+ * * +PG_DIAG_CONTEXT+
508
+ * * +PG_DIAG_SOURCE_FILE+
509
+ * * +PG_DIAG_SOURCE_LINE+
510
+ * * +PG_DIAG_SOURCE_FUNCTION+
511
+ *
512
+ * An example:
513
+ *
514
+ * begin
515
+ * conn.exec( "SELECT * FROM nonexistant_table" )
516
+ * rescue PG::Error => err
517
+ * p [
518
+ * err.result.error_field( PG::Result::PG_DIAG_SEVERITY ),
519
+ * err.result.error_field( PG::Result::PG_DIAG_SQLSTATE ),
520
+ * err.result.error_field( PG::Result::PG_DIAG_MESSAGE_PRIMARY ),
521
+ * err.result.error_field( PG::Result::PG_DIAG_MESSAGE_DETAIL ),
522
+ * err.result.error_field( PG::Result::PG_DIAG_MESSAGE_HINT ),
523
+ * err.result.error_field( PG::Result::PG_DIAG_STATEMENT_POSITION ),
524
+ * err.result.error_field( PG::Result::PG_DIAG_INTERNAL_POSITION ),
525
+ * err.result.error_field( PG::Result::PG_DIAG_INTERNAL_QUERY ),
526
+ * err.result.error_field( PG::Result::PG_DIAG_CONTEXT ),
527
+ * err.result.error_field( PG::Result::PG_DIAG_SOURCE_FILE ),
528
+ * err.result.error_field( PG::Result::PG_DIAG_SOURCE_LINE ),
529
+ * err.result.error_field( PG::Result::PG_DIAG_SOURCE_FUNCTION ),
530
+ * ]
531
+ * end
532
+ *
533
+ * Outputs:
534
+ *
535
+ * ["ERROR", "42P01", "relation \"nonexistant_table\" does not exist", nil, nil,
536
+ * "15", nil, nil, nil, "path/to/parse_relation.c", "857", "parserOpenTable"]
537
+ */
538
+ static VALUE
539
+ pgresult_error_field(VALUE self, VALUE field)
540
+ {
541
+ PGresult *result = pgresult_get( self );
542
+ int fieldcode = NUM2INT( field );
543
+ char * fieldstr = PQresultErrorField( result, fieldcode );
544
+ VALUE ret = Qnil;
545
+
546
+ if ( fieldstr ) {
547
+ ret = rb_tainted_str_new2( fieldstr );
548
+ PG_ENCODING_SET_NOCHECK( ret, ENCODING_GET(self ));
549
+ }
550
+
551
+ return ret;
552
+ }
553
+
554
+ /*
555
+ * call-seq:
556
+ * res.ntuples() -> Integer
557
+ *
558
+ * Returns the number of tuples in the query result.
559
+ */
560
+ static VALUE
561
+ pgresult_ntuples(VALUE self)
562
+ {
563
+ return INT2FIX(PQntuples(pgresult_get(self)));
564
+ }
565
+
566
+ static VALUE
567
+ pgresult_ntuples_for_enum(VALUE self, VALUE args, VALUE eobj)
568
+ {
569
+ return pgresult_ntuples(self);
570
+ }
571
+
572
+ /*
573
+ * call-seq:
574
+ * res.nfields() -> Integer
575
+ *
576
+ * Returns the number of columns in the query result.
577
+ */
578
+ static VALUE
579
+ pgresult_nfields(VALUE self)
580
+ {
581
+ return INT2NUM(PQnfields(pgresult_get(self)));
582
+ }
583
+
584
+ /*
585
+ * call-seq:
586
+ * res.fname( index ) -> String
587
+ *
588
+ * Returns the name of the column corresponding to _index_.
589
+ */
590
+ static VALUE
591
+ pgresult_fname(VALUE self, VALUE index)
592
+ {
593
+ VALUE fname;
594
+ PGresult *result = pgresult_get(self);
595
+ int i = NUM2INT(index);
596
+
597
+ if (i < 0 || i >= PQnfields(result)) {
598
+ rb_raise(rb_eArgError,"invalid field number %d", i);
599
+ }
600
+
601
+ fname = rb_tainted_str_new2(PQfname(result, i));
602
+ PG_ENCODING_SET_NOCHECK(fname, ENCODING_GET(self));
603
+ return rb_obj_freeze(fname);
604
+ }
605
+
606
+ /*
607
+ * call-seq:
608
+ * res.fnumber( name ) -> Integer
609
+ *
610
+ * Returns the index of the field specified by the string +name+.
611
+ * The given +name+ is treated like an identifier in an SQL command, that is,
612
+ * it is downcased unless double-quoted. For example, given a query result
613
+ * generated from the SQL command:
614
+ *
615
+ * result = conn.exec( %{SELECT 1 AS FOO, 2 AS "BAR"} )
616
+ *
617
+ * we would have the results:
618
+ *
619
+ * result.fname( 0 ) # => "foo"
620
+ * result.fname( 1 ) # => "BAR"
621
+ * result.fnumber( "FOO" ) # => 0
622
+ * result.fnumber( "foo" ) # => 0
623
+ * result.fnumber( "BAR" ) # => ArgumentError
624
+ * result.fnumber( %{"BAR"} ) # => 1
625
+ *
626
+ * Raises an ArgumentError if the specified +name+ isn't one of the field names;
627
+ * raises a TypeError if +name+ is not a String.
628
+ */
629
+ static VALUE
630
+ pgresult_fnumber(VALUE self, VALUE name)
631
+ {
632
+ int n;
633
+
634
+ Check_Type(name, T_STRING);
635
+
636
+ n = PQfnumber(pgresult_get(self), StringValueCStr(name));
637
+ if (n == -1) {
638
+ rb_raise(rb_eArgError,"Unknown field: %s", StringValueCStr(name));
639
+ }
640
+ return INT2FIX(n);
641
+ }
642
+
643
+ /*
644
+ * call-seq:
645
+ * res.ftable( column_number ) -> Integer
646
+ *
647
+ * Returns the Oid of the table from which the column _column_number_
648
+ * was fetched.
649
+ *
650
+ * Raises ArgumentError if _column_number_ is out of range or if
651
+ * the Oid is undefined for that column.
652
+ */
653
+ static VALUE
654
+ pgresult_ftable(VALUE self, VALUE column_number)
655
+ {
656
+ Oid n ;
657
+ int col_number = NUM2INT(column_number);
658
+ PGresult *pgresult = pgresult_get(self);
659
+
660
+ if( col_number < 0 || col_number >= PQnfields(pgresult))
661
+ rb_raise(rb_eArgError,"Invalid column index: %d", col_number);
662
+
663
+ n = PQftable(pgresult, col_number);
664
+ return UINT2NUM(n);
665
+ }
666
+
667
+ /*
668
+ * call-seq:
669
+ * res.ftablecol( column_number ) -> Integer
670
+ *
671
+ * Returns the column number (within its table) of the table from
672
+ * which the column _column_number_ is made up.
673
+ *
674
+ * Raises ArgumentError if _column_number_ is out of range or if
675
+ * the column number from its table is undefined for that column.
676
+ */
677
+ static VALUE
678
+ pgresult_ftablecol(VALUE self, VALUE column_number)
679
+ {
680
+ int col_number = NUM2INT(column_number);
681
+ PGresult *pgresult = pgresult_get(self);
682
+
683
+ int n;
684
+
685
+ if( col_number < 0 || col_number >= PQnfields(pgresult))
686
+ rb_raise(rb_eArgError,"Invalid column index: %d", col_number);
687
+
688
+ n = PQftablecol(pgresult, col_number);
689
+ return INT2FIX(n);
690
+ }
691
+
692
+ /*
693
+ * call-seq:
694
+ * res.fformat( column_number ) -> Integer
695
+ *
696
+ * Returns the format (0 for text, 1 for binary) of column
697
+ * _column_number_.
698
+ *
699
+ * Raises ArgumentError if _column_number_ is out of range.
700
+ */
701
+ static VALUE
702
+ pgresult_fformat(VALUE self, VALUE column_number)
703
+ {
704
+ PGresult *result = pgresult_get(self);
705
+ int fnumber = NUM2INT(column_number);
706
+ if (fnumber < 0 || fnumber >= PQnfields(result)) {
707
+ rb_raise(rb_eArgError, "Column number is out of range: %d",
708
+ fnumber);
709
+ }
710
+ return INT2FIX(PQfformat(result, fnumber));
711
+ }
712
+
713
+ /*
714
+ * call-seq:
715
+ * res.ftype( column_number ) -> Integer
716
+ *
717
+ * Returns the data type associated with _column_number_.
718
+ *
719
+ * The integer returned is the internal +OID+ number (in PostgreSQL)
720
+ * of the type. To get a human-readable value for the type, use the
721
+ * returned OID and the field's #fmod value with the format_type() SQL
722
+ * function:
723
+ *
724
+ * # Get the type of the second column of the result 'res'
725
+ * typename = conn.
726
+ * exec( "SELECT format_type($1,$2)", [res.ftype(1), res.fmod(1)] ).
727
+ * getvalue( 0, 0 )
728
+ *
729
+ * Raises an ArgumentError if _column_number_ is out of range.
730
+ */
731
+ static VALUE
732
+ pgresult_ftype(VALUE self, VALUE index)
733
+ {
734
+ PGresult* result = pgresult_get(self);
735
+ int i = NUM2INT(index);
736
+ if (i < 0 || i >= PQnfields(result)) {
737
+ rb_raise(rb_eArgError, "invalid field number %d", i);
738
+ }
739
+ return UINT2NUM(PQftype(result, i));
740
+ }
741
+
742
+ /*
743
+ * call-seq:
744
+ * res.fmod( column_number )
745
+ *
746
+ * Returns the type modifier associated with column _column_number_. See
747
+ * the #ftype method for an example of how to use this.
748
+ *
749
+ * Raises an ArgumentError if _column_number_ is out of range.
750
+ */
751
+ static VALUE
752
+ pgresult_fmod(VALUE self, VALUE column_number)
753
+ {
754
+ PGresult *result = pgresult_get(self);
755
+ int fnumber = NUM2INT(column_number);
756
+ int modifier;
757
+ if (fnumber < 0 || fnumber >= PQnfields(result)) {
758
+ rb_raise(rb_eArgError, "Column number is out of range: %d",
759
+ fnumber);
760
+ }
761
+ modifier = PQfmod(result,fnumber);
762
+
763
+ return INT2NUM(modifier);
764
+ }
765
+
766
+ /*
767
+ * call-seq:
768
+ * res.fsize( index )
769
+ *
770
+ * Returns the size of the field type in bytes. Returns <tt>-1</tt> if the field is variable sized.
771
+ *
772
+ * res = conn.exec("SELECT myInt, myVarChar50 FROM foo")
773
+ * res.size(0) => 4
774
+ * res.size(1) => -1
775
+ */
776
+ static VALUE
777
+ pgresult_fsize(VALUE self, VALUE index)
778
+ {
779
+ PGresult *result;
780
+ int i = NUM2INT(index);
781
+
782
+ result = pgresult_get(self);
783
+ if (i < 0 || i >= PQnfields(result)) {
784
+ rb_raise(rb_eArgError,"invalid field number %d", i);
785
+ }
786
+ return INT2NUM(PQfsize(result, i));
787
+ }
788
+
789
+
790
+ /*
791
+ * call-seq:
792
+ * res.getvalue( tup_num, field_num )
793
+ *
794
+ * Returns the value in tuple number _tup_num_, field _field_num_,
795
+ * or +nil+ if the field is +NULL+.
796
+ */
797
+ static VALUE
798
+ pgresult_getvalue(VALUE self, VALUE tup_num, VALUE field_num)
799
+ {
800
+ t_pg_result *this = pgresult_get_this_safe(self);
801
+ int i = NUM2INT(tup_num);
802
+ int j = NUM2INT(field_num);
803
+
804
+ if(i < 0 || i >= PQntuples(this->pgresult)) {
805
+ rb_raise(rb_eArgError,"invalid tuple number %d", i);
806
+ }
807
+ if(j < 0 || j >= PQnfields(this->pgresult)) {
808
+ rb_raise(rb_eArgError,"invalid field number %d", j);
809
+ }
810
+ return this->p_typemap->funcs.typecast_result_value(this->p_typemap, self, i, j);
811
+ }
812
+
813
+ /*
814
+ * call-seq:
815
+ * res.getisnull(tuple_position, field_position) -> boolean
816
+ *
817
+ * Returns +true+ if the specified value is +nil+; +false+ otherwise.
818
+ */
819
+ static VALUE
820
+ pgresult_getisnull(VALUE self, VALUE tup_num, VALUE field_num)
821
+ {
822
+ PGresult *result;
823
+ int i = NUM2INT(tup_num);
824
+ int j = NUM2INT(field_num);
825
+
826
+ result = pgresult_get(self);
827
+ if (i < 0 || i >= PQntuples(result)) {
828
+ rb_raise(rb_eArgError,"invalid tuple number %d", i);
829
+ }
830
+ if (j < 0 || j >= PQnfields(result)) {
831
+ rb_raise(rb_eArgError,"invalid field number %d", j);
832
+ }
833
+ return PQgetisnull(result, i, j) ? Qtrue : Qfalse;
834
+ }
835
+
836
+ /*
837
+ * call-seq:
838
+ * res.getlength( tup_num, field_num ) -> Integer
839
+ *
840
+ * Returns the (String) length of the field in bytes.
841
+ *
842
+ * Equivalent to <tt>res.value(<i>tup_num</i>,<i>field_num</i>).length</tt>.
843
+ */
844
+ static VALUE
845
+ pgresult_getlength(VALUE self, VALUE tup_num, VALUE field_num)
846
+ {
847
+ PGresult *result;
848
+ int i = NUM2INT(tup_num);
849
+ int j = NUM2INT(field_num);
850
+
851
+ result = pgresult_get(self);
852
+ if (i < 0 || i >= PQntuples(result)) {
853
+ rb_raise(rb_eArgError,"invalid tuple number %d", i);
854
+ }
855
+ if (j < 0 || j >= PQnfields(result)) {
856
+ rb_raise(rb_eArgError,"invalid field number %d", j);
857
+ }
858
+ return INT2FIX(PQgetlength(result, i, j));
859
+ }
860
+
861
+ /*
862
+ * call-seq:
863
+ * res.nparams() -> Integer
864
+ *
865
+ * Returns the number of parameters of a prepared statement.
866
+ * Only useful for the result returned by conn.describePrepared
867
+ */
868
+ static VALUE
869
+ pgresult_nparams(VALUE self)
870
+ {
871
+ PGresult *result;
872
+
873
+ result = pgresult_get(self);
874
+ return INT2FIX(PQnparams(result));
875
+ }
876
+
877
+ /*
878
+ * call-seq:
879
+ * res.paramtype( param_number ) -> Oid
880
+ *
881
+ * Returns the Oid of the data type of parameter _param_number_.
882
+ * Only useful for the result returned by conn.describePrepared
883
+ */
884
+ static VALUE
885
+ pgresult_paramtype(VALUE self, VALUE param_number)
886
+ {
887
+ PGresult *result;
888
+
889
+ result = pgresult_get(self);
890
+ return UINT2NUM(PQparamtype(result,NUM2INT(param_number)));
891
+ }
892
+
893
+ /*
894
+ * call-seq:
895
+ * res.cmd_status() -> String
896
+ *
897
+ * Returns the status string of the last query command.
898
+ */
899
+ static VALUE
900
+ pgresult_cmd_status(VALUE self)
901
+ {
902
+ VALUE ret = rb_tainted_str_new2(PQcmdStatus(pgresult_get(self)));
903
+ PG_ENCODING_SET_NOCHECK(ret, ENCODING_GET(self));
904
+ return ret;
905
+ }
906
+
907
+ /*
908
+ * call-seq:
909
+ * res.cmd_tuples() -> Integer
910
+ *
911
+ * Returns the number of tuples (rows) affected by the SQL command.
912
+ *
913
+ * If the SQL command that generated the PG::Result was not one of:
914
+ *
915
+ * * <tt>SELECT</tt>
916
+ * * <tt>CREATE TABLE AS</tt>
917
+ * * <tt>INSERT</tt>
918
+ * * <tt>UPDATE</tt>
919
+ * * <tt>DELETE</tt>
920
+ * * <tt>MOVE</tt>
921
+ * * <tt>FETCH</tt>
922
+ * * <tt>COPY</tt>
923
+ * * an +EXECUTE+ of a prepared query that contains an +INSERT+, +UPDATE+, or +DELETE+ statement
924
+ *
925
+ * or if no tuples were affected, <tt>0</tt> is returned.
926
+ */
927
+ static VALUE
928
+ pgresult_cmd_tuples(VALUE self)
929
+ {
930
+ long n;
931
+ n = strtol(PQcmdTuples(pgresult_get(self)),NULL, 10);
932
+ return INT2NUM(n);
933
+ }
934
+
935
+ /*
936
+ * call-seq:
937
+ * res.oid_value() -> Integer
938
+ *
939
+ * Returns the +oid+ of the inserted row if applicable,
940
+ * otherwise +nil+.
941
+ */
942
+ static VALUE
943
+ pgresult_oid_value(VALUE self)
944
+ {
945
+ Oid n = PQoidValue(pgresult_get(self));
946
+ if (n == InvalidOid)
947
+ return Qnil;
948
+ else
949
+ return UINT2NUM(n);
950
+ }
951
+
952
+ /* Utility methods not in libpq */
953
+
954
+ /*
955
+ * call-seq:
956
+ * res[ n ] -> Hash
957
+ *
958
+ * Returns tuple _n_ as a hash.
959
+ */
960
+ static VALUE
961
+ pgresult_aref(VALUE self, VALUE index)
962
+ {
963
+ t_pg_result *this = pgresult_get_this_safe(self);
964
+ int tuple_num = NUM2INT(index);
965
+ int field_num;
966
+ int num_tuples = PQntuples(this->pgresult);
967
+ VALUE tuple;
968
+
969
+ if( this->nfields == -1 )
970
+ pgresult_init_fnames( self );
971
+
972
+ if ( tuple_num < 0 || tuple_num >= num_tuples )
973
+ rb_raise( rb_eIndexError, "Index %d is out of range", tuple_num );
974
+
975
+ /* We reuse the Hash of the previous output for larger row counts.
976
+ * This is somewhat faster than populating an empty Hash object. */
977
+ tuple = NIL_P(this->tuple_hash) ? rb_hash_new() : this->tuple_hash;
978
+ for ( field_num = 0; field_num < this->nfields; field_num++ ) {
979
+ VALUE val = this->p_typemap->funcs.typecast_result_value(this->p_typemap, self, tuple_num, field_num);
980
+ rb_hash_aset( tuple, this->fnames[field_num], val );
981
+ }
982
+ /* Store a copy of the filled hash for use at the next row. */
983
+ if( num_tuples > 10 )
984
+ this->tuple_hash = rb_hash_dup(tuple);
985
+
986
+ return tuple;
987
+ }
988
+
989
+ /*
990
+ * call-seq:
991
+ * res.each_row { |row| ... }
992
+ *
993
+ * Yields each row of the result. The row is a list of column values.
994
+ */
995
+ static VALUE
996
+ pgresult_each_row(VALUE self)
997
+ {
998
+ t_pg_result *this;
999
+ int row;
1000
+ int field;
1001
+ int num_rows;
1002
+ int num_fields;
1003
+
1004
+ RETURN_SIZED_ENUMERATOR(self, 0, NULL, pgresult_ntuples_for_enum);
1005
+
1006
+ this = pgresult_get_this_safe(self);
1007
+ num_rows = PQntuples(this->pgresult);
1008
+ num_fields = PQnfields(this->pgresult);
1009
+
1010
+ for ( row = 0; row < num_rows; row++ ) {
1011
+ PG_VARIABLE_LENGTH_ARRAY(VALUE, row_values, num_fields, PG_MAX_COLUMNS)
1012
+
1013
+ /* populate the row */
1014
+ for ( field = 0; field < num_fields; field++ ) {
1015
+ row_values[field] = this->p_typemap->funcs.typecast_result_value(this->p_typemap, self, row, field);
1016
+ }
1017
+ rb_yield( rb_ary_new4( num_fields, row_values ));
1018
+ }
1019
+
1020
+ return Qnil;
1021
+ }
1022
+
1023
+ /*
1024
+ * call-seq:
1025
+ * res.values -> Array
1026
+ *
1027
+ * Returns all tuples as an array of arrays.
1028
+ */
1029
+ static VALUE
1030
+ pgresult_values(VALUE self)
1031
+ {
1032
+ t_pg_result *this = pgresult_get_this_safe(self);
1033
+ int row;
1034
+ int field;
1035
+ int num_rows = PQntuples(this->pgresult);
1036
+ int num_fields = PQnfields(this->pgresult);
1037
+ VALUE results = rb_ary_new2( num_rows );
1038
+
1039
+ for ( row = 0; row < num_rows; row++ ) {
1040
+ PG_VARIABLE_LENGTH_ARRAY(VALUE, row_values, num_fields, PG_MAX_COLUMNS)
1041
+
1042
+ /* populate the row */
1043
+ for ( field = 0; field < num_fields; field++ ) {
1044
+ row_values[field] = this->p_typemap->funcs.typecast_result_value(this->p_typemap, self, row, field);
1045
+ }
1046
+ rb_ary_store( results, row, rb_ary_new4( num_fields, row_values ) );
1047
+ }
1048
+
1049
+ return results;
1050
+ }
1051
+
1052
+ /*
1053
+ * Make a Ruby array out of the encoded values from the specified
1054
+ * column in the given result.
1055
+ */
1056
+ static VALUE
1057
+ make_column_result_array( VALUE self, int col )
1058
+ {
1059
+ t_pg_result *this = pgresult_get_this_safe(self);
1060
+ int rows = PQntuples( this->pgresult );
1061
+ int i;
1062
+ VALUE results = rb_ary_new2( rows );
1063
+
1064
+ if ( col >= PQnfields(this->pgresult) )
1065
+ rb_raise( rb_eIndexError, "no column %d in result", col );
1066
+
1067
+ for ( i=0; i < rows; i++ ) {
1068
+ VALUE val = this->p_typemap->funcs.typecast_result_value(this->p_typemap, self, i, col);
1069
+ rb_ary_store( results, i, val );
1070
+ }
1071
+
1072
+ return results;
1073
+ }
1074
+
1075
+
1076
+ /*
1077
+ * call-seq:
1078
+ * res.column_values( n ) -> array
1079
+ *
1080
+ * Returns an Array of the values from the nth column of each
1081
+ * tuple in the result.
1082
+ *
1083
+ */
1084
+ static VALUE
1085
+ pgresult_column_values(VALUE self, VALUE index)
1086
+ {
1087
+ int col = NUM2INT( index );
1088
+ return make_column_result_array( self, col );
1089
+ }
1090
+
1091
+
1092
+ /*
1093
+ * call-seq:
1094
+ * res.field_values( field ) -> array
1095
+ *
1096
+ * Returns an Array of the values from the given _field_ of each tuple in the result.
1097
+ *
1098
+ */
1099
+ static VALUE
1100
+ pgresult_field_values( VALUE self, VALUE field )
1101
+ {
1102
+ PGresult *result = pgresult_get( self );
1103
+ const char *fieldname = StringValueCStr( field );
1104
+ int fnum = PQfnumber( result, fieldname );
1105
+
1106
+ if ( fnum < 0 )
1107
+ rb_raise( rb_eIndexError, "no such field '%s' in result", fieldname );
1108
+
1109
+ return make_column_result_array( self, fnum );
1110
+ }
1111
+
1112
+
1113
+ /*
1114
+ * call-seq:
1115
+ * res.tuple_values( n ) -> array
1116
+ *
1117
+ * Returns an Array of the field values from the nth row of the result.
1118
+ *
1119
+ */
1120
+ static VALUE
1121
+ pgresult_tuple_values(VALUE self, VALUE index)
1122
+ {
1123
+ int tuple_num = NUM2INT( index );
1124
+ t_pg_result *this;
1125
+ int field;
1126
+ int num_tuples;
1127
+ int num_fields;
1128
+
1129
+ this = pgresult_get_this_safe(self);
1130
+ num_tuples = PQntuples(this->pgresult);
1131
+ num_fields = PQnfields(this->pgresult);
1132
+
1133
+ if ( tuple_num < 0 || tuple_num >= num_tuples )
1134
+ rb_raise( rb_eIndexError, "Index %d is out of range", tuple_num );
1135
+
1136
+ {
1137
+ PG_VARIABLE_LENGTH_ARRAY(VALUE, row_values, num_fields, PG_MAX_COLUMNS)
1138
+
1139
+ /* populate the row */
1140
+ for ( field = 0; field < num_fields; field++ ) {
1141
+ row_values[field] = this->p_typemap->funcs.typecast_result_value(this->p_typemap, self, tuple_num, field);
1142
+ }
1143
+ return rb_ary_new4( num_fields, row_values );
1144
+ }
1145
+ }
1146
+
1147
+ /*
1148
+ * call-seq:
1149
+ * res.tuple( n ) -> PG::Tuple
1150
+ *
1151
+ * Returns a PG::Tuple from the nth row of the result.
1152
+ *
1153
+ */
1154
+ static VALUE
1155
+ pgresult_tuple(VALUE self, VALUE index)
1156
+ {
1157
+ int tuple_num = NUM2INT( index );
1158
+ t_pg_result *this;
1159
+ int num_tuples;
1160
+
1161
+ this = pgresult_get_this_safe(self);
1162
+ num_tuples = PQntuples(this->pgresult);
1163
+
1164
+ if ( tuple_num < 0 || tuple_num >= num_tuples )
1165
+ rb_raise( rb_eIndexError, "Index %d is out of range", tuple_num );
1166
+
1167
+ if( this->field_map == Qnil ){
1168
+ int i;
1169
+ VALUE field_map = rb_hash_new();
1170
+
1171
+ if( this->nfields == -1 )
1172
+ pgresult_init_fnames( self );
1173
+
1174
+ for( i = 0; i < this->nfields; i++ ){
1175
+ rb_hash_aset(field_map, this->fnames[i], INT2FIX(i));
1176
+ }
1177
+ rb_obj_freeze(field_map);
1178
+ this->field_map = field_map;
1179
+ }
1180
+
1181
+ return pg_tuple_new(self, tuple_num);
1182
+ }
1183
+
1184
+
1185
+ /*
1186
+ * call-seq:
1187
+ * res.each{ |tuple| ... }
1188
+ *
1189
+ * Invokes block for each tuple in the result set.
1190
+ */
1191
+ static VALUE
1192
+ pgresult_each(VALUE self)
1193
+ {
1194
+ PGresult *result;
1195
+ int tuple_num;
1196
+
1197
+ RETURN_SIZED_ENUMERATOR(self, 0, NULL, pgresult_ntuples_for_enum);
1198
+
1199
+ result = pgresult_get(self);
1200
+
1201
+ for(tuple_num = 0; tuple_num < PQntuples(result); tuple_num++) {
1202
+ rb_yield(pgresult_aref(self, INT2NUM(tuple_num)));
1203
+ }
1204
+ return self;
1205
+ }
1206
+
1207
+ /*
1208
+ * call-seq:
1209
+ * res.fields() -> Array
1210
+ *
1211
+ * Returns an array of Strings representing the names of the fields in the result.
1212
+ */
1213
+ static VALUE
1214
+ pgresult_fields(VALUE self)
1215
+ {
1216
+ t_pg_result *this = pgresult_get_this_safe(self);
1217
+
1218
+ if( this->nfields == -1 )
1219
+ pgresult_init_fnames( self );
1220
+
1221
+ return rb_ary_new4( this->nfields, this->fnames );
1222
+ }
1223
+
1224
+ /*
1225
+ * call-seq:
1226
+ * res.type_map = typemap
1227
+ *
1228
+ * Set the TypeMap that is used for type casts of result values to ruby objects.
1229
+ *
1230
+ * All value retrieval methods will respect the type map and will do the
1231
+ * type casts from PostgreSQL's wire format to Ruby objects on the fly,
1232
+ * according to the rules and decoders defined in the given typemap.
1233
+ *
1234
+ * +typemap+ must be a kind of PG::TypeMap .
1235
+ *
1236
+ */
1237
+ static VALUE
1238
+ pgresult_type_map_set(VALUE self, VALUE typemap)
1239
+ {
1240
+ t_pg_result *this = pgresult_get_this(self);
1241
+ t_typemap *p_typemap;
1242
+
1243
+ if ( !rb_obj_is_kind_of(typemap, rb_cTypeMap) ) {
1244
+ rb_raise( rb_eTypeError, "wrong argument type %s (expected kind of PG::TypeMap)",
1245
+ rb_obj_classname( typemap ) );
1246
+ }
1247
+ Data_Get_Struct(typemap, t_typemap, p_typemap);
1248
+
1249
+ this->typemap = p_typemap->funcs.fit_to_result( typemap, self );
1250
+ this->p_typemap = DATA_PTR( this->typemap );
1251
+
1252
+ return typemap;
1253
+ }
1254
+
1255
+ /*
1256
+ * call-seq:
1257
+ * res.type_map -> value
1258
+ *
1259
+ * Returns the TypeMap that is currently set for type casts of result values to ruby objects.
1260
+ *
1261
+ */
1262
+ static VALUE
1263
+ pgresult_type_map_get(VALUE self)
1264
+ {
1265
+ t_pg_result *this = pgresult_get_this(self);
1266
+
1267
+ return this->typemap;
1268
+ }
1269
+
1270
+
1271
+ static void
1272
+ yield_hash(VALUE self, int ntuples, int nfields)
1273
+ {
1274
+ int tuple_num;
1275
+ t_pg_result *this = pgresult_get_this(self);
1276
+ UNUSED(nfields);
1277
+
1278
+ for(tuple_num = 0; tuple_num < ntuples; tuple_num++) {
1279
+ rb_yield(pgresult_aref(self, INT2NUM(tuple_num)));
1280
+ }
1281
+
1282
+ pgresult_clear( this );
1283
+ }
1284
+
1285
+ static void
1286
+ yield_array(VALUE self, int ntuples, int nfields)
1287
+ {
1288
+ int row;
1289
+ t_pg_result *this = pgresult_get_this(self);
1290
+
1291
+ for ( row = 0; row < ntuples; row++ ) {
1292
+ PG_VARIABLE_LENGTH_ARRAY(VALUE, row_values, nfields, PG_MAX_COLUMNS)
1293
+ int field;
1294
+
1295
+ /* populate the row */
1296
+ for ( field = 0; field < nfields; field++ ) {
1297
+ row_values[field] = this->p_typemap->funcs.typecast_result_value(this->p_typemap, self, row, field);
1298
+ }
1299
+ rb_yield( rb_ary_new4( nfields, row_values ));
1300
+ }
1301
+
1302
+ pgresult_clear( this );
1303
+ }
1304
+
1305
+ static void
1306
+ yield_tuple(VALUE self, int ntuples, int nfields)
1307
+ {
1308
+ int tuple_num;
1309
+ t_pg_result *this = pgresult_get_this(self);
1310
+ VALUE result = pg_new_result(this->pgresult, this->connection);
1311
+ UNUSED(nfields);
1312
+
1313
+ for(tuple_num = 0; tuple_num < ntuples; tuple_num++) {
1314
+ VALUE tuple = pgresult_tuple(result, INT2FIX(tuple_num));
1315
+ rb_yield( tuple );
1316
+ }
1317
+ }
1318
+
1319
+ static VALUE
1320
+ pgresult_stream_any(VALUE self, void (*yielder)(VALUE, int, int))
1321
+ {
1322
+ t_pg_result *this;
1323
+ int nfields;
1324
+ PGconn *pgconn;
1325
+ PGresult *pgresult;
1326
+
1327
+ RETURN_ENUMERATOR(self, 0, NULL);
1328
+
1329
+ this = pgresult_get_this_safe(self);
1330
+ pgconn = pg_get_pgconn(this->connection);
1331
+ pgresult = this->pgresult;
1332
+ nfields = PQnfields(pgresult);
1333
+
1334
+ for(;;){
1335
+ int ntuples = PQntuples(pgresult);
1336
+
1337
+ switch( PQresultStatus(pgresult) ){
1338
+ case PGRES_TUPLES_OK:
1339
+ if( ntuples == 0 )
1340
+ return self;
1341
+ rb_raise( rb_eInvalidResultStatus, "PG::Result is not in single row mode");
1342
+ case PGRES_SINGLE_TUPLE:
1343
+ break;
1344
+ default:
1345
+ pg_result_check( self );
1346
+ }
1347
+
1348
+ yielder( self, ntuples, nfields );
1349
+
1350
+ pgresult = gvl_PQgetResult(pgconn);
1351
+ if( pgresult == NULL )
1352
+ rb_raise( rb_eNoResultError, "no result received - possibly an intersection with another result retrieval");
1353
+
1354
+ if( nfields != PQnfields(pgresult) )
1355
+ rb_raise( rb_eInvalidChangeOfResultFields, "number of fields must not change in single row mode");
1356
+
1357
+ this->pgresult = pgresult;
1358
+ }
1359
+
1360
+ /* never reached */
1361
+ return self;
1362
+ }
1363
+
1364
+
1365
+ /*
1366
+ * call-seq:
1367
+ * res.stream_each{ |tuple| ... }
1368
+ *
1369
+ * Invokes block for each tuple in the result set in single row mode.
1370
+ *
1371
+ * This is a convenience method for retrieving all result tuples
1372
+ * as they are transferred. It is an alternative to repeated calls of
1373
+ * PG::Connection#get_result , but given that it avoids the overhead of
1374
+ * wrapping each row into a dedicated result object, it delivers data in nearly
1375
+ * the same speed as with ordinary results.
1376
+ *
1377
+ * The base result must be in status PGRES_SINGLE_TUPLE.
1378
+ * It iterates over all tuples until the status changes to PGRES_TUPLES_OK.
1379
+ * A PG::Error is raised for any errors from the server.
1380
+ *
1381
+ * Row description data does not change while the iteration. All value retrieval
1382
+ * methods refer to only the current row. Result#ntuples returns +1+ while
1383
+ * the iteration and +0+ after all tuples were yielded.
1384
+ *
1385
+ * Example:
1386
+ * conn.send_query( "first SQL query; second SQL query" )
1387
+ * conn.set_single_row_mode
1388
+ * conn.get_result.stream_each do |row|
1389
+ * # do something with each received row of the first query
1390
+ * end
1391
+ * conn.get_result.stream_each do |row|
1392
+ * # do something with each received row of the second query
1393
+ * end
1394
+ * conn.get_result # => nil (no more results)
1395
+ *
1396
+ * Available since PostgreSQL-9.2
1397
+ */
1398
+ static VALUE
1399
+ pgresult_stream_each(VALUE self)
1400
+ {
1401
+ return pgresult_stream_any(self, yield_hash);
1402
+ }
1403
+
1404
+ /*
1405
+ * call-seq:
1406
+ * res.stream_each_row { |row| ... }
1407
+ *
1408
+ * Yields each row of the result set in single row mode.
1409
+ * The row is a list of column values.
1410
+ *
1411
+ * This method works equally to #stream_each , but yields an Array of
1412
+ * values.
1413
+ *
1414
+ * Available since PostgreSQL-9.2
1415
+ */
1416
+ static VALUE
1417
+ pgresult_stream_each_row(VALUE self)
1418
+ {
1419
+ return pgresult_stream_any(self, yield_array);
1420
+ }
1421
+
1422
+ /*
1423
+ * call-seq:
1424
+ * res.stream_each_tuple { |tuple| ... }
1425
+ *
1426
+ * Yields each row of the result set in single row mode.
1427
+ *
1428
+ * This method works equally to #stream_each , but yields a PG::Tuple object.
1429
+ *
1430
+ * Available since PostgreSQL-9.2
1431
+ */
1432
+ static VALUE
1433
+ pgresult_stream_each_tuple(VALUE self)
1434
+ {
1435
+ return pgresult_stream_any(self, yield_tuple);
1436
+ }
1437
+
1438
+
1439
+ void
1440
+ init_pg_result()
1441
+ {
1442
+ rb_cPGresult = rb_define_class_under( rb_mPG, "Result", rb_cObject );
1443
+ rb_define_alloc_func( rb_cPGresult, pgresult_s_allocate );
1444
+ rb_include_module(rb_cPGresult, rb_mEnumerable);
1445
+ rb_include_module(rb_cPGresult, rb_mPGconstants);
1446
+
1447
+ /****** PG::Result INSTANCE METHODS: libpq ******/
1448
+ rb_define_method(rb_cPGresult, "result_status", pgresult_result_status, 0);
1449
+ rb_define_method(rb_cPGresult, "res_status", pgresult_res_status, 1);
1450
+ rb_define_method(rb_cPGresult, "error_message", pgresult_error_message, 0);
1451
+ rb_define_alias( rb_cPGresult, "result_error_message", "error_message");
1452
+ rb_define_method(rb_cPGresult, "error_field", pgresult_error_field, 1);
1453
+ rb_define_alias( rb_cPGresult, "result_error_field", "error_field" );
1454
+ rb_define_method(rb_cPGresult, "clear", pg_result_clear, 0);
1455
+ rb_define_method(rb_cPGresult, "check", pg_result_check, 0);
1456
+ rb_define_alias (rb_cPGresult, "check_result", "check");
1457
+ rb_define_method(rb_cPGresult, "ntuples", pgresult_ntuples, 0);
1458
+ rb_define_alias(rb_cPGresult, "num_tuples", "ntuples");
1459
+ rb_define_method(rb_cPGresult, "nfields", pgresult_nfields, 0);
1460
+ rb_define_alias(rb_cPGresult, "num_fields", "nfields");
1461
+ rb_define_method(rb_cPGresult, "fname", pgresult_fname, 1);
1462
+ rb_define_method(rb_cPGresult, "fnumber", pgresult_fnumber, 1);
1463
+ rb_define_method(rb_cPGresult, "ftable", pgresult_ftable, 1);
1464
+ rb_define_method(rb_cPGresult, "ftablecol", pgresult_ftablecol, 1);
1465
+ rb_define_method(rb_cPGresult, "fformat", pgresult_fformat, 1);
1466
+ rb_define_method(rb_cPGresult, "ftype", pgresult_ftype, 1);
1467
+ rb_define_method(rb_cPGresult, "fmod", pgresult_fmod, 1);
1468
+ rb_define_method(rb_cPGresult, "fsize", pgresult_fsize, 1);
1469
+ rb_define_method(rb_cPGresult, "getvalue", pgresult_getvalue, 2);
1470
+ rb_define_method(rb_cPGresult, "getisnull", pgresult_getisnull, 2);
1471
+ rb_define_method(rb_cPGresult, "getlength", pgresult_getlength, 2);
1472
+ rb_define_method(rb_cPGresult, "nparams", pgresult_nparams, 0);
1473
+ rb_define_method(rb_cPGresult, "paramtype", pgresult_paramtype, 1);
1474
+ rb_define_method(rb_cPGresult, "cmd_status", pgresult_cmd_status, 0);
1475
+ rb_define_method(rb_cPGresult, "cmd_tuples", pgresult_cmd_tuples, 0);
1476
+ rb_define_alias(rb_cPGresult, "cmdtuples", "cmd_tuples");
1477
+ rb_define_method(rb_cPGresult, "oid_value", pgresult_oid_value, 0);
1478
+
1479
+ /****** PG::Result INSTANCE METHODS: other ******/
1480
+ rb_define_method(rb_cPGresult, "[]", pgresult_aref, 1);
1481
+ rb_define_method(rb_cPGresult, "each", pgresult_each, 0);
1482
+ rb_define_method(rb_cPGresult, "fields", pgresult_fields, 0);
1483
+ rb_define_method(rb_cPGresult, "each_row", pgresult_each_row, 0);
1484
+ rb_define_method(rb_cPGresult, "values", pgresult_values, 0);
1485
+ rb_define_method(rb_cPGresult, "column_values", pgresult_column_values, 1);
1486
+ rb_define_method(rb_cPGresult, "field_values", pgresult_field_values, 1);
1487
+ rb_define_method(rb_cPGresult, "tuple_values", pgresult_tuple_values, 1);
1488
+ rb_define_method(rb_cPGresult, "tuple", pgresult_tuple, 1);
1489
+ rb_define_method(rb_cPGresult, "cleared?", pgresult_cleared_p, 0);
1490
+ rb_define_method(rb_cPGresult, "autoclear?", pgresult_autoclear_p, 0);
1491
+
1492
+ rb_define_method(rb_cPGresult, "type_map=", pgresult_type_map_set, 1);
1493
+ rb_define_method(rb_cPGresult, "type_map", pgresult_type_map_get, 0);
1494
+
1495
+ /****** PG::Result INSTANCE METHODS: streaming ******/
1496
+ rb_define_method(rb_cPGresult, "stream_each", pgresult_stream_each, 0);
1497
+ rb_define_method(rb_cPGresult, "stream_each_row", pgresult_stream_each_row, 0);
1498
+ rb_define_method(rb_cPGresult, "stream_each_tuple", pgresult_stream_each_tuple, 0);
1499
+ }
1500
+
1501
+