pg 1.1.3 → 1.5.4

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 (140) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/.appveyor.yml +42 -0
  4. data/.gems +6 -0
  5. data/.github/workflows/binary-gems.yml +117 -0
  6. data/.github/workflows/source-gem.yml +141 -0
  7. data/.gitignore +22 -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/Gemfile +14 -0
  15. data/History.md +884 -0
  16. data/Manifest.txt +3 -3
  17. data/README-Windows.rdoc +4 -4
  18. data/README.ja.md +300 -0
  19. data/README.md +286 -0
  20. data/Rakefile +37 -137
  21. data/Rakefile.cross +62 -62
  22. data/certs/ged.pem +24 -0
  23. data/certs/larskanis-2022.pem +26 -0
  24. data/certs/larskanis-2023.pem +24 -0
  25. data/ext/errorcodes.def +80 -0
  26. data/ext/errorcodes.rb +0 -0
  27. data/ext/errorcodes.txt +22 -2
  28. data/ext/extconf.rb +105 -26
  29. data/ext/gvl_wrappers.c +4 -0
  30. data/ext/gvl_wrappers.h +23 -0
  31. data/ext/pg.c +204 -152
  32. data/ext/pg.h +52 -21
  33. data/ext/pg_binary_decoder.c +100 -17
  34. data/ext/pg_binary_encoder.c +238 -13
  35. data/ext/pg_coder.c +109 -34
  36. data/ext/pg_connection.c +1383 -983
  37. data/ext/pg_copy_coder.c +356 -35
  38. data/ext/pg_errors.c +1 -1
  39. data/ext/pg_record_coder.c +522 -0
  40. data/ext/pg_result.c +439 -172
  41. data/ext/pg_text_decoder.c +42 -18
  42. data/ext/pg_text_encoder.c +201 -56
  43. data/ext/pg_tuple.c +97 -66
  44. data/ext/pg_type_map.c +45 -11
  45. data/ext/pg_type_map_all_strings.c +21 -7
  46. data/ext/pg_type_map_by_class.c +59 -27
  47. data/ext/pg_type_map_by_column.c +80 -37
  48. data/ext/pg_type_map_by_mri_type.c +49 -20
  49. data/ext/pg_type_map_by_oid.c +62 -29
  50. data/ext/pg_type_map_in_ruby.c +56 -22
  51. data/ext/{util.c → pg_util.c} +7 -7
  52. data/lib/pg/basic_type_map_based_on_result.rb +67 -0
  53. data/lib/pg/basic_type_map_for_queries.rb +198 -0
  54. data/lib/pg/basic_type_map_for_results.rb +104 -0
  55. data/lib/pg/basic_type_registry.rb +299 -0
  56. data/lib/pg/binary_decoder/date.rb +9 -0
  57. data/lib/pg/binary_decoder/timestamp.rb +26 -0
  58. data/lib/pg/binary_encoder/timestamp.rb +20 -0
  59. data/lib/pg/coder.rb +35 -12
  60. data/lib/pg/connection.rb +744 -84
  61. data/lib/pg/exceptions.rb +15 -1
  62. data/lib/pg/result.rb +13 -1
  63. data/lib/pg/text_decoder/date.rb +18 -0
  64. data/lib/pg/text_decoder/inet.rb +9 -0
  65. data/lib/pg/text_decoder/json.rb +14 -0
  66. data/lib/pg/text_decoder/numeric.rb +9 -0
  67. data/lib/pg/text_decoder/timestamp.rb +30 -0
  68. data/lib/pg/text_encoder/date.rb +12 -0
  69. data/lib/pg/text_encoder/inet.rb +28 -0
  70. data/lib/pg/text_encoder/json.rb +14 -0
  71. data/lib/pg/text_encoder/numeric.rb +9 -0
  72. data/lib/pg/text_encoder/timestamp.rb +24 -0
  73. data/lib/pg/type_map_by_column.rb +2 -1
  74. data/lib/pg/version.rb +4 -0
  75. data/lib/pg.rb +94 -39
  76. data/misc/openssl-pg-segfault.rb +31 -0
  77. data/misc/postgres/History.txt +9 -0
  78. data/misc/postgres/Manifest.txt +5 -0
  79. data/misc/postgres/README.txt +21 -0
  80. data/misc/postgres/Rakefile +21 -0
  81. data/misc/postgres/lib/postgres.rb +16 -0
  82. data/misc/ruby-pg/History.txt +9 -0
  83. data/misc/ruby-pg/Manifest.txt +5 -0
  84. data/misc/ruby-pg/README.txt +21 -0
  85. data/misc/ruby-pg/Rakefile +21 -0
  86. data/misc/ruby-pg/lib/ruby/pg.rb +16 -0
  87. data/pg.gemspec +34 -0
  88. data/rakelib/task_extension.rb +46 -0
  89. data/sample/array_insert.rb +20 -0
  90. data/sample/async_api.rb +102 -0
  91. data/sample/async_copyto.rb +39 -0
  92. data/sample/async_mixed.rb +56 -0
  93. data/sample/check_conn.rb +21 -0
  94. data/sample/copydata.rb +71 -0
  95. data/sample/copyfrom.rb +81 -0
  96. data/sample/copyto.rb +19 -0
  97. data/sample/cursor.rb +21 -0
  98. data/sample/disk_usage_report.rb +177 -0
  99. data/sample/issue-119.rb +94 -0
  100. data/sample/losample.rb +69 -0
  101. data/sample/minimal-testcase.rb +17 -0
  102. data/sample/notify_wait.rb +72 -0
  103. data/sample/pg_statistics.rb +285 -0
  104. data/sample/replication_monitor.rb +222 -0
  105. data/sample/test_binary_values.rb +33 -0
  106. data/sample/wal_shipper.rb +434 -0
  107. data/sample/warehouse_partitions.rb +311 -0
  108. data/translation/.po4a-version +7 -0
  109. data/translation/po/all.pot +936 -0
  110. data/translation/po/ja.po +1036 -0
  111. data/translation/po4a.cfg +12 -0
  112. data.tar.gz.sig +0 -0
  113. metadata +144 -222
  114. metadata.gz.sig +0 -0
  115. data/ChangeLog +0 -6595
  116. data/History.rdoc +0 -485
  117. data/README.ja.rdoc +0 -14
  118. data/README.rdoc +0 -178
  119. data/lib/pg/basic_type_mapping.rb +0 -459
  120. data/lib/pg/binary_decoder.rb +0 -22
  121. data/lib/pg/constants.rb +0 -11
  122. data/lib/pg/text_decoder.rb +0 -47
  123. data/lib/pg/text_encoder.rb +0 -69
  124. data/spec/data/expected_trace.out +0 -26
  125. data/spec/data/random_binary_data +0 -0
  126. data/spec/helpers.rb +0 -381
  127. data/spec/pg/basic_type_mapping_spec.rb +0 -508
  128. data/spec/pg/connection_spec.rb +0 -1849
  129. data/spec/pg/connection_sync_spec.rb +0 -41
  130. data/spec/pg/result_spec.rb +0 -491
  131. data/spec/pg/tuple_spec.rb +0 -280
  132. data/spec/pg/type_map_by_class_spec.rb +0 -138
  133. data/spec/pg/type_map_by_column_spec.rb +0 -222
  134. data/spec/pg/type_map_by_mri_type_spec.rb +0 -136
  135. data/spec/pg/type_map_by_oid_spec.rb +0 -149
  136. data/spec/pg/type_map_in_ruby_spec.rb +0 -164
  137. data/spec/pg/type_map_spec.rb +0 -22
  138. data/spec/pg/type_spec.rb +0 -949
  139. data/spec/pg_spec.rb +0 -50
  140. /data/ext/{util.h → pg_util.h} +0 -0
