pg 1.6.2-aarch64-linux → 1.7.0-aarch64-linux

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 (61) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/CHANGELOG.md +61 -0
  4. data/Gemfile +5 -4
  5. data/README.ja.md +81 -30
  6. data/README.md +20 -10
  7. data/Rakefile +13 -26
  8. data/certs/larskanis-2026.pem +24 -0
  9. data/ext/errorcodes.def +9 -0
  10. data/ext/errorcodes.rb +1 -1
  11. data/ext/errorcodes.txt +8 -1
  12. data/ext/extconf.rb +19 -28
  13. data/ext/gvl_wrappers.c +2 -2
  14. data/ext/gvl_wrappers.h +40 -160
  15. data/ext/pg.c +8 -12
  16. data/ext/pg.h +14 -15
  17. data/ext/pg_binary_decoder.c +6 -2
  18. data/ext/pg_binary_encoder.c +7 -0
  19. data/ext/pg_cancel_connection.c +6 -6
  20. data/ext/pg_coder.c +4 -4
  21. data/ext/pg_connection.c +218 -161
  22. data/ext/pg_copy_coder.c +34 -21
  23. data/ext/pg_record_coder.c +10 -6
  24. data/ext/pg_result.c +131 -61
  25. data/ext/pg_text_decoder.c +6 -6
  26. data/ext/pg_text_encoder.c +7 -2
  27. data/ext/pg_tuple.c +2 -2
  28. data/ext/pg_type_map.c +41 -1
  29. data/ext/pg_type_map_all_strings.c +2 -2
  30. data/ext/pg_type_map_by_class.c +1 -1
  31. data/ext/pg_type_map_by_column.c +2 -2
  32. data/ext/pg_type_map_by_oid.c +1 -1
  33. data/ext/pg_type_map_in_ruby.c +1 -1
  34. data/lib/3.1/pg_ext.so +0 -0
  35. data/lib/3.2/pg_ext.so +0 -0
  36. data/lib/3.3/pg_ext.so +0 -0
  37. data/lib/3.4/pg_ext.so +0 -0
  38. data/lib/4.0/pg_ext.so +0 -0
  39. data/lib/pg/basic_type_map_based_on_result.rb +5 -0
  40. data/lib/pg/basic_type_map_for_queries.rb +9 -2
  41. data/lib/pg/basic_type_map_for_results.rb +5 -0
  42. data/lib/pg/connection.rb +166 -76
  43. data/lib/pg/text_decoder/date.rb +1 -1
  44. data/lib/pg/text_decoder/json.rb +1 -1
  45. data/lib/pg/text_encoder/date.rb +7 -1
  46. data/lib/pg/text_encoder/json.rb +1 -1
  47. data/lib/pg/version.rb +1 -1
  48. data/misc/yugabyte/docker-compose.yml +1 -1
  49. data/pg.gemspec +1 -1
  50. data/ports/aarch64-linux/lib/libpq-ruby-pg.so.1 +0 -0
  51. data/sample/async_mixed.rb +1 -1
  52. data.tar.gz.sig +0 -0
  53. metadata +21 -23
  54. metadata.gz.sig +0 -0
  55. data/lib/2.7/pg_ext.so +0 -0
  56. data/lib/3.0/pg_ext.so +0 -0
  57. data/ports/patches/openssl/3.5.2/0001-aarch64-mingw.patch +0 -21
  58. data/ports/patches/postgresql/17.6/0001-libpq-Process-buffered-SSL-read-bytes-to-support-rec.patch +0 -52
  59. /data/ports/patches/krb5/{1.22.1 → 1.22.2}/0001-Allow-static-linking-krb5-library.patch +0 -0
  60. /data/ports/patches/krb5/{1.22.1 → 1.22.2}/0002-unknown-command-line-option-on-clang.patch +0 -0
  61. /data/ports/patches/postgresql/{17.6 → 18.6}/0001-Use-workaround-of-__builtin_setjmp-only-on-MINGW-on-.patch +0 -0
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++ ){
@@ -181,7 +180,7 @@ static const rb_data_type_t pgresult_type = {
181
180
  pgresult_gc_compact,
182
181
  },
183
182
  0, 0,
184
- 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,
185
184
  };
