pg 1.2.3 → 1.3.5
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.
- 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);
|