data/ext/pg_result.c CHANGED
@@ -1,20 +1,27 @@
1
1
  /*
2
2
  * pg_result.c - PG::Result class extension
3
- * $Id: pg_result.c,v a8b70c42b3e8 2018/07/30 14:09:38 kanis $
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
18
25
 
19
26
  #define PGRESULT_DATA_BLOCKSIZE 2048
20
27
  typedef struct pgresAttValue
@@ -44,7 +51,7 @@ count_leading_zero_bits(unsigned int x)
44
51
  }
45
52
 
46
53
  static ssize_t
47
- pgresult_approx_size(PGresult *result)
54
+ pgresult_approx_size(const PGresult *result)
48
55
  {
49
56
  int num_fields = PQnfields(result);
50
57
  ssize_t size = 0;
@@ -94,25 +101,97 @@ pgresult_approx_size(PGresult *result)
94
101
 
95
102
  return size;
96
103
  }
104
+ #endif
97
105
 
106
+ /*
107
+ * GC Mark function
108
+ */
98
109
  static void
99
- pgresult_clear( t_pg_result *this )
110
+ pgresult_gc_mark( void *_this )
100
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;
101
148
  if( this->pgresult && !this->autoclear ){
102
149
  PQclear(this->pgresult);
103
150
  #ifdef HAVE_RB_GC_ADJUST_MEMORY_USAGE
104
151
  rb_gc_adjust_memory_usage(-this->result_size);
105
152
  #endif
106
153
  }
154
+ this->result_size = 0;
155
+ this->nfields = -1;
107
156
  this->pgresult = NULL;