186
185
 
187
186
  /* Needed by sequel_pg gem, do not delete */
@@ -212,7 +211,6 @@ pg_new_result2(PGresult *result, VALUE rb_pgconn)
212
211
  this->typemap = pg_typemap_all_strings;
213
212
  this->p_typemap = RTYPEDDATA_DATA( this->typemap );
214
213
  this->nfields = -1;
215
- this->tuple_hash = Qnil;
216
214
  this->field_map = Qnil;
217
215
  this->flags = 0;
218
216
  self = TypedData_Wrap_Struct(rb_cPGresult, &pgresult_type, this);
@@ -317,17 +315,17 @@ pg_result_check( VALUE self )
317
315
  case PGRES_SINGLE_TUPLE:
318
316
  case PGRES_EMPTY_QUERY:
319
317
  case PGRES_COMMAND_OK:
320
- #ifdef HAVE_PQENTERPIPELINEMODE
318
+ #ifdef LIBPQ_HAS_PIPELINING
321
319
  case PGRES_PIPELINE_SYNC:
322
320
  #endif
323
- #ifdef HAVE_PQSETCHUNKEDROWSMODE
321
+ #ifdef LIBPQ_HAS_CHUNK_MODE
324
322
  case PGRES_TUPLES_CHUNK:
325
323
  #endif
326
324
  return self;
327
325
  case PGRES_BAD_RESPONSE:
328
326
  case PGRES_FATAL_ERROR:
329
327
  case PGRES_NONFATAL_ERROR:
330
- #ifdef HAVE_PQENTERPIPELINEMODE
328
+ #ifdef LIBPQ_HAS_PIPELINING
331
329
  case PGRES_PIPELINE_ABORTED:
332
330
  #endif
333
331
  error = rb_str_new2( PQresultErrorMessage(this->pgresult) );
@@ -396,6 +394,7 @@ pg_result_freeze(VALUE self)
396
394
  {
397
395
  t_pg_result *this = pgresult_get_this(self);
398
396
 
397
+ ensure_init_for_tuple(self);
399
398
  RB_OBJ_WRITE(self, &this->connection, Qnil);
400
399
  return rb_call_super(0, NULL);
401
400
  }
@@ -466,9 +465,6 @@ pgresult_get(VALUE self)
466
465
  static VALUE pg_cstr_to_sym(char *cstr, unsigned int flags, int enc_idx)
467
466
  {
468
467
  VALUE fname;
469
- #ifdef TRUFFLERUBY
470
- if( flags & (PG_RESULT_FIELD_NAMES_SYMBOL | PG_RESULT_FIELD_NAMES_STATIC_SYMBOL) ){
471
- #else
472
468
  if( flags & PG_RESULT_FIELD_NAMES_SYMBOL ){
473
469
  rb_encoding *enc = rb_enc_from_index(enc_idx);
474
470
  fname = rb_check_symbol_cstr(cstr, strlen(cstr), enc);
@@ -477,14 +473,9 @@ static VALUE pg_cstr_to_sym(char *cstr, unsigned int flags, int enc_idx)
477
473
  PG_ENCODING_SET_NOCHECK(fname, enc_idx);
478
474
  fname = rb_str_intern(fname);
479
475
  }
480
- } else if( flags & PG_RESULT_FIELD_NAMES_STATIC_SYMBOL ){
481
- #endif
482
- rb_encoding *enc = rb_enc_from_index(enc_idx);
483
- fname = ID2SYM(rb_intern3(cstr, strlen(cstr), enc));
484
476
  } else {
485
- fname = rb_str_new2(cstr);
486
- PG_ENCODING_SET_NOCHECK(fname, enc_idx);
487
- 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);
488
479
  }
