pg 0.18.4 → 1.2.3

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 (85) hide show
  1. checksums.yaml +5 -5
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/BSDL +2 -2
  5. data/ChangeLog +0 -5911
  6. data/History.rdoc +240 -0
  7. data/Manifest.txt +8 -20
  8. data/README-Windows.rdoc +4 -4
  9. data/README.ja.rdoc +1 -2
  10. data/README.rdoc +64 -15
  11. data/Rakefile +20 -21
  12. data/Rakefile.cross +67 -69
  13. data/ext/errorcodes.def +101 -0
  14. data/ext/errorcodes.rb +1 -1
  15. data/ext/errorcodes.txt +33 -2
  16. data/ext/extconf.rb +26 -36
  17. data/ext/gvl_wrappers.c +4 -0
  18. data/ext/gvl_wrappers.h +27 -39
  19. data/ext/pg.c +156 -145
  20. data/ext/pg.h +74 -98
  21. data/ext/pg_binary_decoder.c +82 -15
  22. data/ext/pg_binary_encoder.c +20 -19
  23. data/ext/pg_coder.c +103 -21
  24. data/ext/pg_connection.c +917 -523
  25. data/ext/pg_copy_coder.c +50 -12
  26. data/ext/pg_record_coder.c +491 -0
  27. data/ext/pg_result.c +590 -208
  28. data/ext/pg_text_decoder.c +606 -40
  29. data/ext/pg_text_encoder.c +245 -94
  30. data/ext/pg_tuple.c +549 -0
  31. data/ext/pg_type_map.c +14 -7
  32. data/ext/pg_type_map_all_strings.c +4 -4
  33. data/ext/pg_type_map_by_class.c +9 -4
  34. data/ext/pg_type_map_by_column.c +7 -6
  35. data/ext/pg_type_map_by_mri_type.c +1 -1
  36. data/ext/pg_type_map_by_oid.c +3 -2
  37. data/ext/pg_type_map_in_ruby.c +1 -1
  38. data/ext/{util.c → pg_util.c} +10 -10
  39. data/ext/{util.h → pg_util.h} +2 -2
  40. data/lib/pg.rb +23 -13
  41. data/lib/pg/basic_type_mapping.rb +155 -32
  42. data/lib/pg/binary_decoder.rb +23 -0
  43. data/lib/pg/coder.rb +23 -2
  44. data/lib/pg/connection.rb +73 -13
  45. data/lib/pg/constants.rb +2 -1
  46. data/lib/pg/exceptions.rb +2 -1
  47. data/lib/pg/result.rb +24 -7
  48. data/lib/pg/text_decoder.rb +24 -22
  49. data/lib/pg/text_encoder.rb +40 -8
  50. data/lib/pg/tuple.rb +30 -0
  51. data/lib/pg/type_map_by_column.rb +3 -2
  52. data/spec/helpers.rb +61 -36
  53. data/spec/pg/basic_type_mapping_spec.rb +415 -36
  54. data/spec/pg/connection_spec.rb +732 -327
  55. data/spec/pg/connection_sync_spec.rb +41 -0
  56. data/spec/pg/result_spec.rb +253 -21
  57. data/spec/pg/tuple_spec.rb +333 -0
  58. data/spec/pg/type_map_by_class_spec.rb +4 -4
  59. data/spec/pg/type_map_by_column_spec.rb +6 -2
  60. data/spec/pg/type_map_by_mri_type_spec.rb +2 -2
  61. data/spec/pg/type_map_by_oid_spec.rb +3 -3
  62. data/spec/pg/type_map_in_ruby_spec.rb +1 -1
  63. data/spec/pg/type_map_spec.rb +1 -1
  64. data/spec/pg/type_spec.rb +446 -20
  65. data/spec/pg_spec.rb +2 -2
  66. metadata +63 -72
  67. metadata.gz.sig +0 -0
  68. data/sample/array_insert.rb +0 -20
  69. data/sample/async_api.rb +0 -106
  70. data/sample/async_copyto.rb +0 -39
  71. data/sample/async_mixed.rb +0 -56
  72. data/sample/check_conn.rb +0 -21
  73. data/sample/copyfrom.rb +0 -81
  74. data/sample/copyto.rb +0 -19
  75. data/sample/cursor.rb +0 -21
  76. data/sample/disk_usage_report.rb +0 -186
  77. data/sample/issue-119.rb +0 -94
  78. data/sample/losample.rb +0 -69
  79. data/sample/minimal-testcase.rb +0 -17
  80. data/sample/notify_wait.rb +0 -72
  81. data/sample/pg_statistics.rb +0 -294
  82. data/sample/replication_monitor.rb +0 -231
  83. data/sample/test_binary_values.rb +0 -33
  84. data/sample/wal_shipper.rb +0 -434
  85. data/sample/warehouse_partitions.rb +0 -320
@@ -1,21 +1,177 @@
1
1
  /*
2
2
  * pg_result.c - PG::Result class extension
3
- * $Id: pg_result.c,v 1269b8ad77b8 2015/02/06 16:38:23 lars $
3
+ * $Id$
4
4
  *
5
5
  */
6
6
 
7
7
  #include "pg.h"
8
8
 
9
-
10
9
  VALUE rb_cPGresult;
10
+ static VALUE sym_symbol, sym_string, sym_static_symbol;
11
11
 
12
- static void pgresult_gc_free( t_pg_result * );
13
12
  static VALUE pgresult_type_map_set( VALUE, VALUE );
14
- static VALUE pgresult_s_allocate( VALUE );
15
13
  static t_pg_result *pgresult_get_this( VALUE );
16
14
  static t_pg_result *pgresult_get_this_safe( VALUE );
17
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( t_pg_result *this )
111
+ {
112
+ int i;
113
+
114
+ rb_gc_mark( this->connection );
115
+ rb_gc_mark( this->typemap );
116
+ rb_gc_mark( this->tuple_hash );
117
+ rb_gc_mark( this->field_map );
118
+
119
+ for( i=0; i < this->nfields; i++ ){
120
+ rb_gc_mark( this->fnames[i] );
121
+ }
122
+ }
123
+
124
+ /*
125
+ * GC Free function
126
+ */
127
+ static void
128
+ pgresult_clear( t_pg_result *this )
129
+ {
130
+ if( this->pgresult && !this->autoclear ){
131
+ PQclear(this->pgresult);
132
+ #ifdef HAVE_RB_GC_ADJUST_MEMORY_USAGE
133
+ rb_gc_adjust_memory_usage(-this->result_size);
134
+ #endif
135
+ }
136
+ this->result_size = 0;
137
+ this->nfields = -1;
138
+ this->pgresult = NULL;
139
+ }
140
+
141
+ static void
142
+ pgresult_gc_free( t_pg_result *this )
143
+ {
144
+ pgresult_clear( this );
145
+ xfree(this);
146
+ }
18
147
 
