pg 1.5.9 → 1.7.0

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 (67) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/{History.md → CHANGELOG.md} +126 -0
  4. data/Gemfile +11 -7
  5. data/README-Windows.rdoc +1 -1
  6. data/README.ja.md +83 -32
  7. data/README.md +79 -29
  8. data/Rakefile +84 -19
  9. data/certs/larskanis-2026.pem +24 -0
  10. data/ext/errorcodes.def +9 -0
  11. data/ext/errorcodes.rb +1 -1
  12. data/ext/errorcodes.txt +8 -1
  13. data/ext/extconf.rb +194 -30
  14. data/ext/gvl_wrappers.c +13 -2
  15. data/ext/gvl_wrappers.h +47 -134
  16. data/ext/pg.c +23 -16
  17. data/ext/pg.h +23 -24
  18. data/ext/pg_binary_decoder.c +157 -3
  19. data/ext/pg_binary_encoder.c +219 -9
  20. data/ext/pg_cancel_connection.c +360 -0
  21. data/ext/pg_coder.c +58 -9
  22. data/ext/pg_connection.c +558 -291
  23. data/ext/pg_copy_coder.c +36 -23
  24. data/ext/pg_record_coder.c +11 -7
  25. data/ext/pg_result.c +144 -76
  26. data/ext/pg_text_decoder.c +7 -7
  27. data/ext/pg_text_encoder.c +29 -11
  28. data/ext/pg_tuple.c +9 -9
  29. data/ext/pg_type_map.c +45 -3
  30. data/ext/pg_type_map_all_strings.c +3 -3
  31. data/ext/pg_type_map_by_class.c +2 -2
  32. data/ext/pg_type_map_by_column.c +4 -3
  33. data/ext/pg_type_map_by_mri_type.c +1 -1
  34. data/ext/pg_type_map_by_oid.c +4 -2
  35. data/ext/pg_type_map_in_ruby.c +2 -2
  36. data/ext/pg_util.c +2 -2
  37. data/ext/pg_util.h +2 -2
  38. data/lib/pg/basic_type_map_based_on_result.rb +5 -0
  39. data/lib/pg/basic_type_map_for_queries.rb +16 -5
  40. data/lib/pg/basic_type_map_for_results.rb +5 -0
  41. data/lib/pg/basic_type_registry.rb +2 -2
  42. data/lib/pg/cancel_connection.rb +53 -0
  43. data/lib/pg/coder.rb +4 -2
  44. data/lib/pg/connection.rb +393 -180
  45. data/lib/pg/text_decoder/date.rb +1 -1
  46. data/lib/pg/text_decoder/json.rb +1 -1
  47. data/lib/pg/text_encoder/date.rb +7 -1
  48. data/lib/pg/text_encoder/json.rb +1 -1
  49. data/lib/pg/version.rb +2 -1
  50. data/lib/pg.rb +156 -130
  51. data/misc/glibc/Dockerfile +20 -0
  52. data/misc/glibc/docker-compose.yml +9 -0
  53. data/misc/glibc/glibc_spec.rb +5 -0
  54. data/misc/yugabyte/Dockerfile +9 -0
  55. data/misc/yugabyte/docker-compose.yml +28 -0
  56. data/misc/yugabyte/pg-test.rb +45 -0
  57. data/pg.gemspec +5 -3
  58. data/ports/patches/krb5/1.22.2/0001-Allow-static-linking-krb5-library.patch +30 -0
  59. data/ports/patches/krb5/1.22.2/0002-unknown-command-line-option-on-clang.patch +12 -0
  60. data/ports/patches/postgresql/18.6/0001-Use-workaround-of-__builtin_setjmp-only-on-MINGW-on-.patch +42 -0
  61. data/rakelib/pg_gem_helper.rb +64 -0
  62. data/sample/async_mixed.rb +1 -1
  63. data.tar.gz.sig +0 -0
  64. metadata +36 -22
  65. metadata.gz.sig +0 -0
  66. data/Manifest.txt +0 -72
  67. data/Rakefile.cross +0 -303
data/ext/pg_result.c CHANGED
@@ -7,11 +7,12 @@
7
7
  #include "pg.h"
8
8
 
9
9
  VALUE rb_cPGresult;
10
- static VALUE sym_symbol, sym_string, sym_static_symbol;
10
+ static VALUE sym_symbol, sym_string;
11
11
 
12
12
  static VALUE pgresult_type_map_set( VALUE, VALUE );
13
13
  static t_pg_result *pgresult_get_this( VALUE );
14
14
  static t_pg_result *pgresult_get_this_safe( VALUE );
15
+ static void ensure_init_for_tuple(VALUE self);
15
16
 
16
17
  #if defined(HAVE_PQRESULTMEMORYSIZE)
17
18
 
@@ -114,7 +115,6 @@ pgresult_gc_mark( void *_this )
114
115
 
