pg 1.5.4 → 1.6.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/{History.md → CHANGELOG.md} +132 -4
  4. data/Gemfile +15 -6
  5. data/README-Windows.rdoc +1 -1
  6. data/README.ja.md +4 -4
  7. data/README.md +66 -23
  8. data/Rakefile +81 -14
  9. data/certs/kanis@comcard.de.pem +20 -0
  10. data/certs/larskanis-2024.pem +24 -0
  11. data/ext/errorcodes.def +11 -3
  12. data/ext/errorcodes.rb +1 -1
  13. data/ext/errorcodes.txt +9 -5
  14. data/ext/extconf.rb +192 -15
  15. data/ext/gvl_wrappers.c +13 -2
  16. data/ext/gvl_wrappers.h +33 -0
  17. data/ext/pg.c +17 -6
  18. data/ext/pg.h +15 -13
  19. data/ext/pg_binary_decoder.c +153 -1
  20. data/ext/pg_binary_encoder.c +213 -10
  21. data/ext/pg_cancel_connection.c +360 -0
  22. data/ext/pg_coder.c +54 -5
  23. data/ext/pg_connection.c +431 -169
  24. data/ext/pg_copy_coder.c +19 -15
  25. data/ext/pg_record_coder.c +7 -7
  26. data/ext/pg_result.c +106 -54
  27. data/ext/pg_text_decoder.c +5 -2
  28. data/ext/pg_text_encoder.c +39 -20
  29. data/ext/pg_tuple.c +8 -8
  30. data/ext/pg_type_map.c +4 -2
  31. data/ext/pg_type_map_all_strings.c +1 -1
  32. data/ext/pg_type_map_by_class.c +1 -1
  33. data/ext/pg_type_map_by_column.c +2 -1
  34. data/ext/pg_type_map_by_mri_type.c +1 -1
  35. data/ext/pg_type_map_by_oid.c +3 -1
  36. data/ext/pg_type_map_in_ruby.c +1 -1
  37. data/ext/pg_util.c +2 -2
  38. data/ext/pg_util.h +2 -2
  39. data/lib/pg/basic_type_map_for_queries.rb +15 -7
  40. data/lib/pg/basic_type_registry.rb +16 -4
  41. data/lib/pg/cancel_connection.rb +53 -0
  42. data/lib/pg/coder.rb +4 -2
  43. data/lib/pg/connection.rb +310 -167
  44. data/lib/pg/exceptions.rb +6 -0
  45. data/lib/pg/text_decoder/date.rb +3 -0
  46. data/lib/pg/text_decoder/json.rb +3 -0
  47. data/lib/pg/text_encoder/date.rb +1 -0
  48. data/lib/pg/text_encoder/inet.rb +3 -0
  49. data/lib/pg/text_encoder/json.rb +3 -0
  50. data/lib/pg/version.rb +2 -1
  51. data/lib/pg.rb +156 -120
  52. data/misc/glibc/Dockerfile +20 -0
  53. data/misc/glibc/docker-compose.yml +9 -0
  54. data/misc/glibc/glibc_spec.rb +5 -0
  55. data/misc/yugabyte/Dockerfile +9 -0
  56. data/misc/yugabyte/docker-compose.yml +28 -0
  57. data/misc/yugabyte/pg-test.rb +45 -0
  58. data/pg.gemspec +8 -4
  59. data/ports/patches/krb5/1.22.1/0001-Allow-static-linking-krb5-library.patch +30 -0
  60. data/ports/patches/krb5/1.22.1/0002-unknown-command-line-option-on-clang.patch +12 -0
  61. data/ports/patches/openssl/3.5.2/0001-aarch64-mingw.patch +21 -0
  62. data/ports/patches/postgresql/18.1/0001-Use-workaround-of-__builtin_setjmp-only-on-MINGW-on-.patch +42 -0
  63. data/ports/patches/postgresql/18.1/0001-libpq-Process-buffered-SSL-read-bytes-to-support-rec.patch +52 -0
  64. data/rakelib/pg_gem_helper.rb +64 -0
  65. data.tar.gz.sig +0 -0
  66. metadata +49 -47
  67. metadata.gz.sig +0 -0
  68. data/.appveyor.yml +0 -42
  69. data/.gems +0 -6
  70. data/.gemtest +0 -0
  71. data/.github/workflows/binary-gems.yml +0 -117
  72. data/.github/workflows/source-gem.yml +0 -141
  73. data/.gitignore +0 -22
  74. data/.hgsigs +0 -34
  75. data/.hgtags +0 -41
  76. data/.irbrc +0 -23
  77. data/.pryrc +0 -23
  78. data/.tm_properties +0 -21
  79. data/.travis.yml +0 -49
  80. data/Manifest.txt +0 -72
  81. data/Rakefile.cross +0 -298
  82. data/translation/.po4a-version +0 -7
  83. data/translation/po/all.pot +0 -936
  84. data/translation/po/ja.po +0 -1036
  85. data/translation/po4a.cfg +0 -12