489
480
  return fname;
490
481
  }
@@ -513,20 +504,48 @@ static void pgresult_init_fnames(VALUE self)
513
504
  *
514
505
  * The class to represent the query result tuples (rows).
515
506
  * An instance of this class is created as the result of every query.
516
- * All result rows and columns are stored in a memory block attached to the PG::Result object.
517
- * Whenever a value is accessed it is casted to a Ruby object by the assigned #type_map .
507
+ * All result rows and columns are stored in an immutable memory block attached to the PG::Result object unless streaming is used.
518
508
  *
519
- * Since pg-1.1 the amount of memory in use by a PG::Result object is estimated and passed to ruby's garbage collector.
520
- * You can invoke the #clear method to force deallocation of memory of the instance when finished with the result for better memory performance.
521
- *
522
- * Example:
509
+ * A PG::Result has various ways to retrieve the result data:
523
510
  * require 'pg'
524
- * conn = PG.connect(:dbname => 'test')
525
- * res = conn.exec('SELECT 1 AS a, 2 AS b, NULL AS c')
526
- * res.getvalue(0,0) # '1'
527
- * res[0]['b'] # '2'
528
- * 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>
529
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.
530
549
  */
531
550
 
532
551
  /**************************************************************************
@@ -552,7 +571,7 @@ static void pgresult_init_fnames(VALUE self)
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
@@ -705,6 +724,10 @@ pgresult_error_field(VALUE self, VALUE field)
705
724
  * res.ntuples() -> Integer
706
725
  *
707
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
708
731
  */
709
732
  static VALUE
710
733
  pgresult_ntuples(VALUE self)
@@ -723,6 +746,9 @@ pgresult_ntuples_for_enum(VALUE self, VALUE args, VALUE eobj)
723
746
  * res.nfields() -> Integer
724
747
  *
725
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
726
752
  */
727
753
  static VALUE
728
754
  pgresult_nfields(VALUE self)
@@ -752,6 +778,8 @@ pgresult_binary_tuples(VALUE self)
752
778
  * Returns the name of the column corresponding to _index_.
753
779
  * Depending on #field_name_type= it's a String or Symbol.
754
780
  *
781
+ * res = conn.exec('SELECT 1 AS a, 2 AS b, NULL AS c')
782
+ * res.fname(2) # "c"
755
783
  */
756
784
  static VALUE
757
785
  pgresult_fname(VALUE self, VALUE index)
@@ -1122,6 +1150,9 @@ pgresult_oid_value(VALUE self)
1122
1150
  * res[ n ] -> Hash
1123
1151
  *
1124
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"}
1125
1156
  */
1126
1157
  static VALUE
1127
1158
  pgresult_aref(VALUE self, VALUE index)
@@ -1138,16 +1169,11 @@ pgresult_aref(VALUE self, VALUE index)
1138
1169
  if ( tuple_num < 0 || tuple_num >= num_tuples )
1139
1170
  rb_raise( rb_eIndexError, "Index %d is out of range", tuple_num );
1140
1171
 
1141
- /* We reuse the Hash of the previous output for larger row counts.
1142
- * This is somewhat faster than populating an empty Hash object. */
1143
- tuple = NIL_P(this->tuple_hash) ? rb_hash_new() : this->tuple_hash;
1172
+ tuple = rb_hash_new_capa(this->nfields);
1144
1173
  for ( field_num = 0; field_num < this->nfields; field_num++ ) {
1145
1174
  VALUE val = this->p_typemap->funcs.typecast_result_value(this->p_typemap, self, tuple_num, field_num);
1146
1175
  rb_hash_aset( tuple, this->fnames[field_num], val );
1147
1176
  }
1148
- /* Store a copy of the filled hash for use at the next row. */
1149
- if( num_tuples > 10 )
1150
- RB_OBJ_WRITE(self, &this->tuple_hash, rb_hash_dup(tuple));
1151
1177
 
