pg 1.2.3 → 1.5.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 (136) 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 +137 -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 +876 -0
  16. data/Manifest.txt +0 -1
  17. data/README.ja.md +276 -0
  18. data/README.md +286 -0
  19. data/Rakefile +33 -135
  20. data/Rakefile.cross +12 -13
  21. data/certs/ged.pem +24 -0
  22. data/certs/larskanis-2022.pem +26 -0
  23. data/certs/larskanis-2023.pem +24 -0
  24. data/ext/errorcodes.def +12 -0
  25. data/ext/errorcodes.rb +0 -0
  26. data/ext/errorcodes.txt +4 -1
  27. data/ext/extconf.rb +100 -25
  28. data/ext/gvl_wrappers.c +4 -0
  29. data/ext/gvl_wrappers.h +23 -0
  30. data/ext/pg.c +72 -57
  31. data/ext/pg.h +28 -4
  32. data/ext/pg_binary_decoder.c +80 -1
  33. data/ext/pg_binary_encoder.c +225 -1
  34. data/ext/pg_coder.c +96 -33
  35. data/ext/pg_connection.c +996 -697
  36. data/ext/pg_copy_coder.c +351 -33
  37. data/ext/pg_errors.c +1 -1
  38. data/ext/pg_record_coder.c +50 -19
  39. data/ext/pg_result.c +177 -64
  40. data/ext/pg_text_decoder.c +29 -11
  41. data/ext/pg_text_encoder.c +29 -16
  42. data/ext/pg_tuple.c +83 -60
  43. data/ext/pg_type_map.c +44 -10
  44. data/ext/pg_type_map_all_strings.c +17 -3
  45. data/ext/pg_type_map_by_class.c +54 -27
  46. data/ext/pg_type_map_by_column.c +73 -31
  47. data/ext/pg_type_map_by_mri_type.c +48 -19
  48. data/ext/pg_type_map_by_oid.c +59 -27
  49. data/ext/pg_type_map_in_ruby.c +55 -21
  50. data/ext/pg_util.c +2 -2
  51. data/lib/pg/basic_type_map_based_on_result.rb +67 -0
  52. data/lib/pg/basic_type_map_for_queries.rb +198 -0
  53. data/lib/pg/basic_type_map_for_results.rb +104 -0
  54. data/lib/pg/basic_type_registry.rb +299 -0
  55. data/lib/pg/binary_decoder/date.rb +9 -0
  56. data/lib/pg/binary_decoder/timestamp.rb +26 -0
  57. data/lib/pg/binary_encoder/timestamp.rb +20 -0
  58. data/lib/pg/coder.rb +15 -13
  59. data/lib/pg/connection.rb +743 -83
  60. data/lib/pg/exceptions.rb +14 -1
  61. data/lib/pg/text_decoder/date.rb +18 -0
  62. data/lib/pg/text_decoder/inet.rb +9 -0
  63. data/lib/pg/text_decoder/json.rb +14 -0
  64. data/lib/pg/text_decoder/numeric.rb +9 -0
  65. data/lib/pg/text_decoder/timestamp.rb +30 -0
  66. data/lib/pg/text_encoder/date.rb +12 -0
  67. data/lib/pg/text_encoder/inet.rb +28 -0
  68. data/lib/pg/text_encoder/json.rb +14 -0
  69. data/lib/pg/text_encoder/numeric.rb +9 -0
  70. data/lib/pg/text_encoder/timestamp.rb +24 -0
  71. data/lib/pg/version.rb +4 -0
  72. data/lib/pg.rb +94 -39
  73. data/misc/openssl-pg-segfault.rb +31 -0
  74. data/misc/postgres/History.txt +9 -0
  75. data/misc/postgres/Manifest.txt +5 -0
  76. data/misc/postgres/README.txt +21 -0
  77. data/misc/postgres/Rakefile +21 -0
  78. data/misc/postgres/lib/postgres.rb +16 -0
  79. data/misc/ruby-pg/History.txt +9 -0
  80. data/misc/ruby-pg/Manifest.txt +5 -0
  81. data/misc/ruby-pg/README.txt +21 -0
  82. data/misc/ruby-pg/Rakefile +21 -0
  83. data/misc/ruby-pg/lib/ruby/pg.rb +16 -0
  84. data/pg.gemspec +34 -0
  85. data/rakelib/task_extension.rb +46 -0
  86. data/sample/array_insert.rb +20 -0
  87. data/sample/async_api.rb +102 -0
  88. data/sample/async_copyto.rb +39 -0
  89. data/sample/async_mixed.rb +56 -0
  90. data/sample/check_conn.rb +21 -0
  91. data/sample/copydata.rb +71 -0
  92. data/sample/copyfrom.rb +81 -0
  93. data/sample/copyto.rb +19 -0
  94. data/sample/cursor.rb +21 -0
  95. data/sample/disk_usage_report.rb +177 -0
  96. data/sample/issue-119.rb +94 -0
  97. data/sample/losample.rb +69 -0
  98. data/sample/minimal-testcase.rb +17 -0
  99. data/sample/notify_wait.rb +72 -0
  100. data/sample/pg_statistics.rb +285 -0
  101. data/sample/replication_monitor.rb +222 -0
  102. data/sample/test_binary_values.rb +33 -0
  103. data/sample/wal_shipper.rb +434 -0
  104. data/sample/warehouse_partitions.rb +311 -0
  105. data/translation/.po4a-version +7 -0
  106. data/translation/po/all.pot +910 -0
  107. data/translation/po/ja.po +1047 -0
  108. data/translation/po4a.cfg +12 -0
  109. data.tar.gz.sig +0 -0
  110. metadata +142 -210
  111. metadata.gz.sig +0 -0
  112. data/ChangeLog +0 -0
  113. data/History.rdoc +0 -578
  114. data/README.ja.rdoc +0 -13
  115. data/README.rdoc +0 -213
  116. data/lib/pg/basic_type_mapping.rb +0 -522
  117. data/lib/pg/binary_decoder.rb +0 -23
  118. data/lib/pg/constants.rb +0 -12
  119. data/lib/pg/text_decoder.rb +0 -46
  120. data/lib/pg/text_encoder.rb +0 -59
  121. data/spec/data/expected_trace.out +0 -26
  122. data/spec/data/random_binary_data +0 -0
  123. data/spec/helpers.rb +0 -380
  124. data/spec/pg/basic_type_mapping_spec.rb +0 -630
  125. data/spec/pg/connection_spec.rb +0 -1949
  126. data/spec/pg/connection_sync_spec.rb +0 -41
  127. data/spec/pg/result_spec.rb +0 -681
  128. data/spec/pg/tuple_spec.rb +0 -333
  129. data/spec/pg/type_map_by_class_spec.rb +0 -138
  130. data/spec/pg/type_map_by_column_spec.rb +0 -226
  131. data/spec/pg/type_map_by_mri_type_spec.rb +0 -136
  132. data/spec/pg/type_map_by_oid_spec.rb +0 -149
  133. data/spec/pg/type_map_in_ruby_spec.rb +0 -164
  134. data/spec/pg/type_map_spec.rb +0 -22
  135. data/spec/pg/type_spec.rb +0 -1123
  136. data/spec/pg_spec.rb +0 -50
