pg 1.2.3 → 1.4.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (119) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/.appveyor.yml +42 -0
  4. data/.gems +6 -0
  5. data/.github/workflows/binary-gems.yml +117 -0
  6. data/.github/workflows/source-gem.yml +137 -0
  7. data/.gitignore +19 -0
  8. data/.hgsigs +34 -0
  9. data/.hgtags +41 -0
  10. data/.irbrc +23 -0
  11. data/.pryrc +23 -0
  12. data/.tm_properties +21 -0
  13. data/.travis.yml +49 -0
  14. data/Gemfile +14 -0
  15. data/History.md +804 -0
  16. data/Manifest.txt +0 -1
  17. data/README.ja.md +266 -0
  18. data/README.md +272 -0
  19. data/Rakefile +33 -135
  20. data/Rakefile.cross +12 -13
  21. data/certs/ged.pem +24 -0
  22. data/certs/larskanis-2022.pem +26 -0
  23. data/certs/larskanis-2023.pem +24 -0
  24. data/ext/errorcodes.def +12 -0
  25. data/ext/errorcodes.rb +0 -0
  26. data/ext/errorcodes.txt +4 -1
  27. data/ext/extconf.rb +100 -25
  28. data/ext/gvl_wrappers.c +4 -0
  29. data/ext/gvl_wrappers.h +23 -0
  30. data/ext/pg.c +62 -29
  31. data/ext/pg.h +20 -1
  32. data/ext/pg_binary_decoder.c +1 -1
  33. data/ext/pg_binary_encoder.c +1 -1
  34. data/ext/pg_coder.c +83 -29
  35. data/ext/pg_connection.c +953 -670
  36. data/ext/pg_copy_coder.c +46 -17
  37. data/ext/pg_errors.c +1 -1
  38. data/ext/pg_record_coder.c +46 -16
  39. data/ext/pg_result.c +88 -49
  40. data/ext/pg_text_decoder.c +2 -2
  41. data/ext/pg_text_encoder.c +7 -7
  42. data/ext/pg_tuple.c +50 -30
  43. data/ext/pg_type_map.c +42 -9
  44. data/ext/pg_type_map_all_strings.c +16 -2
  45. data/ext/pg_type_map_by_class.c +50 -25
  46. data/ext/pg_type_map_by_column.c +68 -30
  47. data/ext/pg_type_map_by_mri_type.c +48 -19
  48. data/ext/pg_type_map_by_oid.c +53 -24
  49. data/ext/pg_type_map_in_ruby.c +51 -20
  50. data/ext/pg_util.c +2 -2
  51. data/lib/pg/basic_type_map_based_on_result.rb +47 -0
  52. data/lib/pg/basic_type_map_for_queries.rb +193 -0
  53. data/lib/pg/basic_type_map_for_results.rb +81 -0
  54. data/lib/pg/basic_type_registry.rb +301 -0
  55. data/lib/pg/coder.rb +1 -1
  56. data/lib/pg/connection.rb +669 -81
  57. data/lib/pg/exceptions.rb +14 -1
  58. data/lib/pg/version.rb +4 -0
  59. data/lib/pg.rb +45 -36
  60. data/misc/openssl-pg-segfault.rb +31 -0
  61. data/misc/postgres/History.txt +9 -0
  62. data/misc/postgres/Manifest.txt +5 -0
  63. data/misc/postgres/README.txt +21 -0
  64. data/misc/postgres/Rakefile +21 -0
  65. data/misc/postgres/lib/postgres.rb +16 -0
  66. data/misc/ruby-pg/History.txt +9 -0
  67. data/misc/ruby-pg/Manifest.txt +5 -0
  68. data/misc/ruby-pg/README.txt +21 -0
  69. data/misc/ruby-pg/Rakefile +21 -0
  70. data/misc/ruby-pg/lib/ruby/pg.rb +16 -0
  71. data/pg.gemspec +34 -0
  72. data/rakelib/task_extension.rb +46 -0
  73. data/sample/array_insert.rb +20 -0
  74. data/sample/async_api.rb +102 -0
  75. data/sample/async_copyto.rb +39 -0
  76. data/sample/async_mixed.rb +56 -0
  77. data/sample/check_conn.rb +21 -0
  78. data/sample/copydata.rb +71 -0
  79. data/sample/copyfrom.rb +81 -0
  80. data/sample/copyto.rb +19 -0
  81. data/sample/cursor.rb +21 -0
  82. data/sample/disk_usage_report.rb +177 -0
  83. data/sample/issue-119.rb +94 -0
  84. data/sample/losample.rb +69 -0
  85. data/sample/minimal-testcase.rb +17 -0
  86. data/sample/notify_wait.rb +72 -0
  87. data/sample/pg_statistics.rb +285 -0
  88. data/sample/replication_monitor.rb +222 -0
  89. data/sample/test_binary_values.rb +33 -0
  90. data/sample/wal_shipper.rb +434 -0
  91. data/sample/warehouse_partitions.rb +311 -0
  92. data/translation/.po4a-version +7 -0
  93. data/translation/po/all.pot +875 -0
  94. data/translation/po/ja.po +868 -0
  95. data/translation/po4a.cfg +9 -0
  96. data.tar.gz.sig +0 -0
  97. metadata +120 -206
  98. metadata.gz.sig +0 -0
  99. data/ChangeLog +0 -0
  100. data/History.rdoc +0 -578
  101. data/README.ja.rdoc +0 -13
  102. data/README.rdoc +0 -213
  103. data/lib/pg/basic_type_mapping.rb +0 -522
  104. data/spec/data/expected_trace.out +0 -26
  105. data/spec/data/random_binary_data +0 -0
  106. data/spec/helpers.rb +0 -380
  107. data/spec/pg/basic_type_mapping_spec.rb +0 -630
  108. data/spec/pg/connection_spec.rb +0 -1949
  109. data/spec/pg/connection_sync_spec.rb +0 -41
  110. data/spec/pg/result_spec.rb +0 -681
  111. data/spec/pg/tuple_spec.rb +0 -333
  112. data/spec/pg/type_map_by_class_spec.rb +0 -138
  113. data/spec/pg/type_map_by_column_spec.rb +0 -226
  114. data/spec/pg/type_map_by_mri_type_spec.rb +0 -136
  115. data/spec/pg/type_map_by_oid_spec.rb +0 -149
  116. data/spec/pg/type_map_in_ruby_spec.rb +0 -164
  117. data/spec/pg/type_map_spec.rb +0 -22
  118. data/spec/pg/type_spec.rb +0 -1123
  119. data/spec/pg_spec.rb +0 -50
