pg 1.3.0.rc2-x64-mingw-ucrt

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