108
157
  }
109
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
+
110
167
  static size_t
111
- pgresult_memsize( t_pg_result *this )
168
+ pgresult_memsize( const void *_this )
112
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
+ */
113
174
  return this->result_size;
114
175
  }
115
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
+
116
195
  /*
117
196
  * Global functions
118
197
  */
@@ -124,31 +203,35 @@ static VALUE
124
203
  pg_new_result2(PGresult *result, VALUE rb_pgconn)
125
204
  {
126
205
  int nfields = result ? PQnfields(result) : 0;
127
- VALUE self = pgresult_s_allocate( rb_cPGresult );
206
+ VALUE self;
128
207
  t_pg_result *this;
129
208
 
130
209
  this = (t_pg_result *)xmalloc(sizeof(*this) + sizeof(*this->fnames) * nfields);
131
- RTYPEDDATA_DATA(self) = this;
132
-
133
210
  this->pgresult = result;
211
+ /* Initialize connection and typemap prior to any object allocations,
212
+ * to make sure valid objects are marked. */
134
213
  this->connection = rb_pgconn;
135
214
  this->typemap = pg_typemap_all_strings;
136
- this->p_typemap = DATA_PTR( this->typemap );
215
+ this->p_typemap = RTYPEDDATA_DATA( this->typemap );
137
216
  this->nfields = -1;
138
217
  this->tuple_hash = Qnil;
139
218
  this->field_map = Qnil;
140
-
141
- PG_ENCODING_SET_NOCHECK(self, ENCODING_GET(rb_pgconn));
219
+ this->flags = 0;
220
+ self = TypedData_Wrap_Struct(rb_cPGresult, &pgresult_type, this);
142
221
 
143
222
  if( result ){
144
223
  t_pg_connection *p_conn = pg_get_connection(rb_pgconn);
145
224
  VALUE typemap = p_conn->type_map_for_results;
146
-
147
225
  /* Type check is done when assigned to PG::Connection. */
148
- t_typemap *p_typemap = DATA_PTR(typemap);
149
-
150
- this->typemap = p_typemap->funcs.fit_to_result( typemap, self );
151
- this->p_typemap = DATA_PTR( this->typemap );
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();
152
235
  }
153
236
 
154
237
  return self;
@@ -159,22 +242,38 @@ pg_new_result(PGresult *result, VALUE rb_pgconn)
159
242
  {
160
243
  VALUE self = pg_new_result2(result, rb_pgconn);
161
244
  t_pg_result *this = pgresult_get_this(self);
162
- t_pg_connection *p_conn = pg_get_connection(rb_pgconn);
163
245
 
164
246
  this->autoclear = 0;
165
247
 
166
- if( p_conn->guess_result_memsize ){
167
- /* Approximate size of underlying pgresult memory storage and account to ruby GC */
168
- this->result_size = pgresult_approx_size(result);
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);
169
255
 
170
256
  #ifdef HAVE_RB_GC_ADJUST_MEMORY_USAGE
171
- rb_gc_adjust_memory_usage(this->result_size);
257
+ rb_gc_adjust_memory_usage(this->result_size);
172
258
  #endif
173
- }
174
259
 
175
260
  return self;
176
261
  }
177
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
+
178
277
  VALUE
179
278
  pg_new_result_autoclear(PGresult *result, VALUE rb_pgconn)
180
279
  {
@@ -193,7 +292,11 @@ pg_new_result_autoclear(PGresult *result, VALUE rb_pgconn)
193
292
  * call-seq:
194
293
  * res.check -> nil
195
294
  *
196
- * Raises appropriate exception if PG::Result is in a bad state.
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+
197
300
  */
198
301
  VALUE
199
302
  pg_result_check( VALUE self )
@@ -218,10 +321,16 @@ pg_result_check( VALUE self )
218
321
  case PGRES_SINGLE_TUPLE:
219
322
  case PGRES_EMPTY_QUERY:
220
323
  case PGRES_COMMAND_OK:
324
+ #ifdef HAVE_PQENTERPIPELINEMODE
325
+ case PGRES_PIPELINE_SYNC:
326
+ #endif
221
327
  return self;
222
328
  case PGRES_BAD_RESPONSE:
223
329
  case PGRES_FATAL_ERROR:
224
330
  case PGRES_NONFATAL_ERROR:
331
+ #ifdef HAVE_PQENTERPIPELINEMODE
332
+ case PGRES_PIPELINE_ABORTED:
333
+ #endif
225
334
  error = rb_str_new2( PQresultErrorMessage(this->pgresult) );
226
335
  break;
227
336
  default:
@@ -229,7 +338,7 @@ pg_result_check( VALUE self )
229
338
  }