data/ext/pg_result.c CHANGED
@@ -107,17 +107,34 @@ pgresult_approx_size(const PGresult *result)
107
107
  * GC Mark function
108
108
  */
109
109
  static void
110
- pgresult_gc_mark( t_pg_result *this )
110
+ pgresult_gc_mark( void *_this )
111
111
  {
112
+ t_pg_result *this = (t_pg_result *)_this;
112
113
  int i;
113
114
 
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 );
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 );
118
119
 
119
120
  for( i=0; i < this->nfields; i++ ){
120
- rb_gc_mark( this->fnames[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] );
121
138
  }
122
139
  }
123
140
 
@@ -125,8 +142,9 @@ pgresult_gc_mark( t_pg_result *this )
125
142
  * GC Free function
126
143
  */
127
144
  static void
128
- pgresult_clear( t_pg_result *this )
145
+ pgresult_clear( void *_this )
129
146
  {
147
+ t_pg_result *this = (t_pg_result *)_this;
130
148
  if( this->pgresult && !this->autoclear ){
131
149
  PQclear(this->pgresult);
132
150
  #ifdef HAVE_RB_GC_ADJUST_MEMORY_USAGE
@@ -139,15 +157,17 @@ pgresult_clear( t_pg_result *this )
139
157
  }
140
158
 
141
159
  static void
142
- pgresult_gc_free( t_pg_result *this )
160
+ pgresult_gc_free( void *_this )
143
161
  {
162
+ t_pg_result *this = (t_pg_result *)_this;
144
163
  pgresult_clear( this );
145
164
  xfree(this);
146
165
  }
147
166
 
148
167
  static size_t
149
- pgresult_memsize( t_pg_result *this )
168
+ pgresult_memsize( const void *_this )
150
169
  {
170
+ const t_pg_result *this = (const t_pg_result *)_this;
151
171
  /* Ideally the memory 'this' is pointing to should be taken into account as well.
152
172
  * However we don't want to store two memory sizes in t_pg_result just for reporting by ObjectSpace.memsize_of.
153
173
  */
@@ -155,16 +175,15 @@ pgresult_memsize( t_pg_result *this )
155
175
  }
156
176
 
157
177
  static const rb_data_type_t pgresult_type = {
158
- "pg",
178
+ "PG::Result",
159
179
  {
160
- (void (*)(void*))pgresult_gc_mark,
161
- (void (*)(void*))pgresult_gc_free,
162
- (size_t (*)(const void *))pgresult_memsize,
180
+ pgresult_gc_mark,
181
+ pgresult_gc_free,
182
+ pgresult_memsize,
183
+ pg_compact_callback(pgresult_gc_compact),
163
184
  },
164
185
  0, 0,
165
- #ifdef RUBY_TYPED_FREE_IMMEDIATELY
166
- RUBY_TYPED_FREE_IMMEDIATELY,
167
- #endif
186
+ RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | PG_RUBY_TYPED_FROZEN_SHAREABLE,
168
187
  };
169
188
 
170
189
  /* Needed by sequel_pg gem, do not delete */
@@ -189,9 +208,11 @@ pg_new_result2(PGresult *result, VALUE rb_pgconn)
189
208
 
190
209
  this = (t_pg_result *)xmalloc(sizeof(*this) + sizeof(*this->fnames) * nfields);
191
210
  this->pgresult = result;
211
+ /* Initialize connection and typemap prior to any object allocations,
212
+ * to make sure valid objects are marked. */
192
213
  this->connection = rb_pgconn;
193
214
  this->typemap = pg_typemap_all_strings;
194
- this->p_typemap = DATA_PTR( this->typemap );
215
+ this->p_typemap = RTYPEDDATA_DATA( this->typemap );
195
216
  this->nfields = -1;
196
217
  this->tuple_hash = Qnil;
197
218
  this->field_map = Qnil;
@@ -202,11 +223,12 @@ pg_new_result2(PGresult *result, VALUE rb_pgconn)
202
223
  t_pg_connection *p_conn = pg_get_connection(rb_pgconn);
203
224
  VALUE typemap = p_conn->type_map_for_results;
204
225
  /* Type check is done when assigned to PG::Connection. */
205
- t_typemap *p_typemap = DATA_PTR(typemap);
226
+ t_typemap *p_typemap = RTYPEDDATA_DATA(typemap);
206
227
 
207
228
  this->enc_idx = p_conn->enc_idx;
208
- this->typemap = p_typemap->funcs.fit_to_result( typemap, self );
209
- this->p_typemap = DATA_PTR( this->typemap );
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 );
210
232
  this->flags = p_conn->flags;