115
116
  rb_gc_mark_movable( this->connection );
116
117
  rb_gc_mark_movable( this->typemap );
117
- rb_gc_mark_movable( this->tuple_hash );
118
118
  rb_gc_mark_movable( this->field_map );
119
119
 
120
120
  for( i=0; i < this->nfields; i++ ){
@@ -130,7 +130,6 @@ pgresult_gc_compact( void *_this )
130
130
 
131
131
  pg_gc_location( this->connection );
132
132
  pg_gc_location( this->typemap );
133
- pg_gc_location( this->tuple_hash );
134
133
  pg_gc_location( this->field_map );
135
134
 
136
135
  for( i=0; i < this->nfields; i++ ){
@@ -147,9 +146,7 @@ pgresult_clear( void *_this )
147
146
  t_pg_result *this = (t_pg_result *)_this;
148
147
  if( this->pgresult && !this->autoclear ){
149
148
  PQclear(this->pgresult);
150
- #ifdef HAVE_RB_GC_ADJUST_MEMORY_USAGE
151
149
  rb_gc_adjust_memory_usage(-this->result_size);
152
- #endif
153
150
  }
154
151
  this->result_size = 0;
155
152
  this->nfields = -1;
@@ -180,10 +177,10 @@ static const rb_data_type_t pgresult_type = {
180
177
  pgresult_gc_mark,
181
178
  pgresult_gc_free,
182
179
  pgresult_memsize,
183
- pg_compact_callback(pgresult_gc_compact),
180
+ pgresult_gc_compact,
184
181
  },
185
182
  0, 0,
186
- RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | PG_RUBY_TYPED_FROZEN_SHAREABLE,
183
+ RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FROZEN_SHAREABLE,
187
184
  };
188
185
 
189
186
  /* Needed by sequel_pg gem, do not delete */
@@ -214,7 +211,6 @@ pg_new_result2(PGresult *result, VALUE rb_pgconn)
214
211
  this->typemap = pg_typemap_all_strings;
215
212
  this->p_typemap = RTYPEDDATA_DATA( this->typemap );
216
213
  this->nfields = -1;
217
- this->tuple_hash = Qnil;
218
214
  this->field_map = Qnil;
219
215
  this->flags = 0;
220
216
  self = TypedData_Wrap_Struct(rb_cPGresult, &pgresult_type, this);
@@ -253,9 +249,7 @@ pg_new_result(PGresult *result, VALUE rb_pgconn)
253
249
  */
254
250
  this->result_size = pgresult_approx_size(result);
255
251
 
256
- #ifdef HAVE_RB_GC_ADJUST_MEMORY_USAGE
257
252
  rb_gc_adjust_memory_usage(this->result_size);
258
- #endif
259
253
 
260
254
  return self;
261
255
  }
@@ -321,14 +315,17 @@ pg_result_check( VALUE self )
321
315
  case PGRES_SINGLE_TUPLE:
322
316
  case PGRES_EMPTY_QUERY:
323
317
  case PGRES_COMMAND_OK:
324
- #ifdef HAVE_PQENTERPIPELINEMODE
318
+ #ifdef LIBPQ_HAS_PIPELINING
325
319
  case PGRES_PIPELINE_SYNC:
320
+ #endif
321
+ #ifdef LIBPQ_HAS_CHUNK_MODE
322
+ case PGRES_TUPLES_CHUNK:
326
323
  #endif
327
324
  return self;
328
325
  case PGRES_BAD_RESPONSE:
329
326
  case PGRES_FATAL_ERROR:
330
327
  case PGRES_NONFATAL_ERROR:
331
- #ifdef HAVE_PQENTERPIPELINEMODE
328
+ #ifdef LIBPQ_HAS_PIPELINING
332
329
  case PGRES_PIPELINE_ABORTED:
333
330
  #endif
334
331
  error = rb_str_new2( PQresultErrorMessage(this->pgresult) );
@@ -397,6 +394,7 @@ pg_result_freeze(VALUE self)
397
394
  {
398
395
  t_pg_result *this = pgresult_get_this(self);
399
396
 
397
+ ensure_init_for_tuple(self);
400
398
  RB_OBJ_WRITE(self, &this->connection, Qnil);
401
399
  return rb_call_super(0, NULL);
402
400
  }
@@ -467,9 +465,6 @@ pgresult_get(VALUE self)
467
465
  static VALUE pg_cstr_to_sym(char *cstr, unsigned int flags, int enc_idx)