230
339
  }
231
340
 
232
- PG_ENCODING_SET_NOCHECK( error, ENCODING_GET(self) );
341
+ PG_ENCODING_SET_NOCHECK( error, this->enc_idx );
233
342
 
234
343
  sqlstate = PQresultErrorField( this->pgresult, PG_DIAG_SQLSTATE );
235
344
  klass = lookup_error_class( sqlstate );
@@ -261,25 +370,44 @@ pg_result_check( VALUE self )
261
370
  * Special care must be taken when PG::Tuple objects are used.
262
371
  * In this case #clear must not be called unless all PG::Tuple objects of this result are fully materialized.
263
372
  *
264
- * If PG::Result#autoclear? is true then the result is marked as cleared
265
- * and the underlying C struct will be cleared automatically by libpq.
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.
266
374
  *
267
375
  */
268
376
  VALUE
269
377
  pg_result_clear(VALUE self)
270
378
  {
271
379
  t_pg_result *this = pgresult_get_this(self);
380
+ rb_check_frozen(self);
272
381
  pgresult_clear( this );
273
382
  return Qnil;
274
383
  }
275
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
+
276
404
  /*
277
405
  * call-seq:
278
406
  * res.cleared? -> boolean
279
407
  *
280
- * Returns +true+ if the backend result memory has been free'd.
408
+ * Returns +true+ if the backend result memory has been freed.
281
409
  */
282
- VALUE
410
+ static VALUE
283
411
  pgresult_cleared_p( VALUE self )
284
412
  {
285
413
  t_pg_result *this = pgresult_get_this(self);
@@ -290,11 +418,13 @@ pgresult_cleared_p( VALUE self )
290
418
  * call-seq:
291
419
  * res.autoclear? -> boolean
292
420
  *
293
- * Returns +true+ if the underlying C struct will be cleared automatically by libpq.
294
- * Elsewise the result is cleared by PG::Result#clear or by the GC when it's no longer in use.
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 .
295
425
  *
296
426
  */
297
- VALUE
427
+ static VALUE
298
428
  pgresult_autoclear_p( VALUE self )
299
429
  {
300
430
  t_pg_result *this = pgresult_get_this(self);
@@ -305,37 +435,6 @@ pgresult_autoclear_p( VALUE self )
305
435
  * DATA pointer functions
306
436
  */
307
437
 
308
- /*
309
- * GC Mark function
310
- */
311
- static void
312
- pgresult_gc_mark( t_pg_result *this )
313
- {
314
- int i;
315
-
316
- if( !this ) return;
317
- rb_gc_mark( this->connection );
318
- rb_gc_mark( this->typemap );
319
- rb_gc_mark( this->tuple_hash );
320
- rb_gc_mark( this->field_map );
321
-
322
- for( i=0; i < this->nfields; i++ ){
323
- rb_gc_mark( this->fnames[i] );
324
- }
325
- }
326
-
327
- /*
328
- * GC Free function
329
- */
330
- static void
331
- pgresult_gc_free( t_pg_result *this )
332
- {
333
- if( !this ) return;
334
- pgresult_clear( this );
335
-
336
- xfree(this);
337
- }
338
-
339
438
  /*
340
439
  * Fetch the PG::Result object data pointer and check it's
341
440
  * PGresult data pointer for sanity.
@@ -365,32 +464,30 @@ pgresult_get(VALUE self)
365
464
  return this->pgresult;
366
465
  }
367
466
 
368
-
369
- static const rb_data_type_t pgresult_type = {
370
- "pg",
371
- {
372
- (void (*)(void*))pgresult_gc_mark,
373
- (void (*)(void*))pgresult_gc_free,
374
- (size_t (*)(const void *))pgresult_memsize,
375
- },
376
- 0, 0,
377
- #ifdef RUBY_TYPED_FREE_IMMEDIATELY
378
- RUBY_TYPED_FREE_IMMEDIATELY,
379
- #endif
380
- };
381
-
382
- /*
383
- * Document-method: allocate
384
- *
385
- * call-seq:
386
- * PG::Result.allocate -> result
387
- */
388
- static VALUE
389
- pgresult_s_allocate( VALUE klass )
467
+ static VALUE pg_cstr_to_sym(char *cstr, unsigned int flags, int enc_idx)
390
468
  {
391
- VALUE self = TypedData_Wrap_Struct( klass, &pgresult_type, NULL );
392
-
393
- return self;
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;
394
491
  }
395
492
 
396
493
  static void pgresult_init_fnames(VALUE self)
@@ -402,12 +499,10 @@ static void pgresult_init_fnames(VALUE self)
402
499
  int nfields = PQnfields(this->pgresult);
403
500
 
404
501
  for( i=0; i<nfields; i++ ){
405
- VALUE fname = rb_tainted_str_new2(PQfname(this->pgresult, i));
406
- PG_ENCODING_SET_NOCHECK(fname, ENCODING_GET(self));
407
- this->fnames[i] = rb_obj_freeze(fname);
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);
408
505
  this->nfields = i + 1;
409
-
410
- RB_GC_GUARD(fname);
411
506
  }
412
507
  this->nfields = nfields;
413
508
  }