1152
1178
  return tuple;
1153
1179
  }
@@ -1156,7 +1182,10 @@ pgresult_aref(VALUE self, VALUE index)
1156
1182
  * call-seq:
1157
1183
  * res.each_row { |row| ... }
1158
1184
  *
1159
- * 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]
1160
1189
  */
1161
1190
  static VALUE
1162
1191
  pgresult_each_row(VALUE self)
@@ -1191,6 +1220,9 @@ pgresult_each_row(VALUE self)
1191
1220
  * res.values -> Array
1192
1221
  *
1193
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]]
1194
1226
  */
1195
1227
  static VALUE
1196
1228
  pgresult_values(VALUE self)
@@ -1240,12 +1272,13 @@ make_column_result_array( VALUE self, int col )
1240
1272
 
1241
1273
 
1242
1274
  /*
1243
- * call-seq:
1244
- * res.column_values( n ) -> array
1275
+ * call-seq:
1276
+ * res.column_values( n ) -> array
1245
1277
  *
1246
- * Returns an Array of the values from the nth column of each
1247
- * tuple in the result.
1278
+ * Returns an Array of the values from the nth column of each tuple in the result.
1248
1279
  *
1280
+ * res = conn.exec('SELECT 1 AS a, 2 AS b, NULL AS c')
1281
+ * res.column_values(1) # ["2"]
1249
1282
  */
1250
1283
  static VALUE
1251
1284
  pgresult_column_values(VALUE self, VALUE index)
@@ -1256,11 +1289,13 @@ pgresult_column_values(VALUE self, VALUE index)
1256
1289
 
1257
1290
 
1258
1291
  /*
1259
- * call-seq:
1292
+ * call-seq:
1260
1293
  * res.field_values( field ) -> array
1261
1294
  *
1262
- * 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.
1263
1296
  *
1297
+ * res = conn.exec('SELECT 1 AS a, 2 AS b, NULL AS c')
1298
+ * res.field_values(:a) # ["1"]
1264
1299
  */
1265
1300
  static VALUE
1266
1301
  pgresult_field_values( VALUE self, VALUE field )
@@ -1281,11 +1316,13 @@ pgresult_field_values( VALUE self, VALUE field )
1281
1316
 
1282
1317
 
1283
1318
  /*
1284
- * call-seq:
1285
- * res.tuple_values( n ) -> array
1319
+ * call-seq:
1320
+ * res.tuple_values( n ) -> array
1286
1321
  *
1287
- * 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.
1288
1323
  *
1324
+ * res = conn.exec('SELECT 1 AS a, 2 AS b, NULL AS c')
1325
+ * res.tuple_values(0) # ["1", "2", nil]
1289
1326
  */
1290
1327
  static VALUE
1291
1328
  pgresult_tuple_values(VALUE self, VALUE index)
@@ -1320,11 +1357,12 @@ static void ensure_init_for_tuple(VALUE self)
1320
1357
 
1321
1358
  if( this->field_map == Qnil ){
1322
1359
  int i;
1323
- VALUE field_map = rb_hash_new();
1360
+ VALUE field_map;
1324
1361
 
1325
1362
  if( this->nfields == -1 )
1326
1363
  pgresult_init_fnames( self );
1327
1364
 
1365
+ field_map = rb_hash_new_capa(this->nfields);
1328
1366
  for( i = 0; i < this->nfields; i++ ){
1329
1367
  rb_hash_aset(field_map, this->fnames[i], INT2FIX(i));
1330
1368
  }
@@ -1334,11 +1372,13 @@ static void ensure_init_for_tuple(VALUE self)
1334
1372
  }
1335
1373
 