148
+ static size_t
149
+ pgresult_memsize( t_pg_result *this )
150
+ {
151
+ /* Ideally the memory 'this' is pointing to should be taken into account as well.
152
+ * However we don't want to store two memory sizes in t_pg_result just for reporting by ObjectSpace.memsize_of.
153
+ */
154
+ return this->result_size;
155
+ }
156
+
157
+ static const rb_data_type_t pgresult_type = {
158
+ "pg",
159
+ {
160
+ (void (*)(void*))pgresult_gc_mark,
161
+ (void (*)(void*))pgresult_gc_free,
162
+ (size_t (*)(const void *))pgresult_memsize,
163
+ },
164
+ 0, 0,
165
+ #ifdef RUBY_TYPED_FREE_IMMEDIATELY
166
+ RUBY_TYPED_FREE_IMMEDIATELY,
167
+ #endif
168
+ };
169
+
170
+ /* Needed by sequel_pg gem, do not delete */
171
+ int pg_get_result_enc_idx(VALUE self)
172
+ {
173
+ return pgresult_get_this(self)->enc_idx;
174
+ }
19
175
 
20
176
  /*
21
177
  * Global functions
@@ -24,45 +180,88 @@ static t_pg_result *pgresult_get_this_safe( VALUE );
24
180
  /*
25
181
  * Result constructor
26
182
  */
27
- VALUE
28
- pg_new_result(PGresult *result, VALUE rb_pgconn)
183
+ static VALUE
184
+ pg_new_result2(PGresult *result, VALUE rb_pgconn)
29
185
  {
30
186
  int nfields = result ? PQnfields(result) : 0;
31
- VALUE self = pgresult_s_allocate( rb_cPGresult );
187
+ VALUE self;
32
188
  t_pg_result *this;
33
189
 
34
190
  this = (t_pg_result *)xmalloc(sizeof(*this) + sizeof(*this->fnames) * nfields);
35
- DATA_PTR(self) = this;
36
-
37
191
  this->pgresult = result;
38
192
  this->connection = rb_pgconn;
39
193
  this->typemap = pg_typemap_all_strings;
40
194
  this->p_typemap = DATA_PTR( this->typemap );
41
- this->autoclear = 0;
42
195
  this->nfields = -1;
43
196
  this->tuple_hash = Qnil;
44
-
45
- PG_ENCODING_SET_NOCHECK(self, ENCODING_GET(rb_pgconn));
197
+ this->field_map = Qnil;
198
+ this->flags = 0;
199
+ self = TypedData_Wrap_Struct(rb_cPGresult, &pgresult_type, this);
46
200
 
47
201
  if( result ){
48
202
  t_pg_connection *p_conn = pg_get_connection(rb_pgconn);
49
203
  VALUE typemap = p_conn->type_map_for_results;
50
-
51
204
  /* Type check is done when assigned to PG::Connection. */
52
205
  t_typemap *p_typemap = DATA_PTR(typemap);
53
206
 
207
+ this->enc_idx = p_conn->enc_idx;
54
208
  this->typemap = p_typemap->funcs.fit_to_result( typemap, self );
55
209
  this->p_typemap = DATA_PTR( this->typemap );
210
+ this->flags = p_conn->flags;
211
+ } else {
212
+ this->enc_idx = rb_locale_encindex();
56
213
  }
57
214
 
58
215
  return self;
59
216
  }
60
217
 
218
+ VALUE
219
+ pg_new_result(PGresult *result, VALUE rb_pgconn)
220
+ {
221
+ VALUE self = pg_new_result2(result, rb_pgconn);
222
+ t_pg_result *this = pgresult_get_this(self);
223
+
224
+ this->autoclear = 0;
225
+
226
+ /* Estimate size of underlying pgresult memory storage and account to ruby GC.
227
+ * There's no need to adjust the GC for xmalloc'ed memory, but libpq is using libc malloc() ruby doesn't know about.
228
+ */
229
+ /* 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.
230
+ * For now the memory savings don't justify the ifdefs necessary to support both cases.
231
+ */
232
+ this->result_size = pgresult_approx_size(result);
233
+
234
+ #ifdef HAVE_RB_GC_ADJUST_MEMORY_USAGE
235
+ rb_gc_adjust_memory_usage(this->result_size);
236
+ #endif
237
+
238
+ return self;
239
+ }
240
+
241
+ static VALUE
242
+ pg_copy_result(t_pg_result *this)
243
+ {
244
+ int nfields = this->nfields == -1 ? (this->pgresult ? PQnfields(this->pgresult) : 0) : this->nfields;
245
+ size_t len = sizeof(*this) + sizeof(*this->fnames) * nfields;
246
+ t_pg_result *copy;
247
+
248
+ copy = (t_pg_result *)xmalloc(len);
249
+ memcpy(copy, this, len);
250
+ this->result_size = 0;
251
+
252
+ return TypedData_Wrap_Struct(rb_cPGresult, &pgresult_type, copy);
253
+ }
254
+
61
255
  VALUE
62
256
  pg_new_result_autoclear(PGresult *result, VALUE rb_pgconn)
63
257
  {
64
- VALUE self = pg_new_result(result, rb_pgconn);
258
+ VALUE self = pg_new_result2(result, rb_pgconn);
65
259
  t_pg_result *this = pgresult_get_this(self);
260
+
261
+ /* Autocleared results are freed implicit instead of by PQclear().
262
+ * So it's not very useful to be accounted by ruby GC.
263
+ */
264
+ this->result_size = 0;
66
265
  this->autoclear = 1;
67
266
  return self;
68
267
  }
@@ -92,12 +291,8 @@ pg_result_check( VALUE self )
92
291
  case PGRES_TUPLES_OK:
93
292
  case PGRES_COPY_OUT:
94
293
  case PGRES_COPY_IN:
95
- #ifdef HAVE_CONST_PGRES_COPY_BOTH
96
294
  case PGRES_COPY_BOTH:
97
- #endif
98
- #ifdef HAVE_CONST_PGRES_SINGLE_TUPLE
99
295
  case PGRES_SINGLE_TUPLE:
100
- #endif
101
296
  case PGRES_EMPTY_QUERY:
102
297
  case PGRES_COMMAND_OK:
103
298
  return self;
@@ -111,7 +306,7 @@ pg_result_check( VALUE self )
111
306
  }
112
307
  }
113
308
 
114
- PG_ENCODING_SET_NOCHECK( error, ENCODING_GET(self) );
309
+ PG_ENCODING_SET_NOCHECK( error, this->enc_idx );
115
310
 
116
311
  sqlstate = PQresultErrorField( this->pgresult, PG_DIAG_SQLSTATE );
117
312
  klass = lookup_error_class( sqlstate );
@@ -135,19 +330,22 @@ pg_result_check( VALUE self )
135
330
  * call-seq:
136
331
  * res.clear() -> nil
137
332
  *
138
- * Clears the PG::Result object as the result of the query.
333
+ * Clears the PG::Result object as the result of a query.
334
+ * This frees all underlying memory consumed by the result object.
335
+ * Afterwards access to result methods raises PG::Error "result has been cleared".
336
+ *
337
+ * Explicit calling #clear can lead to better memory performance, but is not generally necessary.
338
+ * Special care must be taken when PG::Tuple objects are used.
339
+ * In this case #clear must not be called unless all PG::Tuple objects of this result are fully materialized.
139
340
  *
140
- * If PG::Result#autoclear? is true then the result is marked as cleared
141
- * and the underlying C struct will be cleared automatically by libpq.
341
+ * 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.
142
342
  *
143
343
  */
144
344
  VALUE
145
345
  pg_result_clear(VALUE self)
146
346
  {
147
347
  t_pg_result *this = pgresult_get_this(self);
148
- if( !this->autoclear )
149
- PQclear(pgresult_get(self));
150
- this->pgresult = NULL;
348
+ pgresult_clear( this );
151
349
  return Qnil;
152
350
  }
153
351
 
@@ -168,8 +366,10 @@ pgresult_cleared_p( VALUE self )
168
366
  * call-seq:
169
367
  * res.autoclear? -> boolean
170
368
  *
171
- * Returns +true+ if the underlying C struct will be cleared automatically by libpq.
172
- * Elsewise the result is cleared by PG::Result#clear or by the GC when it's no longer in use.
369
+ * Returns +true+ if the underlying C struct will be cleared at the end of a callback.
370
+ * This applies only to Result objects received by the block to PG::Cinnection#set_notice_receiver .
371
+ *
372
+ * All other Result objects are automatically cleared by the GC when the object is no longer in use or manually by PG::Result#clear .
173
373
  *
174
374
  */
175
375
  VALUE
@@ -183,37 +383,6 @@ pgresult_autoclear_p( VALUE self )
183
383
  * DATA pointer functions
184
384
  */
185
385
 
186
- /*
187
- * GC Mark function
188
- */
189
- static void
190
- pgresult_gc_mark( t_pg_result *this )
191
- {
192
- int i;
193
-
194
- if( !this ) return;
195
- rb_gc_mark( this->connection );
196
- rb_gc_mark( this->typemap );
197
- rb_gc_mark( this->tuple_hash );
198
-
199
- for( i=0; i < this->nfields; i++ ){
200
- rb_gc_mark( this->fnames[i] );
201
- }
202
- }
203
-
204
- /*
205
- * GC Free function
206
- */
207
- static void
208
- pgresult_gc_free( t_pg_result *this )
209
- {
210
- if( !this ) return;
211
- if(this->pgresult != NULL && !this->autoclear)
212
- PQclear(this->pgresult);
213
-
214
- xfree(this);
215
- }
216
-
217
386
  /*
218
387
  * Fetch the PG::Result object data pointer and check it's
219
388
  * PGresult data pointer for sanity.
@@ -243,18 +412,30 @@ pgresult_get(VALUE self)
243
412
  return this->pgresult;
244
413
  }
245
414
 
246
- /*
247
- * Document-method: allocate
248
- *
249
- * call-seq:
250
- * PG::Result.allocate -> result
251
- */
252
- static VALUE
253
- pgresult_s_allocate( VALUE klass )
415
+ static VALUE pg_cstr_to_sym(char *cstr, unsigned int flags, int enc_idx)
254
416
  {
255
- VALUE self = Data_Wrap_Struct( klass, pgresult_gc_mark, pgresult_gc_free, NULL );
256
-
257
- return self;
417
+ VALUE fname;
418
+ #ifdef TRUFFLERUBY
419
+ if( flags & (PG_RESULT_FIELD_NAMES_SYMBOL | PG_RESULT_FIELD_NAMES_STATIC_SYMBOL) ){
420
+ #else
421
+ if( flags & PG_RESULT_FIELD_NAMES_SYMBOL ){
422
+ rb_encoding *enc = rb_enc_from_index(enc_idx);
423
+ fname = rb_check_symbol_cstr(cstr, strlen(cstr), enc);
424
+ if( fname == Qnil ){
425
+ fname = rb_str_new2(cstr);
426
+ PG_ENCODING_SET_NOCHECK(fname, enc_idx);
427
+ fname = rb_str_intern(fname);
428
+ }
429
+ } else if( flags & PG_RESULT_FIELD_NAMES_STATIC_SYMBOL ){
430
+ #endif
431
+ rb_encoding *enc = rb_enc_from_index(enc_idx);
432
+ fname = ID2SYM(rb_intern3(cstr, strlen(cstr), enc));
433
+ } else {
434
+ fname = rb_str_new2(cstr);
435
+ PG_ENCODING_SET_NOCHECK(fname, enc_idx);
436
+ fname = rb_obj_freeze(fname);
437
+ }
438
+ return fname;
258
439
  }
259
440
 
260
441
  static void pgresult_init_fnames(VALUE self)
@@ -266,12 +447,9 @@ static void pgresult_init_fnames(VALUE self)
266
447
  int nfields = PQnfields(this->pgresult);
267
448
 
268
449
  for( i=0; i<nfields; i++ ){
269
- VALUE fname = rb_tainted_str_new2(PQfname(this->pgresult, i));
270
- PG_ENCODING_SET_NOCHECK(fname, ENCODING_GET(self));
271
- this->fnames[i] = rb_obj_freeze(fname);
450
+ char *cfname = PQfname(this->pgresult, i);
451
+ this->fnames[i] = pg_cstr_to_sym(cfname, this->flags, this->enc_idx);
272
452
  this->nfields = i + 1;
273
-
274
- RB_GC_GUARD(fname);
275
453
  }
276
454
  this->nfields = nfields;
277
455
  }