@@ -419,6 +514,8 @@ static void pgresult_init_fnames(VALUE self)
419
514
  *
420
515
  * The class to represent the query result tuples (rows).
421
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 .
422
519
  *
423
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.
424
521
  * You can invoke the #clear method to force deallocation of memory of the instance when finished with the result for better memory performance.
@@ -451,6 +548,11 @@ static void pgresult_init_fnames(VALUE self)
451
548
  * * +PGRES_NONFATAL_ERROR+
452
549
  * * +PGRES_FATAL_ERROR+
453
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.
454
556
  */
455
557
  static VALUE
456
558
  pgresult_result_status(VALUE self)
@@ -460,16 +562,39 @@ pgresult_result_status(VALUE self)
460
562
 
461
563
  /*
462
564
  * call-seq:
463
- * res.res_status( status ) -> String
565
+ * PG::Result.res_status( status ) -> String
464
566
  *
465
- * Returns the string representation of status +status+.
567
+ * Returns the string representation of +status+.
466
568
  *
467
569
  */
468
570
  static VALUE
469
- pgresult_res_status(VALUE self, VALUE status)
571
+ pgresult_s_res_status(VALUE self, VALUE status)
470
572
  {
471
- VALUE ret = rb_tainted_str_new2(PQresStatus(NUM2INT(status)));
472
- PG_ENCODING_SET_NOCHECK(ret, ENCODING_GET(self));
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);
473
598
  return ret;
474
599
  }
475
600
 
@@ -482,11 +607,40 @@ pgresult_res_status(VALUE self, VALUE status)
482
607
  static VALUE
483
608
  pgresult_error_message(VALUE self)
484
609
  {
485
- VALUE ret = rb_tainted_str_new2(PQresultErrorMessage(pgresult_get(self)));
486
- PG_ENCODING_SET_NOCHECK(ret, ENCODING_GET(self));
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);
487
613
  return ret;
488
614
  }
489
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
+
490
644
  /*
491
645
  * call-seq:
492
646
  * res.error_field(fieldcode) -> String
@@ -536,14 +690,14 @@ pgresult_error_message(VALUE self)
536
690
  static VALUE
537
691
  pgresult_error_field(VALUE self, VALUE field)
538
692
  {
539
- PGresult *result = pgresult_get( self );
693
+ t_pg_result *this = pgresult_get_this_safe(self);
540
694
  int fieldcode = NUM2INT( field );
541
- char * fieldstr = PQresultErrorField( result, fieldcode );
695
+ char * fieldstr = PQresultErrorField( this->pgresult, fieldcode );
542
696
  VALUE ret = Qnil;
543
697
 
544
698
  if ( fieldstr ) {
545
- ret = rb_tainted_str_new2( fieldstr );
546
- PG_ENCODING_SET_NOCHECK( ret, ENCODING_GET(self ));
699
+ ret = rb_str_new2( fieldstr );
700
+ PG_ENCODING_SET_NOCHECK( ret, this->enc_idx );
547
701
  }
548
702
 
549
703
  return ret;
@@ -581,24 +735,40 @@ pgresult_nfields(VALUE self)
581
735
 
582
736
  /*
583
737
  * call-seq:
584
- * res.fname( index ) -> String
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
585
754
  *
586
755
  * Returns the name of the column corresponding to _index_.
756
+ * Depending on #field_name_type= it's a String or Symbol.
757
+ *
587
758
  */
588
759
  static VALUE
589
760
  pgresult_fname(VALUE self, VALUE index)