1336
1374
  /*
1337
- * call-seq:
1338
- * res.tuple( n ) -> PG::Tuple
1375
+ * call-seq:
1376
+ * res.tuple( n ) -> PG::Tuple
1339
1377
  *
1340
- * Returns a PG::Tuple from the nth row of the result.
1378
+ * Returns a PG::Tuple from the nth row of the result.
1341
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>
1342
1382
  */
1343
1383
  static VALUE
1344
1384
  pgresult_tuple(VALUE self, VALUE index)
@@ -1363,7 +1403,10 @@ pgresult_tuple(VALUE self, VALUE index)
1363
1403
  * call-seq:
1364
1404
  * res.each{ |tuple| ... }
1365
1405
  *
1366
- * 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}
1367
1410
  */
1368
1411
  static VALUE
1369
1412
  pgresult_each(VALUE self)
@@ -1381,11 +1424,40 @@ pgresult_each(VALUE self)
1381
1424
  return self;
1382
1425
  }
1383
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
+
1384
1453
  /*
1385
1454
  * call-seq:
1386
1455
  * res.fields() -> Array
1387
1456
  *
1388
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"]
1389
1461
  */
1390
1462
  static VALUE
1391
1463
  pgresult_fields(VALUE self)
@@ -1410,6 +1482,7 @@ pgresult_fields(VALUE self)
1410
1482
  *
1411
1483
  * +typemap+ must be a kind of PG::TypeMap .
1412
1484
  *
1485
+ * See also #map_types! and PG::BasicTypeMapForResults
1413
1486
  */
1414
1487
  static VALUE
1415
1488
  pgresult_type_map_set(VALUE self, VALUE typemap)
@@ -1433,6 +1506,7 @@ pgresult_type_map_set(VALUE self, VALUE typemap)
1433
1506
  * res.type_map -> value
1434
1507
  *
1435
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 .
1436
1510
  *
1437
1511
  */
1438
1512
  static VALUE
@@ -1525,7 +1599,7 @@ pgresult_stream_any(VALUE self, int (*yielder)(VALUE, int, int, void*), void* da
1525
1599
  return self;
1526
1600
  rb_raise( rb_eInvalidResultStatus, "PG::Result is not in single row mode");
1527
1601
  case PGRES_SINGLE_TUPLE:
1528
- #ifdef HAVE_PQSETCHUNKEDROWSMODE
1602
+ #ifdef LIBPQ_HAS_CHUNK_MODE
1529
1603
  case PGRES_TUPLES_CHUNK:
1530
1604
  #endif
1531
1605
  break;
@@ -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
 
@@ -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);
@@ -1743,6 +1812,7 @@ init_pg_result(void)
1743
1812
  rb_define_method(rb_cPGresult, "each", pgresult_each, 0);
1744
1813
  rb_define_method(rb_cPGresult, "fields", pgresult_fields, 0);
1745
1814
  rb_define_method(rb_cPGresult, "each_row", pgresult_each_row, 0);
1815
+ rb_define_method(rb_cPGresult, "each_tuple", pgresult_each_tuple, 0);
1746
1816
  rb_define_method(rb_cPGresult, "values", pgresult_values, 0);
1747
1817
  rb_define_method(rb_cPGresult, "column_values", pgresult_column_values, 1);
1748
1818
  rb_define_method(rb_cPGresult, "field_values", pgresult_field_values, 1);
