yugabyte_ysql 0.1

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