@@ -283,12 +461,15 @@ static void pgresult_init_fnames(VALUE self)
283
461
  *
284
462
  * The class to represent the query result tuples (rows).
285
463
  * An instance of this class is created as the result of every query.
286
- * You may need to invoke the #clear method of the instance when finished with
287
- * the result for better memory performance.
464
+ * All result rows and columns are stored in a memory block attached to the PG::Result object.
465
+ * Whenever a value is accessed it is casted to a Ruby object by the assigned #type_map .
466
+ *
467
+ * Since pg-1.1 the amount of memory in use by a PG::Result object is estimated and passed to ruby's garbage collector.
468
+ * You can invoke the #clear method to force deallocation of memory of the instance when finished with the result for better memory performance.
288
469
  *
289
470
  * Example:
290
471
  * require 'pg'
291
- * conn = PGconn.open(:dbname => 'test')
472
+ * conn = PG.connect(:dbname => 'test')
292
473
  * res = conn.exec('SELECT 1 AS a, 2 AS b, NULL AS c')
293
474
  * res.getvalue(0,0) # '1'
294
475
  * res[0]['b'] # '2'
@@ -302,7 +483,7 @@ static void pgresult_init_fnames(VALUE self)
302
483
 
303
484
  /*
304
485
  * call-seq:
305
- * res.result_status() -> Fixnum
486
+ * res.result_status() -> Integer
306
487
  *
307
488
  * Returns the status of the query. The status value is one of:
308
489
  * * +PGRES_EMPTY_QUERY+
@@ -331,8 +512,9 @@ pgresult_result_status(VALUE self)
331
512
  static VALUE
332
513
  pgresult_res_status(VALUE self, VALUE status)
333
514
  {
334
- VALUE ret = rb_tainted_str_new2(PQresStatus(NUM2INT(status)));
335
- PG_ENCODING_SET_NOCHECK(ret, ENCODING_GET(self));
515
+ t_pg_result *this = pgresult_get_this_safe(self);
516
+ VALUE ret = rb_str_new2(PQresStatus(NUM2INT(status)));
517
+ PG_ENCODING_SET_NOCHECK(ret, this->enc_idx);
336
518
  return ret;
337
519
  }
338
520
 
@@ -345,10 +527,39 @@ pgresult_res_status(VALUE self, VALUE status)
345
527
  static VALUE
346
528
  pgresult_error_message(VALUE self)
347
529
  {
348
- VALUE ret = rb_tainted_str_new2(PQresultErrorMessage(pgresult_get(self)));
349
- PG_ENCODING_SET_NOCHECK(ret, ENCODING_GET(self));
530
+ t_pg_result *this = pgresult_get_this_safe(self);
531
+ VALUE ret = rb_str_new2(PQresultErrorMessage(this->pgresult));
532
+ PG_ENCODING_SET_NOCHECK(ret, this->enc_idx);
533
+ return ret;
534
+ }
535
+
536
+ #ifdef HAVE_PQRESULTVERBOSEERRORMESSAGE
537
+ /*
538
+ * call-seq:
539
+ * res.verbose_error_message( verbosity, show_context ) -> String
540
+ *
541
+ * Returns a reformatted version of the error message associated with a PGresult object.
542
+ *
543
+ * Available since PostgreSQL-9.6
544
+ */
545
+ static VALUE
546
+ pgresult_verbose_error_message(VALUE self, VALUE verbosity, VALUE show_context)
547
+ {
548
+ t_pg_result *this = pgresult_get_this_safe(self);
549
+ VALUE ret;
550
+ char *c_str;
551
+
552
+ c_str = PQresultVerboseErrorMessage(this->pgresult, NUM2INT(verbosity), NUM2INT(show_context));
553
+ if(!c_str)
554
+ rb_raise(rb_eNoMemError, "insufficient memory to format error message");
555
+
556
+ ret = rb_str_new2(c_str);
557
+ PQfreemem(c_str);
558
+ PG_ENCODING_SET_NOCHECK(ret, this->enc_idx);
559
+
350
560
  return ret;
351
561
  }
562
+ #endif
352
563
 
353
564
  /*
354
565
  * call-seq:
@@ -399,14 +610,14 @@ pgresult_error_message(VALUE self)
399
610
  static VALUE
400
611
  pgresult_error_field(VALUE self, VALUE field)
401
612
  {
402
- PGresult *result = pgresult_get( self );
613
+ t_pg_result *this = pgresult_get_this_safe(self);
403
614
  int fieldcode = NUM2INT( field );
404
- char * fieldstr = PQresultErrorField( result, fieldcode );
615
+ char * fieldstr = PQresultErrorField( this->pgresult, fieldcode );
405
616
  VALUE ret = Qnil;
406
617
 
407
618
  if ( fieldstr ) {
408
- ret = rb_tainted_str_new2( fieldstr );
409
- PG_ENCODING_SET_NOCHECK( ret, ENCODING_GET(self ));
619
+ ret = rb_str_new2( fieldstr );
620
+ PG_ENCODING_SET_NOCHECK( ret, this->enc_idx );
410
621
  }
411
622
 
412
623
  return ret;
@@ -414,7 +625,7 @@ pgresult_error_field(VALUE self, VALUE field)
414
625
 
415
626
  /*
416
627
  * call-seq:
417
- * res.ntuples() -> Fixnum
628
+ * res.ntuples() -> Integer
418
629
  *
419
630
  * Returns the number of tuples in the query result.
420
631
  */
@@ -427,7 +638,7 @@ pgresult_ntuples(VALUE self)
427
638
  static VALUE
428
639
  pgresult_ntuples_for_enum(VALUE self, VALUE args, VALUE eobj)
429
640
  {
430
- return pgresult_ntuples(self);
641
+ return pgresult_ntuples(self);
431
642
  }
432
643
 
433
644
  /*
@@ -444,29 +655,30 @@ pgresult_nfields(VALUE self)
444
655
 
445
656
  /*
446
657
  * call-seq:
447
- * res.fname( index ) -> String
658
+ * res.fname( index ) -> String or Symbol
448
659
  *
449
660
  * Returns the name of the column corresponding to _index_.
661
+ * Depending on #field_name_type= it's a String or Symbol.
662
+ *
450
663
  */