468
466
  {
469
467
  VALUE fname;
470
- #ifdef TRUFFLERUBY
471
- if( flags & (PG_RESULT_FIELD_NAMES_SYMBOL | PG_RESULT_FIELD_NAMES_STATIC_SYMBOL) ){
472
- #else
473
468
  if( flags & PG_RESULT_FIELD_NAMES_SYMBOL ){
474
469
  rb_encoding *enc = rb_enc_from_index(enc_idx);
475
470
  fname = rb_check_symbol_cstr(cstr, strlen(cstr), enc);
@@ -478,14 +473,9 @@ static VALUE pg_cstr_to_sym(char *cstr, unsigned int flags, int enc_idx)
478
473
  PG_ENCODING_SET_NOCHECK(fname, enc_idx);
479
474
  fname = rb_str_intern(fname);
480
475
  }
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
476
  } else {
486
- fname = rb_str_new2(cstr);
487
- PG_ENCODING_SET_NOCHECK(fname, enc_idx);
488
- fname = rb_obj_freeze(fname);
477
+ rb_encoding *enc = rb_enc_from_index(enc_idx);
478
+ fname = rb_enc_interned_str(cstr, strlen(cstr), enc);
489
479
  }
490
480
  return fname;
491
481
  }
@@ -514,20 +504,48 @@ static void pgresult_init_fnames(VALUE self)
514
504
  *
515
505
  * The class to represent the query result tuples (rows).
516
506
  * An instance of this class is created as the result of every query.
517
- * All result rows and columns are stored in a memory block attached to the PG::Result object.
518
- * Whenever a value is accessed it is casted to a Ruby object by the assigned #type_map .
519
- *
520
- * Since pg-1.1 the amount of memory in use by a PG::Result object is estimated and passed to ruby's garbage collector.
521
- * You can invoke the #clear method to force deallocation of memory of the instance when finished with the result for better memory performance.
507
+ * All result rows and columns are stored in an immutable memory block attached to the PG::Result object unless streaming is used.
522
508
  *
523
- * Example:
509
+ * A PG::Result has various ways to retrieve the result data:
524
510
  * require 'pg'
525
- * conn = PG.connect(:dbname => 'test')
526
- * res = conn.exec('SELECT 1 AS a, 2 AS b, NULL AS c')
527
- * res.getvalue(0,0) # '1'
528
- * res[0]['b'] # '2'
529
- * res[0]['c'] # nil
511
+ * conn = PG.connect(dbname: 'test')
512
+ * res = conn.exec('SELECT 1 AS a, 2 AS b, NULL AS c')
513
+ * res.num_fields # 3
514
+ * res.num_tuples # 1
515
+ * res.fname(2) # "c"
516
+ * res.fields # ["a", "b", "c"]
517
+ * res.getvalue(0,0) # '1'
518
+ * res[0] # {"a" => "1", "b" => "2", "c" => "3"}
519
+ * res.tuple_values(0) # ["1", "2", nil]
520
+ * res.tuple(0) # #<PG::Tuple a: "1", b: "2", c: nil>
521
+ * res.values # [["1", "2", nil]]
522
+ * res.field_values(:a) # ["1"]
523
+ * res.column_values(1) # ["2"]
524
+ * res.each.first # {"a" => "1", "b" => "2", "c" => nil}
525
+ * res.each_row.first # ["1", "2", nil]
526
+ * res.each_tuple.first # #<PG::Tuple a: "1", b: "2", c: nil>
527
+ *
528
+ * Whenever a value is accessed it is casted to a Ruby object by the assigned #type_map which is PG::TypeMapAllStrings by default.
529
+ * Similarly field names can be retrieved either as strings (default) or as symbols which can be switched per #field_name_type= .
530
+ *
531
+ * res = conn.exec('SELECT 1 AS a, 2 AS b, NULL AS c')
532
+ * res.type_map = PG::TypeMapByColumn.new([PG::TextDecoder::Integer.new]*3)
533
+ * res.field_name_type = :symbol
534
+ * res.fname(2) # :c
535
+ * res.fields # [:a, :b, :c]
536
+ * res.getvalue(0,0) # 1
537
+ * res[0] # {a: 1, b: 2, c: nil}
538
+ * res.tuple_values(0) # [1, 2, nil]
539
+ * res.tuple(0) # #<PG::Tuple a: 1, b: 2, c: nil>
540
+ * res.values # [[1, 2, nil]]
541
+ * res.field_values(:a) # [1]
542
+ * res.column_values(1) # [2]
543
+ * res.each.first # {a: 1, b: 2, c: nil}
544
+ * res.each_row.first # [1, 2, nil]
545
+ * res.each_tuple.first # #<PG::Tuple a: 1, b: 2, c: nil>
530
546
  *
547
+ * Since pg-1.1 the amount of memory in use by a PG::Result object is estimated and passed to ruby's garbage collector.
548
+ * You can invoke the #clear method to force deallocation of memory of the instance when finished with the result for better memory performance.
531
549
  */
532
550
 
