pg 1.2.3 → 1.3.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/.appveyor.yml +36 -0
- data/.gems +6 -0
- data/.github/workflows/binary-gems.yml +86 -0
- data/.github/workflows/source-gem.yml +129 -0
- data/.gitignore +13 -0
- data/.hgsigs +34 -0
- data/.hgtags +41 -0
- data/.irbrc +23 -0
- data/.pryrc +23 -0
- data/.tm_properties +21 -0
- data/.travis.yml +49 -0
- data/Gemfile +14 -0
- data/History.rdoc +153 -7
- data/Manifest.txt +0 -1
- data/README.rdoc +7 -6
- data/Rakefile +27 -138
- data/Rakefile.cross +8 -5
- data/certs/ged.pem +24 -0
- data/certs/larskanis-2022.pem +26 -0
- data/ext/errorcodes.def +8 -0
- data/ext/errorcodes.rb +0 -0
- data/ext/errorcodes.txt +3 -1
- data/ext/extconf.rb +131 -25
- data/ext/gvl_wrappers.c +4 -0
- data/ext/gvl_wrappers.h +23 -0
- data/ext/pg.c +59 -4
- data/ext/pg.h +19 -1
- data/ext/pg_coder.c +82 -28
- data/ext/pg_connection.c +680 -508
- data/ext/pg_copy_coder.c +45 -16
- data/ext/pg_record_coder.c +45 -15
- data/ext/pg_result.c +77 -40
- data/ext/pg_text_decoder.c +1 -1
- data/ext/pg_text_encoder.c +6 -6
- data/ext/pg_tuple.c +49 -29
- data/ext/pg_type_map.c +41 -8
- data/ext/pg_type_map_all_strings.c +15 -1
- data/ext/pg_type_map_by_class.c +49 -24
- data/ext/pg_type_map_by_column.c +66 -28
- data/ext/pg_type_map_by_mri_type.c +47 -18
- data/ext/pg_type_map_by_oid.c +52 -23
- data/ext/pg_type_map_in_ruby.c +50 -19
- data/ext/pg_util.c +2 -2
- data/lib/pg/basic_type_map_based_on_result.rb +47 -0
- data/lib/pg/basic_type_map_for_queries.rb +193 -0
- data/lib/pg/basic_type_map_for_results.rb +81 -0
- data/lib/pg/basic_type_registry.rb +301 -0
- data/lib/pg/coder.rb +1 -1
- data/lib/pg/connection.rb +589 -58
- data/lib/pg/version.rb +4 -0
- data/lib/pg.rb +47 -32
- data/misc/openssl-pg-segfault.rb +31 -0
- data/misc/postgres/History.txt +9 -0
- data/misc/postgres/Manifest.txt +5 -0
- data/misc/postgres/README.txt +21 -0
- data/misc/postgres/Rakefile +21 -0
- data/misc/postgres/lib/postgres.rb +16 -0
- data/misc/ruby-pg/History.txt +9 -0
- data/misc/ruby-pg/Manifest.txt +5 -0
- data/misc/ruby-pg/README.txt +21 -0
- data/misc/ruby-pg/Rakefile +21 -0
- data/misc/ruby-pg/lib/ruby/pg.rb +16 -0
- data/pg.gemspec +32 -0
- data/rakelib/task_extension.rb +46 -0
- data/sample/array_insert.rb +20 -0
- data/sample/async_api.rb +102 -0
- data/sample/async_copyto.rb +39 -0
- data/sample/async_mixed.rb +56 -0
- data/sample/check_conn.rb +21 -0
- data/sample/copydata.rb +71 -0
- data/sample/copyfrom.rb +81 -0
- data/sample/copyto.rb +19 -0
- data/sample/cursor.rb +21 -0
- data/sample/disk_usage_report.rb +177 -0
- data/sample/issue-119.rb +94 -0
- data/sample/losample.rb +69 -0
- data/sample/minimal-testcase.rb +17 -0
- data/sample/notify_wait.rb +72 -0
- data/sample/pg_statistics.rb +285 -0
- data/sample/replication_monitor.rb +222 -0
- data/sample/test_binary_values.rb +33 -0
- data/sample/wal_shipper.rb +434 -0
- data/sample/warehouse_partitions.rb +311 -0
- data.tar.gz.sig +0 -0
- metadata +87 -224
- metadata.gz.sig +0 -0
- data/ChangeLog +0 -0
- data/lib/pg/basic_type_mapping.rb +0 -522
- data/spec/data/expected_trace.out +0 -26
- data/spec/data/random_binary_data +0 -0
- data/spec/helpers.rb +0 -380
- data/spec/pg/basic_type_mapping_spec.rb +0 -630
- data/spec/pg/connection_spec.rb +0 -1949
- data/spec/pg/connection_sync_spec.rb +0 -41
- data/spec/pg/result_spec.rb +0 -681
- data/spec/pg/tuple_spec.rb +0 -333
- data/spec/pg/type_map_by_class_spec.rb +0 -138
- data/spec/pg/type_map_by_column_spec.rb +0 -226
- data/spec/pg/type_map_by_mri_type_spec.rb +0 -136
- data/spec/pg/type_map_by_oid_spec.rb +0 -149
- data/spec/pg/type_map_in_ruby_spec.rb +0 -164
- data/spec/pg/type_map_spec.rb +0 -22
- data/spec/pg/type_spec.rb +0 -1123
- 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(
|
24
|
+
pg_copycoder_mark( void *_this )
|
25
25
|
{
|
26
|
-
|
27
|
-
|
28
|
-
|
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 =
|
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 =
|
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 =
|
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 =
|
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 =
|
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 =
|
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 =
|
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 =
|
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 =
|
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 =
|
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 =
|
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
|
-
|
429
|
+
long input_len;
|
401
430
|
|
402
431
|
/* Remember start of field on input side */
|
403
432
|
start_ptr = cur_ptr;
|
data/ext/pg_record_coder.c
CHANGED
@@ -16,17 +16,45 @@ typedef struct {
|
|
16
16
|
|
17
17
|
|
18
18
|
static void
|
19
|
-
pg_recordcoder_mark(
|
19
|
+
pg_recordcoder_mark( void *_this )
|
20
20
|
{
|
21
|
-
|
22
|
-
|
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 =
|
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 =
|
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 =
|
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 =
|
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.
|
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 =
|
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
|
-
|
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
|
-
* #
|
320
|
-
* PG::BasicTypeRegistry.
|
321
|
-
* #
|
322
|
-
*
|
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 =
|
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. */
|
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(
|
110
|
+
pgresult_gc_mark( void *_this )
|
111
111
|
{
|
112
|
+
t_pg_result *this = (t_pg_result *)_this;
|
112
113
|
int i;
|
113
114
|
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
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
|
-
|
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(
|
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(
|
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(
|
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
|
-
"
|
178
|
+
"PG::Result",
|
159
179
|
{
|
160
|
-
|
161
|
-
|
162
|
-
|
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 =
|
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 =
|
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 =
|
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
|
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::
|
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
|
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
|
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
|
-
|
1329
|
-
|
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 =
|
1364
|
+
this->p_typemap = RTYPEDDATA_DATA( this->typemap );
|
1336
1365
|
|
1337
1366
|
return typemap;
|
1338
1367
|
}
|
@@ -1354,7 +1383,7 @@ pgresult_type_map_get(VALUE self)
|
|
1354
1383
|
|
1355
1384
|
|
1356
1385
|
static void
|
1357
|
-
yield_hash(VALUE self, int ntuples, int nfields)
|
1386
|
+
yield_hash(VALUE self, int ntuples, int nfields, void *data)
|
1358
1387
|
{
|
1359
1388
|
int tuple_num;
|
1360
1389
|
t_pg_result *this = pgresult_get_this(self);
|
@@ -1368,7 +1397,7 @@ yield_hash(VALUE self, int ntuples, int nfields)
|
|
1368
1397
|
}
|
1369
1398
|
|
1370
1399
|
static void
|
1371
|
-
yield_array(VALUE self, int ntuples, int nfields)
|
1400
|
+
yield_array(VALUE self, int ntuples, int nfields, void *data)
|
1372
1401
|
{
|
1373
1402
|
int row;
|
1374
1403
|
t_pg_result *this = pgresult_get_this(self);
|
@@ -1388,7 +1417,7 @@ yield_array(VALUE self, int ntuples, int nfields)
|
|
1388
1417
|
}
|
1389
1418
|
|
1390
1419
|
static void
|
1391
|
-
yield_tuple(VALUE self, int ntuples, int nfields)
|
1420
|
+
yield_tuple(VALUE self, int ntuples, int nfields, void *data)
|
1392
1421
|
{
|
1393
1422
|
int tuple_num;
|
1394
1423
|
t_pg_result *this = pgresult_get_this(self);
|
@@ -1407,8 +1436,9 @@ yield_tuple(VALUE self, int ntuples, int nfields)
|
|
1407
1436
|
}
|
1408
1437
|
}
|
1409
1438
|
|
1410
|
-
static
|
1411
|
-
|
1439
|
+
/* Non-static, and data pointer for use by sequel_pg */
|
1440
|
+
VALUE
|
1441
|
+
pgresult_stream_any(VALUE self, void (*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,7 +1467,12 @@ 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
|
+
yielder( self, ntuples, nfields, data );
|
1471
|
+
|
1472
|
+
if( gvl_PQisBusy(pgconn) ){
|
1473
|
+
/* wait for input (without blocking) before reading each result */
|
1474
|
+
pgconn_block( 0, NULL, this->connection );
|
1475
|
+
}
|
1440
1476
|
|
1441
1477
|
pgresult = gvl_PQgetResult(pgconn);
|
1442
1478
|
if( pgresult == NULL )
|
@@ -1487,7 +1523,7 @@ pgresult_stream_any(VALUE self, void (*yielder)(VALUE, int, int))
|
|
1487
1523
|
static VALUE
|
1488
1524
|
pgresult_stream_each(VALUE self)
|
1489
1525
|
{
|
1490
|
-
return pgresult_stream_any(self, yield_hash);
|
1526
|
+
return pgresult_stream_any(self, yield_hash, NULL);
|
1491
1527
|
}
|
1492
1528
|
|
1493
1529
|
/*
|
@@ -1503,7 +1539,7 @@ pgresult_stream_each(VALUE self)
|
|
1503
1539
|
static VALUE
|
1504
1540
|
pgresult_stream_each_row(VALUE self)
|
1505
1541
|
{
|
1506
|
-
return pgresult_stream_any(self, yield_array);
|
1542
|
+
return pgresult_stream_any(self, yield_array, NULL);
|
1507
1543
|
}
|
1508
1544
|
|
1509
1545
|
/*
|
@@ -1520,7 +1556,7 @@ pgresult_stream_each_tuple(VALUE self)
|
|
1520
1556
|
/* allocate VALUEs that are shared between all streamed tuples */
|
1521
1557
|
ensure_init_for_tuple(self);
|
1522
1558
|
|
1523
|
-
return pgresult_stream_any(self, yield_tuple);
|
1559
|
+
return pgresult_stream_any(self, yield_tuple, NULL);
|
1524
1560
|
}
|
1525
1561
|
|
1526
1562
|
/*
|
@@ -1531,7 +1567,7 @@ pgresult_stream_each_tuple(VALUE self)
|
|
1531
1567
|
* It can be set to one of:
|
1532
1568
|
* * +:string+ to use String based field names
|
1533
1569
|
* * +: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.
|
1570
|
+
* * +:static_symbol+ to use pinned Symbol (can not be garbage collected) - Don't use this, it will probably be removed in future.
|
1535
1571
|
*
|
1536
1572
|
* The default is retrieved from PG::Connection#field_name_type , which defaults to +:string+ .
|
1537
1573
|
*
|
@@ -1587,7 +1623,8 @@ init_pg_result()
|
|
1587
1623
|
sym_symbol = ID2SYM(rb_intern("symbol"));
|
1588
1624
|
sym_static_symbol = ID2SYM(rb_intern("static_symbol"));
|
1589
1625
|
|
1590
|
-
rb_cPGresult = rb_define_class_under( rb_mPG, "Result",
|
1626
|
+
rb_cPGresult = rb_define_class_under( rb_mPG, "Result", rb_cObject );
|
1627
|
+
rb_undef_alloc_func(rb_cPGresult);
|
1591
1628
|
rb_include_module(rb_cPGresult, rb_mEnumerable);
|
1592
1629
|
rb_include_module(rb_cPGresult, rb_mPGconstants);
|
1593
1630
|
|
data/ext/pg_text_decoder.c
CHANGED
@@ -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
|
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:
|
data/ext/pg_text_encoder.c
CHANGED
@@ -191,7 +191,7 @@ pg_text_enc_integer(t_pg_coder *this, VALUE value, char *out, VALUE *intermediat
|
|
191
191
|
if (neg)
|
192
192
|
*out++ = '-';
|
193
193
|
|
194
|
-
len = out - start;
|
194
|
+
len = (int)(out - start);
|
195
195
|
|
196
196
|
/* Reverse string. */
|
197
197
|
out--;
|
@@ -252,7 +252,7 @@ pg_text_enc_float(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate,
|
|
252
252
|
}
|
253
253
|
|
254
254
|
/*
|
255
|
-
* The following
|
255
|
+
* The following computation is roughly a conversion kind of
|
256
256
|
* sprintf( out, "%.16E", dvalue);
|
257
257
|
*/
|
258
258
|
|
@@ -403,11 +403,11 @@ pg_text_enc_bytea(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate,
|
|
403
403
|
*optr++ = hextab[c >> 4];
|
404
404
|
*optr++ = hextab[c & 0xf];
|
405
405
|
}
|
406
|
-
return optr - out;
|
406
|
+
return (int)(optr - out);
|
407
407
|
}else{
|
408
408
|
*intermediate = rb_obj_as_string(value);
|
409
409
|
/* The output starts with "\x" and each character is converted to hex. */
|
410
|
-
return 2 +
|
410
|
+
return 2 + RSTRING_LENINT(*intermediate) * 2;
|
411
411
|
}
|
412
412
|
}
|
413
413
|
|
@@ -610,8 +610,8 @@ quote_identifier( VALUE value, VALUE out_string, char *current_out ){
|
|
610
610
|
static char *
|
611
611
|
pg_text_enc_array_identifier(VALUE value, VALUE string, char *out, int enc_idx)
|
612
612
|
{
|
613
|
-
|
614
|
-
|
613
|
+
long i;
|
614
|
+
long nr_elems;
|
615
615
|
|
616
616
|
Check_Type(value, T_ARRAY);
|
617
617
|
nr_elems = RARRAY_LEN(value);
|