@@ -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" );
@@ -381,8 +381,8 @@ pg_text_enc_numeric(t_pg_coder *this, VALUE value, char *out, VALUE *intermediat
381
381
  static VALUE
382
382
  init_pg_text_encoder_numeric(VALUE rb_mPG_TextDecoder)
383
383
  {
384
+ rb_gc_register_address(&s_str_F);
384
385
  s_str_F = rb_str_freeze(rb_str_new_cstr("F"));
385
- rb_global_variable(&s_str_F);
386
386
  rb_funcall(rb_mPG, rb_intern("require_bigdecimal_without_warning"), 0);
387
387
  s_cBigDecimal = rb_const_get(rb_cObject, rb_intern("BigDecimal"));
388
388
 
@@ -430,9 +430,14 @@ pg_text_enc_bytea(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate,
430
430
  }
431
431
  return (int)(optr - out);
432
432
  }else{
433
+ long size;
433
434
  *intermediate = rb_obj_as_string(value);
435
+ size = RSTRING_LEN(*intermediate);
436
+
434
437
  /* The output starts with "\x" and each character is converted to hex. */
435
- return 2 + RSTRING_LENINT(*intermediate) * 2;
438
+ if( size > INT_MAX / 2 - 2 )
439
+ rb_raise( rb_eArgError, "too large input string for PG::TextEncoder::Bytea: %ld", size );
440
+ return (int)(2 + size * 2);
436
441
  }
437
442
  }
438
443
 
data/ext/pg_tuple.c CHANGED
@@ -128,7 +128,7 @@ static const rb_data_type_t pg_tuple_type = {
128
128
  pg_tuple_gc_compact,
129
129
  },
130
130
  0, 0,
131
- RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | PG_RUBY_TYPED_FROZEN_SHAREABLE,
131
+ RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FROZEN_SHAREABLE,
132
132
  };
133
133
 
134
134
  /*
@@ -510,7 +510,7 @@ pg_tuple_load(VALUE self, VALUE a)
510
510
  if (RARRAY_LENINT(field_names) != num_fields)
511
511
  rb_raise(rb_eTypeError, "different number of fields and values");
512
512
 
513
- field_map = rb_hash_new();
513
+ field_map = rb_hash_new_capa(num_fields);
514
514
  for( i = 0; i < num_fields; i++ ){
515
515
  rb_hash_aset(field_map, RARRAY_AREF(field_names, i), INT2FIX(i));
516
516
  }
data/ext/pg_type_map.c CHANGED
@@ -37,7 +37,7 @@ const rb_data_type_t pg_typemap_type = {
37
37
  },
38
38
  0,
39
39
  0,
40
- RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | PG_RUBY_TYPED_FROZEN_SHAREABLE,
40
+ RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FROZEN_SHAREABLE,
41
41
  };
42
42
 
43
43
  VALUE rb_cTypeMap;
@@ -115,6 +115,45 @@ pg_typemap_s_allocate( VALUE klass )
115
115
  return self;
116
116
  }
117
117
 
118
+ /*
119
+ * call-seq:
120
+ * res.query_param_encoders(params)
121
+ *
122
+ * Retrieve the encoders that are used to encode the given values to be submitted to the database server.
123
+ * The selection of the encoders is defined in the derived type map class.
124
+ *
125
+ * +params+ must be an Array of values to be encoded.
126
+ * It's like +params+ given to exec_params .
127
+ *
128
+ * Returns an Array with the same length as +params+.
129
+ *
130
+ */
131
+ static VALUE
132
+ pg_typemap_query_param_encoders( VALUE self, VALUE params )
133
+ {
134
+ t_typemap *this = RTYPEDDATA_DATA( self );
135
+ int nParams;
136
+ int i=0;
137
+ VALUE res;
138
+
139
+ Check_Type(params, T_ARRAY);
140
+
141
+ this->funcs.fit_to_query( self, params );
142
+
143
+ nParams = RARRAY_LENINT(params);
144
+ res = rb_ary_new2(nParams);
145
+
146
+ for ( i = 0; i < nParams; i++ ) {
147
+ t_pg_coder *conv;
148
+ VALUE param_value = rb_ary_entry(params, i);
149
+
150
+ /* Let the given typemap select a coder for this param */
151
+ conv = this->funcs.typecast_query_param(this, param_value, i);
152
+ rb_ary_push(res, conv ? conv->coder_obj : Qnil);
153
+ }
154
+ return res;
155
+ }
156
+
118
157
  /*
119
158
  * call-seq:
120
159
  * res.default_type_map = typemap
@@ -194,6 +233,7 @@ init_pg_type_map(void)
194
233
  */
