pg 1.6.3 → 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 (50) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/CHANGELOG.md +52 -6
  4. data/Gemfile +1 -0
  5. data/README.ja.md +81 -30
  6. data/README.md +14 -7
  7. data/Rakefile +8 -7
  8. data/certs/larskanis-2026.pem +24 -0
  9. data/ext/extconf.rb +18 -28
  10. data/ext/gvl_wrappers.c +2 -2
  11. data/ext/gvl_wrappers.h +40 -160
  12. data/ext/pg.c +8 -12
  13. data/ext/pg.h +8 -11
  14. data/ext/pg_binary_decoder.c +6 -2
  15. data/ext/pg_binary_encoder.c +7 -0
  16. data/ext/pg_cancel_connection.c +6 -6
  17. data/ext/pg_coder.c +4 -4
  18. data/ext/pg_connection.c +196 -159
  19. data/ext/pg_copy_coder.c +34 -21
  20. data/ext/pg_record_coder.c +10 -6
  21. data/ext/pg_result.c +42 -26
  22. data/ext/pg_text_decoder.c +6 -6
  23. data/ext/pg_text_encoder.c +7 -2
  24. data/ext/pg_tuple.c +1 -1
  25. data/ext/pg_type_map.c +41 -1
  26. data/ext/pg_type_map_all_strings.c +2 -2
  27. data/ext/pg_type_map_by_class.c +1 -1
  28. data/ext/pg_type_map_by_column.c +2 -2
  29. data/ext/pg_type_map_by_oid.c +1 -1
  30. data/ext/pg_type_map_in_ruby.c +1 -1
  31. data/lib/pg/basic_type_map_based_on_result.rb +5 -0
  32. data/lib/pg/basic_type_map_for_queries.rb +9 -2
  33. data/lib/pg/basic_type_map_for_results.rb +5 -0
  34. data/lib/pg/connection.rb +166 -76
  35. data/lib/pg/text_decoder/date.rb +1 -1
  36. data/lib/pg/text_decoder/json.rb +1 -1
  37. data/lib/pg/text_encoder/date.rb +7 -1
  38. data/lib/pg/text_encoder/json.rb +1 -1
  39. data/lib/pg/version.rb +1 -1
  40. data/misc/yugabyte/docker-compose.yml +1 -1
  41. data/pg.gemspec +1 -1
  42. data/sample/async_mixed.rb +1 -1
  43. data.tar.gz.sig +0 -0
  44. metadata +18 -19
  45. metadata.gz.sig +0 -0
  46. data/ports/patches/openssl/3.5.2/0001-aarch64-mingw.patch +0 -21
  47. data/ports/patches/postgresql/18.1/0001-libpq-Process-buffered-SSL-read-bytes-to-support-rec.patch +0 -52
  48. /data/ports/patches/krb5/{1.22.1 → 1.22.2}/0001-Allow-static-linking-krb5-library.patch +0 -0
  49. /data/ports/patches/krb5/{1.22.1 → 1.22.2}/0002-unknown-command-line-option-on-clang.patch +0 -0
  50. /data/ports/patches/postgresql/{18.1 → 18.6}/0001-Use-workaround-of-__builtin_setjmp-only-on-MINGW-on-.patch +0 -0
data/ext/pg_copy_coder.c CHANGED
@@ -55,7 +55,7 @@ static const rb_data_type_t pg_copycoder_type = {
55
55
  },
56
56
  &pg_coder_type,
57
57
  0,
58
- RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | PG_RUBY_TYPED_FROZEN_SHAREABLE,
58
+ RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FROZEN_SHAREABLE,
59
59
  };
60
60
 
61
61
  static VALUE
