pg 1.3.0.rc2-x64-mingw-ucrt

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
+ }