451
664
  static VALUE
452
665
  pgresult_fname(VALUE self, VALUE index)
453
666
  {
454
- VALUE fname;
455
- PGresult *result = pgresult_get(self);
667
+ t_pg_result *this = pgresult_get_this_safe(self);
456
668
  int i = NUM2INT(index);
669
+ char *cfname;
457
670
 
458
- if (i < 0 || i >= PQnfields(result)) {
671
+ if (i < 0 || i >= PQnfields(this->pgresult)) {
459
672
  rb_raise(rb_eArgError,"invalid field number %d", i);
460
673
  }
461
674
 
462
- fname = rb_tainted_str_new2(PQfname(result, i));
463
- PG_ENCODING_SET_NOCHECK(fname, ENCODING_GET(self));
464
- return rb_obj_freeze(fname);
675
+ cfname = PQfname(this->pgresult, i);
676
+ return pg_cstr_to_sym(cfname, this->flags, this->enc_idx);
465
677
  }
466
678
 
467
679
  /*
468
680
  * call-seq:
469
- * res.fnumber( name ) -> Fixnum
681
+ * res.fnumber( name ) -> Integer
470
682
  *
471
683
  * Returns the index of the field specified by the string +name+.
472
684
  * The given +name+ is treated like an identifier in an SQL command, that is,
@@ -527,7 +739,7 @@ pgresult_ftable(VALUE self, VALUE column_number)
527
739
 
528
740
  /*
529
741
  * call-seq:
530
- * res.ftablecol( column_number ) -> Fixnum
742
+ * res.ftablecol( column_number ) -> Integer
531
743
  *
532
744
  * Returns the column number (within its table) of the table from
533
745
  * which the column _column_number_ is made up.
@@ -552,7 +764,7 @@ pgresult_ftablecol(VALUE self, VALUE column_number)
552
764
 
553
765
  /*
554
766
  * call-seq:
555
- * res.fformat( column_number ) -> Fixnum
767
+ * res.fformat( column_number ) -> Integer
556
768
  *
557
769
  * Returns the format (0 for text, 1 for binary) of column
558
770
  * _column_number_.
@@ -696,7 +908,7 @@ pgresult_getisnull(VALUE self, VALUE tup_num, VALUE field_num)
696
908
 
697
909
  /*
698
910
  * call-seq:
699
- * res.getlength( tup_num, field_num ) -> Fixnum
911
+ * res.getlength( tup_num, field_num ) -> Integer
700
912
  *
701
913
  * Returns the (String) length of the field in bytes.
702
914
  *
@@ -721,7 +933,7 @@ pgresult_getlength(VALUE self, VALUE tup_num, VALUE field_num)
721
933
 
722
934
  /*
723
935
  * call-seq:
724
- * res.nparams() -> Fixnum
936
+ * res.nparams() -> Integer
725
937
  *
726
938
  * Returns the number of parameters of a prepared statement.
727
939
  * Only useful for the result returned by conn.describePrepared
@@ -760,8 +972,9 @@ pgresult_paramtype(VALUE self, VALUE param_number)
760
972
  static VALUE
761
973
  pgresult_cmd_status(VALUE self)
762
974
  {
763
- VALUE ret = rb_tainted_str_new2(PQcmdStatus(pgresult_get(self)));
764
- PG_ENCODING_SET_NOCHECK(ret, ENCODING_GET(self));
975
+ t_pg_result *this = pgresult_get_this_safe(self);
976
+ VALUE ret = rb_str_new2(PQcmdStatus(this->pgresult));
977
+ PG_ENCODING_SET_NOCHECK(ret, this->enc_idx);
765
978
  return ret;
766
979
  }
767
980
 
@@ -772,11 +985,17 @@ pgresult_cmd_status(VALUE self)
772
985
  * Returns the number of tuples (rows) affected by the SQL command.
773
986
  *
774
987
  * If the SQL command that generated the PG::Result was not one of:
775
- * * +INSERT+
776
- * * +UPDATE+
777
- * * +DELETE+
778
- * * +MOVE+
779
- * * +FETCH+
988
+ *
989
+ * * <tt>SELECT</tt>
990
+ * * <tt>CREATE TABLE AS</tt>
991
+ * * <tt>INSERT</tt>
992
+ * * <tt>UPDATE</tt>
993
+ * * <tt>DELETE</tt>
994
+ * * <tt>MOVE</tt>
995
+ * * <tt>FETCH</tt>
996
+ * * <tt>COPY</tt>
997
+ * * an +EXECUTE+ of a prepared query that contains an +INSERT+, +UPDATE+, or +DELETE+ statement
998
+ *
780
999
  * or if no tuples were affected, <tt>0</tt> is returned.
781
1000
  */
782
1001
  static VALUE
@@ -955,8 +1174,12 @@ static VALUE
955
1174
  pgresult_field_values( VALUE self, VALUE field )
956
1175
  {
957
1176
  PGresult *result = pgresult_get( self );
958
- const char *fieldname = StringValueCStr( field );
959
- int fnum = PQfnumber( result, fieldname );
1177
+ const char *fieldname;
1178
+ int fnum;
1179
+
1180
+ if( RB_TYPE_P(field, T_SYMBOL) ) field = rb_sym_to_s( field );
1181
+ fieldname = StringValueCStr( field );
1182
+ fnum = PQfnumber( result, fieldname );
960
1183
 
961
1184
  if ( fnum < 0 )
962
1185
  rb_raise( rb_eIndexError, "no such field '%s' in result", fieldname );
@@ -965,6 +1188,85 @@ pgresult_field_values( VALUE self, VALUE field )
965
1188
  }
966
1189
 
967
1190
 
1191
+ /*
1192
+ * call-seq:
1193
+ * res.tuple_values( n ) -> array
1194
+ *
1195
+ * Returns an Array of the field values from the nth row of the result.
1196
+ *
1197
+ */
1198
+ static VALUE
1199
+ pgresult_tuple_values(VALUE self, VALUE index)
1200
+ {
1201
+ int tuple_num = NUM2INT( index );
1202
+ t_pg_result *this;
1203
+ int field;
1204
+ int num_tuples;
1205
+ int num_fields;
1206
+
1207
+ this = pgresult_get_this_safe(self);
1208
+ num_tuples = PQntuples(this->pgresult);
1209
+ num_fields = PQnfields(this->pgresult);
1210
+
1211
+ if ( tuple_num < 0 || tuple_num >= num_tuples )
1212
+ rb_raise( rb_eIndexError, "Index %d is out of range", tuple_num );
1213
+
1214
+ {
1215
+ PG_VARIABLE_LENGTH_ARRAY(VALUE, row_values, num_fields, PG_MAX_COLUMNS)
1216
+
1217
+ /* populate the row */
1218
+ for ( field = 0; field < num_fields; field++ ) {
1219
+ row_values[field] = this->p_typemap->funcs.typecast_result_value(this->p_typemap, self, tuple_num, field);
1220
+ }
1221
+ return rb_ary_new4( num_fields, row_values );
1222
+ }
1223
+ }
1224
+
1225
+ static void ensure_init_for_tuple(VALUE self)
1226
+ {
1227
+ t_pg_result *this = pgresult_get_this_safe(self);
1228
+
1229
+ if( this->field_map == Qnil ){
1230
+ int i;
1231
+ VALUE field_map = rb_hash_new();
1232
+
1233
+ if( this->nfields == -1 )
1234
+ pgresult_init_fnames( self );
1235
+
1236
+ for( i = 0; i < this->nfields; i++ ){
1237
+ rb_hash_aset(field_map, this->fnames[i], INT2FIX(i));
1238
+ }
1239
+ rb_obj_freeze(field_map);
1240
+ this->field_map = field_map;
1241
+ }
1242
+ }
1243
+
1244
+ /*
1245
+ * call-seq:
1246
+ * res.tuple( n ) -> PG::Tuple
1247
+ *
1248
+ * Returns a PG::Tuple from the nth row of the result.
1249
+ *
1250
+ */
1251
+ static VALUE
1252
+ pgresult_tuple(VALUE self, VALUE index)
1253
+ {
1254
+ int tuple_num = NUM2INT( index );
1255
+ t_pg_result *this;
1256
+ int num_tuples;
1257
+
1258
+ this = pgresult_get_this_safe(self);
1259
+ num_tuples = PQntuples(this->pgresult);
1260
+
1261
+ if ( tuple_num < 0 || tuple_num >= num_tuples )
1262
+ rb_raise( rb_eIndexError, "Index %d is out of range", tuple_num );
1263
+
1264
+ ensure_init_for_tuple(self);
1265
+
1266
+ return pg_tuple_new(self, tuple_num);
1267
+ }
1268
+
1269
+
968
1270
  /*
969
1271
  * call-seq:
970
1272
  * res.each{ |tuple| ... }
@@ -991,7 +1293,7 @@ pgresult_each(VALUE self)
991
1293
  * call-seq:
992
1294
  * res.fields() -> Array
993
1295
  *
994
- * Returns an array of Strings representing the names of the fields in the result.
1296
+ * Depending on #field_name_type= returns an array of strings or symbols representing the names of the fields in the result.
995
1297
  */
996
1298
  static VALUE
997
1299
  pgresult_fields(VALUE self)
@@ -1050,40 +1352,63 @@ pgresult_type_map_get(VALUE self)
1050
1352
  return this->typemap;
1051
1353
  }