195
234
  rb_cTypeMap = rb_define_class_under( rb_mPG, "TypeMap", rb_cObject );
196
235
  rb_define_alloc_func( rb_cTypeMap, pg_typemap_s_allocate );
236
+ rb_define_method( rb_cTypeMap, "query_param_encoders", pg_typemap_query_param_encoders, 1 );
197
237
 
198
238
  rb_mDefaultTypeMappable = rb_define_module_under( rb_cTypeMap, "DefaultTypeMappable");
199
239
  rb_define_method( rb_mDefaultTypeMappable, "default_type_map=", pg_typemap_default_type_map_set, 1 );
@@ -18,7 +18,7 @@ static const rb_data_type_t pg_tmas_type = {
18
18
  },
19
19
  &pg_typemap_type,
20
20
  0,
21
- RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | PG_RUBY_TYPED_FROZEN_SHAREABLE,
21
+ RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FROZEN_SHAREABLE,
22
22
  };
23
23
 
24
24
  VALUE rb_cTypeMapAllStrings;
@@ -125,6 +125,6 @@ init_pg_type_map_all_strings(void)
125
125
  rb_cTypeMapAllStrings = rb_define_class_under( rb_mPG, "TypeMapAllStrings", rb_cTypeMap );
126
126
  rb_define_alloc_func( rb_cTypeMapAllStrings, pg_tmas_s_allocate );
127
127
 
128
- pg_typemap_all_strings = rb_obj_freeze( rb_funcall( rb_cTypeMapAllStrings, rb_intern("new"), 0 ));
129
128
  rb_gc_register_address( &pg_typemap_all_strings );
129
+ pg_typemap_all_strings = rb_obj_freeze( rb_funcall( rb_cTypeMapAllStrings, rb_intern("new"), 0 ));
130
130
  }
@@ -157,7 +157,7 @@ static const rb_data_type_t pg_tmbk_type = {
157
157
  },
158
158
  &pg_typemap_type,
159
159
  0,
160
- RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | PG_RUBY_TYPED_FROZEN_SHAREABLE,
160
+ RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FROZEN_SHAREABLE,
161
161
  };
162
162
 
163
163
  static VALUE
@@ -55,7 +55,7 @@ pg_tmbc_fit_to_query( VALUE self, VALUE params )
55
55
  t_typemap *default_tm;
56
56
 
57
57
  Check_Type(params, T_ARRAY);
58
- nfields = (int)RARRAY_LEN( params );
58
+ nfields = RARRAY_LENINT( params );
59
59
  if ( this->nfields != nfields ) {
60
60
  rb_raise( rb_eArgError, "number of result fields (%d) does not match number of mapped columns (%d)",
61
61
  nfields, this->nfields );
@@ -233,7 +233,7 @@ static const rb_data_type_t pg_tmbc_type = {
233
233
  },
234
234
  &pg_typemap_type,
235
235
  0,
236
- RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | PG_RUBY_TYPED_FROZEN_SHAREABLE,
236
+ RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FROZEN_SHAREABLE,
237
237
  };
238
238
 
239
239
  static VALUE
@@ -194,7 +194,7 @@ static const rb_data_type_t pg_tmbo_type = {
194
194
  },
195
195
  &pg_typemap_type,
196
196
  0,
197
- RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | PG_RUBY_TYPED_FROZEN_SHAREABLE,
197
+ RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FROZEN_SHAREABLE,
198
198
  };
199
199
 
200
200
  static VALUE
@@ -44,7 +44,7 @@ static const rb_data_type_t pg_tmir_type = {
44
44
  },
45
45
  &pg_typemap_type,
46
46
  0,
47
- RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | PG_RUBY_TYPED_FROZEN_SHAREABLE,
47
+ RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FROZEN_SHAREABLE,
48
48
  };
49
49
 
50
50
  /*