pg 1.5.9 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/{History.md → CHANGELOG.md} +126 -0
- data/Gemfile +11 -7
- data/README-Windows.rdoc +1 -1
- data/README.ja.md +83 -32
- data/README.md +79 -29
- data/Rakefile +84 -19
- data/certs/larskanis-2026.pem +24 -0
- data/ext/errorcodes.def +9 -0
- data/ext/errorcodes.rb +1 -1
- data/ext/errorcodes.txt +8 -1
- data/ext/extconf.rb +194 -30
- data/ext/gvl_wrappers.c +13 -2
- data/ext/gvl_wrappers.h +47 -134
- data/ext/pg.c +23 -16
- data/ext/pg.h +23 -24
- data/ext/pg_binary_decoder.c +157 -3
- data/ext/pg_binary_encoder.c +219 -9
- data/ext/pg_cancel_connection.c +360 -0
- data/ext/pg_coder.c +58 -9
- data/ext/pg_connection.c +558 -291
- data/ext/pg_copy_coder.c +36 -23
- data/ext/pg_record_coder.c +11 -7
- data/ext/pg_result.c +144 -76
- data/ext/pg_text_decoder.c +7 -7
- data/ext/pg_text_encoder.c +29 -11
- data/ext/pg_tuple.c +9 -9
- data/ext/pg_type_map.c +45 -3
- data/ext/pg_type_map_all_strings.c +3 -3
- data/ext/pg_type_map_by_class.c +2 -2
- data/ext/pg_type_map_by_column.c +4 -3
- data/ext/pg_type_map_by_mri_type.c +1 -1
- data/ext/pg_type_map_by_oid.c +4 -2
- data/ext/pg_type_map_in_ruby.c +2 -2
- data/ext/pg_util.c +2 -2
- data/ext/pg_util.h +2 -2
- data/lib/pg/basic_type_map_based_on_result.rb +5 -0
- data/lib/pg/basic_type_map_for_queries.rb +16 -5
- data/lib/pg/basic_type_map_for_results.rb +5 -0
- data/lib/pg/basic_type_registry.rb +2 -2
- data/lib/pg/cancel_connection.rb +53 -0
- data/lib/pg/coder.rb +4 -2
- data/lib/pg/connection.rb +393 -180
- data/lib/pg/text_decoder/date.rb +1 -1
- data/lib/pg/text_decoder/json.rb +1 -1
- data/lib/pg/text_encoder/date.rb +7 -1
- data/lib/pg/text_encoder/json.rb +1 -1
- data/lib/pg/version.rb +2 -1
- data/lib/pg.rb +156 -130
- data/misc/glibc/Dockerfile +20 -0
- data/misc/glibc/docker-compose.yml +9 -0
- data/misc/glibc/glibc_spec.rb +5 -0
- data/misc/yugabyte/Dockerfile +9 -0
- data/misc/yugabyte/docker-compose.yml +28 -0
- data/misc/yugabyte/pg-test.rb +45 -0
- data/pg.gemspec +5 -3
- data/ports/patches/krb5/1.22.2/0001-Allow-static-linking-krb5-library.patch +30 -0
- data/ports/patches/krb5/1.22.2/0002-unknown-command-line-option-on-clang.patch +12 -0
- data/ports/patches/postgresql/18.6/0001-Use-workaround-of-__builtin_setjmp-only-on-MINGW-on-.patch +42 -0
- data/rakelib/pg_gem_helper.rb +64 -0
- data/sample/async_mixed.rb +1 -1
- data.tar.gz.sig +0 -0
- metadata +36 -22
- metadata.gz.sig +0 -0
- data/Manifest.txt +0 -72
- data/Rakefile.cross +0 -303
data/ext/pg_text_encoder.c
CHANGED
|
@@ -231,7 +231,7 @@ pg_text_enc_integer(t_pg_coder *this, VALUE value, char *out, VALUE *intermediat
|
|
|
231
231
|
*
|
|
232
232
|
*/
|
|
233
233
|
static int
|
|
234
|
-
pg_text_enc_float(t_pg_coder *conv, VALUE value, char *out, VALUE *
|
|
234
|
+
pg_text_enc_float(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate1, int enc_idx)
|
|
235
235
|
{
|
|
236
236
|
if(out){
|
|
237
237
|
double dvalue = NUM2DBL(value);
|
|
@@ -239,7 +239,6 @@ pg_text_enc_float(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate,
|
|
|
239
239
|
int neg = 0;
|
|
240
240
|
int exp2i, exp10i, i;
|
|
241
241
|
unsigned long long ll, remainder, oldval;
|
|
242
|
-
VALUE intermediate;
|
|
243
242
|
|
|
244
243
|
/* Cast to the same strings as value.to_s . */
|
|
245
244
|
if( isinf(dvalue) ){
|
|
@@ -283,6 +282,7 @@ pg_text_enc_float(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate,
|
|
|
283
282
|
|
|
284
283
|
if( exp10i <= -5 || exp10i >= 15 ) {
|
|
285
284
|
/* Write the float in exponent format (1.23e45) */
|
|
285
|
+
VALUE intermediate;
|
|
286
286
|
|
|
287
287
|
/* write fraction digits from right to left */
|
|
288
288
|
for( i = MAX_DOUBLE_DIGITS; i > 1; i--){
|
|
@@ -381,8 +381,8 @@ pg_text_enc_numeric(t_pg_coder *this, VALUE value, char *out, VALUE *intermediat
|
|
|
381
381
|
static VALUE
|
|
382
382
|
init_pg_text_encoder_numeric(VALUE rb_mPG_TextDecoder)
|
|
383
383
|
{
|
|
384
|
+
rb_gc_register_address(&s_str_F);
|
|
384
385
|
s_str_F = rb_str_freeze(rb_str_new_cstr("F"));
|
|
385
|
-
rb_global_variable(&s_str_F);
|
|
386
386
|
rb_funcall(rb_mPG, rb_intern("require_bigdecimal_without_warning"), 0);
|
|
387
387
|
s_cBigDecimal = rb_const_get(rb_cObject, rb_intern("BigDecimal"));
|
|
388
388
|
|
|
@@ -430,9 +430,14 @@ pg_text_enc_bytea(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate,
|
|
|
430
430
|
}
|
|
431
431
|
return (int)(optr - out);
|
|
432
432
|
}else{
|
|
433
|
+
long size;
|
|
433
434
|
*intermediate = rb_obj_as_string(value);
|
|
435
|
+
size = RSTRING_LEN(*intermediate);
|
|
436
|
+
|
|
434
437
|
/* The output starts with "\x" and each character is converted to hex. */
|
|
435
|
-
|
|
438
|
+
if( size > INT_MAX / 2 - 2 )
|
|
439
|
+
rb_raise( rb_eArgError, "too large input string for PG::TextEncoder::Bytea: %ld", size );
|
|
440
|
+
return (int)(2 + size * 2);
|
|
436
441
|
}
|
|
437
442
|
}
|
|
438
443
|
|
|
@@ -537,7 +542,7 @@ quote_string(t_pg_coder *this, VALUE value, VALUE string, char *current_out, int
|
|
|
537
542
|
}
|
|
538
543
|
|
|
539
544
|
static char *
|
|
540
|
-
write_array(t_pg_composite_coder *this, VALUE value, char *current_out, VALUE string, int quote, int enc_idx)
|
|
545
|
+
write_array(t_pg_composite_coder *this, VALUE value, char *current_out, VALUE string, int quote, int enc_idx, int dimension)
|
|
541
546
|
{
|
|
542
547
|
int i;
|
|
543
548
|
|
|
@@ -545,6 +550,10 @@ write_array(t_pg_composite_coder *this, VALUE value, char *current_out, VALUE st
|
|
|
545
550
|
current_out = pg_rb_str_ensure_capa( string, 2, current_out, NULL );
|
|
546
551
|
*current_out++ = '{';
|
|
547
552
|
|
|
553
|
+
if( RARRAY_LEN(value) == 0 && this->dimensions >= 0 && dimension != this->dimensions ){
|
|
554
|
+
rb_raise(rb_eArgError, "less array dimensions to encode (%d) than expected (%d)", dimension, this->dimensions);
|
|
555
|
+
}
|
|
556
|
+
|
|
548
557
|
for( i=0; i<RARRAY_LEN(value); i++){
|
|
549
558
|
VALUE entry = rb_ary_entry(value, i);
|
|
550
559
|
|
|
@@ -554,17 +563,26 @@ write_array(t_pg_composite_coder *this, VALUE value, char *current_out, VALUE st
|
|
|
554
563
|
}
|
|
555
564
|
|
|
556
565
|
switch(TYPE(entry)){
|
|
557
|
-
case T_ARRAY:
|
|
558
|
-
current_out = write_array(this, entry, current_out, string, quote, enc_idx);
|
|
559
|
-
break;
|
|
560
566
|
case T_NIL:
|
|
567
|
+
if( this->dimensions >= 0 && dimension != this->dimensions ){
|
|
568
|
+
rb_raise(rb_eArgError, "less array dimensions to encode (%d) than expected (%d)", dimension, this->dimensions);
|
|
569
|
+
}
|
|
561
570
|
current_out = pg_rb_str_ensure_capa( string, 4, current_out, NULL );
|
|
562
571
|
*current_out++ = 'N';
|
|
563
572
|
*current_out++ = 'U';
|
|
564
573
|
*current_out++ = 'L';
|
|
565
574
|
*current_out++ = 'L';
|
|
566
575
|
break;
|
|
576
|
+
case T_ARRAY:
|
|
577
|
+
if( this->dimensions < 0 || dimension < this->dimensions ){
|
|
578
|
+
current_out = write_array(this, entry, current_out, string, quote, enc_idx, dimension+1);
|
|
579
|
+
break;
|
|
580
|
+
}
|
|
581
|
+
/* Number of dimensions reached -> handle array as normal value */
|
|
567
582
|
default:
|
|
583
|
+
if( this->dimensions >= 0 && dimension != this->dimensions ){
|
|
584
|
+
rb_raise(rb_eArgError, "less array dimensions to encode (%d) than expected (%d)", dimension, this->dimensions);
|
|
585
|
+
}
|
|
568
586
|
current_out = quote_string( this->elem, entry, string, current_out, quote, quote_array_buffer, this, enc_idx );
|
|
569
587
|
}
|
|
570
588
|
}
|
|
@@ -596,7 +614,7 @@ pg_text_enc_array(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate,
|
|
|
596
614
|
VALUE out_str = rb_str_new(NULL, 0);
|
|
597
615
|
PG_ENCODING_SET_NOCHECK(out_str, enc_idx);
|
|
598
616
|
|
|
599
|
-
end_ptr = write_array(this, value, RSTRING_PTR(out_str), out_str, this->needs_quotation, enc_idx);
|
|
617
|
+
end_ptr = write_array(this, value, RSTRING_PTR(out_str), out_str, this->needs_quotation, enc_idx, 1);
|
|
600
618
|
|
|
601
619
|
rb_str_set_len( out_str, end_ptr - RSTRING_PTR(out_str) );
|
|
602
620
|
*intermediate = out_str;
|
|
@@ -771,7 +789,7 @@ pg_text_enc_to_base64(t_pg_coder *conv, VALUE value, char *out, VALUE *intermedi
|
|
|
771
789
|
if(out){
|
|
772
790
|
/* Second encoder pass, if required */
|
|
773
791
|
strlen = enc_func(this->elem, value, out, intermediate, enc_idx);
|
|
774
|
-
|
|
792
|
+
rbpg_base64_encode( out, out, strlen );
|
|
775
793
|
|
|
776
794
|
return BASE64_ENCODED_SIZE(strlen);
|
|
777
795
|
} else {
|
|
@@ -786,7 +804,7 @@ pg_text_enc_to_base64(t_pg_coder *conv, VALUE value, char *out, VALUE *intermedi
|
|
|
786
804
|
out_str = rb_str_new(NULL, BASE64_ENCODED_SIZE(strlen));
|
|
787
805
|
PG_ENCODING_SET_NOCHECK(out_str, enc_idx);
|
|
788
806
|
|
|
789
|
-
|
|
807
|
+
rbpg_base64_encode( RSTRING_PTR(out_str), RSTRING_PTR(subint), strlen);
|
|
790
808
|
*intermediate = out_str;
|
|
791
809
|
|
|
792
810
|
return -1;
|
data/ext/pg_tuple.c
CHANGED
|
@@ -125,17 +125,17 @@ static const rb_data_type_t pg_tuple_type = {
|
|
|
125
125
|
pg_tuple_gc_mark,
|
|
126
126
|
pg_tuple_gc_free,
|
|
127
127
|
pg_tuple_memsize,
|
|
128
|
-
|
|
128
|
+
pg_tuple_gc_compact,
|
|
129
129
|
},
|
|
130
130
|
0, 0,
|
|
131
|
-
RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED |
|
|
131
|
+
RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FROZEN_SHAREABLE,
|
|
132
132
|
};
|
|
133
133
|
|
|
134
134
|
/*
|
|
135
135
|
* Document-method: allocate
|
|
136
136
|
*
|
|
137
137
|
* call-seq:
|
|
138
|
-
* PG::
|
|
138
|
+
* PG::Tuple.allocate -> obj
|
|
139
139
|
*/
|
|
140
140
|
static VALUE
|
|
141
141
|
pg_tuple_s_allocate( VALUE klass )
|
|
@@ -242,10 +242,10 @@ pg_tuple_materialize(VALUE self)
|
|
|
242
242
|
* An integer +key+ is interpreted as column index.
|
|
243
243
|
* Negative values of index count from the end of the array.
|
|
244
244
|
*
|
|
245
|
-
* Depending on Result#field_name_type= a string or symbol +key+ is interpreted as column name.
|
|
245
|
+
* Depending on PG::Result#field_name_type= a string or symbol +key+ is interpreted as column name.
|
|
246
246
|
*
|
|
247
247
|
* If the key can't be found, there are several options:
|
|
248
|
-
* With no other arguments, it will raise a IndexError exception;
|
|
248
|
+
* With no other arguments, it will raise a +IndexError+ exception;
|
|
249
249
|
* if default is given, then that will be returned;
|
|
250
250
|
* if the optional code block is specified, then that will be run and its result returned.
|
|
251
251
|
*/
|
|
@@ -302,7 +302,7 @@ pg_tuple_fetch(int argc, VALUE *argv, VALUE self)
|
|
|
302
302
|
* An integer +key+ is interpreted as column index.
|
|
303
303
|
* Negative values of index count from the end of the array.
|
|
304
304
|
*
|
|
305
|
-
* Depending on Result#field_name_type= a string or symbol +key+ is interpreted as column name.
|
|
305
|
+
* Depending on PG::Result#field_name_type= a string or symbol +key+ is interpreted as column name.
|
|
306
306
|
*
|
|
307
307
|
* If the key can't be found, it returns +nil+ .
|
|
308
308
|
*/
|
|
@@ -405,7 +405,7 @@ pg_tuple_each_value(VALUE self)
|
|
|
405
405
|
* tup.values -> Array
|
|
406
406
|
*
|
|
407
407
|
* Returns the values of this tuple as Array.
|
|
408
|
-
*
|
|
408
|
+
* <tt>res.tuple(i).values</tt> is equal to <tt>res.tuple_values(i)</tt> .
|
|
409
409
|
*/
|
|
410
410
|
static VALUE
|
|
411
411
|
pg_tuple_values(VALUE self)
|
|
@@ -474,7 +474,7 @@ pg_tuple_dump(VALUE self)
|
|
|
474
474
|
values = rb_ary_new4(this->num_fields, &this->values[0]);
|
|
475
475
|
a = rb_ary_new3(2, field_names, values);
|
|
476
476
|
|
|
477
|
-
|
|
477
|
+
rb_copy_generic_ivar(a, self);
|
|
478
478
|
|
|
479
479
|
return a;
|
|
480
480
|
}
|
|
@@ -510,7 +510,7 @@ pg_tuple_load(VALUE self, VALUE a)
|
|
|
510
510
|
if (RARRAY_LENINT(field_names) != num_fields)
|
|
511
511
|
rb_raise(rb_eTypeError, "different number of fields and values");
|
|
512
512
|
|
|
513
|
-
field_map =
|
|
513
|
+
field_map = rb_hash_new_capa(num_fields);
|
|
514
514
|
for( i = 0; i < num_fields; i++ ){
|
|
515
515
|
rb_hash_aset(field_map, RARRAY_AREF(field_names, i), INT2FIX(i));
|
|
516
516
|
}
|
data/ext/pg_type_map.c
CHANGED
|
@@ -33,11 +33,11 @@ const rb_data_type_t pg_typemap_type = {
|
|
|
33
33
|
pg_typemap_mark,
|
|
34
34
|
RUBY_TYPED_DEFAULT_FREE,
|
|
35
35
|
pg_typemap_memsize,
|
|
36
|
-
|
|
36
|
+
pg_typemap_compact,
|
|
37
37
|
},
|
|
38
38
|
0,
|
|
39
39
|
0,
|
|
40
|
-
RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED |
|
|
40
|
+
RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FROZEN_SHAREABLE,
|
|
41
41
|
};
|
|
42
42
|
|
|
43
43
|
VALUE rb_cTypeMap;
|
|
@@ -115,6 +115,45 @@ pg_typemap_s_allocate( VALUE klass )
|
|
|
115
115
|
return self;
|
|
116
116
|
}
|
|
117
117
|
|
|
118
|
+
/*
|
|
119
|
+
* call-seq:
|
|
120
|
+
* res.query_param_encoders(params)
|
|
121
|
+
*
|
|
122
|
+
* Retrieve the encoders that are used to encode the given values to be submitted to the database server.
|
|
123
|
+
* The selection of the encoders is defined in the derived type map class.
|
|
124
|
+
*
|
|
125
|
+
* +params+ must be an Array of values to be encoded.
|
|
126
|
+
* It's like +params+ given to exec_params .
|
|
127
|
+
*
|
|
128
|
+
* Returns an Array with the same length as +params+.
|
|
129
|
+
*
|
|
130
|
+
*/
|
|
131
|
+
static VALUE
|
|
132
|
+
pg_typemap_query_param_encoders( VALUE self, VALUE params )
|
|
133
|
+
{
|
|
134
|
+
t_typemap *this = RTYPEDDATA_DATA( self );
|
|
135
|
+
int nParams;
|
|
136
|
+
int i=0;
|
|
137
|
+
VALUE res;
|
|
138
|
+
|
|
139
|
+
Check_Type(params, T_ARRAY);
|
|
140
|
+
|
|
141
|
+
this->funcs.fit_to_query( self, params );
|
|
142
|
+
|
|
143
|
+
nParams = RARRAY_LENINT(params);
|
|
144
|
+
res = rb_ary_new2(nParams);
|
|
145
|
+
|
|
146
|
+
for ( i = 0; i < nParams; i++ ) {
|
|
147
|
+
t_pg_coder *conv;
|
|
148
|
+
VALUE param_value = rb_ary_entry(params, i);
|
|
149
|
+
|
|
150
|
+
/* Let the given typemap select a coder for this param */
|
|
151
|
+
conv = this->funcs.typecast_query_param(this, param_value, i);
|
|
152
|
+
rb_ary_push(res, conv ? conv->coder_obj : Qnil);
|
|
153
|
+
}
|
|
154
|
+
return res;
|
|
155
|
+
}
|
|
156
|
+
|
|
118
157
|
/*
|
|
119
158
|
* call-seq:
|
|
120
159
|
* res.default_type_map = typemap
|
|
@@ -187,11 +226,14 @@ init_pg_type_map(void)
|
|
|
187
226
|
*
|
|
188
227
|
* This is the base class for type maps.
|
|
189
228
|
* See derived classes for implementations of different type cast strategies
|
|
190
|
-
* ( PG::TypeMapByColumn, PG::TypeMapByOid ).
|
|
229
|
+
* ( PG::TypeMapByColumn, PG::TypeMapByOid, etc.).
|
|
230
|
+
*
|
|
231
|
+
* Find more type maps in the {README}[rdoc-ref:README.md@Type+Casts].
|
|
191
232
|
*
|
|
192
233
|
*/
|
|
193
234
|
rb_cTypeMap = rb_define_class_under( rb_mPG, "TypeMap", rb_cObject );
|
|
194
235
|
rb_define_alloc_func( rb_cTypeMap, pg_typemap_s_allocate );
|
|
236
|
+
rb_define_method( rb_cTypeMap, "query_param_encoders", pg_typemap_query_param_encoders, 1 );
|
|
195
237
|
|
|
196
238
|
rb_mDefaultTypeMappable = rb_define_module_under( rb_cTypeMap, "DefaultTypeMappable");
|
|
197
239
|
rb_define_method( rb_mDefaultTypeMappable, "default_type_map=", pg_typemap_default_type_map_set, 1 );
|
|
@@ -14,11 +14,11 @@ static const rb_data_type_t pg_tmas_type = {
|
|
|
14
14
|
pg_typemap_mark,
|
|
15
15
|
RUBY_TYPED_DEFAULT_FREE,
|
|
16
16
|
pg_typemap_memsize,
|
|
17
|
-
|
|
17
|
+
pg_typemap_compact,
|
|
18
18
|
},
|
|
19
19
|
&pg_typemap_type,
|
|
20
20
|
0,
|
|
21
|
-
RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED |
|
|
21
|
+
RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FROZEN_SHAREABLE,
|
|
22
22
|
};
|
|
23
23
|
|
|
24
24
|
VALUE rb_cTypeMapAllStrings;
|
|
@@ -125,6 +125,6 @@ init_pg_type_map_all_strings(void)
|
|
|
125
125
|
rb_cTypeMapAllStrings = rb_define_class_under( rb_mPG, "TypeMapAllStrings", rb_cTypeMap );
|
|
126
126
|
rb_define_alloc_func( rb_cTypeMapAllStrings, pg_tmas_s_allocate );
|
|
127
127
|
|
|
128
|
-
pg_typemap_all_strings = rb_obj_freeze( rb_funcall( rb_cTypeMapAllStrings, rb_intern("new"), 0 ));
|
|
129
128
|
rb_gc_register_address( &pg_typemap_all_strings );
|
|
129
|
+
pg_typemap_all_strings = rb_obj_freeze( rb_funcall( rb_cTypeMapAllStrings, rb_intern("new"), 0 ));
|
|
130
130
|
}
|
data/ext/pg_type_map_by_class.c
CHANGED
|
@@ -153,11 +153,11 @@ static const rb_data_type_t pg_tmbk_type = {
|
|
|
153
153
|
pg_tmbk_mark,
|
|
154
154
|
RUBY_TYPED_DEFAULT_FREE,
|
|
155
155
|
pg_tmbk_memsize,
|
|
156
|
-
|
|
156
|
+
pg_tmbk_compact,
|
|
157
157
|
},
|
|
158
158
|
&pg_typemap_type,
|
|
159
159
|
0,
|
|
160
|
-
RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED |
|
|
160
|
+
RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FROZEN_SHAREABLE,
|
|
161
161
|
};
|
|
162
162
|
|
|
163
163
|
static VALUE
|
data/ext/pg_type_map_by_column.c
CHANGED
|
@@ -54,7 +54,8 @@ pg_tmbc_fit_to_query( VALUE self, VALUE params )
|
|
|
54
54
|
t_tmbc *this = RTYPEDDATA_DATA( self );
|
|
55
55
|
t_typemap *default_tm;
|
|
56
56
|
|
|
57
|
-
|
|
57
|
+
Check_Type(params, T_ARRAY);
|
|
58
|
+
nfields = RARRAY_LENINT( params );
|
|
58
59
|
if ( this->nfields != nfields ) {
|
|
59
60
|
rb_raise( rb_eArgError, "number of result fields (%d) does not match number of mapped columns (%d)",
|
|
60
61
|
nfields, this->nfields );
|
|
@@ -228,11 +229,11 @@ static const rb_data_type_t pg_tmbc_type = {
|
|
|
228
229
|
pg_tmbc_mark,
|
|
229
230
|
pg_tmbc_free,
|
|
230
231
|
pg_tmbc_memsize,
|
|
231
|
-
|
|
232
|
+
pg_tmbc_compact,
|
|
232
233
|
},
|
|
233
234
|
&pg_typemap_type,
|
|
234
235
|
0,
|
|
235
|
-
RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED |
|
|
236
|
+
RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FROZEN_SHAREABLE,
|
|
236
237
|
};
|
|
237
238
|
|
|
238
239
|
static VALUE
|
data/ext/pg_type_map_by_oid.c
CHANGED
|
@@ -190,11 +190,11 @@ static const rb_data_type_t pg_tmbo_type = {
|
|
|
190
190
|
pg_tmbo_mark,
|
|
191
191
|
RUBY_TYPED_DEFAULT_FREE,
|
|
192
192
|
pg_tmbo_memsize,
|
|
193
|
-
|
|
193
|
+
pg_tmbo_compact,
|
|
194
194
|
},
|
|
195
195
|
&pg_typemap_type,
|
|
196
196
|
0,
|
|
197
|
-
RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED |
|
|
197
|
+
RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FROZEN_SHAREABLE,
|
|
198
198
|
};
|
|
199
199
|
|
|
200
200
|
static VALUE
|
|
@@ -315,6 +315,8 @@ pg_tmbo_coders( VALUE self )
|
|
|
315
315
|
* The type map will do Hash lookups for each result value, if the number of rows
|
|
316
316
|
* is below or equal +number+.
|
|
317
317
|
*
|
|
318
|
+
* Default is 10.
|
|
319
|
+
*
|
|
318
320
|
*/
|
|
319
321
|
static VALUE
|
|
320
322
|
pg_tmbo_max_rows_for_online_lookup_set( VALUE self, VALUE value )
|
data/ext/pg_type_map_in_ruby.c
CHANGED
|
@@ -40,11 +40,11 @@ static const rb_data_type_t pg_tmir_type = {
|
|
|
40
40
|
pg_typemap_mark,
|
|
41
41
|
RUBY_TYPED_DEFAULT_FREE,
|
|
42
42
|
pg_tmir_memsize,
|
|
43
|
-
|
|
43
|
+
pg_tmir_compact,
|
|
44
44
|
},
|
|
45
45
|
&pg_typemap_type,
|
|
46
46
|
0,
|
|
47
|
-
RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED |
|
|
47
|
+
RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FROZEN_SHAREABLE,
|
|
48
48
|
};
|
|
49
49
|
|
|
50
50
|
/*
|
data/ext/pg_util.c
CHANGED
|
@@ -15,7 +15,7 @@ static const char base64_encode_table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijk
|
|
|
15
15
|
* in-place (with _out_ == _in_).
|
|
16
16
|
*/
|
|
17
17
|
void
|
|
18
|
-
|
|
18
|
+
rbpg_base64_encode( char *out, const char *in, int len)
|
|
19
19
|
{
|
|
20
20
|
const unsigned char *in_ptr = (const unsigned char *)in + len;
|
|
21
21
|
char *out_ptr = out + BASE64_ENCODED_SIZE(len);
|
|
@@ -72,7 +72,7 @@ static const unsigned char base64_decode_table[] =
|
|
|
72
72
|
* It is possible to decode a string in-place (with _out_ == _in_).
|
|
73
73
|
*/
|
|
74
74
|
int
|
|
75
|
-
|
|
75
|
+
rbpg_base64_decode( char *out, const char *in, unsigned int len)
|
|
76
76
|
{
|
|
77
77
|
unsigned char a, b, c, d;
|
|
78
78
|
const unsigned char *in_ptr = (const unsigned char *)in;
|
data/ext/pg_util.h
CHANGED
|
@@ -57,8 +57,8 @@
|
|
|
57
57
|
#define BASE64_ENCODED_SIZE(strlen) (((strlen) + 2) / 3 * 4)
|
|
58
58
|
#define BASE64_DECODED_SIZE(base64len) (((base64len) + 3) / 4 * 3)
|
|
59
59
|
|
|
60
|
-
void
|
|
61
|
-
int
|
|
60
|
+
void rbpg_base64_encode( char *out, const char *in, int len);
|
|
61
|
+
int rbpg_base64_decode( char *out, const char *in, unsigned int len);
|
|
62
62
|
|
|
63
63
|
int rbpg_strncasecmp(const char *s1, const char *s2, size_t n);
|
|
64
64
|
|
|
@@ -53,14 +53,23 @@ class PG::BasicTypeMapForQueries < PG::TypeMapByClass
|
|
|
53
53
|
@coder_maps = build_coder_maps(connection_or_coder_maps, registry: registry)
|
|
54
54
|
@array_encoders_by_klass = array_encoders_by_klass
|
|
55
55
|
@encode_array_as = :array
|
|
56
|
-
@if_undefined = if_undefined ||
|
|
56
|
+
@if_undefined = if_undefined || UndefinedDefault
|
|
57
57
|
init_encoders
|
|
58
58
|
end
|
|
59
59
|
|
|
60
|
-
|
|
61
|
-
|
|
60
|
+
# Returns the PG::BasicTypeRegistry::CoderMapsBundle used to translate encoders to OIDs.
|
|
61
|
+
def coder_maps_bundle
|
|
62
|
+
@coder_maps
|
|
62
63
|
end
|
|
63
64
|
|
|
65
|
+
class UndefinedDefault
|
|
66
|
+
def self.call(oid_name, format)
|
|
67
|
+
raise UndefinedEncoder, "no encoder defined for type #{oid_name.inspect} format #{format}"
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
private_constant :UndefinedDefault
|
|
72
|
+
|
|
64
73
|
# Change the mechanism that is used to encode ruby array values
|
|
65
74
|
#
|
|
66
75
|
# Possible values:
|
|
@@ -173,13 +182,14 @@ class PG::BasicTypeMapForQueries < PG::TypeMapByClass
|
|
|
173
182
|
end
|
|
174
183
|
|
|
175
184
|
DEFAULT_TYPE_MAP = PG.make_shareable({
|
|
176
|
-
TrueClass => [
|
|
177
|
-
FalseClass => [
|
|
185
|
+
TrueClass => [0, 'bool', 'bool'],
|
|
186
|
+
FalseClass => [0, 'bool', 'bool'],
|
|
178
187
|
# We use text format and no type OID for numbers, because setting the OID can lead
|
|
179
188
|
# to unnecessary type conversions on server side.
|
|
180
189
|
Integer => [0, 'int8'],
|
|
181
190
|
Float => [0, 'float8'],
|
|
182
191
|
Time => [0, 'timestamptz'],
|
|
192
|
+
Date => [0, 'date'],
|
|
183
193
|
# We use text format and no type OID for IPAddr, because setting the OID can lead
|
|
184
194
|
# to unnecessary inet/cidr conversions on the server side.
|
|
185
195
|
IPAddr => [0, 'inet'],
|
|
@@ -196,6 +206,7 @@ class PG::BasicTypeMapForQueries < PG::TypeMapByClass
|
|
|
196
206
|
String => [0, '_text'],
|
|
197
207
|
Float => [0, '_float8'],
|
|
198
208
|
Time => [0, '_timestamptz'],
|
|
209
|
+
Date => [0, '_date'],
|
|
199
210
|
IPAddr => [0, '_inet'],
|
|
200
211
|
}.merge(has_bigdecimal ? {BigDecimal => [0, '_numeric']} : {}))
|
|
201
212
|
private_constant :DEFAULT_ARRAY_TYPE_MAP
|
|
@@ -101,4 +101,9 @@ class PG::BasicTypeMapForResults < PG::TypeMapByOid
|
|
|
101
101
|
typenames = @coder_maps.typenames_by_oid
|
|
102
102
|
self.default_type_map = WarningTypeMap.new(typenames)
|
|
103
103
|
end
|
|
104
|
+
|
|
105
|
+
# Returns the PG::BasicTypeRegistry::CoderMapsBundle used to translate result OIDs to decoders.
|
|
106
|
+
def coder_maps_bundle
|
|
107
|
+
@coder_maps
|
|
108
|
+
end
|
|
104
109
|
end
|
|
@@ -127,8 +127,8 @@ class PG::BasicTypeRegistry
|
|
|
127
127
|
@maps = [
|
|
128
128
|
[0, :encoder, PG::TextEncoder::Array],
|
|
129
129
|
[0, :decoder, PG::TextDecoder::Array],
|
|
130
|
-
[1, :encoder,
|
|
131
|
-
[1, :decoder,
|
|
130
|
+
[1, :encoder, PG::BinaryEncoder::Array],
|
|
131
|
+
[1, :decoder, PG::BinaryDecoder::Array],
|
|
132
132
|
].inject([]) do |h, (format, direction, arraycoder)|
|
|
133
133
|
coders = registry.coders_for(format, direction) || {}
|
|
134
134
|
h[format] ||= {}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# -*- ruby -*-
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require 'pg' unless defined?( PG )
|
|
5
|
+
|
|
6
|
+
if defined?(PG::CancelConnection)
|
|
7
|
+
class PG::CancelConnection
|
|
8
|
+
include PG::Connection::Pollable
|
|
9
|
+
|
|
10
|
+
alias c_initialize initialize
|
|
11
|
+
|
|
12
|
+
def initialize(conn)
|
|
13
|
+
c_initialize(conn)
|
|
14
|
+
|
|
15
|
+
# A cancel connection is always to one destination server only.
|
|
16
|
+
# Prepare conninfo_hash with just enough information to allow a shared polling_loop.
|
|
17
|
+
@host = conn.host
|
|
18
|
+
@hostaddr = conn.hostaddr
|
|
19
|
+
@port = conn.port
|
|
20
|
+
|
|
21
|
+
@conninfo_hash = {
|
|
22
|
+
host: @host,
|
|
23
|
+
hostaddr: @hostaddr,
|
|
24
|
+
port: @port.to_s,
|
|
25
|
+
connect_timeout: conn.conninfo_hash[:connect_timeout],
|
|
26
|
+
}
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# call-seq:
|
|
30
|
+
# conn.cancel
|
|
31
|
+
#
|
|
32
|
+
# Requests that the server abandons processing of the current command in a blocking manner.
|
|
33
|
+
#
|
|
34
|
+
# If the cancel request wasn't successfully dispatched an error message is raised.
|
|
35
|
+
#
|
|
36
|
+
# Successful dispatch of the cancellation is no guarantee that the request will have any effect, however.
|
|
37
|
+
# If the cancellation is effective, the command being canceled will terminate early and raises an error.
|
|
38
|
+
# If the cancellation fails (say, because the server was already done processing the command), then there will be no visible result at all.
|
|
39
|
+
#
|
|
40
|
+
def cancel
|
|
41
|
+
start
|
|
42
|
+
polling_loop(:poll)
|
|
43
|
+
end
|
|
44
|
+
alias async_cancel cancel
|
|
45
|
+
|
|
46
|
+
# These private methods are there to allow a shared polling_loop.
|
|
47
|
+
private
|
|
48
|
+
attr_reader :host
|
|
49
|
+
attr_reader :hostaddr
|
|
50
|
+
attr_reader :port
|
|
51
|
+
attr_reader :conninfo_hash
|
|
52
|
+
end
|
|
53
|
+
end
|
data/lib/pg/coder.rb
CHANGED
|
@@ -72,16 +72,18 @@ module PG
|
|
|
72
72
|
|
|
73
73
|
class CompositeCoder < Coder
|
|
74
74
|
def to_h
|
|
75
|
-
{ **super,
|
|
75
|
+
h = { **super,
|
|
76
76
|
elements_type: elements_type,
|
|
77
77
|
needs_quotation: needs_quotation?,
|
|
78
78
|
delimiter: delimiter,
|
|
79
79
|
}
|
|
80
|
+
h[:dimensions] = dimensions if dimensions # Write only when set, for Marshal compat with pg<1.6
|
|
81
|
+
h
|
|
80
82
|
end
|
|
81
83
|
|
|
82
84
|
def inspect
|
|
83
85
|
str = super
|
|
84
|
-
str[-1,0] = " elements_type=#{elements_type.inspect} #{needs_quotation? ? 'needs' : 'no'} quotation"
|
|
86
|
+
str[-1,0] = " elements_type=#{elements_type.inspect} #{needs_quotation? ? 'needs' : 'no'} quotation#{dimensions && " #{dimensions} dimensions"}"
|
|
85
87
|
str
|
|
86
88
|
end
|
|
87
89
|
end
|