1052
1354
 
1053
- #ifdef HAVE_PQSETSINGLEROWMODE
1054
- /*
1055
- * call-seq:
1056
- * res.stream_each{ |tuple| ... }
1057
- *
1058
- * Invokes block for each tuple in the result set in single row mode.
1059
- *
1060
- * This is a convenience method for retrieving all result tuples
1061
- * as they are transferred. It is an alternative to repeated calls of
1062
- * PG::Connection#get_result , but given that it avoids the overhead of
1063
- * wrapping each row into a dedicated result object, it delivers data in nearly
1064
- * the same speed as with ordinary results.
1065
- *
1066
- * The result must be in status PGRES_SINGLE_TUPLE.
1067
- * It iterates over all tuples until the status changes to PGRES_TUPLES_OK.
1068
- * A PG::Error is raised for any errors from the server.
1069
- *
1070
- * Row description data does not change while the iteration. All value retrieval
1071
- * methods refer to only the current row. Result#ntuples returns +1+ while
1072
- * the iteration and +0+ after all tuples were yielded.
1073
- *
1074
- * Example:
1075
- * conn.send_query( "first SQL query; second SQL query" )
1076
- * conn.set_single_row_mode
1077
- * conn.get_result.stream_each do |row|
1078
- * # do something with the received row of the first query
1079
- * end
1080
- * conn.get_result.stream_each do |row|
1081
- * # do something with the received row of the second query
1082
- * end
1083
- * conn.get_result # => nil (no more results)
1084
- */
1355
+
1356
+ static void
1357
+ yield_hash(VALUE self, int ntuples, int nfields)
1358
+ {
1359
+ int tuple_num;
1360
+ t_pg_result *this = pgresult_get_this(self);
1361
+ UNUSED(nfields);
1362
+
1363
+ for(tuple_num = 0; tuple_num < ntuples; tuple_num++) {
1364
+ rb_yield(pgresult_aref(self, INT2NUM(tuple_num)));
1365
+ }
1366
+
1367
+ pgresult_clear( this );
1368
+ }
1369
+
1370
+ static void
1371
+ yield_array(VALUE self, int ntuples, int nfields)
1372
+ {
1373
+ int row;
1374
+ t_pg_result *this = pgresult_get_this(self);
1375
+
1376
+ for ( row = 0; row < ntuples; row++ ) {
1377
+ PG_VARIABLE_LENGTH_ARRAY(VALUE, row_values, nfields, PG_MAX_COLUMNS)
1378
+ int field;
1379
+
1380
+ /* populate the row */
1381
+ for ( field = 0; field < nfields; field++ ) {
1382
+ row_values[field] = this->p_typemap->funcs.typecast_result_value(this->p_typemap, self, row, field);
1383
+ }
1384
+ rb_yield( rb_ary_new4( nfields, row_values ));
1385
+ }
1386
+
1387
+ pgresult_clear( this );
1388
+ }
1389
+
1390
+ static void
1391
+ yield_tuple(VALUE self, int ntuples, int nfields)
1392
+ {
1393
+ int tuple_num;
1394
+ t_pg_result *this = pgresult_get_this(self);
1395
+ VALUE copy;
1396
+ UNUSED(nfields);
1397
+
1398
+ /* make a copy of the base result, that is bound to the PG::Tuple */
1399
+ copy = pg_copy_result(this);
1400
+ /* The copy is now owner of the PGresult and is responsible to PQclear it.
1401
+ * We clear the pgresult here, so that it's not double freed on error within yield. */
1402
+ this->pgresult = NULL;
1403
+
1404
+ for(tuple_num = 0; tuple_num < ntuples; tuple_num++) {
1405
+ VALUE tuple = pgresult_tuple(copy, INT2FIX(tuple_num));
1406
+ rb_yield( tuple );
1407
+ }
1408
+ }
1409
+
1085
1410
  static VALUE