533
551
  /**************************************************************************
@@ -549,10 +567,11 @@ static void pgresult_init_fnames(VALUE self)
549
567
  * * +PGRES_FATAL_ERROR+
550
568
  * * +PGRES_COPY_BOTH+
551
569
  * * +PGRES_SINGLE_TUPLE+
570
+ * * +PGRES_TUPLES_CHUNK+
552
571
  * * +PGRES_PIPELINE_SYNC+
553
572
  * * +PGRES_PIPELINE_ABORTED+
554
573
  *
555
- * Use <tt>res.res_status</tt> to retrieve the string representation.
574
+ * Use #res_status or Result.res_status to retrieve the string representation.
556
575
  */
557
576
  static VALUE
558
577
  pgresult_result_status(VALUE self)
@@ -564,7 +583,7 @@ pgresult_result_status(VALUE self)
564
583
  * call-seq:
565
584
  * PG::Result.res_status( status ) -> String
566
585
  *
567
- * Returns the string representation of +status+.
586
+ * Returns the string representation of #result_status.
568
587
  *
569
588
  */
570
589
  static VALUE
@@ -578,7 +597,7 @@ pgresult_s_res_status(VALUE self, VALUE status)
578
597
  * res.res_status -> String
579
598
  * res.res_status( status ) -> String
580
599
  *
581
- * Returns the string representation of the status of the result or of the provided +status+.
600
+ * Returns the string representation of the status of the result or of the provided #result_status.
582
601
  *
583
602
  */
584
603
  static VALUE
@@ -613,14 +632,12 @@ pgresult_error_message(VALUE self)
613
632
  return ret;
614
633
  }
615
634
 
616
- #ifdef HAVE_PQRESULTVERBOSEERRORMESSAGE
617
635
  /*
618
636
  * call-seq:
619
637
  * res.verbose_error_message( verbosity, show_context ) -> String
620
638
  *
621
- * Returns a reformatted version of the error message associated with a PGresult object.
639
+ * Returns a reformatted version of the error message associated with the PG::Result object.
622
640
  *
623
- * Available since PostgreSQL-9.6
624
641
  */
625
642
  static VALUE
626
643
  pgresult_verbose_error_message(VALUE self, VALUE verbosity, VALUE show_context)
@@ -639,7 +656,6 @@ pgresult_verbose_error_message(VALUE self, VALUE verbosity, VALUE show_context)
639
656
 
640
657
  return ret;
641
658
  }
642
- #endif
643
659
 
644
660
  /*
645
661
  * call-seq:
@@ -708,6 +724,10 @@ pgresult_error_field(VALUE self, VALUE field)
708
724
  * res.ntuples() -> Integer
709
725
  *
710
726
  * Returns the number of tuples in the query result.
727
+ *
728
+ * res = conn.exec('SELECT 1 AS a, 2 AS b, NULL AS c')
729
+ * res.ntuples # 1
730
+ * res.num_tuples # 1
711
731
  */
712
732
  static VALUE
713
733
  pgresult_ntuples(VALUE self)
@@ -726,6 +746,9 @@ pgresult_ntuples_for_enum(VALUE self, VALUE args, VALUE eobj)
726
746
  * res.nfields() -> Integer
727
747
  *
728
748
  * Returns the number of columns in the query result.
749
+ * res = conn.exec('SELECT 1 AS a, 2 AS b, NULL AS c')
750
+ * res.nfields # 3
751
+ * res.num_fields # 3
729
752
  */
730
753
  static VALUE
731
754
  pgresult_nfields(VALUE self)
@@ -737,9 +760,9 @@ pgresult_nfields(VALUE self)
737
760
  * call-seq:
738
761
  * res.binary_tuples() -> Integer
739
762
  *
740
- * Returns 1 if the PGresult contains binary data and 0 if it contains text data.
763
+ * Returns 1 if the PG::Result contains binary data and 0 if it contains text data.
741
764
  *
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.
765
+ * This function is deprecated (except for its use in connection with COPY), because it is possible for a single PG::Result to contain text data in some columns and binary data in others.
743
766
  * Result#fformat is preferred. binary_tuples returns 1 only if all columns of the result are binary (format 1).
744
767
  */
745
768
  static VALUE
@@ -755,6 +778,8 @@ pgresult_binary_tuples(VALUE self)
755
778
  * Returns the name of the column corresponding to _index_.
756
779
  * Depending on #field_name_type= it's a String or Symbol.
757
780
  *
781
+ * res = conn.exec('SELECT 1 AS a, 2 AS b, NULL AS c')
782
+ * res.fname(2) # "c"
758
783
  */
759
784
  static VALUE
760
785
  pgresult_fname(VALUE self, VALUE index)
@@ -1125,6 +1150,9 @@ pgresult_oid_value(VALUE self)
1125
1150
  * res[ n ] -> Hash
1126
1151
  *
1127
1152
  * Returns tuple _n_ as a hash.
1153
+ *
1154
+ * res = conn.exec('SELECT 1 AS a, 2 AS b, NULL AS c')
1155
+ * res[0] # {"a" => "1", "b" => "2", "c" => "3"}
1128
1156
  */
1129
1157
  static VALUE
1130
1158
  pgresult_aref(VALUE self, VALUE index)