211
233
  } else {
212
234
  this->enc_idx = rb_locale_encindex();
@@ -270,7 +292,11 @@ pg_new_result_autoclear(PGresult *result, VALUE rb_pgconn)
270
292
  * call-seq:
271
293
  * res.check -> nil
272
294
  *
273
- * 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+
274
300
  */
275
301
  VALUE
276
302
  pg_result_check( VALUE self )
@@ -295,10 +321,16 @@ pg_result_check( VALUE self )
295
321
  case PGRES_SINGLE_TUPLE:
296
322
  case PGRES_EMPTY_QUERY:
297
323
  case PGRES_COMMAND_OK:
324
+ #ifdef HAVE_PQENTERPIPELINEMODE
325
+ case PGRES_PIPELINE_SYNC:
326
+ #endif
298
327
  return self;
299
328
  case PGRES_BAD_RESPONSE:
300
329
  case PGRES_FATAL_ERROR:
301
330
  case PGRES_NONFATAL_ERROR:
331
+ #ifdef HAVE_PQENTERPIPELINEMODE
332
+ case PGRES_PIPELINE_ABORTED:
333
+ #endif
302
334
  error = rb_str_new2( PQresultErrorMessage(this->pgresult) );
303
335
  break;
304
336
  default:
@@ -345,17 +377,37 @@ VALUE
345
377
  pg_result_clear(VALUE self)
346
378
  {
347
379
  t_pg_result *this = pgresult_get_this(self);
380
+ rb_check_frozen(self);
348
381
  pgresult_clear( this );
349
382
  return Qnil;
350
383
  }
351
384
 
352
385
  /*
353
386
  * call-seq:
354
- * res.cleared? -> boolean
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.
355
393
  *
356
- * Returns +true+ if the backend result memory has been free'd.
357
394
  */
358
395
  VALUE
396
+ static 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
359
411
  pgresult_cleared_p( VALUE self )
360
412
  {
361
413
  t_pg_result *this = pgresult_get_this(self);
@@ -367,12 +419,12 @@ pgresult_cleared_p( VALUE self )
367
419
  * res.autoclear? -> boolean
368
420
  *
369
421
  * 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 .
422
+ * This applies only to Result objects received by the block to PG::Connection#set_notice_receiver .
371
423
  *
372
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 .
373
425
  *
374
426
  */
375
- VALUE
427
+ static VALUE
376
428
  pgresult_autoclear_p( VALUE self )
377
429
  {
378
430
  t_pg_result *this = pgresult_get_this(self);
@@ -448,7 +500,8 @@ static void pgresult_init_fnames(VALUE self)
448
500
 
449
501
  for( i=0; i<nfields; i++ ){
450
502
  char *cfname = PQfname(this->pgresult, i);
451
- this->fnames[i] = pg_cstr_to_sym(cfname, this->flags, this->enc_idx);
503
+ VALUE fname = pg_cstr_to_sym(cfname, this->flags, this->enc_idx);
504
+ RB_OBJ_WRITE(self, &this->fnames[i], fname);
452
505
  this->nfields = i + 1;
453
506
  }
454
507
  this->nfields = nfields;
@@ -495,6 +548,11 @@ static void pgresult_init_fnames(VALUE self)
495
548
  * * +PGRES_NONFATAL_ERROR+
496
549
  * * +PGRES_FATAL_ERROR+
497
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.
498
556
  */
499
557
  static VALUE
500
558
  pgresult_result_status(VALUE self)
@@ -504,16 +562,38 @@ pgresult_result_status(VALUE self)
504
562
 
505
563
  /*
506
564
  * call-seq:
507
- * res.res_status( status ) -> String
565
+ * PG::Result.res_status( status ) -> String
508
566
  *
509
- * Returns the string representation of status +status+.
567
+ * Returns the string representation of +status+.
510
568
  *
511
569
  */
512
570
  static VALUE
513
- pgresult_res_status(VALUE self, VALUE status)
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)
514
586
  {
515
587
  t_pg_result *this = pgresult_get_this_safe(self);
516
- VALUE ret = rb_str_new2(PQresStatus(NUM2INT(status)));
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
+ }
517
597
  PG_ENCODING_SET_NOCHECK(ret, this->enc_idx);
518
598
  return ret;
519
599
  }
@@ -653,6 +733,21 @@ pgresult_nfields(VALUE self)
653
733
  return INT2NUM(PQnfields(pgresult_get(self)));
654
734
  }