data/ext/pg_copy_coder.c CHANGED
@@ -21,18 +21,47 @@ typedef struct {
21
21
 
22
22
 
23
23
  static void
24
- pg_copycoder_mark( t_pg_copycoder *this )
24
+ pg_copycoder_mark( void *_this )
25
25
  {
26
- pg_coder_mark(&this->comp);
27
- rb_gc_mark(this->typemap);
28
- rb_gc_mark(this->null_string);
26
+ t_pg_copycoder *this = (t_pg_copycoder *)_this;
27
+ rb_gc_mark_movable(this->typemap);
28
+ rb_gc_mark_movable(this->null_string);
29
29
  }
30
30
 
31
+ static size_t
32
+ pg_copycoder_memsize( const void *_this )
33
+ {
34
+ const t_pg_copycoder *this = (const t_pg_copycoder *)_this;
35
+ return sizeof(*this);
36
+ }
37
+
38
+ static void
39
+ pg_copycoder_compact( void *_this )
40
+ {
41
+ t_pg_copycoder *this = (t_pg_copycoder *)_this;
42
+ pg_coder_compact(&this->comp);
43
+ pg_gc_location(this->typemap);
44
+ pg_gc_location(this->null_string);
45
+ }
46
+
47
+ static const rb_data_type_t pg_copycoder_type = {
48
+ "PG::CopyCoder",
49
+ {
50
+ pg_copycoder_mark,
51
+ RUBY_TYPED_DEFAULT_FREE,
52
+ pg_copycoder_memsize,
53
+ pg_compact_callback(pg_copycoder_compact),
54
+ },
55
+ &pg_coder_type,
56
+ 0,
57
+ RUBY_TYPED_FREE_IMMEDIATELY,
58
+ };
59
+
31
60
  static VALUE
32
61
  pg_copycoder_encoder_allocate( VALUE klass )
33
62
  {
34
63
  t_pg_copycoder *this;
35
- VALUE self = Data_Make_Struct( klass, t_pg_copycoder, pg_copycoder_mark, -1, this );
64
+ VALUE self = TypedData_Make_Struct( klass, t_pg_copycoder, &pg_copycoder_type, this );
36
65
  pg_coder_init_encoder( self );
37
66
  this->typemap = pg_typemap_all_strings;
38
67
  this->delimiter = '\t';
@@ -44,7 +73,7 @@ static VALUE
44
73
  pg_copycoder_decoder_allocate( VALUE klass )
45
74
  {
46
75
  t_pg_copycoder *this;
47
- VALUE self = Data_Make_Struct( klass, t_pg_copycoder, pg_copycoder_mark, -1, this );
76
+ VALUE self = TypedData_Make_Struct( klass, t_pg_copycoder, &pg_copycoder_type, this );
48
77
  pg_coder_init_decoder( self );
49
78
  this->typemap = pg_typemap_all_strings;
50
79
  this->delimiter = '\t';
@@ -63,7 +92,7 @@ pg_copycoder_decoder_allocate( VALUE klass )
63
92
  static VALUE
64
93
  pg_copycoder_delimiter_set(VALUE self, VALUE delimiter)
65
94
  {
66
- t_pg_copycoder *this = DATA_PTR(self);
95
+ t_pg_copycoder *this = RTYPEDDATA_DATA(self);
67
96
  StringValue(delimiter);
68
97
  if(RSTRING_LEN(delimiter) != 1)
69
98
  rb_raise( rb_eArgError, "delimiter size must be one byte");
@@ -80,7 +109,7 @@ pg_copycoder_delimiter_set(VALUE self, VALUE delimiter)
80
109
  static VALUE
81
110
  pg_copycoder_delimiter_get(VALUE self)
82
111
  {
83
- t_pg_copycoder *this = DATA_PTR(self);
112
+ t_pg_copycoder *this = RTYPEDDATA_DATA(self);
84
113
  return rb_str_new(&this->delimiter, 1);
85
114
  }
86
115
 
@@ -93,7 +122,7 @@ pg_copycoder_delimiter_get(VALUE self)
93
122
  static VALUE
94
123
  pg_copycoder_null_string_set(VALUE self, VALUE null_string)
95
124
  {
96
- t_pg_copycoder *this = DATA_PTR(self);
125
+ t_pg_copycoder *this = RTYPEDDATA_DATA(self);
97
126
  StringValue(null_string);
98
127
  this->null_string = null_string;
99
128
  return null_string;
@@ -105,7 +134,7 @@ pg_copycoder_null_string_set(VALUE self, VALUE null_string)
105
134
  static VALUE
106
135
  pg_copycoder_null_string_get(VALUE self)
107
136
  {
108
- t_pg_copycoder *this = DATA_PTR(self);
137
+ t_pg_copycoder *this = RTYPEDDATA_DATA(self);
109
138
  return this->null_string;
110
139
  }
111
140
 
@@ -123,7 +152,7 @@ pg_copycoder_null_string_get(VALUE self)
123
152
  static VALUE
124
153
  pg_copycoder_type_map_set(VALUE self, VALUE type_map)
125
154
  {
126
- t_pg_copycoder *this = DATA_PTR( self );
155
+ t_pg_copycoder *this = RTYPEDDATA_DATA( self );
127
156
 
128
157
  if ( !rb_obj_is_kind_of(type_map, rb_cTypeMap) ){
129
158
  rb_raise( rb_eTypeError, "wrong elements type %s (expected some kind of PG::TypeMap)",
@@ -143,7 +172,7 @@ pg_copycoder_type_map_set(VALUE self, VALUE type_map)
143
172
  static VALUE
144
173
  pg_copycoder_type_map_get(VALUE self)
145
174
  {
146
- t_pg_copycoder *this = DATA_PTR( self );
175
+ t_pg_copycoder *this = RTYPEDDATA_DATA( self );
147
176
 
148
177
  return this->typemap;
149
178
  }
@@ -188,7 +217,7 @@ pg_text_enc_copy_row(t_pg_coder *conv, VALUE value, char *out, VALUE *intermedia
188
217
  char *current_out;
189
218
  char *end_capa_ptr;
190
219
 
191
- p_typemap = DATA_PTR( this->typemap );
220
+ p_typemap = RTYPEDDATA_DATA( this->typemap );
192
221
  p_typemap->funcs.fit_to_query( this->typemap, value );
193
222
 
194
223
  /* Allocate a new string with embedded capacity and realloc exponential when needed. */
@@ -225,7 +254,7 @@ pg_text_enc_copy_row(t_pg_coder *conv, VALUE value, char *out, VALUE *intermedia
225
254
 
226
255
  if( strlen == -1 ){
227
256
  /* we can directly use String value in subint */
228
- strlen = RSTRING_LEN(subint);
257
+ strlen = RSTRING_LENINT(subint);
229
258
 
230
259
  /* size of string assuming the worst case, that every character must be escaped. */
231
260
  PG_RB_STR_ENSURE_CAPA( *intermediate, strlen * 2, current_out, end_capa_ptr );
@@ -376,7 +405,7 @@ pg_text_dec_copy_row(t_pg_coder *conv, const char *input_line, int len, int _tup
376
405
  char *end_capa_ptr;
377
406
  t_typemap *p_typemap;
378
407
 
379
- p_typemap = DATA_PTR( this->typemap );
408
+ p_typemap = RTYPEDDATA_DATA( this->typemap );
380
409
  expected_fields = p_typemap->funcs.fit_to_copy_get( this->typemap );
381
410
 
382
411
  /* The received input string will probably have this->nfields fields. */
@@ -397,7 +426,7 @@ pg_text_dec_copy_row(t_pg_coder *conv, const char *input_line, int len, int _tup
397
426
  int found_delim = 0;
398
427
  const char *start_ptr;
399
428
  const char *end_ptr;
400
- int input_len;
429
+ long input_len;
401
430
 
402
431
  /* Remember start of field on input side */
403
432
  start_ptr = cur_ptr;
@@ -563,7 +592,7 @@ pg_text_dec_copy_row(t_pg_coder *conv, const char *input_line, int len, int _tup
563
592
 
564
593
 
565
594
  void
566
- init_pg_copycoder()
595
+ init_pg_copycoder(void)
567
596
  {
568
597
  /* Document-class: PG::CopyCoder < PG::Coder
569
598
  *
data/ext/pg_errors.c CHANGED
@@ -70,7 +70,7 @@ lookup_error_class(const char *sqlstate)
70
70
  }
71
71
 
72
72
  void
73
- init_pg_errors()
73
+ init_pg_errors(void)
74
74
  {
75
75
  rb_hErrors = rb_hash_new();
76
76
  rb_define_const( rb_mPG, "ERROR_CLASSES", rb_hErrors );
@@ -16,17 +16,45 @@ typedef struct {
16
16
 
17
17
 
18
18
  static void
19
- pg_recordcoder_mark( t_pg_recordcoder *this )
19
+ pg_recordcoder_mark( void *_this )
20
20
  {
21
- pg_coder_mark(&this->comp);
22
- rb_gc_mark(this->typemap);
21
+ t_pg_recordcoder *this = (t_pg_recordcoder *)_this;
22
+ rb_gc_mark_movable(this->typemap);
23
23
  }
24
24
 
25
+ static size_t
26
+ pg_recordcoder_memsize( const void *_this )
27
+ {
28
+ const t_pg_recordcoder *this = (const t_pg_recordcoder *)_this;
29
+ return sizeof(*this);
30
+ }
31
+
32
+ static void
33
+ pg_recordcoder_compact( void *_this )
34
+ {
35
+ t_pg_recordcoder *this = (t_pg_recordcoder *)_this;
36
+ pg_coder_compact(&this->comp);
37
+ pg_gc_location(this->typemap);
38
+ }
39
+
40
+ static const rb_data_type_t pg_recordcoder_type = {
41
+ "PG::RecordCoder",
42
+ {
43
+ pg_recordcoder_mark,
44
+ RUBY_TYPED_DEFAULT_FREE,
45
+ pg_recordcoder_memsize,
46
+ pg_compact_callback(pg_recordcoder_compact),
47
+ },
48
+ &pg_coder_type,
49
+ 0,
50
+ RUBY_TYPED_FREE_IMMEDIATELY,
51
+ };
52
+
25
53
  static VALUE
26
54
  pg_recordcoder_encoder_allocate( VALUE klass )
27
55
  {
28
56
  t_pg_recordcoder *this;
29
- VALUE self = Data_Make_Struct( klass, t_pg_recordcoder, pg_recordcoder_mark, -1, this );
57
+ VALUE self = TypedData_Make_Struct( klass, t_pg_recordcoder, &pg_recordcoder_type, this );
30
58
  pg_coder_init_encoder( self );
31
59
  this->typemap = pg_typemap_all_strings;
32
60
  return self;
@@ -36,7 +64,7 @@ static VALUE
36
64
  pg_recordcoder_decoder_allocate( VALUE klass )
37
65
  {
38
66
  t_pg_recordcoder *this;
39
- VALUE self = Data_Make_Struct( klass, t_pg_recordcoder, pg_recordcoder_mark, -1, this );
67
+ VALUE self = TypedData_Make_Struct( klass, t_pg_recordcoder, &pg_recordcoder_type, this );
40
68
  pg_coder_init_decoder( self );
41
69
  this->typemap = pg_typemap_all_strings;
42
70
  return self;
@@ -56,7 +84,7 @@ pg_recordcoder_decoder_allocate( VALUE klass )
56
84
  static VALUE
57
85
  pg_recordcoder_type_map_set(VALUE self, VALUE type_map)
58
86
  {
59
- t_pg_recordcoder *this = DATA_PTR( self );
87
+ t_pg_recordcoder *this = RTYPEDDATA_DATA( self );
60
88
 
61
89
  if ( !rb_obj_is_kind_of(type_map, rb_cTypeMap) ){
62
90
  rb_raise( rb_eTypeError, "wrong elements type %s (expected some kind of PG::TypeMap)",
@@ -76,7 +104,7 @@ pg_recordcoder_type_map_set(VALUE self, VALUE type_map)
76
104
  static VALUE
77
105
  pg_recordcoder_type_map_get(VALUE self)
78
106
  {
79
- t_pg_recordcoder *this = DATA_PTR( self );
107
+ t_pg_recordcoder *this = RTYPEDDATA_DATA( self );
80
108
 
81
109
  return this->typemap;
82
110
  }
@@ -106,7 +134,7 @@ pg_recordcoder_type_map_get(VALUE self)
106
134
  * tm = PG::TypeMapByColumn.new([PG::TextEncoder::Float.new]*2)
107
135
  * # Use this type map to encode the record:
108
136
  * PG::TextEncoder::Record.new(type_map: tm).encode([1,2])
109
- * # => "(\"1.0000000000000000E+00\",\"2.0000000000000000E+00\")"
137
+ * # => "(\"1.0\",\"2.0\")"
110
138
  *
111
139
  * Records can also be encoded and decoded directly to and from the database.
112
140
  * This avoids intermediate string allocations and is very fast.
@@ -156,7 +184,7 @@ pg_text_enc_record(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate
156
184
  char *current_out;
157
185
  char *end_capa_ptr;
158
186
 
159
- p_typemap = DATA_PTR( this->typemap );
187
+ p_typemap = RTYPEDDATA_DATA( this->typemap );
160
188
  p_typemap->funcs.fit_to_query( this->typemap, value );
161
189
 
162
190
  /* Allocate a new string with embedded capacity and realloc exponential when needed. */
@@ -168,7 +196,7 @@ pg_text_enc_record(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate
168
196
  for( i=0; i<RARRAY_LEN(value); i++){
169
197
  char *ptr1;
170
198
  char *ptr2;
171
- int strlen;
199
+ long strlen;
172
200
  int backslashs;
173
201
  VALUE subint;
174
202
  VALUE entry;
@@ -316,10 +344,12 @@ record_isspace(char ch)
316
344
  * oids = conn.exec( "SELECT (NULL::complex).*" )
317
345
  * # Build a type map (PG::TypeMapByColumn) for decoding the "complex" type
318
346
  * dtm = PG::BasicTypeMapForResults.new(conn).build_column_map( oids )
319
- * # Register a record decoder for decoding our type "complex"
320
- * PG::BasicTypeRegistry.register_coder(PG::TextDecoder::Record.new(type_map: dtm, name: "complex"))
321
- * # Apply the basic type registry to all results retrieved from the server
322
- * conn.type_map_for_results = PG::BasicTypeMapForResults.new(conn)
347
+ * # Build a type map and populate with basic types
348
+ * btr = PG::BasicTypeRegistry.new.register_default_types
349
+ * # Register a new record decoder for decoding our type "complex"
350
+ * btr.register_coder(PG::TextDecoder::Record.new(type_map: dtm, name: "complex"))
351
+ * # Apply our basic type registry to all results retrieved from the server
352
+ * conn.type_map_for_results = PG::BasicTypeMapForResults.new(conn, registry: btr)
323
353
  * # Now queries decode the "complex" type (and many basic types) automatically
324
354
  * conn.exec("SELECT * FROM my_table").to_a
325
355
  * # => [{"v1"=>[2.0, 3.0], "v2"=>[4.0, 5.0]}, {"v1"=>[6.0, 7.0], "v2"=>[8.0, 9.0]}]
@@ -358,7 +388,7 @@ pg_text_dec_record(t_pg_coder *conv, char *input_line, int len, int _tuple, int
358
388
  char *end_capa_ptr;
359
389
  t_typemap *p_typemap;
360
390
 
361
- p_typemap = DATA_PTR( this->typemap );
391
+ p_typemap = RTYPEDDATA_DATA( this->typemap );
362
392
  expected_fields = p_typemap->funcs.fit_to_copy_get( this->typemap );
363
393
 
364
394
  /* The received input string will probably have this->nfields fields. */
@@ -464,7 +494,7 @@ pg_text_dec_record(t_pg_coder *conv, char *input_line, int len, int _tuple, int
464
494
 
465
495
 
466
496
  void
467
- init_pg_recordcoder()
497
+ init_pg_recordcoder(void)
468
498
  {
469
499
  /* Document-class: PG::RecordCoder < PG::Coder
470
500
  *
data/ext/pg_result.c CHANGED
@@ -107,17 +107,34 @@ pgresult_approx_size(const PGresult *result)
107
107
  * GC Mark function
108
108
  */
109
109
  static void
110
- pgresult_gc_mark( t_pg_result *this )
110
+ pgresult_gc_mark( void *_this )
111
111
  {
112
+ t_pg_result *this = (t_pg_result *)_this;
112
113
  int i;
113
114
 
114
- rb_gc_mark( this->connection );
115
- rb_gc_mark( this->typemap );
116
- rb_gc_mark( this->tuple_hash );
117
- rb_gc_mark( this->field_map );
115
+ rb_gc_mark_movable( this->connection );
116
+ rb_gc_mark_movable( this->typemap );
117
+ rb_gc_mark_movable( this->tuple_hash );
118
+ rb_gc_mark_movable( this->field_map );
118
119
 
119
120
  for( i=0; i < this->nfields; i++ ){
120
- rb_gc_mark( this->fnames[i] );
121
+ rb_gc_mark_movable( this->fnames[i] );
122
+ }
123
+ }
124
+
125
+ static void
126
+ pgresult_gc_compact( void *_this )
127
+ {
128
+ t_pg_result *this = (t_pg_result *)_this;
129
+ int i;
130
+
131
+ pg_gc_location( this->connection );
132
+ pg_gc_location( this->typemap );
133
+ pg_gc_location( this->tuple_hash );
134
+ pg_gc_location( this->field_map );
135
+
136
+ for( i=0; i < this->nfields; i++ ){
137
+ pg_gc_location( this->fnames[i] );
121
138
  }
122
139
  }
123
140
 
@@ -125,8 +142,9 @@ pgresult_gc_mark( t_pg_result *this )
125
142
  * GC Free function
126
143
  */
127
144
  static void
128
- pgresult_clear( t_pg_result *this )
145
+ pgresult_clear( void *_this )
129
146
  {
147
+ t_pg_result *this = (t_pg_result *)_this;
130
148
  if( this->pgresult && !this->autoclear ){
131
149
  PQclear(this->pgresult);
132
150
  #ifdef HAVE_RB_GC_ADJUST_MEMORY_USAGE
@@ -139,15 +157,17 @@ pgresult_clear( t_pg_result *this )
139
157
  }
140
158
 
141
159
  static void
142
- pgresult_gc_free( t_pg_result *this )
160
+ pgresult_gc_free( void *_this )
143
161
  {
162
+ t_pg_result *this = (t_pg_result *)_this;
144
163
  pgresult_clear( this );
145
164
  xfree(this);
146
165
  }
147
166
 
148
167
  static size_t
149
- pgresult_memsize( t_pg_result *this )
168
+ pgresult_memsize( const void *_this )
150
169
  {
170
+ const t_pg_result *this = (const t_pg_result *)_this;
151
171
  /* Ideally the memory 'this' is pointing to should be taken into account as well.
152
172
  * However we don't want to store two memory sizes in t_pg_result just for reporting by ObjectSpace.memsize_of.
153
173
  */
@@ -155,16 +175,15 @@ pgresult_memsize( t_pg_result *this )
155
175
  }
156
176
 
157
177
  static const rb_data_type_t pgresult_type = {
158
- "pg",
178
+ "PG::Result",
159
179
  {
160
- (void (*)(void*))pgresult_gc_mark,
161
- (void (*)(void*))pgresult_gc_free,
162
- (size_t (*)(const void *))pgresult_memsize,
180
+ pgresult_gc_mark,
181
+ pgresult_gc_free,
182
+ pgresult_memsize,
183
+ pg_compact_callback(pgresult_gc_compact),
163
184
  },
164
185
  0, 0,
165
- #ifdef RUBY_TYPED_FREE_IMMEDIATELY
166
186
  RUBY_TYPED_FREE_IMMEDIATELY,
167
- #endif
168
187
  };
169
188
 
170
189
  /* Needed by sequel_pg gem, do not delete */
@@ -191,7 +210,7 @@ pg_new_result2(PGresult *result, VALUE rb_pgconn)
191
210
  this->pgresult = result;
192
211
  this->connection = rb_pgconn;
193
212
  this->typemap = pg_typemap_all_strings;
194
- this->p_typemap = DATA_PTR( this->typemap );
213
+ this->p_typemap = RTYPEDDATA_DATA( this->typemap );
195
214
  this->nfields = -1;
196
215
  this->tuple_hash = Qnil;
197
216
  this->field_map = Qnil;
@@ -202,11 +221,11 @@ pg_new_result2(PGresult *result, VALUE rb_pgconn)
202
221
  t_pg_connection *p_conn = pg_get_connection(rb_pgconn);
203
222
  VALUE typemap = p_conn->type_map_for_results;
204
223
  /* Type check is done when assigned to PG::Connection. */
205
- t_typemap *p_typemap = DATA_PTR(typemap);
224
+ t_typemap *p_typemap = RTYPEDDATA_DATA(typemap);
206
225
 
207
226
  this->enc_idx = p_conn->enc_idx;
208
227
  this->typemap = p_typemap->funcs.fit_to_result( typemap, self );
209
- this->p_typemap = DATA_PTR( this->typemap );
228
+ this->p_typemap = RTYPEDDATA_DATA( this->typemap );
210
229
  this->flags = p_conn->flags;
211
230
  } else {
212
231
  this->enc_idx = rb_locale_encindex();
@@ -270,7 +289,11 @@ pg_new_result_autoclear(PGresult *result, VALUE rb_pgconn)
270
289
  * call-seq:
271
290
  * res.check -> nil
272
291
  *
273
- * Raises appropriate exception if PG::Result is in a bad state.
292
+ * Raises appropriate exception if PG::Result is in a bad state, which is:
293
+ * * +PGRES_BAD_RESPONSE+
294
+ * * +PGRES_FATAL_ERROR+
295
+ * * +PGRES_NONFATAL_ERROR+
296
+ * * +PGRES_PIPELINE_ABORTED+
274
297
  */
275
298
  VALUE
276
299
  pg_result_check( VALUE self )
@@ -295,10 +318,16 @@ pg_result_check( VALUE self )
295
318
  case PGRES_SINGLE_TUPLE:
296
319
  case PGRES_EMPTY_QUERY:
297
320
  case PGRES_COMMAND_OK:
321
+ #ifdef HAVE_PQENTERPIPELINEMODE
322
+ case PGRES_PIPELINE_SYNC:
323
+ #endif
298
324
  return self;
299
325
  case PGRES_BAD_RESPONSE:
300
326
  case PGRES_FATAL_ERROR:
301
327
  case PGRES_NONFATAL_ERROR:
328
+ #ifdef HAVE_PQENTERPIPELINEMODE
329
+ case PGRES_PIPELINE_ABORTED:
330
+ #endif
302
331
  error = rb_str_new2( PQresultErrorMessage(this->pgresult) );
303
332
  break;
304
333
  default:
@@ -353,7 +382,7 @@ pg_result_clear(VALUE self)
353
382
  * call-seq:
354
383
  * res.cleared? -> boolean
355
384
  *
356
- * Returns +true+ if the backend result memory has been free'd.
385
+ * Returns +true+ if the backend result memory has been freed.
357
386
  */
358
387
  VALUE
359
388
  pgresult_cleared_p( VALUE self )
@@ -367,7 +396,7 @@ pgresult_cleared_p( VALUE self )
367
396
  * res.autoclear? -> boolean
368
397
  *
369
398
  * Returns +true+ if the underlying C struct will be cleared at the end of a callback.
370
- * This applies only to Result objects received by the block to PG::Cinnection#set_notice_receiver .
399
+ * This applies only to Result objects received by the block to PG::Connection#set_notice_receiver .
371
400
  *
372
401
  * All other Result objects are automatically cleared by the GC when the object is no longer in use or manually by PG::Result#clear .
373
402
  *
@@ -495,6 +524,9 @@ static void pgresult_init_fnames(VALUE self)
495
524
  * * +PGRES_NONFATAL_ERROR+
496
525
  * * +PGRES_FATAL_ERROR+
497
526
  * * +PGRES_COPY_BOTH+
527
+ * * +PGRES_SINGLE_TUPLE+
528
+ * * +PGRES_PIPELINE_SYNC+
529
+ * * +PGRES_PIPELINE_ABORTED+
498
530
  */
499
531
  static VALUE
500
532
  pgresult_result_status(VALUE self)
@@ -506,7 +538,7 @@ pgresult_result_status(VALUE self)
506
538
  * call-seq:
507
539
  * res.res_status( status ) -> String
508
540
  *
509
- * Returns the string representation of status +status+.
541
+ * Returns the string representation of +status+.
510
542
  *
511
543
  */
512
544
  static VALUE
@@ -1003,7 +1035,7 @@ pgresult_cmd_tuples(VALUE self)
1003
1035
  {
1004
1036
  long n;
1005
1037
  n = strtol(PQcmdTuples(pgresult_get(self)),NULL, 10);
1006
- return INT2NUM(n);
1038
+ return LONG2NUM(n);
1007
1039
  }
1008
1040
 
1009
1041
  /*
@@ -1325,14 +1357,11 @@ pgresult_type_map_set(VALUE self, VALUE typemap)
1325
1357
  t_pg_result *this = pgresult_get_this(self);
1326
1358
  t_typemap *p_typemap;
1327
1359
 
1328
- if ( !rb_obj_is_kind_of(typemap, rb_cTypeMap) ) {
1329
- rb_raise( rb_eTypeError, "wrong argument type %s (expected kind of PG::TypeMap)",
1330
- rb_obj_classname( typemap ) );
1331
- }
1332
- Data_Get_Struct(typemap, t_typemap, p_typemap);
1360
+ /* Check type of method param */
1361
+ TypedData_Get_Struct(typemap, t_typemap, &pg_typemap_type, p_typemap);
1333
1362
 
1334
1363
  this->typemap = p_typemap->funcs.fit_to_result( typemap, self );
1335
- this->p_typemap = DATA_PTR( this->typemap );
1364
+ this->p_typemap = RTYPEDDATA_DATA( this->typemap );
1336
1365
 
1337
1366
  return typemap;
1338
1367
  }
@@ -1353,22 +1382,21 @@ pgresult_type_map_get(VALUE self)
1353
1382
  }
1354
1383
 
1355
1384
 
1356
- static void
1357
- yield_hash(VALUE self, int ntuples, int nfields)
1385
+ static int
1386
+ yield_hash(VALUE self, int ntuples, int nfields, void *data)
1358
1387
  {
1359
1388
  int tuple_num;
1360
- t_pg_result *this = pgresult_get_this(self);
1361
1389
  UNUSED(nfields);
1362
1390
 
1363
1391
  for(tuple_num = 0; tuple_num < ntuples; tuple_num++) {
1364
1392
  rb_yield(pgresult_aref(self, INT2NUM(tuple_num)));
1365
1393
  }
1366
1394
 
1367
- pgresult_clear( this );
1395
+ return 1; /* clear the result */
1368
1396
  }
1369
1397
 
1370
- static void
1371
- yield_array(VALUE self, int ntuples, int nfields)
1398
+ static int
1399
+ yield_array(VALUE self, int ntuples, int nfields, void *data)
1372
1400
  {
1373
1401
  int row;
1374
1402
  t_pg_result *this = pgresult_get_this(self);
@@ -1384,11 +1412,11 @@ yield_array(VALUE self, int ntuples, int nfields)
1384
1412
  rb_yield( rb_ary_new4( nfields, row_values ));
1385
1413
  }
1386
1414
 
1387
- pgresult_clear( this );
1415
+ return 1; /* clear the result */
1388
1416
  }
1389
1417
 
1390
- static void
1391
- yield_tuple(VALUE self, int ntuples, int nfields)
1418
+ static int
1419
+ yield_tuple(VALUE self, int ntuples, int nfields, void *data)
1392
1420
  {
1393
1421
  int tuple_num;
1394
1422
  t_pg_result *this = pgresult_get_this(self);
@@ -1405,10 +1433,12 @@ yield_tuple(VALUE self, int ntuples, int nfields)
1405
1433
  VALUE tuple = pgresult_tuple(copy, INT2FIX(tuple_num));
1406
1434
  rb_yield( tuple );
1407
1435
  }
1436
+ return 0; /* don't clear the result */
1408
1437
  }
1409
1438
 
1410
- static VALUE
1411
- pgresult_stream_any(VALUE self, void (*yielder)(VALUE, int, int))
1439
+ /* Non-static, and data pointer for use by sequel_pg */
1440
+ VALUE
1441
+ pgresult_stream_any(VALUE self, int (*yielder)(VALUE, int, int, void*), void* data)
1412
1442
  {
1413
1443
  t_pg_result *this;
1414
1444
  int nfields;
@@ -1427,6 +1457,7 @@ pgresult_stream_any(VALUE self, void (*yielder)(VALUE, int, int))
1427
1457
 
1428
1458
  switch( PQresultStatus(pgresult) ){
1429
1459
  case PGRES_TUPLES_OK:
1460
+ case PGRES_COMMAND_OK:
1430
1461
  if( ntuples == 0 )
1431
1462
  return self;
1432
1463
  rb_raise( rb_eInvalidResultStatus, "PG::Result is not in single row mode");
@@ -1436,14 +1467,21 @@ pgresult_stream_any(VALUE self, void (*yielder)(VALUE, int, int))
1436
1467
  pg_result_check( self );
1437
1468
  }
1438
1469
 
1439
- yielder( self, ntuples, nfields );
1470
+ if( yielder( self, ntuples, nfields, data ) ){
1471
+ pgresult_clear( this );
1472
+ }
1473
+
1474
+ if( gvl_PQisBusy(pgconn) ){
1475
+ /* wait for input (without blocking) before reading each result */
1476
+ pgconn_block( 0, NULL, this->connection );
1477
+ }
1440
1478
 
1441
1479
  pgresult = gvl_PQgetResult(pgconn);
1442
1480
  if( pgresult == NULL )
1443
- rb_raise( rb_eNoResultError, "no result received - possibly an intersection with another result retrieval");
1481
+ rb_raise( rb_eNoResultError, "no result received - possibly an intersection with another query");
1444
1482
 
1445
1483
  if( nfields != PQnfields(pgresult) )
1446
- rb_raise( rb_eInvalidChangeOfResultFields, "number of fields must not change in single row mode");
1484
+ rb_raise( rb_eInvalidChangeOfResultFields, "number of fields changed in single row mode from %d to %d - this is a sign for intersection with another query", nfields, PQnfields(pgresult));
1447
1485
 
1448
1486
  this->pgresult = pgresult;
1449
1487
  }
@@ -1487,7 +1525,7 @@ pgresult_stream_any(VALUE self, void (*yielder)(VALUE, int, int))
1487
1525
  static VALUE
1488
1526
  pgresult_stream_each(VALUE self)
1489
1527
  {
1490
- return pgresult_stream_any(self, yield_hash);
1528
+ return pgresult_stream_any(self, yield_hash, NULL);
1491
1529
  }
1492
1530
 
1493
1531
  /*
@@ -1503,7 +1541,7 @@ pgresult_stream_each(VALUE self)
1503
1541
  static VALUE
1504
1542
  pgresult_stream_each_row(VALUE self)
1505
1543
  {
1506
- return pgresult_stream_any(self, yield_array);
1544
+ return pgresult_stream_any(self, yield_array, NULL);
1507
1545
  }
1508
1546
 
1509
1547
  /*
@@ -1520,7 +1558,7 @@ pgresult_stream_each_tuple(VALUE self)
1520
1558
  /* allocate VALUEs that are shared between all streamed tuples */
1521
1559
  ensure_init_for_tuple(self);
1522
1560
 
1523
- return pgresult_stream_any(self, yield_tuple);
1561
+ return pgresult_stream_any(self, yield_tuple, NULL);
1524
1562
  }
1525
1563
 
1526
1564
  /*
@@ -1531,7 +1569,7 @@ pgresult_stream_each_tuple(VALUE self)
1531
1569
  * It can be set to one of:
1532
1570
  * * +:string+ to use String based field names
1533
1571
  * * +:symbol+ to use Symbol based field names
1534
- * * +:static_symbol+ to use pinned Symbol (can not be garbage collected) - Don't use this, it will probably removed in future.
1572
+ * * +:static_symbol+ to use pinned Symbol (can not be garbage collected) - Don't use this, it will probably be removed in future.
1535
1573
  *
1536
1574
  * The default is retrieved from PG::Connection#field_name_type , which defaults to +:string+ .
1537
1575
  *
@@ -1581,13 +1619,14 @@ pgresult_field_name_type_get(VALUE self)
1581
1619
  }
1582
1620
 
1583
1621
  void
1584
- init_pg_result()
1622
+ init_pg_result(void)
1585
1623
  {
1586
1624
  sym_string = ID2SYM(rb_intern("string"));
1587
1625
  sym_symbol = ID2SYM(rb_intern("symbol"));
1588
1626
  sym_static_symbol = ID2SYM(rb_intern("static_symbol"));
1589
1627
 
1590
- rb_cPGresult = rb_define_class_under( rb_mPG, "Result", rb_cData );
1628
+ rb_cPGresult = rb_define_class_under( rb_mPG, "Result", rb_cObject );
1629
+ rb_undef_alloc_func(rb_cPGresult);
1591
1630
  rb_include_module(rb_cPGresult, rb_mEnumerable);
1592
1631
  rb_include_module(rb_cPGresult, rb_mPGconstants);
1593
1632
 
@@ -854,7 +854,7 @@ pg_text_dec_inet(t_pg_coder *conv, const char *val, int len, int tuple, int fiel
854
854
 
855
855
  ip_int_native = read_nbo32(dst);
856
856
 
857
- /* Work around broken IPAddr behavior of convering portion
857
+ /* Work around broken IPAddr behavior of converting portion
858
858
  of address after netmask to 0 */
859
859
  switch (mask) {
860
860
  case 0:
@@ -923,7 +923,7 @@ pg_text_dec_inet(t_pg_coder *conv, const char *val, int len, int tuple, int fiel
923
923
  }
924
924
 
925
925
  void
926
- init_pg_text_decoder()
926
+ init_pg_text_decoder(void)
927
927
  {
928
928
  rb_require("ipaddr");
929
929
  s_IPAddr = rb_funcall(rb_cObject, rb_intern("const_get"), 1, rb_str_new2("IPAddr"));