@@ -1141,16 +1169,11 @@ pgresult_aref(VALUE self, VALUE index)
1141
1169
  if ( tuple_num < 0 || tuple_num >= num_tuples )
1142
1170
  rb_raise( rb_eIndexError, "Index %d is out of range", tuple_num );
1143
1171
 
1144
- /* We reuse the Hash of the previous output for larger row counts.
1145
- * This is somewhat faster than populating an empty Hash object. */
1146
- tuple = NIL_P(this->tuple_hash) ? rb_hash_new() : this->tuple_hash;
1172
+ tuple = rb_hash_new_capa(this->nfields);
1147
1173
  for ( field_num = 0; field_num < this->nfields; field_num++ ) {
1148
1174
  VALUE val = this->p_typemap->funcs.typecast_result_value(this->p_typemap, self, tuple_num, field_num);
1149
1175
  rb_hash_aset( tuple, this->fnames[field_num], val );
1150
1176
  }
1151
- /* Store a copy of the filled hash for use at the next row. */
1152
- if( num_tuples > 10 )
1153
- RB_OBJ_WRITE(self, &this->tuple_hash, rb_hash_dup(tuple));
1154
1177
 
1155
1178
  return tuple;
1156
1179
  }
@@ -1159,7 +1182,10 @@ pgresult_aref(VALUE self, VALUE index)
1159
1182
  * call-seq:
1160
1183
  * res.each_row { |row| ... }
1161
1184
  *
1162
- * Yields each row of the result. The row is a list of column values.
1185
+ * Yields an Array object for each row in the result.
1186
+ *
1187
+ * res = conn.exec('SELECT 1 AS a, 2 AS b, NULL AS c')
1188
+ * res.each_row.first # ["1", "2", nil]
1163
1189
  */
1164
1190
  static VALUE
1165
1191
  pgresult_each_row(VALUE self)
@@ -1194,6 +1220,9 @@ pgresult_each_row(VALUE self)
1194
1220
  * res.values -> Array
1195
1221
  *
1196
1222
  * Returns all tuples as an array of arrays.
1223
+ *
1224
+ * res = conn.exec('SELECT 1 AS a, 2 AS b, NULL AS c')
1225
+ * res.values # [["1", "2", nil]]
1197
1226
  */
1198
1227
  static VALUE
1199
1228
  pgresult_values(VALUE self)
@@ -1243,12 +1272,13 @@ make_column_result_array( VALUE self, int col )
1243
1272
 
1244
1273
 
1245
1274
  /*
1246
- * call-seq:
1247
- * res.column_values( n ) -> array
1275
+ * call-seq:
1276
+ * res.column_values( n ) -> array
1248
1277
  *
1249
- * Returns an Array of the values from the nth column of each
1250
- * tuple in the result.
1278
+ * Returns an Array of the values from the nth column of each tuple in the result.
1251
1279
  *
1280
+ * res = conn.exec('SELECT 1 AS a, 2 AS b, NULL AS c')
1281
+ * res.column_values(1) # ["2"]
1252
1282
  */
1253
1283
  static VALUE
1254
1284
  pgresult_column_values(VALUE self, VALUE index)
@@ -1259,11 +1289,13 @@ pgresult_column_values(VALUE self, VALUE index)
1259
1289
 
1260
1290
 
1261
1291
  /*
1262
- * call-seq:
1292
+ * call-seq:
1263
1293
  * res.field_values( field ) -> array
1264
1294
  *
1265
- * Returns an Array of the values from the given _field_ of each tuple in the result.
1295
+ * Returns an Array of the values from the given _field_ of each tuple in the result.
1266
1296
  *
1297
+ * res = conn.exec('SELECT 1 AS a, 2 AS b, NULL AS c')
1298
+ * res.field_values(:a) # ["1"]
1267
1299
  */
1268
1300
  static VALUE
1269
1301
  pgresult_field_values( VALUE self, VALUE field )
@@ -1284,11 +1316,13 @@ pgresult_field_values( VALUE self, VALUE field )
1284
1316
 
1285
1317
 
1286
1318
  /*
1287
- * call-seq:
1288
- * res.tuple_values( n ) -> array
1319
+ * call-seq:
1320
+ * res.tuple_values( n ) -> array
1289
1321
  *
1290
- * Returns an Array of the field values from the nth row of the result.
1322
+ * Returns an Array of the field values from the nth row of the result.
1291
1323
  *
1324
+ * res = conn.exec('SELECT 1 AS a, 2 AS b, NULL AS c')
1325
+ * res.tuple_values(0) # ["1", "2", nil]
1292
1326
  */
1293
1327
  static VALUE
1294
1328
  pgresult_tuple_values(VALUE self, VALUE index)
@@ -1323,11 +1357,12 @@ static void ensure_init_for_tuple(VALUE self)
1323
1357
 