655
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
+
656
751
  /*
657
752
  * call-seq:
658
753
  * res.fname( index ) -> String or Symbol
@@ -1003,7 +1098,7 @@ pgresult_cmd_tuples(VALUE self)
1003
1098
  {
1004
1099
  long n;
1005
1100
  n = strtol(PQcmdTuples(pgresult_get(self)),NULL, 10);
1006
- return INT2NUM(n);
1101
+ return LONG2NUM(n);
1007
1102
  }
1008
1103
 
1009
1104
  /*
@@ -1055,7 +1150,7 @@ pgresult_aref(VALUE self, VALUE index)
1055
1150
  }
1056
1151
  /* Store a copy of the filled hash for use at the next row. */
1057
1152
  if( num_tuples > 10 )
1058
- this->tuple_hash = rb_hash_dup(tuple);
1153
+ RB_OBJ_WRITE(self, &this->tuple_hash, rb_hash_dup(tuple));
1059
1154
 
1060
1155
  return tuple;
1061
1156
  }
@@ -1237,7 +1332,7 @@ static void ensure_init_for_tuple(VALUE self)
1237
1332
  rb_hash_aset(field_map, this->fnames[i], INT2FIX(i));
1238
1333
  }
1239
1334
  rb_obj_freeze(field_map);