data/ext/pg_copy_coder.c CHANGED
@@ -51,7 +51,7 @@ static const rb_data_type_t pg_copycoder_type = {
51
51
  pg_copycoder_mark,
52
52
  RUBY_TYPED_DEFAULT_FREE,
53
53
  pg_copycoder_memsize,
54
- pg_compact_callback(pg_copycoder_compact),
54
+ pg_copycoder_compact,
55
55
  },
56
56
  &pg_coder_type,
57
57
  0,
@@ -212,6 +212,7 @@ pg_copycoder_type_map_get(VALUE self)
212
212
  *
213
213
  * See also PG::TextDecoder::CopyRow for the decoding direction with
214
214
  * PG::Connection#get_copy_data .
215
+ * And see PG::BinaryEncoder::CopyRow for an encoder of the COPY binary format.
215
216
  */
216
217
  static int
217
218
  pg_text_enc_copy_row(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate, int enc_idx)
@@ -235,7 +236,7 @@ pg_text_enc_copy_row(t_pg_coder *conv, VALUE value, char *out, VALUE *intermedia
235
236
  char *ptr1;
236
237
  char *ptr2;
237
238
  int strlen;
238
- int backslashs;
239
+ int backslashes;
239
240
  VALUE subint;
240
241
  VALUE entry;
241
242
 
@@ -286,19 +287,19 @@ pg_text_enc_copy_row(t_pg_coder *conv, VALUE value, char *out, VALUE *intermedia
286
287
  ptr2 = current_out + strlen;
287
288
 
288
289
  /* count required backlashs */
289
- for(backslashs = 0; ptr1 != ptr2; ptr1++) {
290
+ for(backslashes = 0; ptr1 != ptr2; ptr1++) {
290
291
  /* Escape backslash itself, newline, carriage return, and the current delimiter character. */
291
292
  if(*ptr1 == '\\' || *ptr1 == '\n' || *ptr1 == '\r' || *ptr1 == this->delimiter){
292
- backslashs++;
293
+ backslashes++;
293
294
  }
294
295
  }
295
296
 
296
297
  ptr1 = current_out + strlen;
297
- ptr2 = current_out + strlen + backslashs;
298
+ ptr2 = current_out + strlen + backslashes;
298
299
  current_out = ptr2;
299
300
 
300
301
  /* Then store the escaped string on the final position, walking
301
- * right to left, until all backslashs are placed. */
302
+ * right to left, until all backslashes are placed. */
302
303
  while( ptr1 != ptr2 ) {
303
304
  *--ptr2 = *--ptr1;
304
305
  if(*ptr1 == '\\' || *ptr1 == '\n' || *ptr1 == '\r' || *ptr1 == this->delimiter){
@@ -358,6 +359,7 @@ pg_text_enc_copy_row(t_pg_coder *conv, VALUE value, char *out, VALUE *intermedia
358
359
  *
359
360
  * See also PG::BinaryDecoder::CopyRow for the decoding direction with
360
361
  * PG::Connection#get_copy_data .
362
+ * And see PG::TextEncoder::CopyRow for an encoder of the COPY text format.
361
363
  */
362
364
  static int
363
365
  pg_bin_enc_copy_row(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate, int enc_idx)
@@ -391,7 +393,7 @@ pg_bin_enc_copy_row(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediat
391
393
 
392
394
  switch(TYPE(entry)){
393
395
  case T_NIL:
394
- /* 4 bytes for -1 indicationg a NULL value */
396
+ /* 4 bytes for -1 indicating a NULL value */
395
397
  PG_RB_STR_ENSURE_CAPA( *intermediate, 4, current_out, end_capa_ptr );
396
398
  write_nbo32(-1, current_out);
397
399
  current_out += 4;
@@ -496,6 +498,7 @@ GetDecimalFromHex(char hex)
496
498
  *
497
499
  * See also PG::TextEncoder::CopyRow for the encoding direction with
498
500
  * PG::Connection#put_copy_data .
501
+ * And see PG::BinaryDecoder::CopyRow for a decoder of the COPY binary format.
499
502
  */
500
503
  /*
501
504
  * Parse the current line into separate attributes (fields),
@@ -763,6 +766,7 @@ static const char BinarySignature[11] = "PGCOPY\n\377\r\n\0";
763
766
  *
764
767
  * See also PG::BinaryEncoder::CopyRow for the encoding direction with
765
768
  * PG::Connection#put_copy_data .
769
+ * And see PG::TextDecoder::CopyRow for a decoder of the COPY text format.
766
770
  */
767
771
  static VALUE
768
772
  pg_bin_dec_copy_row(t_pg_coder *conv, const char *input_line, int len, int _tuple, int _field, int enc_idx)
@@ -795,26 +799,26 @@ pg_bin_dec_copy_row(t_pg_coder *conv, const char *input_line, int len, int _tupl
795
799
  cur_ptr = input_line;
796
800
  line_end_ptr = input_line + len;
797
801
 
798
- if (cur_ptr + 11 <= line_end_ptr && memcmp(cur_ptr, BinarySignature, 11) == 0){
802
+ if (line_end_ptr - cur_ptr >= 11 && memcmp(cur_ptr, BinarySignature, 11) == 0){
799
803
  /* binary COPY header signature detected -> just drop it */
800
804
  int ext_bytes;
801
805
  cur_ptr += 11;
802
806
 
803
807
  /* read flags */
804
- if (cur_ptr + 4 > line_end_ptr) goto length_error;
808
+ if (line_end_ptr - cur_ptr < 4 ) goto length_error;
805
809
  cur_ptr += 4;
806
810
 
807
811
  /* read header extensions */
808
- if (cur_ptr + 4 > line_end_ptr) goto length_error;
812
+ if (line_end_ptr - cur_ptr < 4 ) goto length_error;
809
813
  ext_bytes = read_nbo32(cur_ptr);
810
814
  if (ext_bytes < 0) goto length_error;
811
815
  cur_ptr += 4;
812
- if (cur_ptr + ext_bytes > line_end_ptr) goto length_error;
816
+ if (line_end_ptr - cur_ptr < ext_bytes ) goto length_error;
813
817
  cur_ptr += ext_bytes;
814
818
  }
815
819
 
816
820
  /* read row header */
817
- if (cur_ptr + 2 > line_end_ptr) goto length_error;
821
+ if (line_end_ptr - cur_ptr < 2 ) goto length_error;
818
822
  nfields = read_nbo16(cur_ptr);
819
823
  cur_ptr += 2;
820
824
 
@@ -827,10 +831,9 @@ pg_bin_dec_copy_row(t_pg_coder *conv, const char *input_line, int len, int _tupl
827
831
 
828
832
  for( fieldno = 0; fieldno < nfields; fieldno++){
829
833
  long input_len;
830
- VALUE field_value;
831
834
 
832
835
  /* read field size */
833
- if (cur_ptr + 4 > line_end_ptr) goto length_error;
836
+ if (line_end_ptr - cur_ptr < 4 ) goto length_error;
834
837
  input_len = read_nbo32(cur_ptr);
835
838
  cur_ptr += 4;
836
839
 
@@ -839,7 +842,8 @@ pg_bin_dec_copy_row(t_pg_coder *conv, const char *input_line, int len, int _tupl
839
842
  /* NULL indicator */
840
843
  rb_ary_push(array, Qnil);
841
844
  } else {
842
- if (cur_ptr + input_len > line_end_ptr) goto length_error;
845
+ VALUE field_value;
846
+ if (line_end_ptr - cur_ptr < input_len ) goto length_error;
843
847
 
844
848
  /* copy input data to field_str */
845
849
  PG_RB_STR_ENSURE_CAPA( field_str, input_len, output_ptr, end_capa_ptr );
@@ -43,7 +43,7 @@ static const rb_data_type_t pg_recordcoder_type = {
43
43
  pg_recordcoder_mark,
44
44
  RUBY_TYPED_DEFAULT_FREE,
45
45
  pg_recordcoder_memsize,
46
- pg_compact_callback(pg_recordcoder_compact),
46
+ pg_recordcoder_compact,
47
47
  },
48
48
  &pg_coder_type,
49
49
  0,
@@ -198,7 +198,7 @@ pg_text_enc_record(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate
198
198
  char *ptr1;
199
199
  char *ptr2;
200
200
  long strlen;
201
- int backslashs;
201
+ int backslashes;
202
202
  VALUE subint;
203
203
  VALUE entry;
204
204
 
@@ -249,19 +249,19 @@ pg_text_enc_record(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate
249
249
  ptr2 = current_out + strlen;
250
250
 
251
251
  /* count required backlashs */
252
- for(backslashs = 0; ptr1 != ptr2; ptr1++) {
252
+ for(backslashes = 0; ptr1 != ptr2; ptr1++) {
253
253
  /* Escape backslash itself, newline, carriage return, and the current delimiter character. */
254
254
  if(*ptr1 == '"' || *ptr1 == '\\'){
255
- backslashs++;
255
+ backslashes++;
256
256
  }
257
257
  }
258
258
 
259
259
  ptr1 = current_out + strlen;
260
- ptr2 = current_out + strlen + backslashs;
260
+ ptr2 = current_out + strlen + backslashes;
261
261
  current_out = ptr2;
262
262
 
263
263
  /* Then store the escaped string on the final position, walking
264
- * right to left, until all backslashs are placed. */
264
+ * right to left, until all backslashes are placed. */
265
265
  while( ptr1 != ptr2 ) {
266
266
  *--ptr2 = *--ptr1;
267
267
  if(*ptr1 == '"' || *ptr1 == '\\'){
@@ -340,7 +340,7 @@ record_isspace(char ch)
340
340
  * conn.exec("SELECT * FROM my_table").map_types!(PG::TypeMapByColumn.new([deco]*2)).to_a
341
341
  * # => [{"v1"=>[2.0, 3.0], "v2"=>[4.0, 5.0]}, {"v1"=>[6.0, 7.0], "v2"=>[8.0, 9.0]}]
342
342
  *
343
- * It's more very convenient to use the PG::BasicTypeRegistry, which is based on database OIDs.
343
+ * It's more convenient to use the PG::BasicTypeRegistry, which is based on database OIDs.
344
344
  * # Fetch a NULL record of our type to retrieve the OIDs of the two fields "r" and "i"
345
345
  * oids = conn.exec( "SELECT (NULL::complex).*" )
346
346
  * # Build a type map (PG::TypeMapByColumn) for decoding the "complex" type
data/ext/pg_result.c CHANGED
@@ -12,6 +12,7 @@ static VALUE sym_symbol, sym_string, sym_static_symbol;
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,7 +177,7 @@ 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
183
  RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | PG_RUBY_TYPED_FROZEN_SHAREABLE,
@@ -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
  }
@@ -323,6 +317,9 @@ pg_result_check( VALUE self )
323
317
  case PGRES_COMMAND_OK:
324
318
  #ifdef HAVE_PQENTERPIPELINEMODE
325
319
  case PGRES_PIPELINE_SYNC:
320
+ #endif
321
+ #ifdef HAVE_PQSETCHUNKEDROWSMODE
322
+ case PGRES_TUPLES_CHUNK:
326
323
  #endif
327
324
  return self;
328
325
  case PGRES_BAD_RESPONSE:
@@ -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
  }
@@ -514,20 +512,46 @@ static void pgresult_init_fnames(VALUE self)
514
512
  *
515
513
  * The class to represent the query result tuples (rows).
516
514
  * 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.
515
+ * All result rows and columns are stored in an immutable memory block attached to the PG::Result object unless streaming is used.
522
516
  *
523
- * Example:
517
+ * A PG::Result has various ways to retrieve the result data:
524
518
  * 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
519
+ * conn = PG.connect(dbname: 'test')
520
+ * res = conn.exec('SELECT 1 AS a, 2 AS b, NULL AS c')
521
+ * res.num_fields # 3
522
+ * res.num_tuples # 1
523
+ * res.fname(2) # "c"
524
+ * res.fields # ["a", "b", "c"]
525
+ * res.getvalue(0,0) # '1'
526
+ * res[0] # {"a" => "1", "b" => "2", "c" => "3"}
527
+ * res.tuple_values(0) # ["1", "2", nil]
528
+ * res.tuple(0) # #<PG::Tuple a: "1", b: "2", c: nil>
529
+ * res.values # [["1", "2", nil]]
530
+ * res.field_values(:a) # ["1"]
531
+ * res.column_values(1) # ["2"]
532
+ * res.each.first # {"a" => "1", "b" => "2", "c" => nil}
533
+ * res.each_row.first # ["1", "2", nil]
534
+ *
535
+ * Whenever a value is accessed it is casted to a Ruby object by the assigned #type_map which is PG::TypeMapAllStrings by default.
536
+ * Similarly field names can be retrieved either as strings (default) or as symbols which can be switched per #field_name_type= .
537
+ *
538
+ * res = conn.exec('SELECT 1 AS a, 2 AS b, NULL AS c')
539
+ * res.type_map = PG::TypeMapByColumn.new([PG::TextDecoder::Integer.new]*3)
540
+ * res.field_name_type = :symbol
541
+ * res.fname(2) # :c
542
+ * res.fields # [:a, :b, :c]
543
+ * res.getvalue(0,0) # 1
544
+ * res[0] # {a: 1, b: 2, c: nil}
545
+ * res.tuple_values(0) # [1, 2, nil]
546
+ * res.tuple(0) # #<PG::Tuple a: 1, b: 2, c: nil>
547
+ * res.values # [[1, 2, nil]]
548
+ * res.field_values(:a) # [1]
549
+ * res.column_values(1) # [2]
550
+ * res.each.first # {a: 1, b: 2, c: nil}
551
+ * res.each_row.first # [1, 2, nil]
530
552
  *
553
+ * 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
+ * You can invoke the #clear method to force deallocation of memory of the instance when finished with the result for better memory performance.
531
555
  */
532
556
 
533
557
  /**************************************************************************
@@ -549,6 +573,7 @@ static void pgresult_init_fnames(VALUE self)
549
573
  * * +PGRES_FATAL_ERROR+
550
574
  * * +PGRES_COPY_BOTH+
551
575
  * * +PGRES_SINGLE_TUPLE+
576
+ * * +PGRES_TUPLES_CHUNK+
552
577
  * * +PGRES_PIPELINE_SYNC+
553
578
  * * +PGRES_PIPELINE_ABORTED+
554
579
  *
@@ -613,14 +638,12 @@ pgresult_error_message(VALUE self)
613
638
  return ret;
614
639
  }
615
640
 
616
- #ifdef HAVE_PQRESULTVERBOSEERRORMESSAGE
617
641
  /*
618
642
  * call-seq:
619
643
  * res.verbose_error_message( verbosity, show_context ) -> String
620
644
  *
621
- * Returns a reformatted version of the error message associated with a PGresult object.
645
+ * Returns a reformatted version of the error message associated with the PG::Result object.
622
646
  *
623
- * Available since PostgreSQL-9.6
624
647
  */
625
648
  static VALUE
626
649
  pgresult_verbose_error_message(VALUE self, VALUE verbosity, VALUE show_context)
@@ -639,7 +662,6 @@ pgresult_verbose_error_message(VALUE self, VALUE verbosity, VALUE show_context)
639
662
 
640
663
  return ret;
641
664
  }
642
- #endif
643
665
 
644
666
  /*
645
667
  * call-seq:
@@ -664,7 +686,7 @@ pgresult_verbose_error_message(VALUE self, VALUE verbosity, VALUE show_context)
664
686
  * An example:
665
687
  *
666
688
  * begin
667
- * conn.exec( "SELECT * FROM nonexistant_table" )
689
+ * conn.exec( "SELECT * FROM nonexistent_table" )
668
690
  * rescue PG::Error => err
669
691
  * p [
670
692
  * err.result.error_field( PG::Result::PG_DIAG_SEVERITY ),
@@ -684,7 +706,7 @@ pgresult_verbose_error_message(VALUE self, VALUE verbosity, VALUE show_context)
684
706
  *
685
707
  * Outputs:
686
708
  *
687
- * ["ERROR", "42P01", "relation \"nonexistant_table\" does not exist", nil, nil,
709
+ * ["ERROR", "42P01", "relation \"nonexistent_table\" does not exist", nil, nil,
688
710
  * "15", nil, nil, nil, "path/to/parse_relation.c", "857", "parserOpenTable"]
689
711
  */
690
712
  static VALUE
@@ -708,6 +730,10 @@ pgresult_error_field(VALUE self, VALUE field)
708
730
  * res.ntuples() -> Integer
709
731
  *
710
732
  * Returns the number of tuples in the query result.
733
+ *
734
+ * res = conn.exec('SELECT 1 AS a, 2 AS b, NULL AS c')
735
+ * res.ntuples # 1
736
+ * res.num_tuples # 1
711
737
  */
712
738
  static VALUE
713
739
  pgresult_ntuples(VALUE self)
@@ -726,6 +752,9 @@ pgresult_ntuples_for_enum(VALUE self, VALUE args, VALUE eobj)
726
752
  * res.nfields() -> Integer
727
753
  *
728
754
  * Returns the number of columns in the query result.
755
+ * res = conn.exec('SELECT 1 AS a, 2 AS b, NULL AS c')
756
+ * res.nfields # 3
757
+ * res.num_fields # 3
729
758
  */
730
759
  static VALUE
731
760
  pgresult_nfields(VALUE self)
@@ -737,9 +766,9 @@ pgresult_nfields(VALUE self)
737
766
  * call-seq:
738
767
  * res.binary_tuples() -> Integer
739
768
  *
740
- * Returns 1 if the PGresult contains binary data and 0 if it contains text data.
769
+ * Returns 1 if the PG::Result contains binary data and 0 if it contains text data.
741
770
  *
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.
771
+ * 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
772
  * Result#fformat is preferred. binary_tuples returns 1 only if all columns of the result are binary (format 1).
744
773
  */
745
774
  static VALUE
@@ -755,6 +784,8 @@ pgresult_binary_tuples(VALUE self)
755
784
  * Returns the name of the column corresponding to _index_.
756
785
  * Depending on #field_name_type= it's a String or Symbol.
757
786
  *
787
+ * res = conn.exec('SELECT 1 AS a, 2 AS b, NULL AS c')
788
+ * res.fname(2) # "c"
758
789
  */
759
790
  static VALUE
760
791
  pgresult_fname(VALUE self, VALUE index)
@@ -1125,6 +1156,9 @@ pgresult_oid_value(VALUE self)
1125
1156
  * res[ n ] -> Hash
1126
1157
  *
1127
1158
  * Returns tuple _n_ as a hash.
1159
+ *
1160
+ * res = conn.exec('SELECT 1 AS a, 2 AS b, NULL AS c')
1161
+ * res[0] # {"a" => "1", "b" => "2", "c" => "3"}
1128
1162
  */
1129
1163
  static VALUE
1130
1164
  pgresult_aref(VALUE self, VALUE index)
@@ -1141,16 +1175,11 @@ pgresult_aref(VALUE self, VALUE index)
1141
1175
  if ( tuple_num < 0 || tuple_num >= num_tuples )
1142
1176
  rb_raise( rb_eIndexError, "Index %d is out of range", tuple_num );
1143
1177
 
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;
1178
+ tuple = rb_hash_new_capa(this->nfields);
1147
1179
  for ( field_num = 0; field_num < this->nfields; field_num++ ) {
1148
1180
  VALUE val = this->p_typemap->funcs.typecast_result_value(this->p_typemap, self, tuple_num, field_num);
1149
1181
  rb_hash_aset( tuple, this->fnames[field_num], val );
1150
1182
  }
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
1183
 
1155
1184
  return tuple;
1156
1185
  }
@@ -1159,7 +1188,10 @@ pgresult_aref(VALUE self, VALUE index)
1159
1188
  * call-seq:
1160
1189
  * res.each_row { |row| ... }
1161
1190
  *
1162
- * Yields each row of the result. The row is a list of column values.
1191
+ * Yields an Array object for each row in the result.
1192
+ *
1193
+ * res = conn.exec('SELECT 1 AS a, 2 AS b, NULL AS c')
1194
+ * res.each_row.first # ["1", "2", nil]
1163
1195
  */
1164
1196
  static VALUE
1165
1197
  pgresult_each_row(VALUE self)
@@ -1194,6 +1226,9 @@ pgresult_each_row(VALUE self)
1194
1226
  * res.values -> Array
1195
1227
  *
1196
1228
  * Returns all tuples as an array of arrays.
1229
+ *
1230
+ * res = conn.exec('SELECT 1 AS a, 2 AS b, NULL AS c')
1231
+ * res.values # [["1", "2", nil]]
1197
1232
  */
1198
1233
  static VALUE
1199
1234
  pgresult_values(VALUE self)
@@ -1243,12 +1278,13 @@ make_column_result_array( VALUE self, int col )
1243
1278
 
1244
1279
 
1245
1280
  /*
1246
- * call-seq:
1247
- * res.column_values( n ) -> array
1281
+ * call-seq:
1282
+ * res.column_values( n ) -> array
1248
1283
  *
1249
- * Returns an Array of the values from the nth column of each
1250
- * tuple in the result.
1284
+ * Returns an Array of the values from the nth column of each tuple in the result.
1251
1285
  *
1286
+ * res = conn.exec('SELECT 1 AS a, 2 AS b, NULL AS c')
1287
+ * res.column_values(1) # ["2"]
1252
1288
  */
1253
1289
  static VALUE
1254
1290
  pgresult_column_values(VALUE self, VALUE index)
@@ -1259,11 +1295,13 @@ pgresult_column_values(VALUE self, VALUE index)
1259
1295
 
1260
1296
 
1261
1297
  /*
1262
- * call-seq:
1298
+ * call-seq:
1263
1299
  * res.field_values( field ) -> array
1264
1300
  *
1265
- * Returns an Array of the values from the given _field_ of each tuple in the result.
1301
+ * Returns an Array of the values from the given _field_ of each tuple in the result.
1266
1302
  *
1303
+ * res = conn.exec('SELECT 1 AS a, 2 AS b, NULL AS c')
1304
+ * res.field_values(:a) # ["1"]
1267
1305
  */
1268
1306
  static VALUE
1269
1307
  pgresult_field_values( VALUE self, VALUE field )
@@ -1284,11 +1322,13 @@ pgresult_field_values( VALUE self, VALUE field )
1284
1322
 
1285
1323
 
1286
1324
  /*
1287
- * call-seq:
1288
- * res.tuple_values( n ) -> array
1325
+ * call-seq:
1326
+ * res.tuple_values( n ) -> array
1289
1327
  *
1290
- * Returns an Array of the field values from the nth row of the result.
1328
+ * Returns an Array of the field values from the nth row of the result.
1291
1329
  *
1330
+ * res = conn.exec('SELECT 1 AS a, 2 AS b, NULL AS c')
1331
+ * res.tuple_values(0) # ["1", "2", nil]
1292
1332
  */
1293
1333
  static VALUE
1294
1334
  pgresult_tuple_values(VALUE self, VALUE index)
@@ -1323,11 +1363,12 @@ static void ensure_init_for_tuple(VALUE self)
1323
1363
 
1324
1364
  if( this->field_map == Qnil ){
1325
1365
  int i;
1326
- VALUE field_map = rb_hash_new();
1366
+ VALUE field_map;
1327
1367
 
1328
1368
  if( this->nfields == -1 )
1329
1369
  pgresult_init_fnames( self );
1330
1370
 
1371
+ field_map = rb_hash_new_capa(this->nfields);
1331
1372
  for( i = 0; i < this->nfields; i++ ){
1332
1373
  rb_hash_aset(field_map, this->fnames[i], INT2FIX(i));
1333
1374
  }
@@ -1337,11 +1378,13 @@ static void ensure_init_for_tuple(VALUE self)
1337
1378
  }
1338
1379
 
1339
1380
  /*
1340
- * call-seq:
1341
- * res.tuple( n ) -> PG::Tuple
1381
+ * call-seq:
1382
+ * res.tuple( n ) -> PG::Tuple
1342
1383
  *
1343
- * Returns a PG::Tuple from the nth row of the result.
1384
+ * Returns a PG::Tuple from the nth row of the result.
1344
1385
  *
1386
+ * res = conn.exec('SELECT 1 AS a, 2 AS b, NULL AS c')
1387
+ * res.tuple(0) # #<PG::Tuple a: "1", b: "2", c: nil>
1345
1388
  */
1346
1389
  static VALUE
1347
1390
  pgresult_tuple(VALUE self, VALUE index)
@@ -1366,7 +1409,10 @@ pgresult_tuple(VALUE self, VALUE index)
1366
1409
  * call-seq:
1367
1410
  * res.each{ |tuple| ... }
1368
1411
  *
1369
- * Invokes block for each tuple in the result set.
1412
+ * Yields a Hash object for each row in the result.
1413
+ *
1414
+ * res = conn.exec('SELECT 1 AS a, 2 AS b, NULL AS c')
1415
+ * res.each.first # {"a" => "1", "b" => "2", "c" => nil}
1370
1416
  */
1371
1417
  static VALUE
1372
1418
  pgresult_each(VALUE self)
@@ -1389,6 +1435,9 @@ pgresult_each(VALUE self)
1389
1435
  * res.fields() -> Array
1390
1436
  *
1391
1437
  * Depending on #field_name_type= returns an array of strings or symbols representing the names of the fields in the result.
1438
+ *
1439
+ * res = conn.exec('SELECT 1 AS a, 2 AS b, NULL AS c')
1440
+ * res.fields # ["a", "b", "c"]
1392
1441
  */
1393
1442
  static VALUE
1394
1443
  pgresult_fields(VALUE self)
@@ -1405,7 +1454,7 @@ pgresult_fields(VALUE self)
1405
1454
  * call-seq:
1406
1455
  * res.type_map = typemap
1407
1456
  *
1408
- * Set the TypeMap that is used for type casts of result values to ruby objects.
1457
+ * Set the PG::TypeMap that is used for type casts of result values to ruby objects.
1409
1458
  *
1410
1459
  * All value retrieval methods will respect the type map and will do the
1411
1460
  * type casts from PostgreSQL's wire format to Ruby objects on the fly,
@@ -1413,6 +1462,7 @@ pgresult_fields(VALUE self)
1413
1462
  *
1414
1463
  * +typemap+ must be a kind of PG::TypeMap .
1415
1464
  *
1465
+ * See also #map_types! and PG::BasicTypeMapForResults
1416
1466
  */
1417
1467
  static VALUE
1418
1468
  pgresult_type_map_set(VALUE self, VALUE typemap)
@@ -1435,7 +1485,8 @@ pgresult_type_map_set(VALUE self, VALUE typemap)
1435
1485
  * call-seq:
1436
1486
  * res.type_map -> value
1437
1487
  *
1438
- * Returns the TypeMap that is currently set for type casts of result values to ruby objects.
1488
+ * Returns the PG::TypeMap that is currently set for type casts of result values to ruby objects.
1489
+ * The default is retrieved from PG::Connection#type_map_for_results , which defaults to PG::TypeMapAllStrings .
1439
1490
  *
1440
1491
  */
1441
1492
  static VALUE
@@ -1528,6 +1579,9 @@ pgresult_stream_any(VALUE self, int (*yielder)(VALUE, int, int, void*), void* da
1528
1579
  return self;
1529
1580
  rb_raise( rb_eInvalidResultStatus, "PG::Result is not in single row mode");
1530
1581
  case PGRES_SINGLE_TUPLE:
1582
+ #ifdef HAVE_PQSETCHUNKEDROWSMODE
1583
+ case PGRES_TUPLES_CHUNK:
1584
+ #endif
1531
1585
  break;
1532
1586
  default:
1533
1587
  pg_result_check( self );
@@ -1572,8 +1626,8 @@ pgresult_stream_any(VALUE self, int (*yielder)(VALUE, int, int, void*), void* da
1572
1626
  * wrapping each row into a dedicated result object, it delivers data in nearly
1573
1627
  * the same speed as with ordinary results.
1574
1628
  *
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.
1629
+ * The base result must be in status +PGRES_SINGLE_TUPLE+ or +PGRES_TUPLES_CHUNK+.
1630
+ * It iterates over all tuples until the status changes to +PGRES_TUPLES_OK+.
1577
1631
  * A PG::Error is raised for any errors from the server.
1578
1632
  *
1579
1633
  * Row description data does not change while the iteration. All value retrieval
@@ -1707,10 +1761,8 @@ init_pg_result(void)
1707
1761
  rb_define_singleton_method(rb_cPGresult, "res_status", pgresult_s_res_status, 1);
1708
1762
  rb_define_method(rb_cPGresult, "error_message", pgresult_error_message, 0);
1709
1763
  rb_define_alias( rb_cPGresult, "result_error_message", "error_message");
1710
- #ifdef HAVE_PQRESULTVERBOSEERRORMESSAGE
1711
1764
  rb_define_method(rb_cPGresult, "verbose_error_message", pgresult_verbose_error_message, 2);
1712
1765
  rb_define_alias( rb_cPGresult, "result_verbose_error_message", "verbose_error_message");
1713
- #endif
1714
1766
  rb_define_method(rb_cPGresult, "error_field", pgresult_error_field, 1);
1715
1767
  rb_define_alias( rb_cPGresult, "result_error_field", "error_field" );
1716
1768
  rb_define_method(rb_cPGresult, "clear", pg_result_clear, 0);
@@ -163,6 +163,8 @@ pg_text_dec_integer(t_pg_coder *conv, const char *val, int len, int tuple, int f
163
163
  * This is a decoder class for conversion of PostgreSQL numeric types
164
164
  * to Ruby BigDecimal objects.
165
165
  *
166
+ * As soon as this class is used, it requires the 'bigdecimal' gem.
167
+ *
166
168
  */
167
169
  static VALUE
168
170
  pg_text_dec_numeric(t_pg_coder *conv, const char *val, int len, int tuple, int field, int enc_idx)
@@ -174,7 +176,7 @@ pg_text_dec_numeric(t_pg_coder *conv, const char *val, int len, int tuple, int f
174
176
  static VALUE
175
177
  init_pg_text_decoder_numeric(VALUE rb_mPG_TextDecoder)
176
178
  {
177
- rb_require("bigdecimal");
179
+ rb_funcall(rb_mPG, rb_intern("require_bigdecimal_without_warning"), 0);
178
180
  s_id_BigDecimal = rb_intern("BigDecimal");
179
181
 
180
182
  /* dummy = rb_define_class_under( rb_mPG_TextDecoder, "Numeric", rb_cPG_SimpleDecoder ); */
@@ -577,7 +579,7 @@ pg_text_dec_from_base64(t_pg_coder *conv, const char *val, int len, int tuple, i
577
579
  /* create a buffer of the expected decoded length */
578
580
  VALUE out_value = rb_str_new(NULL, BASE64_DECODED_SIZE(len));
579
581
 
580
- decoded_len = base64_decode( RSTRING_PTR(out_value), val, len );
582
+ decoded_len = rbpg_base64_decode( RSTRING_PTR(out_value), val, len );
581
583
  rb_str_set_len(out_value, decoded_len);
582
584
 
583
585
  /* Is it a pure String conversion? Then we can directly send out_value to the user. */
@@ -811,6 +813,7 @@ static VALUE pg_text_dec_timestamp(t_pg_coder *conv, const char *val, int len, i
811
813
  * This is a decoder class for conversion of PostgreSQL inet type
812
814
  * to Ruby IPAddr values.
813
815
  *
816
+ * As soon as this class is used, it requires the ruby standard library 'ipaddr'.
814
817
  */
815
818
  static VALUE
816
819
  pg_text_dec_inet(t_pg_coder *conv, const char *val, int len, int tuple, int field, int enc_idx)