1324
1358
  if( this->field_map == Qnil ){
1325
1359
  int i;
1326
- VALUE field_map = rb_hash_new();
1360
+ VALUE field_map;
1327
1361
 
1328
1362
  if( this->nfields == -1 )
1329
1363
  pgresult_init_fnames( self );
1330
1364
 
1365
+ field_map = rb_hash_new_capa(this->nfields);
1331
1366
  for( i = 0; i < this->nfields; i++ ){
1332
1367
  rb_hash_aset(field_map, this->fnames[i], INT2FIX(i));
1333
1368
  }
@@ -1337,11 +1372,13 @@ static void ensure_init_for_tuple(VALUE self)
1337
1372
  }
1338
1373
 
1339
1374
  /*
1340
- * call-seq:
1341
- * res.tuple( n ) -> PG::Tuple
1375
+ * call-seq:
1376
+ * res.tuple( n ) -> PG::Tuple
1342
1377
  *
1343
- * Returns a PG::Tuple from the nth row of the result.
1378
+ * Returns a PG::Tuple from the nth row of the result.
1344
1379
  *
1380
+ * res = conn.exec('SELECT 1 AS a, 2 AS b, NULL AS c')
1381
+ * res.tuple(0) # #<PG::Tuple a: "1", b: "2", c: nil>
1345
1382
  */
1346
1383
  static VALUE
1347
1384
  pgresult_tuple(VALUE self, VALUE index)
@@ -1366,7 +1403,10 @@ pgresult_tuple(VALUE self, VALUE index)
1366
1403
  * call-seq:
1367
1404
  * res.each{ |tuple| ... }
1368
1405
  *
1369
- * Invokes block for each tuple in the result set.
1406
+ * Yields a Hash object for each row in the result.
1407
+ *
1408
+ * res = conn.exec('SELECT 1 AS a, 2 AS b, NULL AS c')
1409
+ * res.each.first # {"a" => "1", "b" => "2", "c" => nil}
1370
1410
  */
1371
1411
  static VALUE
1372
1412
  pgresult_each(VALUE self)
@@ -1384,11 +1424,40 @@ pgresult_each(VALUE self)
1384
1424
  return self;
1385
1425
  }
1386
1426
 
1427
+ /*
1428
+ * call-seq:
1429
+ * res.each_tuple{ |tuple| ... }
1430
+ *
1431
+ * Yields a PG::Tuple object for each row in the result.
1432
+ *
1433
+ * res = conn.exec('SELECT 1 AS a, 2 AS b, NULL AS c')
1434
+ * res.each_tuple.first # #<PG::Tuple a: "1", b: "2", c: nil>
1435
+ */
1436
+ static VALUE
1437
+ pgresult_each_tuple(VALUE self)
1438
+ {
1439
+ PGresult *result;
1440
+ int tuple_num;
1441
+
1442
+ RETURN_SIZED_ENUMERATOR(self, 0, NULL, pgresult_ntuples_for_enum);
1443
+
1444
+ result = pgresult_get(self);
1445
+
1446
+ for(tuple_num = 0; tuple_num < PQntuples(result); tuple_num++) {
1447
+ VALUE tuple = pgresult_tuple(self, INT2FIX(tuple_num));
1448
+ rb_yield( tuple );
1449
+ }
1450
+ return self;
1451
+ }
1452
+
1387
1453
  /*
1388
1454
  * call-seq:
1389
1455
  * res.fields() -> Array
1390
1456
  *
1391
1457
  * Depending on #field_name_type= returns an array of strings or symbols representing the names of the fields in the result.
1458
+ *
1459
+ * res = conn.exec('SELECT 1 AS a, 2 AS b, NULL AS c')
1460
+ * res.fields # ["a", "b", "c"]
1392
1461
  */
1393
1462
  static VALUE
1394
1463
  pgresult_fields(VALUE self)
@@ -1405,7 +1474,7 @@ pgresult_fields(VALUE self)
1405
1474
  * call-seq:
1406
1475
  * res.type_map = typemap
1407
1476
  *
1408
- * Set the TypeMap that is used for type casts of result values to ruby objects.
1477
+ * Set the PG::TypeMap that is used for type casts of result values to ruby objects.
1409
1478
  *
1410
1479
  * All value retrieval methods will respect the type map and will do the
1411
1480
  * type casts from PostgreSQL's wire format to Ruby objects on the fly,
@@ -1413,6 +1482,7 @@ pgresult_fields(VALUE self)
1413
1482
  *
1414
1483
  * +typemap+ must be a kind of PG::TypeMap .
1415
1484
  *
1485
+ * See also #map_types! and PG::BasicTypeMapForResults
1416
1486
  */
1417
1487
  static VALUE
1418
1488
  pgresult_type_map_set(VALUE self, VALUE typemap)
@@ -1435,7 +1505,8 @@ pgresult_type_map_set(VALUE self, VALUE typemap)
1435
1505
  * call-seq:
1436
1506
  * res.type_map -> value
1437
1507
  *
1438
- * Returns the TypeMap that is currently set for type casts of result values to ruby objects.
1508
+ * Returns the PG::TypeMap that is currently set for type casts of result values to ruby objects.
1509
+ * The default is retrieved from PG::Connection#type_map_for_results , which defaults to PG::TypeMapAllStrings .
1439
1510
  *
1440
1511
  */
1441
1512
  static VALUE
@@ -1528,6 +1599,9 @@ pgresult_stream_any(VALUE self, int (*yielder)(VALUE, int, int, void*), void* da
1528
1599
  return self;
1529
1600
  rb_raise( rb_eInvalidResultStatus, "PG::Result is not in single row mode");
1530
1601
  case PGRES_SINGLE_TUPLE:
1602
+ #ifdef LIBPQ_HAS_CHUNK_MODE
1603
+ case PGRES_TUPLES_CHUNK:
1604
+ #endif
1531
1605
  break;
1532
1606
  default:
1533
1607
  pg_result_check( self );
@@ -1543,12 +1617,12 @@ pgresult_stream_any(VALUE self, int (*yielder)(VALUE, int, int, void*), void* da
1543
1617
  pgresult_clear( this );
1544
1618
  }
1545
1619
 
1546
- if( gvl_PQisBusy(pgconn) ){
1620
+ if( PQisBusy(pgconn) ){
1547
1621
  /* wait for input (without blocking) before reading each result */
1548
1622
  pgconn_block( 0, NULL, this->connection );
1549
1623
  }
1550
1624
 
1551
- pgresult = gvl_PQgetResult(pgconn);
1625
+ pgresult = PQgetResult(pgconn);
1552
1626
  if( pgresult == NULL )
1553
1627
  rb_raise( rb_eNoResultError, "no result received - possibly an intersection with another query");
1554
1628
 
@@ -1572,8 +1646,8 @@ pgresult_stream_any(VALUE self, int (*yielder)(VALUE, int, int, void*), void* da
1572
1646
  * wrapping each row into a dedicated result object, it delivers data in nearly
1573
1647
  * the same speed as with ordinary results.
1574
1648
  *
1575
- * The base result must be in status PGRES_SINGLE_TUPLE.
1576
- * It iterates over all tuples until the status changes to PGRES_TUPLES_OK.
1649
+ * The base result must be in status +PGRES_SINGLE_TUPLE+ or +PGRES_TUPLES_CHUNK+.
1650
+ * It iterates over all tuples until the status changes to +PGRES_TUPLES_OK+.
1577
1651
  * A PG::Error is raised for any errors from the server.
1578
1652
  *
1579
1653
  * Row description data does not change while the iteration. All value retrieval
@@ -1638,7 +1712,6 @@ pgresult_stream_each_tuple(VALUE self)
1638
1712
  * It can be set to one of:
1639
1713
  * * +:string+ to use String based field names
1640
1714
  * * +: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
1715
  *
1643
1716
  * The default is retrieved from PG::Connection#field_name_type , which defaults to +:string+ .
1644
1717
  *
@@ -1661,7 +1734,6 @@ pgresult_field_name_type_set(VALUE self, VALUE sym)
1661
1734
 
1662
1735
  this->flags &= ~PG_RESULT_FIELD_NAMES_MASK;
1663
1736
  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
1737
  else if ( sym == sym_string );
1666
1738
  else rb_raise(rb_eArgError, "invalid argument %+"PRIsVALUE, sym);
1667
1739
 
@@ -1682,8 +1754,6 @@ pgresult_field_name_type_get(VALUE self)
1682
1754
  t_pg_result *this = pgresult_get_this(self);
1683
1755
  if( this->flags & PG_RESULT_FIELD_NAMES_SYMBOL ){
1684
1756
  return sym_symbol;
1685
- } else if( this->flags & PG_RESULT_FIELD_NAMES_STATIC_SYMBOL ){
1686
- return sym_static_symbol;
1687
1757
  } else {
1688
1758
  return sym_string;
1689
1759
  }
@@ -1694,7 +1764,6 @@ init_pg_result(void)
1694
1764
  {
1695
1765
  sym_string = ID2SYM(rb_intern("string"));
1696
1766
  sym_symbol = ID2SYM(rb_intern("symbol"));
1697
- sym_static_symbol = ID2SYM(rb_intern("static_symbol"));
1698
1767
 
1699
1768
  rb_cPGresult = rb_define_class_under( rb_mPG, "Result", rb_cObject );
1700
1769
  rb_undef_alloc_func(rb_cPGresult);
@@ -1707,10 +1776,8 @@ init_pg_result(void)
1707
1776
  rb_define_singleton_method(rb_cPGresult, "res_status", pgresult_s_res_status, 1);
1708
1777
  rb_define_method(rb_cPGresult, "error_message", pgresult_error_message, 0);
1709
1778
  rb_define_alias( rb_cPGresult, "result_error_message", "error_message");
1710
- #ifdef HAVE_PQRESULTVERBOSEERRORMESSAGE
1711
1779
  rb_define_method(rb_cPGresult, "verbose_error_message", pgresult_verbose_error_message, 2);
1712
1780
  rb_define_alias( rb_cPGresult, "result_verbose_error_message", "verbose_error_message");
1713
- #endif
1714
1781
  rb_define_method(rb_cPGresult, "error_field", pgresult_error_field, 1);
1715
1782
  rb_define_alias( rb_cPGresult, "result_error_field", "error_field" );
1716
1783
  rb_define_method(rb_cPGresult, "clear", pg_result_clear, 0);
@@ -1745,6 +1812,7 @@ init_pg_result(void)
1745
1812
  rb_define_method(rb_cPGresult, "each", pgresult_each, 0);
1746
1813
  rb_define_method(rb_cPGresult, "fields", pgresult_fields, 0);
1747
1814
  rb_define_method(rb_cPGresult, "each_row", pgresult_each_row, 0);
1815
+ rb_define_method(rb_cPGresult, "each_tuple", pgresult_each_tuple, 0);
1748
1816
  rb_define_method(rb_cPGresult, "values", pgresult_values, 0);
1749
1817
  rb_define_method(rb_cPGresult, "column_values", pgresult_column_values, 1);
1750
1818
  rb_define_method(rb_cPGresult, "field_values", pgresult_field_values, 1);
@@ -579,7 +579,7 @@ pg_text_dec_from_base64(t_pg_coder *conv, const char *val, int len, int tuple, i
579
579
  /* create a buffer of the expected decoded length */
580
580
  VALUE out_value = rb_str_new(NULL, BASE64_DECODED_SIZE(len));
581
581
 
582
- decoded_len = base64_decode( RSTRING_PTR(out_value), val, len );
582
+ decoded_len = rbpg_base64_decode( RSTRING_PTR(out_value), val, len );
583
583
  rb_str_set_len(out_value, decoded_len);
584
584
 
585
585
  /* Is it a pure String conversion? Then we can directly send out_value to the user. */
@@ -942,8 +942,8 @@ static VALUE
942
942
  init_pg_text_decoder_inet(VALUE rb_mPG_TextDecoder)
943
943
  {
944
944
  rb_require("ipaddr");
945
+ rb_gc_register_address(&s_IPAddr);
945
946
  s_IPAddr = rb_funcall(rb_cObject, rb_intern("const_get"), 1, rb_str_new2("IPAddr"));
946
- rb_global_variable(&s_IPAddr);
947
947
  s_ivar_family = rb_intern("@family");
948
948
  s_ivar_addr = rb_intern("@addr");
949
949
  s_ivar_mask_addr = rb_intern("@mask_addr");
@@ -953,10 +953,10 @@ init_pg_text_decoder_inet(VALUE rb_mPG_TextDecoder)
953
953
 
954
954
  use_ipaddr_alloc = RTEST(rb_eval_string("IPAddr.new.instance_variables.sort == [:@addr, :@family, :@mask_addr]"));
955
955
 
956
+ rb_gc_register_address(&s_vmasks4);
957
+ rb_gc_register_address(&s_vmasks6);
956
958
  s_vmasks4 = rb_eval_string("a = [0]*33; a[0] = 0; a[32] = 0xffffffff; 31.downto(1){|i| a[i] = a[i+1] - (1 << (31 - i))}; a.freeze");
957
- rb_global_variable(&s_vmasks4);
958
959
  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");
959
- rb_global_variable(&s_vmasks6);
960
960
 
961
961
  /* dummy = rb_define_class_under( rb_mPG_TextDecoder, "Inet", rb_cPG_SimpleDecoder ); */
962
962
  pg_define_coder( "Inet", pg_text_dec_inet, rb_cPG_SimpleDecoder, rb_mPG_TextDecoder);
@@ -973,12 +973,12 @@ init_pg_text_decoder(void)
973
973
  s_id_utc = rb_intern("utc");
974
974
  s_id_getlocal = rb_intern("getlocal");
975
975
 
976
+ rb_gc_register_address(&s_nan);
977
+ rb_gc_register_address(&s_pos_inf);
978
+ rb_gc_register_address(&s_neg_inf);
976
979
  s_nan = rb_eval_string("0.0/0.0");
977
- rb_global_variable(&s_nan);
978
980
  s_pos_inf = rb_eval_string("1.0/0.0");
979
- rb_global_variable(&s_pos_inf);
980
981
  s_neg_inf = rb_eval_string("-1.0/0.0");
981
- rb_global_variable(&s_neg_inf);
982
982
 
983
983
  /* This module encapsulates all decoder classes with text input format */
984
984
  rb_mPG_TextDecoder = rb_define_module_under( rb_mPG, "TextDecoder" );