590
761
  {
591
- VALUE fname;
592
- PGresult *result = pgresult_get(self);
762
+ t_pg_result *this = pgresult_get_this_safe(self);
593
763
  int i = NUM2INT(index);
764
+ char *cfname;
594
765
 
595
- if (i < 0 || i >= PQnfields(result)) {
766
+ if (i < 0 || i >= PQnfields(this->pgresult)) {
596
767
  rb_raise(rb_eArgError,"invalid field number %d", i);
597
768
  }
598
769
 
599
- fname = rb_tainted_str_new2(PQfname(result, i));
600
- PG_ENCODING_SET_NOCHECK(fname, ENCODING_GET(self));
601
- return rb_obj_freeze(fname);
770
+ cfname = PQfname(this->pgresult, i);
771
+ return pg_cstr_to_sym(cfname, this->flags, this->enc_idx);
602
772
  }
603
773
 
604
774
  /*
@@ -897,8 +1067,9 @@ pgresult_paramtype(VALUE self, VALUE param_number)
897
1067
  static VALUE
898
1068
  pgresult_cmd_status(VALUE self)
899
1069
  {
900
- VALUE ret = rb_tainted_str_new2(PQcmdStatus(pgresult_get(self)));
901
- PG_ENCODING_SET_NOCHECK(ret, ENCODING_GET(self));
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);
902
1073
  return ret;
903
1074
  }
904
1075
 
@@ -927,7 +1098,7 @@ pgresult_cmd_tuples(VALUE self)
927
1098
  {
928
1099
  long n;
929
1100
  n = strtol(PQcmdTuples(pgresult_get(self)),NULL, 10);
930
- return INT2NUM(n);
1101
+ return LONG2NUM(n);
931
1102
  }
932
1103
 
933
1104
  /*
@@ -979,7 +1150,7 @@ pgresult_aref(VALUE self, VALUE index)
979
1150
  }
980
1151
  /* Store a copy of the filled hash for use at the next row. */
981
1152
  if( num_tuples > 10 )
982
- this->tuple_hash = rb_hash_dup(tuple);
1153
+ RB_OBJ_WRITE(self, &this->tuple_hash, rb_hash_dup(tuple));
983
1154
 
984
1155
  return tuple;
985
1156
  }
@@ -1098,8 +1269,12 @@ static VALUE
1098
1269
  pgresult_field_values( VALUE self, VALUE field )
1099
1270
  {
1100
1271
  PGresult *result = pgresult_get( self );
1101
- const char *fieldname = StringValueCStr( field );
1102
- int fnum = PQfnumber( result, fieldname );
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 );
1103
1278
 
1104
1279
  if ( fnum < 0 )
1105
1280
  rb_raise( rb_eIndexError, "no such field '%s' in result", fieldname );
@@ -1142,6 +1317,25 @@ pgresult_tuple_values(VALUE self, VALUE index)
1142
1317
  }
1143
1318
  }
1144
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
+
1145
1339
  /*
1146
1340
  * call-seq:
1147
1341
  * res.tuple( n ) -> PG::Tuple
@@ -1162,19 +1356,7 @@ pgresult_tuple(VALUE self, VALUE index)
1162
1356
  if ( tuple_num < 0 || tuple_num >= num_tuples )
1163
1357
  rb_raise( rb_eIndexError, "Index %d is out of range", tuple_num );
1164
1358
 
1165
- if( this->field_map == Qnil ){
1166
- int i;
1167
- VALUE field_map = rb_hash_new();
1168
-
1169
- if( this->nfields == -1 )
1170
- pgresult_init_fnames( self );
1171
-
1172
- for( i = 0; i < this->nfields; i++ ){
1173
- rb_hash_aset(field_map, this->fnames[i], INT2FIX(i));
1174
- }
1175
- rb_obj_freeze(field_map);
1176
- this->field_map = field_map;
1177
- }
1359
+ ensure_init_for_tuple(self);
1178
1360
 
1179
1361
  return pg_tuple_new(self, tuple_num);
1180
1362
  }
@@ -1206,7 +1388,7 @@ pgresult_each(VALUE self)
1206
1388
  * call-seq:
1207
1389
  * res.fields() -> Array
1208
1390
  *
1209
- * Returns an array of Strings representing the names of the fields in the result.
1391
+ * Depending on #field_name_type= returns an array of strings or symbols representing the names of the fields in the result.
1210
1392
  */
1211
1393
  static VALUE
1212
1394
  pgresult_fields(VALUE self)
@@ -1238,14 +1420,13 @@ pgresult_type_map_set(VALUE self, VALUE typemap)
1238
1420
  t_pg_result *this = pgresult_get_this(self);
1239
1421
  t_typemap *p_typemap;
1240
1422
 
1241
- if ( !rb_obj_is_kind_of(typemap, rb_cTypeMap) ) {
1242
- rb_raise( rb_eTypeError, "wrong argument type %s (expected kind of PG::TypeMap)",
1243
- rb_obj_classname( typemap ) );
1244
- }
1245
- Data_Get_Struct(typemap, t_typemap, p_typemap);
1423
+ rb_check_frozen(self);
1424
+ /* Check type of method param */
1425
+ TypedData_Get_Struct(typemap, t_typemap, &pg_typemap_type, p_typemap);
1246
1426
 