1086
- pgresult_stream_each(VALUE self)
1411
+ pgresult_stream_any(VALUE self, void (*yielder)(VALUE, int, int))
1087
1412
  {
1088
1413
  t_pg_result *this;
1089
1414
  int nfields;
@@ -1098,7 +1423,6 @@ pgresult_stream_each(VALUE self)
1098
1423
  nfields = PQnfields(pgresult);
1099
1424
 
1100
1425
  for(;;){
1101
- int tuple_num;
1102
1426
  int ntuples = PQntuples(pgresult);
1103
1427
 
1104
1428
  switch( PQresultStatus(pgresult) ){
@@ -1112,14 +1436,7 @@ pgresult_stream_each(VALUE self)
1112
1436
  pg_result_check( self );
1113
1437
  }
1114
1438
 
1115
- for(tuple_num = 0; tuple_num < ntuples; tuple_num++) {
1116
- rb_yield(pgresult_aref(self, INT2NUM(tuple_num)));
1117
- }
1118
-
1119
- if( !this->autoclear ){
1120
- PQclear( pgresult );
1121
- this->pgresult = NULL;
1122
- }
1439
+ yielder( self, ntuples, nfields );
1123
1440
 
1124
1441
  pgresult = gvl_PQgetResult(pgconn);
1125
1442
  if( pgresult == NULL )
@@ -1135,6 +1452,44 @@ pgresult_stream_each(VALUE self)
1135
1452
  return self;
1136
1453
  }
1137
1454
 
1455
+
1456
+ /*
1457
+ * call-seq:
1458
+ * res.stream_each{ |tuple| ... }
1459
+ *
1460
+ * Invokes block for each tuple in the result set in single row mode.
1461
+ *
1462
+ * This is a convenience method for retrieving all result tuples
1463
+ * as they are transferred. It is an alternative to repeated calls of
1464
+ * PG::Connection#get_result , but given that it avoids the overhead of
1465
+ * wrapping each row into a dedicated result object, it delivers data in nearly
1466
+ * the same speed as with ordinary results.
1467
+ *
1468
+ * The base result must be in status PGRES_SINGLE_TUPLE.
1469
+ * It iterates over all tuples until the status changes to PGRES_TUPLES_OK.
1470
+ * A PG::Error is raised for any errors from the server.
1471
+ *
1472
+ * Row description data does not change while the iteration. All value retrieval
1473
+ * methods refer to only the current row. Result#ntuples returns +1+ while
1474
+ * the iteration and +0+ after all tuples were yielded.
1475
+ *
1476
+ * Example:
1477
+ * conn.send_query( "first SQL query; second SQL query" )
1478
+ * conn.set_single_row_mode
1479
+ * conn.get_result.stream_each do |row|
1480
+ * # do something with each received row of the first query
1481
+ * end
1482
+ * conn.get_result.stream_each do |row|
1483
+ * # do something with each received row of the second query
1484
+ * end
1485
+ * conn.get_result # => nil (no more results)
1486
+ */
1487
+ static VALUE
1488
+ pgresult_stream_each(VALUE self)
1489
+ {
1490
+ return pgresult_stream_any(self, yield_hash);
1491
+ }
1492
+
1138
1493
  /*
1139
1494
  * call-seq:
1140
1495
  * res.stream_each_row { |row| ... }
@@ -1148,70 +1503,91 @@ pgresult_stream_each(VALUE self)
1148
1503
  static VALUE
1149
1504
  pgresult_stream_each_row(VALUE self)
1150
1505
  {
1151
- t_pg_result *this;
1152
- int row;
1153
- int nfields;
1154
- PGconn *pgconn;
1155
- PGresult *pgresult;
1156
-
1157
- RETURN_ENUMERATOR(self, 0, NULL);
1158
-
1159
- this = pgresult_get_this_safe(self);
1160
- pgconn = pg_get_pgconn(this->connection);
1161
- pgresult = this->pgresult;
1162
- nfields = PQnfields(pgresult);
1163
-
1164
- for(;;){
1165
- int ntuples = PQntuples(pgresult);
1166
-
1167
- switch( PQresultStatus(pgresult) ){
1168
- case PGRES_TUPLES_OK:
1169
- if( ntuples == 0 )
1170
- return self;
1171
- rb_raise( rb_eInvalidResultStatus, "PG::Result is not in single row mode");
1172
- case PGRES_SINGLE_TUPLE:
1173
- break;
1174
- default:
1175
- pg_result_check( self );
1176
- }
1506
+ return pgresult_stream_any(self, yield_array);
1507
+ }
1177
1508
 
1178
- for ( row = 0; row < ntuples; row++ ) {
1179
- PG_VARIABLE_LENGTH_ARRAY(VALUE, row_values, nfields, PG_MAX_COLUMNS)
1180
- int field;
1509
+ /*
1510
+ * call-seq:
1511
+ * res.stream_each_tuple { |tuple| ... }
1512
+ *
1513
+ * Yields each row of the result set in single row mode.
1514
+ *
1515
+ * This method works equally to #stream_each , but yields a PG::Tuple object.
1516
+ */
1517
+ static VALUE
1518
+ pgresult_stream_each_tuple(VALUE self)
1519
+ {
1520
+ /* allocate VALUEs that are shared between all streamed tuples */
1521
+ ensure_init_for_tuple(self);
1181
1522
 
1182
- /* populate the row */
1183
- for ( field = 0; field < nfields; 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( nfields, row_values ));
1187
- }
1523
+ return pgresult_stream_any(self, yield_tuple);
1524
+ }
1188
1525
 