1240
- this->field_map = field_map;
1335
+ RB_OBJ_WRITE(self, &this->field_map, field_map);
1241
1336
  }
1242
1337
  }
1243
1338
 
@@ -1325,14 +1420,13 @@ pgresult_type_map_set(VALUE self, VALUE typemap)
1325
1420
  t_pg_result *this = pgresult_get_this(self);
1326
1421
  t_typemap *p_typemap;
1327
1422
 
1328
- if ( !rb_obj_is_kind_of(typemap, rb_cTypeMap) ) {
1329
- rb_raise( rb_eTypeError, "wrong argument type %s (expected kind of PG::TypeMap)",
1330
- rb_obj_classname( typemap ) );
1331
- }
1332
- 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);
1333
1426
 
1334
- this->typemap = p_typemap->funcs.fit_to_result( typemap, self );
1335
- 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 );
1336
1430
 
1337
1431
  return typemap;
1338
1432
  }
@@ -1353,22 +1447,21 @@ pgresult_type_map_get(VALUE self)
1353
1447
  }
1354
1448
 
1355
1449
 
1356
- static void
1357
- yield_hash(VALUE self, int ntuples, int nfields)
1450
+ static int
1451
+ yield_hash(VALUE self, int ntuples, int nfields, void *data)
1358
1452
  {
1359
1453
  int tuple_num;
1360
- t_pg_result *this = pgresult_get_this(self);
1361
1454
  UNUSED(nfields);
1362
1455
 
1363
1456
  for(tuple_num = 0; tuple_num < ntuples; tuple_num++) {
1364
1457
  rb_yield(pgresult_aref(self, INT2NUM(tuple_num)));
1365
1458
  }
1366
1459
 
1367
- pgresult_clear( this );
1460
+ return 1; /* clear the result */
1368
1461
  }
1369
1462
 
1370
- static void
1371
- yield_array(VALUE self, int ntuples, int nfields)
1463
+ static int
1464
+ yield_array(VALUE self, int ntuples, int nfields, void *data)
1372
1465
  {
1373
1466
  int row;
1374
1467
  t_pg_result *this = pgresult_get_this(self);
@@ -1384,11 +1477,11 @@ yield_array(VALUE self, int ntuples, int nfields)
1384
1477
  rb_yield( rb_ary_new4( nfields, row_values ));
1385
1478
  }
1386
1479
 
1387
- pgresult_clear( this );
1480
+ return 1; /* clear the result */
1388
1481
  }
1389
1482
 
1390
- static void
1391
- yield_tuple(VALUE self, int ntuples, int nfields)
1483
+ static int
1484
+ yield_tuple(VALUE self, int ntuples, int nfields, void *data)
1392
1485
  {
1393
1486
  int tuple_num;
1394
1487
  t_pg_result *this = pgresult_get_this(self);
@@ -1405,16 +1498,19 @@ yield_tuple(VALUE self, int ntuples, int nfields)
1405
1498
  VALUE tuple = pgresult_tuple(copy, INT2FIX(tuple_num));
1406
1499
  rb_yield( tuple );
1407
1500
  }
1501
+ return 0; /* don't clear the result */
1408
1502
  }
1409
1503
 
1410
- static VALUE
1411
- 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)
1412
1507
  {
1413
1508
  t_pg_result *this;
1414
- int nfields;
1509
+ int nfields, nfields2;
1415
1510
  PGconn *pgconn;
1416
1511
  PGresult *pgresult;
1417
1512
 
1513
+ rb_check_frozen(self);
1418
1514
  RETURN_ENUMERATOR(self, 0, NULL);
1419
1515
 
1420
1516
  this = pgresult_get_this_safe(self);
@@ -1427,6 +1523,7 @@ pgresult_stream_any(VALUE self, void (*yielder)(VALUE, int, int))
1427
1523
 
1428
1524
  switch( PQresultStatus(pgresult) ){
1429
1525
  case PGRES_TUPLES_OK:
1526
+ case PGRES_COMMAND_OK:
1430
1527
  if( ntuples == 0 )
1431
1528
  return self;
1432
1529
  rb_raise( rb_eInvalidResultStatus, "PG::Result is not in single row mode");
@@ -1436,14 +1533,24 @@ pgresult_stream_any(VALUE self, void (*yielder)(VALUE, int, int))
1436
1533
  pg_result_check( self );
1437
1534
  }
1438
1535
 
1439
- 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
+ }
1440
1550
 