1247
- this->typemap = p_typemap->funcs.fit_to_result( typemap, self );
1248
- this->p_typemap = DATA_PTR( this->typemap );
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 );
1249
1430
 
1250
1431
  return typemap;
1251
1432
  }
@@ -1266,22 +1447,21 @@ pgresult_type_map_get(VALUE self)
1266
1447
  }
1267
1448
 
1268
1449
 
1269
- static void
1270
- yield_hash(VALUE self, int ntuples, int nfields)
1450
+ static int
1451
+ yield_hash(VALUE self, int ntuples, int nfields, void *data)
1271
1452
  {
1272
1453
  int tuple_num;
1273
- t_pg_result *this = pgresult_get_this(self);
1274
1454
  UNUSED(nfields);
1275
1455
 
1276
1456
  for(tuple_num = 0; tuple_num < ntuples; tuple_num++) {
1277
1457
  rb_yield(pgresult_aref(self, INT2NUM(tuple_num)));
1278
1458
  }
1279
1459
 
1280
- pgresult_clear( this );
1460
+ return 1; /* clear the result */
1281
1461
  }
1282
1462
 
1283
- static void
1284
- yield_array(VALUE self, int ntuples, int nfields)
1463
+ static int
1464
+ yield_array(VALUE self, int ntuples, int nfields, void *data)
1285
1465
  {
1286
1466
  int row;
1287
1467
  t_pg_result *this = pgresult_get_this(self);
@@ -1297,31 +1477,40 @@ yield_array(VALUE self, int ntuples, int nfields)
1297
1477
  rb_yield( rb_ary_new4( nfields, row_values ));
1298
1478
  }
1299
1479
 
1300
- pgresult_clear( this );
1480
+ return 1; /* clear the result */
1301
1481
  }
1302
1482
 
1303
- static void
1304
- yield_tuple(VALUE self, int ntuples, int nfields)
1483
+ static int
1484
+ yield_tuple(VALUE self, int ntuples, int nfields, void *data)
1305
1485
  {
1306
1486
  int tuple_num;
1307
1487
  t_pg_result *this = pgresult_get_this(self);
1308
- VALUE result = pg_new_result(this->pgresult, this->connection);
1488
+ VALUE copy;
1309
1489
  UNUSED(nfields);
1310
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
+
1311
1497
  for(tuple_num = 0; tuple_num < ntuples; tuple_num++) {
1312
- VALUE tuple = pgresult_tuple(result, INT2FIX(tuple_num));
1498
+ VALUE tuple = pgresult_tuple(copy, INT2FIX(tuple_num));
1313
1499
  rb_yield( tuple );
1314
1500
  }
1501
+ return 0; /* don't clear the result */
1315
1502
  }
1316
1503
 
1317
- static VALUE
1318
- pgresult_stream_any(VALUE self, void (*yielder)(VALUE, int, int))
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)
1319
1507
  {
1320
1508
  t_pg_result *this;
1321
- int nfields;
1509
+ int nfields, nfields2;
1322
1510
  PGconn *pgconn;
1323
1511
  PGresult *pgresult;
1324
1512
 
1513
+ rb_check_frozen(self);
1325
1514
  RETURN_ENUMERATOR(self, 0, NULL);
1326
1515
 
1327
1516
  this = pgresult_get_this_safe(self);
@@ -1334,6 +1523,7 @@ pgresult_stream_any(VALUE self, void (*yielder)(VALUE, int, int))
1334
1523
 
1335
1524
  switch( PQresultStatus(pgresult) ){
1336
1525
  case PGRES_TUPLES_OK:
1526
+ case PGRES_COMMAND_OK:
1337
1527
  if( ntuples == 0 )
1338
1528
  return self;
1339
1529
  rb_raise( rb_eInvalidResultStatus, "PG::Result is not in single row mode");
@@ -1343,14 +1533,24 @@ pgresult_stream_any(VALUE self, void (*yielder)(VALUE, int, int))
1343
1533
  pg_result_check( self );
1344
1534
  }
1345
1535
 
1346
- yielder( self, ntuples, nfields );
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
+ }
1347
1550
 
1348
1551
  pgresult = gvl_PQgetResult(pgconn);
1349
1552
  if( pgresult == NULL )
1350
- rb_raise( rb_eNoResultError, "no result received - possibly an intersection with another result retrieval");
1351
-
1352
- if( nfields != PQnfields(pgresult) )
1353
- rb_raise( rb_eInvalidChangeOfResultFields, "number of fields must not change in single row mode");
1553
+ rb_raise( rb_eNoResultError, "no result received - possibly an intersection with another query");
1354
1554
 
1355
1555
  this->pgresult = pgresult;
1356
1556
  }