1189
- if( !this->autoclear ){
1190
- PQclear( pgresult );
1191
- this->pgresult = NULL;
1192
- }
1526
+ /*
1527
+ * call-seq:
1528
+ * res.field_name_type = Symbol
1529
+ *
1530
+ * Set type of field names specific to this result.
1531
+ * It can be set to one of:
1532
+ * * +:string+ to use String based field names
1533
+ * * +:symbol+ to use Symbol based field names
1534
+ * * +:static_symbol+ to use pinned Symbol (can not be garbage collected) - Don't use this, it will probably removed in future.
1535
+ *
1536
+ * The default is retrieved from PG::Connection#field_name_type , which defaults to +:string+ .
1537
+ *
1538
+ * This setting affects several result methods:
1539
+ * * keys of Hash returned by #[] , #each and #stream_each
1540
+ * * #fields
1541
+ * * #fname
1542
+ * * field names used by #tuple and #stream_each_tuple
1543
+ *
1544
+ * The type of field names can only be changed before any of the affected methods have been called.
1545
+ *
1546
+ */
1547
+ static VALUE
1548
+ pgresult_field_name_type_set(VALUE self, VALUE sym)
1549
+ {
1550
+ t_pg_result *this = pgresult_get_this(self);
1551
+ if( this->nfields != -1 ) rb_raise(rb_eArgError, "field names are already materialized");
1193
1552
 
1194
- pgresult = gvl_PQgetResult(pgconn);
1195
- if( pgresult == NULL )
1196
- rb_raise( rb_eNoResultError, "no result received - possibly an intersection with another result retrieval");
1553
+ this->flags &= ~PG_RESULT_FIELD_NAMES_MASK;
1554
+ if( sym == sym_symbol ) this->flags |= PG_RESULT_FIELD_NAMES_SYMBOL;
1555
+ else if ( sym == sym_static_symbol ) this->flags |= PG_RESULT_FIELD_NAMES_STATIC_SYMBOL;
1556
+ else if ( sym == sym_string );
1557
+ else rb_raise(rb_eArgError, "invalid argument %+"PRIsVALUE, sym);
1197
1558
 
1198
- if( nfields != PQnfields(pgresult) )
1199
- rb_raise( rb_eInvalidChangeOfResultFields, "number of fields must not change in single row mode");
1559
+ return sym;
1560
+ }
1200
1561
 
1201
- this->pgresult = pgresult;
1562
+ /*
1563
+ * call-seq:
1564
+ * res.field_name_type -> Symbol
1565
+ *
1566
+ * Get type of field names.
1567
+ *
1568
+ * See description at #field_name_type=
1569
+ */
1570
+ static VALUE
1571
+ pgresult_field_name_type_get(VALUE self)
1572
+ {
1573
+ t_pg_result *this = pgresult_get_this(self);
1574
+ if( this->flags & PG_RESULT_FIELD_NAMES_SYMBOL ){
1575
+ return sym_symbol;
1576
+ } else if( this->flags & PG_RESULT_FIELD_NAMES_STATIC_SYMBOL ){
1577
+ return sym_static_symbol;
1578
+ } else {
1579
+ return sym_string;
1202
1580
  }
1203
-
1204
- /* never reached */
1205
- return self;
1206
1581
  }
1207
- #endif
1208
-
1209
1582
 
1210
1583
  void
1211
1584
  init_pg_result()
1212
1585
  {
1213
- rb_cPGresult = rb_define_class_under( rb_mPG, "Result", rb_cObject );
1214
- rb_define_alloc_func( rb_cPGresult, pgresult_s_allocate );
1586
+ sym_string = ID2SYM(rb_intern("string"));
1587
+ sym_symbol = ID2SYM(rb_intern("symbol"));
1588
+ sym_static_symbol = ID2SYM(rb_intern("static_symbol"));
1589
+
1590
+ rb_cPGresult = rb_define_class_under( rb_mPG, "Result", rb_cData );
1215
1591
  rb_include_module(rb_cPGresult, rb_mEnumerable);
1216
1592
  rb_include_module(rb_cPGresult, rb_mPGconstants);
1217
1593
 
@@ -1220,6 +1596,10 @@ init_pg_result()
1220
1596
  rb_define_method(rb_cPGresult, "res_status", pgresult_res_status, 1);
1221
1597
  rb_define_method(rb_cPGresult, "error_message", pgresult_error_message, 0);
1222
1598
  rb_define_alias( rb_cPGresult, "result_error_message", "error_message");
1599
+ #ifdef HAVE_PQRESULTVERBOSEERRORMESSAGE
1600
+ rb_define_method(rb_cPGresult, "verbose_error_message", pgresult_verbose_error_message, 2);
1601
+ rb_define_alias( rb_cPGresult, "result_verbose_error_message", "verbose_error_message");
1602
+ #endif
1223
1603
  rb_define_method(rb_cPGresult, "error_field", pgresult_error_field, 1);
1224
1604
  rb_define_alias( rb_cPGresult, "result_error_field", "error_field" );
1225
1605
  rb_define_method(rb_cPGresult, "clear", pg_result_clear, 0);
@@ -1255,17 +1635,19 @@ init_pg_result()
1255
1635
  rb_define_method(rb_cPGresult, "values", pgresult_values, 0);
1256
1636
  rb_define_method(rb_cPGresult, "column_values", pgresult_column_values, 1);
1257
1637
  rb_define_method(rb_cPGresult, "field_values", pgresult_field_values, 1);
1638
+ rb_define_method(rb_cPGresult, "tuple_values", pgresult_tuple_values, 1);
1639
+ rb_define_method(rb_cPGresult, "tuple", pgresult_tuple, 1);
1258
1640
  rb_define_method(rb_cPGresult, "cleared?", pgresult_cleared_p, 0);
1259
1641
  rb_define_method(rb_cPGresult, "autoclear?", pgresult_autoclear_p, 0);
1260
1642
 
1261
1643
  rb_define_method(rb_cPGresult, "type_map=", pgresult_type_map_set, 1);
1262
1644
  rb_define_method(rb_cPGresult, "type_map", pgresult_type_map_get, 0);
1263
1645
 
1264
- #ifdef HAVE_PQSETSINGLEROWMODE
1265
1646
  /****** PG::Result INSTANCE METHODS: streaming ******/
1266
1647
  rb_define_method(rb_cPGresult, "stream_each", pgresult_stream_each, 0);
1267
1648
  rb_define_method(rb_cPGresult, "stream_each_row", pgresult_stream_each_row, 0);
1268
- #endif
1269
- }
1270
-
1649
+ rb_define_method(rb_cPGresult, "stream_each_tuple", pgresult_stream_each_tuple, 0);
1271
1650
 
1651
+ rb_define_method(rb_cPGresult, "field_name_type=", pgresult_field_name_type_set, 1 );
1652
+ rb_define_method(rb_cPGresult, "field_name_type", pgresult_field_name_type_get, 0 );
1653
+ }