1441
1551
  pgresult = gvl_PQgetResult(pgconn);
1442
1552
  if( pgresult == NULL )
1443
- rb_raise( rb_eNoResultError, "no result received - possibly an intersection with another result retrieval");
1444
-
1445
- if( nfields != PQnfields(pgresult) )
1446
- 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");
1447
1554
 
1448
1555
  this->pgresult = pgresult;
1449
1556
  }
@@ -1487,7 +1594,7 @@ pgresult_stream_any(VALUE self, void (*yielder)(VALUE, int, int))
1487
1594
  static VALUE
1488
1595
  pgresult_stream_each(VALUE self)
1489
1596
  {
1490
- return pgresult_stream_any(self, yield_hash);
1597
+ return pgresult_stream_any(self, yield_hash, NULL);
1491
1598
  }
1492
1599
 
1493
1600
  /*
@@ -1503,7 +1610,7 @@ pgresult_stream_each(VALUE self)
1503
1610
  static VALUE
1504
1611
  pgresult_stream_each_row(VALUE self)
1505
1612
  {
1506
- return pgresult_stream_any(self, yield_array);
1613
+ return pgresult_stream_any(self, yield_array, NULL);
1507
1614
  }
1508
1615
 
1509
1616
  /*
@@ -1520,7 +1627,7 @@ pgresult_stream_each_tuple(VALUE self)
1520
1627
  /* allocate VALUEs that are shared between all streamed tuples */
1521
1628
  ensure_init_for_tuple(self);
1522
1629
 
1523
- return pgresult_stream_any(self, yield_tuple);
1630
+ return pgresult_stream_any(self, yield_tuple, NULL);
1524
1631
  }
1525
1632
 
1526
1633
  /*
@@ -1531,7 +1638,7 @@ pgresult_stream_each_tuple(VALUE self)
1531
1638
  * It can be set to one of:
1532
1639
  * * +:string+ to use String based field names
1533
1640
  * * +: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.
1641
+ * * +:static_symbol+ to use pinned Symbol (can not be garbage collected) - Don't use this, it will probably be removed in future.
1535
1642
  *
1536
1643
  * The default is retrieved from PG::Connection#field_name_type , which defaults to +:string+ .
1537
1644
  *
@@ -1548,6 +1655,8 @@ static VALUE
1548
1655
  pgresult_field_name_type_set(VALUE self, VALUE sym)
1549
1656
  {
1550
1657
  t_pg_result *this = pgresult_get_this(self);
1658
+
1659
+ rb_check_frozen(self);
1551
1660
  if( this->nfields != -1 ) rb_raise(rb_eArgError, "field names are already materialized");
1552
1661
 
1553
1662
  this->flags &= ~PG_RESULT_FIELD_NAMES_MASK;
@@ -1581,19 +1690,21 @@ pgresult_field_name_type_get(VALUE self)
1581
1690
  }
1582
1691
 
1583
1692
  void
1584
- init_pg_result()
1693
+ init_pg_result(void)
1585
1694
  {
1586
1695
  sym_string = ID2SYM(rb_intern("string"));
1587
1696
  sym_symbol = ID2SYM(rb_intern("symbol"));
1588
1697
  sym_static_symbol = ID2SYM(rb_intern("static_symbol"));
1589
1698
 
1590
- rb_cPGresult = rb_define_class_under( rb_mPG, "Result", rb_cData );
1699
+ rb_cPGresult = rb_define_class_under( rb_mPG, "Result", rb_cObject );
1700
+ rb_undef_alloc_func(rb_cPGresult);
1591
1701
  rb_include_module(rb_cPGresult, rb_mEnumerable);
1592
1702
  rb_include_module(rb_cPGresult, rb_mPGconstants);
1593
1703
 
1594
1704
  /****** PG::Result INSTANCE METHODS: libpq ******/
1595
1705
  rb_define_method(rb_cPGresult, "result_status", pgresult_result_status, 0);
1596
- 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);
1597
1708
  rb_define_method(rb_cPGresult, "error_message", pgresult_error_message, 0);