@@ -219,20 +219,21 @@ pg_text_enc_copy_row(t_pg_coder *conv, VALUE value, char *out, VALUE *intermedia
219
219
  {
220
220
  t_pg_copycoder *this = (t_pg_copycoder *)conv;
221
221
  t_pg_coder_enc_func enc_func;
222
- static t_pg_coder *p_elem_coder;
222
+ t_pg_coder *p_elem_coder;
223
223
  int i;
224
+ VALUE rb_typemap = this->typemap;
224
225
  t_typemap *p_typemap;
225
226
  char *current_out;
226
227
  char *end_capa_ptr;
227
228
 
228
- p_typemap = RTYPEDDATA_DATA( this->typemap );
229
- p_typemap->funcs.fit_to_query( this->typemap, value );
229
+ p_typemap = RTYPEDDATA_DATA( rb_typemap );
230
+ p_typemap->funcs.fit_to_query( rb_typemap, value );
230
231
 
231
232
  /* Allocate a new string with embedded capacity and realloc exponential when needed. */
232
233
  PG_RB_STR_NEW( *intermediate, current_out, end_capa_ptr );
233
234
  PG_ENCODING_SET_NOCHECK(*intermediate, enc_idx);
234
235
 
235
- for( i=0; i<RARRAY_LEN(value); i++){
236
+ for( i=0; i<RARRAY_LENINT(value); i++){
236
237
  char *ptr1;
237
238
  char *ptr2;
238
239
  int strlen;
@@ -265,7 +266,7 @@ pg_text_enc_copy_row(t_pg_coder *conv, VALUE value, char *out, VALUE *intermedia
265
266
  strlen = RSTRING_LENINT(subint);
266
267
 
267
268
  /* size of string assuming the worst case, that every character must be escaped. */
268
- PG_RB_STR_ENSURE_CAPA( *intermediate, strlen * 2, current_out, end_capa_ptr );
269
+ PG_RB_STR_ENSURE_CAPA( *intermediate, (size_t)strlen * 2, current_out, end_capa_ptr );
269
270
 
270
271
  /* Copy string from subint with backslash escaping */
271
272
  for(ptr1 = RSTRING_PTR(subint); ptr1 < RSTRING_PTR(subint) + strlen; ptr1++) {
@@ -278,7 +279,7 @@ pg_text_enc_copy_row(t_pg_coder *conv, VALUE value, char *out, VALUE *intermedia
278
279
  } else {
279
280
  /* 2nd pass for writing the data to prepared buffer */
280
281
  /* size of string assuming the worst case, that every character must be escaped. */
281
- PG_RB_STR_ENSURE_CAPA( *intermediate, strlen * 2, current_out, end_capa_ptr );
282
+ PG_RB_STR_ENSURE_CAPA( *intermediate, (size_t)strlen * 2, current_out, end_capa_ptr );
282
283
 
283
284
  /* Place the unescaped string at current output position. */
284
285
  strlen = enc_func(p_elem_coder, entry, current_out, &subint, enc_idx);
@@ -314,6 +315,7 @@ pg_text_enc_copy_row(t_pg_coder *conv, VALUE value, char *out, VALUE *intermedia
314
315
 
315
316
  rb_str_set_len( *intermediate, current_out - RSTRING_PTR(*intermediate) );
316
317
 
318
+ RB_GC_GUARD(rb_typemap);
317
319
  return -1;
318
320
  }
319
321
 
@@ -366,12 +368,17 @@ pg_bin_enc_copy_row(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediat
366
368
  {
367
369
  t_pg_copycoder *this = (t_pg_copycoder *)conv;
368
370
  int i;
371
+ VALUE rb_typemap = this->typemap;
369
372
  t_typemap *p_typemap;
370
373
  char *current_out;
371
374
  char *end_capa_ptr;
372
375
 
373
- p_typemap = RTYPEDDATA_DATA( this->typemap );
374
- p_typemap->funcs.fit_to_query( this->typemap, value );
376
+ if( RARRAY_LEN(value) >= 32768 ){
377
+ rb_raise( rb_eArgError, "too many columns in array for PG::BinaryEncoder::CopyRow: %ld", RARRAY_LEN(value) );
378
+ }
379
+
380
+ p_typemap = RTYPEDDATA_DATA( rb_typemap );
381
+ p_typemap->funcs.fit_to_query( rb_typemap, value );
375
382
 
376
383
  /* Allocate a new string with embedded capacity and realloc exponential when needed. */
377
384
  PG_RB_STR_NEW( *intermediate, current_out, end_capa_ptr );
@@ -382,12 +389,12 @@ pg_bin_enc_copy_row(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediat
382
389
  write_nbo16(RARRAY_LEN(value), current_out);
383
390
  current_out += 2;
384
391
 
385
- for( i=0; i<RARRAY_LEN(value); i++){
392
+ for( i=0; i<RARRAY_LENINT(value); i++){
386
393
  int strlen;
387
394
  VALUE subint;
388
395
  VALUE entry;
389
396
  t_pg_coder_enc_func enc_func;
390
- static t_pg_coder *p_elem_coder;
397
+ t_pg_coder *p_elem_coder;
391
398
 
392
399
  entry = rb_ary_entry(value, i);
393
400
 
@@ -409,7 +416,7 @@ pg_bin_enc_copy_row(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediat
409
416
  /* we can directly use String value in subint */
410
417
  strlen = RSTRING_LENINT(subint);
411
418
 
412
- PG_RB_STR_ENSURE_CAPA( *intermediate, 4 + strlen, current_out, end_capa_ptr );
419
+ PG_RB_STR_ENSURE_CAPA( *intermediate, (size_t)4 + strlen, current_out, end_capa_ptr );
413
420
  /* 4 bytes length */
414
421
  write_nbo32(strlen, current_out);
415
422
  current_out += 4;
@@ -418,7 +425,7 @@ pg_bin_enc_copy_row(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediat
418
425
  current_out += strlen;
419
426
  } else {
420
427
  /* 2nd pass for writing the data to prepared buffer */
421
- PG_RB_STR_ENSURE_CAPA( *intermediate, 4 + strlen, current_out, end_capa_ptr );
428
+ PG_RB_STR_ENSURE_CAPA( *intermediate, (size_t)4 + strlen, current_out, end_capa_ptr );
422
429
  /* 4 bytes length */
423
430
  write_nbo32(strlen, current_out);
424
431
  current_out += 4;
@@ -432,6 +439,7 @@ pg_bin_enc_copy_row(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediat
432
439
 
433
440
  rb_str_set_len( *intermediate, current_out - RSTRING_PTR(*intermediate) );
434
441
 
442
+ RB_GC_GUARD(rb_typemap);
435
443
  return -1;
436
444
  }
437
445
 
@@ -530,10 +538,11 @@ pg_text_dec_copy_row(t_pg_coder *conv, const char *input_line, int len, int _tup
530
538
  const char *cur_ptr;
531
539
  const char *line_end_ptr;
532
540
  char *end_capa_ptr;
541
+ VALUE rb_typemap = this->typemap;
533
542
  t_typemap *p_typemap;
534
543
 
535
- p_typemap = RTYPEDDATA_DATA( this->typemap );
536
- expected_fields = p_typemap->funcs.fit_to_copy_get( this->typemap );
544
+ p_typemap = RTYPEDDATA_DATA( rb_typemap );
545
+ expected_fields = p_typemap->funcs.fit_to_copy_get( rb_typemap );
537
546
 
538
547
  /* The received input string will probably have this->nfields fields. */
539
548
  array = rb_ary_new2(expected_fields);
@@ -553,7 +562,7 @@ pg_text_dec_copy_row(t_pg_coder *conv, const char *input_line, int len, int _tup
553
562
  int found_delim = 0;
554
563
  const char *start_ptr;
555
564
  const char *end_ptr;
556
- long input_len;
565
+ size_t input_len;
557
566
 
558
567
  /* Remember start of field on input side */
559
568
  start_ptr = cur_ptr;
@@ -688,7 +697,7 @@ pg_text_dec_copy_row(t_pg_coder *conv, const char *input_line, int len, int _tup
688
697
 
689
698
  /* Check whether raw input matched null marker */
690
699
  input_len = end_ptr - start_ptr;
691
- if (input_len == RSTRING_LEN(this->null_string) &&
700
+ if (input_len == (size_t)RSTRING_LEN(this->null_string) &&
692
701
  strncmp(start_ptr, RSTRING_PTR(this->null_string), input_len) == 0) {
693
702
  rb_ary_push(array, Qnil);
694
703
  } else {
@@ -714,11 +723,13 @@ pg_text_dec_copy_row(t_pg_coder *conv, const char *input_line, int len, int _tup
714
723
  break;
715
724
  }
716
725
 
726
+ RB_GC_GUARD(rb_typemap);
727
+
717
728
  return array;
718
729
  }
719
730
 
720
731
 
721
- static const char BinarySignature[11] = "PGCOPY\n\377\r\n\0";
732
+ static const char BinarySignature[11] = {'P','G','C','O','P','Y','\n','\377','\r','\n','\0'};
722
733
 
723
734
  /*
724
735
  * Document-class: PG::BinaryDecoder::CopyRow < PG::CopyDecoder
@@ -786,10 +797,11 @@ pg_bin_dec_copy_row(t_pg_coder *conv, const char *input_line, int len, int _tupl
786
797
  const char *cur_ptr;
787
798
  const char *line_end_ptr;
788
799
  char *end_capa_ptr;
800
+ VALUE rb_typemap = this->typemap;
789
801
  t_typemap *p_typemap;
790
802
 
791
- p_typemap = RTYPEDDATA_DATA( this->typemap );
792
- expected_fields = p_typemap->funcs.fit_to_copy_get( this->typemap );
803
+ p_typemap = RTYPEDDATA_DATA( rb_typemap );
804
+ expected_fields = p_typemap->funcs.fit_to_copy_get( rb_typemap );
793
805
 
794
806
  /* Allocate a new string with embedded capacity and realloc later with
795
807
  * exponential growing size when needed. */
@@ -830,7 +842,7 @@ pg_bin_dec_copy_row(t_pg_coder *conv, const char *input_line, int len, int _tupl
830
842
  array = rb_ary_new2(expected_fields);
831
843
 
832
844
  for( fieldno = 0; fieldno < nfields; fieldno++){
833
- long input_len;
845
+ int input_len;
834
846
 
835
847
  /* read field size */
836
848
  if (line_end_ptr - cur_ptr < 4 ) goto length_error;
@@ -871,6 +883,7 @@ pg_bin_dec_copy_row(t_pg_coder *conv, const char *input_line, int len, int _tupl
871
883
  if (cur_ptr < line_end_ptr)
872
884
  rb_raise( rb_eArgError, "trailing data after row data at position: %ld", (long)(cur_ptr - input_line) + 1 );
873
885
 
886
+ RB_GC_GUARD(rb_typemap);
874
887
  return array;
875
888
 
876
889
  length_error:
@@ -47,7 +47,7 @@ static const rb_data_type_t pg_recordcoder_type = {
47
47
  },
48
48
  &pg_coder_type,
49
49
  0,
50
- RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | PG_RUBY_TYPED_FROZEN_SHAREABLE,
50
+ RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FROZEN_SHAREABLE,
51
51
  };
52
52
 
53
53
  static VALUE
@@ -179,14 +179,15 @@ pg_text_enc_record(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate
179
179
  {
180
180
  t_pg_recordcoder *this = (t_pg_recordcoder *)conv;
181
181
  t_pg_coder_enc_func enc_func;
182
- static t_pg_coder *p_elem_coder;
182
+ t_pg_coder *p_elem_coder;
183
183
  int i;
184
+ VALUE rb_typemap = this->typemap;
184
185
  t_typemap *p_typemap;
185
186
  char *current_out;
186
187
  char *end_capa_ptr;
187
188
 
188
- p_typemap = RTYPEDDATA_DATA( this->typemap );
189
- p_typemap->funcs.fit_to_query( this->typemap, value );
189
+ p_typemap = RTYPEDDATA_DATA( rb_typemap );
190
+ p_typemap->funcs.fit_to_query( rb_typemap, value );
190
191
 
191
192
  /* Allocate a new string with embedded capacity and realloc exponential when needed. */
192
193
  PG_RB_STR_NEW( *intermediate, current_out, end_capa_ptr );
@@ -277,6 +278,7 @@ pg_text_enc_record(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate
277
278
 
278
279
  rb_str_set_len( *intermediate, current_out - RSTRING_PTR(*intermediate) );
279
280
 
281
+ RB_GC_GUARD(rb_typemap);
280
282
  return -1;
281
283
  }
282
284
 
@@ -387,10 +389,11 @@ pg_text_dec_record(t_pg_coder *conv, char *input_line, int len, int _tuple, int
387
389
  char *output_ptr;
388
390
  char *cur_ptr;
389
391
  char *end_capa_ptr;
392
+ VALUE rb_typemap = this->typemap;
390
393
  t_typemap *p_typemap;
391
394
 
392
- p_typemap = RTYPEDDATA_DATA( this->typemap );
393
- expected_fields = p_typemap->funcs.fit_to_copy_get( this->typemap );
395
+ p_typemap = RTYPEDDATA_DATA( rb_typemap );
396
+ expected_fields = p_typemap->funcs.fit_to_copy_get( rb_typemap );
394
397
 
395
398
  /* The received input string will probably have this->nfields fields. */
396
399
  array = rb_ary_new2(expected_fields);
@@ -490,6 +493,7 @@ pg_text_dec_record(t_pg_coder *conv, char *input_line, int len, int _tuple, int
490
493
  if (*cur_ptr)
491
494
  rb_raise( rb_eArgError, "malformed record literal: \"%s\" - Junk after right parenthesis.", input_line );
492
495
 
496
+ RB_GC_GUARD(rb_typemap);
493
497
  return array;
494
498
  }
495
499
 
data/ext/pg_result.c CHANGED
@@ -7,7 +7,7 @@
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 );
@@ -180,7 +180,7 @@ static const rb_data_type_t pgresult_type = {
180
180
  pgresult_gc_compact,
181
181
  },
182
182
  0, 0,
183
- 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,
184
184
  };
185
185
 
186
186
  /* Needed by sequel_pg gem, do not delete */
@@ -315,17 +315,17 @@ pg_result_check( VALUE self )
315
315
  case PGRES_SINGLE_TUPLE:
316
316
  case PGRES_EMPTY_QUERY:
317
317
  case PGRES_COMMAND_OK:
318
- #ifdef HAVE_PQENTERPIPELINEMODE
318
+ #ifdef LIBPQ_HAS_PIPELINING
319
319
  case PGRES_PIPELINE_SYNC:
320
320
  #endif
321
- #ifdef HAVE_PQSETCHUNKEDROWSMODE
321
+ #ifdef LIBPQ_HAS_CHUNK_MODE
322
322
  case PGRES_TUPLES_CHUNK:
323
323
  #endif
324
324
  return self;
325
325
  case PGRES_BAD_RESPONSE:
326
326
  case PGRES_FATAL_ERROR:
327
327
  case PGRES_NONFATAL_ERROR:
328
- #ifdef HAVE_PQENTERPIPELINEMODE
328
+ #ifdef LIBPQ_HAS_PIPELINING
329
329
  case PGRES_PIPELINE_ABORTED:
330
330
  #endif
331
331
  error = rb_str_new2( PQresultErrorMessage(this->pgresult) );
@@ -465,9 +465,6 @@ pgresult_get(VALUE self)
465
465
  static VALUE pg_cstr_to_sym(char *cstr, unsigned int flags, int enc_idx)
466
466
  {
467
467
  VALUE fname;
468
- #ifdef TRUFFLERUBY
469
- if( flags & (PG_RESULT_FIELD_NAMES_SYMBOL | PG_RESULT_FIELD_NAMES_STATIC_SYMBOL) ){
470
- #else
471
468
  if( flags & PG_RESULT_FIELD_NAMES_SYMBOL ){
472
469
  rb_encoding *enc = rb_enc_from_index(enc_idx);
473
470
  fname = rb_check_symbol_cstr(cstr, strlen(cstr), enc);
@@ -476,14 +473,9 @@ static VALUE pg_cstr_to_sym(char *cstr, unsigned int flags, int enc_idx)
476
473
  PG_ENCODING_SET_NOCHECK(fname, enc_idx);
477
474
  fname = rb_str_intern(fname);
478
475
  }
479
- } else if( flags & PG_RESULT_FIELD_NAMES_STATIC_SYMBOL ){
480
- #endif
481
- rb_encoding *enc = rb_enc_from_index(enc_idx);
482
- fname = ID2SYM(rb_intern3(cstr, strlen(cstr), enc));
483
476
  } else {
484
- fname = rb_str_new2(cstr);
485
- PG_ENCODING_SET_NOCHECK(fname, enc_idx);
486
- 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);
487
479
  }
488
480
  return fname;
489
481
  }
@@ -531,6 +523,7 @@ static void pgresult_init_fnames(VALUE self)
531
523
  * res.column_values(1) # ["2"]
532
524
  * res.each.first # {"a" => "1", "b" => "2", "c" => nil}
533
525
  * res.each_row.first # ["1", "2", nil]
526
+ * res.each_tuple.first # #<PG::Tuple a: "1", b: "2", c: nil>
534
527
  *
535
528
  * Whenever a value is accessed it is casted to a Ruby object by the assigned #type_map which is PG::TypeMapAllStrings by default.
536
529
  * Similarly field names can be retrieved either as strings (default) or as symbols which can be switched per #field_name_type= .
@@ -549,6 +542,7 @@ static void pgresult_init_fnames(VALUE self)
549
542
  * res.column_values(1) # [2]
550
543
  * res.each.first # {a: 1, b: 2, c: nil}
551
544
  * res.each_row.first # [1, 2, nil]
545
+ * res.each_tuple.first # #<PG::Tuple a: 1, b: 2, c: nil>
552
546
  *
553
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.
554
548
  * You can invoke the #clear method to force deallocation of memory of the instance when finished with the result for better memory performance.
@@ -577,7 +571,7 @@ static void pgresult_init_fnames(VALUE self)
577
571
  * * +PGRES_PIPELINE_SYNC+
578
572
  * * +PGRES_PIPELINE_ABORTED+
579
573
  *
580
- * Use <tt>res.res_status</tt> to retrieve the string representation.
574
+ * Use #res_status or Result.res_status to retrieve the string representation.
581
575
  */
582
576
  static VALUE
583
577
  pgresult_result_status(VALUE self)
@@ -589,7 +583,7 @@ pgresult_result_status(VALUE self)
589
583
  * call-seq:
590
584
  * PG::Result.res_status( status ) -> String
591
585
  *
592
- * Returns the string representation of +status+.
586
+ * Returns the string representation of #result_status.
593
587
  *
594
588
  */
595
589
  static VALUE
@@ -603,7 +597,7 @@ pgresult_s_res_status(VALUE self, VALUE status)
603
597
  * res.res_status -> String
604
598
  * res.res_status( status ) -> String
605
599
  *
606
- * 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.
607
601
  *
608
602
  */
609
603
  static VALUE
@@ -1430,6 +1424,32 @@ pgresult_each(VALUE self)
1430
1424
  return self;
1431
1425
  }
1432
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
+
1433
1453
  /*
1434
1454
  * call-seq:
1435
1455
  * res.fields() -> Array
@@ -1579,7 +1599,7 @@ pgresult_stream_any(VALUE self, int (*yielder)(VALUE, int, int, void*), void* da
1579
1599
  return self;
1580
1600
  rb_raise( rb_eInvalidResultStatus, "PG::Result is not in single row mode");
1581
1601
  case PGRES_SINGLE_TUPLE:
1582
- #ifdef HAVE_PQSETCHUNKEDROWSMODE
1602
+ #ifdef LIBPQ_HAS_CHUNK_MODE
1583
1603
  case PGRES_TUPLES_CHUNK:
1584
1604
  #endif
1585
1605
  break;
@@ -1597,12 +1617,12 @@ pgresult_stream_any(VALUE self, int (*yielder)(VALUE, int, int, void*), void* da
1597
1617
  pgresult_clear( this );
1598
1618
  }
1599
1619
 
1600
- if( gvl_PQisBusy(pgconn) ){
1620
+ if( PQisBusy(pgconn) ){
1601
1621
  /* wait for input (without blocking) before reading each result */
1602
1622
  pgconn_block( 0, NULL, this->connection );
1603
1623
  }
1604
1624
 
1605
- pgresult = gvl_PQgetResult(pgconn);
1625
+ pgresult = PQgetResult(pgconn);
1606
1626
  if( pgresult == NULL )
1607
1627
  rb_raise( rb_eNoResultError, "no result received - possibly an intersection with another query");
1608
1628
 
@@ -1692,7 +1712,6 @@ pgresult_stream_each_tuple(VALUE self)
1692
1712
  * It can be set to one of:
1693
1713
  * * +:string+ to use String based field names
1694
1714
  * * +:symbol+ to use Symbol based field names
1695
- * * +:static_symbol+ to use pinned Symbol (can not be garbage collected) - Don't use this, it will probably be removed in future.
1696
1715
  *
1697
1716
  * The default is retrieved from PG::Connection#field_name_type , which defaults to +:string+ .
1698
1717
  *
@@ -1715,7 +1734,6 @@ pgresult_field_name_type_set(VALUE self, VALUE sym)
1715
1734
 
1716
1735
  this->flags &= ~PG_RESULT_FIELD_NAMES_MASK;
1717
1736
  if( sym == sym_symbol ) this->flags |= PG_RESULT_FIELD_NAMES_SYMBOL;
1718
- else if ( sym == sym_static_symbol ) this->flags |= PG_RESULT_FIELD_NAMES_STATIC_SYMBOL;
1719
1737
  else if ( sym == sym_string );
1720
1738
  else rb_raise(rb_eArgError, "invalid argument %+"PRIsVALUE, sym);
1721
1739
 
@@ -1736,8 +1754,6 @@ pgresult_field_name_type_get(VALUE self)
1736
1754
  t_pg_result *this = pgresult_get_this(self);
1737
1755
  if( this->flags & PG_RESULT_FIELD_NAMES_SYMBOL ){
1738
1756
  return sym_symbol;
1739
- } else if( this->flags & PG_RESULT_FIELD_NAMES_STATIC_SYMBOL ){
1740
- return sym_static_symbol;
1741
1757
  } else {
1742
1758
  return sym_string;
1743
1759
  }
@@ -1748,7 +1764,6 @@ init_pg_result(void)
1748
1764
  {
1749
1765
  sym_string = ID2SYM(rb_intern("string"));
1750
1766
  sym_symbol = ID2SYM(rb_intern("symbol"));
1751
- sym_static_symbol = ID2SYM(rb_intern("static_symbol"));
1752
1767
 
1753
1768
  rb_cPGresult = rb_define_class_under( rb_mPG, "Result", rb_cObject );
1754
1769
  rb_undef_alloc_func(rb_cPGresult);
@@ -1797,6 +1812,7 @@ init_pg_result(void)
1797
1812
  rb_define_method(rb_cPGresult, "each", pgresult_each, 0);
1798
1813
  rb_define_method(rb_cPGresult, "fields", pgresult_fields, 0);
1799
1814
  rb_define_method(rb_cPGresult, "each_row", pgresult_each_row, 0);
1815
+ rb_define_method(rb_cPGresult, "each_tuple", pgresult_each_tuple, 0);
1800
1816
  rb_define_method(rb_cPGresult, "values", pgresult_values, 0);
1801
1817
  rb_define_method(rb_cPGresult, "column_values", pgresult_column_values, 1);
1802
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
  /*
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
  /*
@@ -64,4 +64,9 @@ class PG::BasicTypeMapBasedOnResult < PG::TypeMapByOid
64
64
  add_coder(coder)
65
65
  end
66
66
  end
67
+
68
+ # Returns the PG::BasicTypeRegistry::CoderMapsBundle used to translate result OIDs to encoders.
69
+ def coder_maps_bundle
70
+ @coder_maps
71
+ end
67
72
  end