@@ -1390,13 +1590,11 @@ pgresult_stream_any(VALUE self, void (*yielder)(VALUE, int, int))
1390
1590
  * # do something with each received row of the second query
1391
1591
  * end
1392
1592
  * conn.get_result # => nil (no more results)
1393
- *
1394
- * Available since PostgreSQL-9.2
1395
1593
  */
1396
1594
  static VALUE
1397
1595
  pgresult_stream_each(VALUE self)
1398
1596
  {
1399
- return pgresult_stream_any(self, yield_hash);
1597
+ return pgresult_stream_any(self, yield_hash, NULL);
1400
1598
  }
1401
1599
 
1402
1600
  /*
@@ -1408,13 +1606,11 @@ pgresult_stream_each(VALUE self)
1408
1606
  *
1409
1607
  * This method works equally to #stream_each , but yields an Array of
1410
1608
  * values.
1411
- *
1412
- * Available since PostgreSQL-9.2
1413
1609
  */
1414
1610
  static VALUE
1415
1611
  pgresult_stream_each_row(VALUE self)
1416
1612
  {
1417
- return pgresult_stream_any(self, yield_array);
1613
+ return pgresult_stream_any(self, yield_array, NULL);
1418
1614
  }
1419
1615
 
1420
1616
  /*
@@ -1424,38 +1620,108 @@ pgresult_stream_each_row(VALUE self)
1424
1620
  * Yields each row of the result set in single row mode.
1425
1621
  *
1426
1622
  * This method works equally to #stream_each , but yields a PG::Tuple object.
1427
- *
1428
- * Available since PostgreSQL-9.2
1429
1623
  */
1430
1624
  static VALUE
1431
1625
  pgresult_stream_each_tuple(VALUE self)
1432
1626
  {
1433
- return pgresult_stream_any(self, yield_tuple);
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;
1434
1669
  }
1435
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
+ }
1436
1691
 
1437
1692
  void
1438
- init_pg_result()
1693
+ init_pg_result(void)
1439
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
+
1440
1699
  rb_cPGresult = rb_define_class_under( rb_mPG, "Result", rb_cObject );
1441
- rb_define_alloc_func( rb_cPGresult, pgresult_s_allocate );
1700
+ rb_undef_alloc_func(rb_cPGresult);
1442
1701
  rb_include_module(rb_cPGresult, rb_mEnumerable);
1443
1702
  rb_include_module(rb_cPGresult, rb_mPGconstants);
1444
1703
 
1445
1704
  /****** PG::Result INSTANCE METHODS: libpq ******/
1446
1705
  rb_define_method(rb_cPGresult, "result_status", pgresult_result_status, 0);
1447
- rb_define_method(rb_cPGresult, "res_status", pgresult_res_status, 1);
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);
1448
1708
  rb_define_method(rb_cPGresult, "error_message", pgresult_error_message, 0);
1449
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
1450
1714
  rb_define_method(rb_cPGresult, "error_field", pgresult_error_field, 1);
1451
1715
  rb_define_alias( rb_cPGresult, "result_error_field", "error_field" );
1452
1716
  rb_define_method(rb_cPGresult, "clear", pg_result_clear, 0);
1717
+ rb_define_method(rb_cPGresult, "freeze", pg_result_freeze, 0 );
1453
1718
  rb_define_method(rb_cPGresult, "check", pg_result_check, 0);
1454
1719
  rb_define_alias (rb_cPGresult, "check_result", "check");
1455
1720
  rb_define_method(rb_cPGresult, "ntuples", pgresult_ntuples, 0);
1456
1721
  rb_define_alias(rb_cPGresult, "num_tuples", "ntuples");
1457
1722
  rb_define_method(rb_cPGresult, "nfields", pgresult_nfields, 0);
1458
1723
  rb_define_alias(rb_cPGresult, "num_fields", "nfields");
1724
+ rb_define_method(rb_cPGresult, "binary_tuples", pgresult_binary_tuples, 0);
1459
1725
  rb_define_method(rb_cPGresult, "fname", pgresult_fname, 1);
1460
1726
  rb_define_method(rb_cPGresult, "fnumber", pgresult_fnumber, 1);
1461
1727
  rb_define_method(rb_cPGresult, "ftable", pgresult_ftable, 1);
@@ -1494,6 +1760,7 @@ init_pg_result()
1494
1760
  rb_define_method(rb_cPGresult, "stream_each", pgresult_stream_each, 0);
1495
1761
  rb_define_method(rb_cPGresult, "stream_each_row", pgresult_stream_each_row, 0);
1496
1762
  rb_define_method(rb_cPGresult, "stream_each_tuple", pgresult_stream_each_tuple, 0);
1497
- }
1498
-
1499
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
+ }