1598
1709
  rb_define_alias( rb_cPGresult, "result_error_message", "error_message");
1599
1710
  #ifdef HAVE_PQRESULTVERBOSEERRORMESSAGE
@@ -1603,12 +1714,14 @@ init_pg_result()
1603
1714
  rb_define_method(rb_cPGresult, "error_field", pgresult_error_field, 1);
1604
1715
  rb_define_alias( rb_cPGresult, "result_error_field", "error_field" );
1605
1716
  rb_define_method(rb_cPGresult, "clear", pg_result_clear, 0);
1717
+ rb_define_method(rb_cPGresult, "freeze", pg_result_freeze, 0 );
1606
1718
  rb_define_method(rb_cPGresult, "check", pg_result_check, 0);
1607
1719
  rb_define_alias (rb_cPGresult, "check_result", "check");
1608
1720
  rb_define_method(rb_cPGresult, "ntuples", pgresult_ntuples, 0);
1609
1721
  rb_define_alias(rb_cPGresult, "num_tuples", "ntuples");
1610
1722
  rb_define_method(rb_cPGresult, "nfields", pgresult_nfields, 0);
1611
1723
  rb_define_alias(rb_cPGresult, "num_fields", "nfields");
1724
+ rb_define_method(rb_cPGresult, "binary_tuples", pgresult_binary_tuples, 0);
1612
1725
  rb_define_method(rb_cPGresult, "fname", pgresult_fname, 1);
1613
1726
  rb_define_method(rb_cPGresult, "fnumber", pgresult_fnumber, 1);
1614
1727
  rb_define_method(rb_cPGresult, "ftable", pgresult_ftable, 1);
@@ -43,7 +43,6 @@
43
43
  #include <string.h>
44
44
 
45
45
  VALUE rb_mPG_TextDecoder;
46
- static ID s_id_decode;
47
46
  static ID s_id_Rational;
48
47
  static ID s_id_new;
49
48
  static ID s_id_utc;
@@ -171,6 +170,19 @@ pg_text_dec_numeric(t_pg_coder *conv, const char *val, int len, int tuple, int f
171
170
  return rb_funcall(rb_cObject, s_id_BigDecimal, 1, rb_str_new(val, len));
172
171
  }
173
172
 
173
+ /* called per autoload when TextDecoder::Numeric is used */
174
+ static VALUE
175
+ init_pg_text_decoder_numeric(VALUE rb_mPG_TextDecoder)
176
+ {
177
+ rb_require("bigdecimal");
178
+ s_id_BigDecimal = rb_intern("BigDecimal");
179
+
180
+ /* dummy = rb_define_class_under( rb_mPG_TextDecoder, "Numeric", rb_cPG_SimpleDecoder ); */
181
+ pg_define_coder( "Numeric", pg_text_dec_numeric, rb_cPG_SimpleDecoder, rb_mPG_TextDecoder );
182
+
183
+ return Qnil;
184
+ }
185
+
174
186
  /*
175
187
  * Document-class: PG::TextDecoder::Float < PG::SimpleDecoder
176
188
  *
@@ -854,7 +866,7 @@ pg_text_dec_inet(t_pg_coder *conv, const char *val, int len, int tuple, int fiel
854
866
 
855
867
  ip_int_native = read_nbo32(dst);
856
868
 
857
- /* Work around broken IPAddr behavior of convering portion
869
+ /* Work around broken IPAddr behavior of converting portion
858
870
  of address after netmask to 0 */
859
871
  switch (mask) {
860
872
  case 0:
@@ -922,8 +934,9 @@ pg_text_dec_inet(t_pg_coder *conv, const char *val, int len, int tuple, int fiel
922
934
  return ip;
923
935
  }
924
936
 
925
- void
926
- init_pg_text_decoder()
937
+ /* called per autoload when TextDecoder::Inet is used */
938
+ static VALUE
939
+ init_pg_text_decoder_inet(VALUE rb_mPG_TextDecoder)
927
940
  {
928
941
  rb_require("ipaddr");
929
942
  s_IPAddr = rb_funcall(rb_cObject, rb_intern("const_get"), 1, rb_str_new2("IPAddr"));
@@ -942,14 +955,21 @@ init_pg_text_decoder()
942
955
  s_vmasks6 = rb_eval_string("a = [0]*129; a[0] = 0; a[128] = 0xffffffffffffffffffffffffffffffff; 127.downto(1){|i| a[i] = a[i+1] - (1 << (127 - i))}; a.freeze");
943
956
  rb_global_variable(&s_vmasks6);
944
957
 
945
- s_id_decode = rb_intern("decode");
958
+ /* dummy = rb_define_class_under( rb_mPG_TextDecoder, "Inet", rb_cPG_SimpleDecoder ); */
959
+ pg_define_coder( "Inet", pg_text_dec_inet, rb_cPG_SimpleDecoder, rb_mPG_TextDecoder);
960
+
961
+ return Qnil;
962
+ }
963
+
964
+
965
+ void
966
+ init_pg_text_decoder(void)
967
+ {
946
968
  s_id_Rational = rb_intern("Rational");
947
969
  s_id_new = rb_intern("new");
948
970
  s_id_utc = rb_intern("utc");
949
971
  s_id_getlocal = rb_intern("getlocal");
950
972
 
951
- rb_require("bigdecimal");
952
- s_id_BigDecimal = rb_intern("BigDecimal");
953
973
  s_nan = rb_eval_string("0.0/0.0");
954
974
  rb_global_variable(&s_nan);
955
975
  s_pos_inf = rb_eval_string("1.0/0.0");
@@ -959,6 +979,8 @@ init_pg_text_decoder()
959
979
 
960
980
  /* This module encapsulates all decoder classes with text input format */
961
981
  rb_mPG_TextDecoder = rb_define_module_under( rb_mPG, "TextDecoder" );
982
+ rb_define_private_method(rb_singleton_class(rb_mPG_TextDecoder), "init_inet", init_pg_text_decoder_inet, 0);
983
+ rb_define_private_method(rb_singleton_class(rb_mPG_TextDecoder), "init_numeric", init_pg_text_decoder_numeric, 0);
962
984
 
963
985
  /* Make RDoc aware of the decoder classes... */
964
986
  /* dummy = rb_define_class_under( rb_mPG_TextDecoder, "Boolean", rb_cPG_SimpleDecoder ); */
@@ -967,8 +989,6 @@ init_pg_text_decoder()
967
989
  pg_define_coder( "Integer", pg_text_dec_integer, rb_cPG_SimpleDecoder, rb_mPG_TextDecoder );
968
990
  /* dummy = rb_define_class_under( rb_mPG_TextDecoder, "Float", rb_cPG_SimpleDecoder ); */
969
991
  pg_define_coder( "Float", pg_text_dec_float, rb_cPG_SimpleDecoder, rb_mPG_TextDecoder );
970
- /* dummy = rb_define_class_under( rb_mPG_TextDecoder, "Numeric", rb_cPG_SimpleDecoder ); */
971
- pg_define_coder( "Numeric", pg_text_dec_numeric, rb_cPG_SimpleDecoder, rb_mPG_TextDecoder );
972
992
  /* dummy = rb_define_class_under( rb_mPG_TextDecoder, "String", rb_cPG_SimpleDecoder ); */
973
993
  pg_define_coder( "String", pg_text_dec_string, rb_cPG_SimpleDecoder, rb_mPG_TextDecoder );
974
994
  /* dummy = rb_define_class_under( rb_mPG_TextDecoder, "Bytea", rb_cPG_SimpleDecoder ); */
@@ -977,8 +997,6 @@ init_pg_text_decoder()
977
997
  pg_define_coder( "Identifier", pg_text_dec_identifier, rb_cPG_SimpleDecoder, rb_mPG_TextDecoder );
978
998
  /* dummy = rb_define_class_under( rb_mPG_TextDecoder, "Timestamp", rb_cPG_SimpleDecoder ); */
979
999
  pg_define_coder( "Timestamp", pg_text_dec_timestamp, rb_cPG_SimpleDecoder, rb_mPG_TextDecoder);
980
- /* dummy = rb_define_class_under( rb_mPG_TextDecoder, "Inet", rb_cPG_SimpleDecoder ); */
981
- pg_define_coder( "Inet", pg_text_dec_inet, rb_cPG_SimpleDecoder, rb_mPG_TextDecoder);
982
1000
 
983
1001
  /* dummy = rb_define_class_under( rb_mPG_TextDecoder, "Array", rb_cPG_CompositeDecoder ); */
984
1002
  pg_define_coder( "Array", pg_text_dec_array, rb_cPG_CompositeDecoder, rb_mPG_TextDecoder );