pg 1.5.8 → 1.6.2
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} +76 -0
- data/Gemfile +7 -4
- data/README-Windows.rdoc +1 -1
- data/README.ja.md +4 -4
- data/README.md +60 -20
- data/Rakefile +92 -14
- data/ext/errorcodes.def +4 -5
- data/ext/errorcodes.txt +2 -5
- data/ext/extconf.rb +188 -15
- data/ext/gvl_wrappers.c +13 -2
- data/ext/gvl_wrappers.h +33 -0
- data/ext/pg.c +16 -5
- data/ext/pg.h +9 -9
- data/ext/pg_binary_decoder.c +151 -1
- data/ext/pg_binary_encoder.c +212 -9
- data/ext/pg_cancel_connection.c +360 -0
- data/ext/pg_coder.c +54 -5
- data/ext/pg_connection.c +368 -158
- data/ext/pg_copy_coder.c +2 -2
- data/ext/pg_record_coder.c +1 -1
- data/ext/pg_result.c +15 -17
- data/ext/pg_text_decoder.c +1 -1
- data/ext/pg_text_encoder.c +22 -9
- data/ext/pg_tuple.c +7 -7
- data/ext/pg_type_map.c +4 -2
- data/ext/pg_type_map_all_strings.c +1 -1
- data/ext/pg_type_map_by_class.c +1 -1
- data/ext/pg_type_map_by_column.c +2 -1
- data/ext/pg_type_map_by_mri_type.c +1 -1
- data/ext/pg_type_map_by_oid.c +3 -1
- data/ext/pg_type_map_in_ruby.c +1 -1
- data/ext/pg_util.c +2 -2
- data/ext/pg_util.h +2 -2
- data/lib/pg/basic_type_map_for_queries.rb +7 -3
- 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 +259 -138
- 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 +8 -4
- data/ports/patches/krb5/1.22.1/0001-Allow-static-linking-krb5-library.patch +30 -0
- data/ports/patches/krb5/1.22.1/0002-unknown-command-line-option-on-clang.patch +12 -0
- data/ports/patches/openssl/3.5.2/0001-aarch64-mingw.patch +21 -0
- data/ports/patches/postgresql/17.6/0001-Use-workaround-of-__builtin_setjmp-only-on-MINGW-on-.patch +42 -0
- data/ports/patches/postgresql/17.6/0001-libpq-Process-buffered-SSL-read-bytes-to-support-rec.patch +52 -0
- data/rakelib/pg_gem_helper.rb +64 -0
- data.tar.gz.sig +0 -0
- metadata +36 -36
- metadata.gz.sig +0 -0
- data/.appveyor.yml +0 -42
- data/.gems +0 -6
- data/.gemtest +0 -0
- data/.github/workflows/binary-gems.yml +0 -117
- data/.github/workflows/source-gem.yml +0 -152
- data/.gitignore +0 -22
- data/.hgsigs +0 -34
- data/.hgtags +0 -41
- data/.irbrc +0 -23
- data/.pryrc +0 -23
- data/.tm_properties +0 -21
- data/.travis.yml +0 -49
- data/Manifest.txt +0 -72
- data/Rakefile.cross +0 -298
data/ext/pg_copy_coder.c
CHANGED
@@ -51,7 +51,7 @@ static const rb_data_type_t pg_copycoder_type = {
|
|
51
51
|
pg_copycoder_mark,
|
52
52
|
RUBY_TYPED_DEFAULT_FREE,
|
53
53
|
pg_copycoder_memsize,
|
54
|
-
|
54
|
+
pg_copycoder_compact,
|
55
55
|
},
|
56
56
|
&pg_coder_type,
|
57
57
|
0,
|
@@ -831,7 +831,6 @@ pg_bin_dec_copy_row(t_pg_coder *conv, const char *input_line, int len, int _tupl
|
|
831
831
|
|
832
832
|
for( fieldno = 0; fieldno < nfields; fieldno++){
|
833
833
|
long input_len;
|
834
|
-
VALUE field_value;
|
835
834
|
|
836
835
|
/* read field size */
|
837
836
|
if (line_end_ptr - cur_ptr < 4 ) goto length_error;
|
@@ -843,6 +842,7 @@ pg_bin_dec_copy_row(t_pg_coder *conv, const char *input_line, int len, int _tupl
|
|
843
842
|
/* NULL indicator */
|
844
843
|
rb_ary_push(array, Qnil);
|
845
844
|
} else {
|
845
|
+
VALUE field_value;
|
846
846
|
if (line_end_ptr - cur_ptr < input_len ) goto length_error;
|
847
847
|
|
848
848
|
/* copy input data to field_str */
|
data/ext/pg_record_coder.c
CHANGED
data/ext/pg_result.c
CHANGED
@@ -147,9 +147,7 @@ pgresult_clear( void *_this )
|
|
147
147
|
t_pg_result *this = (t_pg_result *)_this;
|
148
148
|
if( this->pgresult && !this->autoclear ){
|
149
149
|
PQclear(this->pgresult);
|
150
|
-
#ifdef HAVE_RB_GC_ADJUST_MEMORY_USAGE
|
151
150
|
rb_gc_adjust_memory_usage(-this->result_size);
|
152
|
-
#endif
|
153
151
|
}
|
154
152
|
this->result_size = 0;
|
155
153
|
this->nfields = -1;
|
@@ -180,7 +178,7 @@ static const rb_data_type_t pgresult_type = {
|
|
180
178
|
pgresult_gc_mark,
|
181
179
|
pgresult_gc_free,
|
182
180
|
pgresult_memsize,
|
183
|
-
|
181
|
+
pgresult_gc_compact,
|
184
182
|
},
|
185
183
|
0, 0,
|
186
184
|
RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | PG_RUBY_TYPED_FROZEN_SHAREABLE,
|
@@ -253,9 +251,7 @@ pg_new_result(PGresult *result, VALUE rb_pgconn)
|
|
253
251
|
*/
|
254
252
|
this->result_size = pgresult_approx_size(result);
|
255
253
|
|
256
|
-
#ifdef HAVE_RB_GC_ADJUST_MEMORY_USAGE
|
257
254
|
rb_gc_adjust_memory_usage(this->result_size);
|
258
|
-
#endif
|
259
255
|
|
260
256
|
return self;
|
261
257
|
}
|
@@ -323,6 +319,9 @@ pg_result_check( VALUE self )
|
|
323
319
|
case PGRES_COMMAND_OK:
|
324
320
|
#ifdef HAVE_PQENTERPIPELINEMODE
|
325
321
|
case PGRES_PIPELINE_SYNC:
|
322
|
+
#endif
|
323
|
+
#ifdef HAVE_PQSETCHUNKEDROWSMODE
|
324
|
+
case PGRES_TUPLES_CHUNK:
|
326
325
|
#endif
|
327
326
|
return self;
|
328
327
|
case PGRES_BAD_RESPONSE:
|
@@ -549,6 +548,7 @@ static void pgresult_init_fnames(VALUE self)
|
|
549
548
|
* * +PGRES_FATAL_ERROR+
|
550
549
|
* * +PGRES_COPY_BOTH+
|
551
550
|
* * +PGRES_SINGLE_TUPLE+
|
551
|
+
* * +PGRES_TUPLES_CHUNK+
|
552
552
|
* * +PGRES_PIPELINE_SYNC+
|
553
553
|
* * +PGRES_PIPELINE_ABORTED+
|
554
554
|
*
|
@@ -613,14 +613,12 @@ pgresult_error_message(VALUE self)
|
|
613
613
|
return ret;
|
614
614
|
}
|
615
615
|
|
616
|
-
#ifdef HAVE_PQRESULTVERBOSEERRORMESSAGE
|
617
616
|
/*
|
618
617
|
* call-seq:
|
619
618
|
* res.verbose_error_message( verbosity, show_context ) -> String
|
620
619
|
*
|
621
|
-
* Returns a reformatted version of the error message associated with
|
620
|
+
* Returns a reformatted version of the error message associated with the PG::Result object.
|
622
621
|
*
|
623
|
-
* Available since PostgreSQL-9.6
|
624
622
|
*/
|
625
623
|
static VALUE
|
626
624
|
pgresult_verbose_error_message(VALUE self, VALUE verbosity, VALUE show_context)
|
@@ -639,7 +637,6 @@ pgresult_verbose_error_message(VALUE self, VALUE verbosity, VALUE show_context)
|
|
639
637
|
|
640
638
|
return ret;
|
641
639
|
}
|
642
|
-
#endif
|
643
640
|
|
644
641
|
/*
|
645
642
|
* call-seq:
|
@@ -737,9 +734,9 @@ pgresult_nfields(VALUE self)
|
|
737
734
|
* call-seq:
|
738
735
|
* res.binary_tuples() -> Integer
|
739
736
|
*
|
740
|
-
* Returns 1 if the
|
737
|
+
* Returns 1 if the PG::Result contains binary data and 0 if it contains text data.
|
741
738
|
*
|
742
|
-
* This function is deprecated (except for its use in connection with COPY), because it is possible for a single
|
739
|
+
* This function is deprecated (except for its use in connection with COPY), because it is possible for a single PG::Result to contain text data in some columns and binary data in others.
|
743
740
|
* Result#fformat is preferred. binary_tuples returns 1 only if all columns of the result are binary (format 1).
|
744
741
|
*/
|
745
742
|
static VALUE
|
@@ -1405,7 +1402,7 @@ pgresult_fields(VALUE self)
|
|
1405
1402
|
* call-seq:
|
1406
1403
|
* res.type_map = typemap
|
1407
1404
|
*
|
1408
|
-
* Set the TypeMap that is used for type casts of result values to ruby objects.
|
1405
|
+
* Set the PG::TypeMap that is used for type casts of result values to ruby objects.
|
1409
1406
|
*
|
1410
1407
|
* All value retrieval methods will respect the type map and will do the
|
1411
1408
|
* type casts from PostgreSQL's wire format to Ruby objects on the fly,
|
@@ -1435,7 +1432,7 @@ pgresult_type_map_set(VALUE self, VALUE typemap)
|
|
1435
1432
|
* call-seq:
|
1436
1433
|
* res.type_map -> value
|
1437
1434
|
*
|
1438
|
-
* Returns the TypeMap that is currently set for type casts of result values to ruby objects.
|
1435
|
+
* Returns the PG::TypeMap that is currently set for type casts of result values to ruby objects.
|
1439
1436
|
*
|
1440
1437
|
*/
|
1441
1438
|
static VALUE
|
@@ -1528,6 +1525,9 @@ pgresult_stream_any(VALUE self, int (*yielder)(VALUE, int, int, void*), void* da
|
|
1528
1525
|
return self;
|
1529
1526
|
rb_raise( rb_eInvalidResultStatus, "PG::Result is not in single row mode");
|
1530
1527
|
case PGRES_SINGLE_TUPLE:
|
1528
|
+
#ifdef HAVE_PQSETCHUNKEDROWSMODE
|
1529
|
+
case PGRES_TUPLES_CHUNK:
|
1530
|
+
#endif
|
1531
1531
|
break;
|
1532
1532
|
default:
|
1533
1533
|
pg_result_check( self );
|
@@ -1572,8 +1572,8 @@ pgresult_stream_any(VALUE self, int (*yielder)(VALUE, int, int, void*), void* da
|
|
1572
1572
|
* wrapping each row into a dedicated result object, it delivers data in nearly
|
1573
1573
|
* the same speed as with ordinary results.
|
1574
1574
|
*
|
1575
|
-
* The base result must be in status PGRES_SINGLE_TUPLE
|
1576
|
-
* It iterates over all tuples until the status changes to PGRES_TUPLES_OK
|
1575
|
+
* The base result must be in status +PGRES_SINGLE_TUPLE+ or +PGRES_TUPLES_CHUNK+.
|
1576
|
+
* It iterates over all tuples until the status changes to +PGRES_TUPLES_OK+.
|
1577
1577
|
* A PG::Error is raised for any errors from the server.
|
1578
1578
|
*
|
1579
1579
|
* Row description data does not change while the iteration. All value retrieval
|
@@ -1707,10 +1707,8 @@ init_pg_result(void)
|
|
1707
1707
|
rb_define_singleton_method(rb_cPGresult, "res_status", pgresult_s_res_status, 1);
|
1708
1708
|
rb_define_method(rb_cPGresult, "error_message", pgresult_error_message, 0);
|
1709
1709
|
rb_define_alias( rb_cPGresult, "result_error_message", "error_message");
|
1710
|
-
#ifdef HAVE_PQRESULTVERBOSEERRORMESSAGE
|
1711
1710
|
rb_define_method(rb_cPGresult, "verbose_error_message", pgresult_verbose_error_message, 2);
|
1712
1711
|
rb_define_alias( rb_cPGresult, "result_verbose_error_message", "verbose_error_message");
|
1713
|
-
#endif
|
1714
1712
|
rb_define_method(rb_cPGresult, "error_field", pgresult_error_field, 1);
|
1715
1713
|
rb_define_alias( rb_cPGresult, "result_error_field", "error_field" );
|
1716
1714
|
rb_define_method(rb_cPGresult, "clear", pg_result_clear, 0);
|
data/ext/pg_text_decoder.c
CHANGED
@@ -579,7 +579,7 @@ pg_text_dec_from_base64(t_pg_coder *conv, const char *val, int len, int tuple, i
|
|
579
579
|
/* create a buffer of the expected decoded length */
|
580
580
|
VALUE out_value = rb_str_new(NULL, BASE64_DECODED_SIZE(len));
|
581
581
|
|
582
|
-
decoded_len =
|
582
|
+
decoded_len = rbpg_base64_decode( RSTRING_PTR(out_value), val, len );
|
583
583
|
rb_str_set_len(out_value, decoded_len);
|
584
584
|
|
585
585
|
/* Is it a pure String conversion? Then we can directly send out_value to the user. */
|
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--){
|
@@ -537,7 +537,7 @@ quote_string(t_pg_coder *this, VALUE value, VALUE string, char *current_out, int
|
|
537
537
|
}
|
538
538
|
|
539
539
|
static char *
|
540
|
-
write_array(t_pg_composite_coder *this, VALUE value, char *current_out, VALUE string, int quote, int enc_idx)
|
540
|
+
write_array(t_pg_composite_coder *this, VALUE value, char *current_out, VALUE string, int quote, int enc_idx, int dimension)
|
541
541
|
{
|
542
542
|
int i;
|
543
543
|
|
@@ -545,6 +545,10 @@ write_array(t_pg_composite_coder *this, VALUE value, char *current_out, VALUE st
|
|
545
545
|
current_out = pg_rb_str_ensure_capa( string, 2, current_out, NULL );
|
546
546
|
*current_out++ = '{';
|
547
547
|
|
548
|
+
if( RARRAY_LEN(value) == 0 && this->dimensions >= 0 && dimension != this->dimensions ){
|
549
|
+
rb_raise(rb_eArgError, "less array dimensions to encode (%d) than expected (%d)", dimension, this->dimensions);
|
550
|
+
}
|
551
|
+
|
548
552
|
for( i=0; i<RARRAY_LEN(value); i++){
|
549
553
|
VALUE entry = rb_ary_entry(value, i);
|
550
554
|
|
@@ -554,17 +558,26 @@ write_array(t_pg_composite_coder *this, VALUE value, char *current_out, VALUE st
|
|
554
558
|
}
|
555
559
|
|
556
560
|
switch(TYPE(entry)){
|
557
|
-
case T_ARRAY:
|
558
|
-
current_out = write_array(this, entry, current_out, string, quote, enc_idx);
|
559
|
-
break;
|
560
561
|
case T_NIL:
|
562
|
+
if( this->dimensions >= 0 && dimension != this->dimensions ){
|
563
|
+
rb_raise(rb_eArgError, "less array dimensions to encode (%d) than expected (%d)", dimension, this->dimensions);
|
564
|
+
}
|
561
565
|
current_out = pg_rb_str_ensure_capa( string, 4, current_out, NULL );
|
562
566
|
*current_out++ = 'N';
|
563
567
|
*current_out++ = 'U';
|
564
568
|
*current_out++ = 'L';
|
565
569
|
*current_out++ = 'L';
|
566
570
|
break;
|
571
|
+
case T_ARRAY:
|
572
|
+
if( this->dimensions < 0 || dimension < this->dimensions ){
|
573
|
+
current_out = write_array(this, entry, current_out, string, quote, enc_idx, dimension+1);
|
574
|
+
break;
|
575
|
+
}
|
576
|
+
/* Number of dimensions reached -> handle array as normal value */
|
567
577
|
default:
|
578
|
+
if( this->dimensions >= 0 && dimension != this->dimensions ){
|
579
|
+
rb_raise(rb_eArgError, "less array dimensions to encode (%d) than expected (%d)", dimension, this->dimensions);
|
580
|
+
}
|
568
581
|
current_out = quote_string( this->elem, entry, string, current_out, quote, quote_array_buffer, this, enc_idx );
|
569
582
|
}
|
570
583
|
}
|
@@ -596,7 +609,7 @@ pg_text_enc_array(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate,
|
|
596
609
|
VALUE out_str = rb_str_new(NULL, 0);
|
597
610
|
PG_ENCODING_SET_NOCHECK(out_str, enc_idx);
|
598
611
|
|
599
|
-
end_ptr = write_array(this, value, RSTRING_PTR(out_str), out_str, this->needs_quotation, enc_idx);
|
612
|
+
end_ptr = write_array(this, value, RSTRING_PTR(out_str), out_str, this->needs_quotation, enc_idx, 1);
|
600
613
|
|
601
614
|
rb_str_set_len( out_str, end_ptr - RSTRING_PTR(out_str) );
|
602
615
|
*intermediate = out_str;
|
@@ -771,7 +784,7 @@ pg_text_enc_to_base64(t_pg_coder *conv, VALUE value, char *out, VALUE *intermedi
|
|
771
784
|
if(out){
|
772
785
|
/* Second encoder pass, if required */
|
773
786
|
strlen = enc_func(this->elem, value, out, intermediate, enc_idx);
|
774
|
-
|
787
|
+
rbpg_base64_encode( out, out, strlen );
|
775
788
|
|
776
789
|
return BASE64_ENCODED_SIZE(strlen);
|
777
790
|
} else {
|
@@ -786,7 +799,7 @@ pg_text_enc_to_base64(t_pg_coder *conv, VALUE value, char *out, VALUE *intermedi
|
|
786
799
|
out_str = rb_str_new(NULL, BASE64_ENCODED_SIZE(strlen));
|
787
800
|
PG_ENCODING_SET_NOCHECK(out_str, enc_idx);
|
788
801
|
|
789
|
-
|
802
|
+
rbpg_base64_encode( RSTRING_PTR(out_str), RSTRING_PTR(subint), strlen);
|
790
803
|
*intermediate = out_str;
|
791
804
|
|
792
805
|
return -1;
|
data/ext/pg_tuple.c
CHANGED
@@ -125,7 +125,7 @@ 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
131
|
RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | PG_RUBY_TYPED_FROZEN_SHAREABLE,
|
@@ -135,7 +135,7 @@ static const rb_data_type_t pg_tuple_type = {
|
|
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
|
}
|
data/ext/pg_type_map.c
CHANGED
@@ -33,7 +33,7 @@ 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,
|
@@ -187,7 +187,9 @@ init_pg_type_map(void)
|
|
187
187
|
*
|
188
188
|
* This is the base class for type maps.
|
189
189
|
* See derived classes for implementations of different type cast strategies
|
190
|
-
* ( PG::TypeMapByColumn, PG::TypeMapByOid ).
|
190
|
+
* ( PG::TypeMapByColumn, PG::TypeMapByOid, etc.).
|
191
|
+
*
|
192
|
+
* Find more type maps in the {README}[rdoc-ref:README.md@Type+Casts].
|
191
193
|
*
|
192
194
|
*/
|
193
195
|
rb_cTypeMap = rb_define_class_under( rb_mPG, "TypeMap", rb_cObject );
|
data/ext/pg_type_map_by_class.c
CHANGED
data/ext/pg_type_map_by_column.c
CHANGED
@@ -54,6 +54,7 @@ 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
|
+
Check_Type(params, T_ARRAY);
|
57
58
|
nfields = (int)RARRAY_LEN( 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)",
|
@@ -228,7 +229,7 @@ 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,
|
data/ext/pg_type_map_by_oid.c
CHANGED
@@ -190,7 +190,7 @@ 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,
|
@@ -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
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,18 @@ 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
|
+
class UndefinedDefault
|
61
|
+
def self.call(oid_name, format)
|
62
|
+
raise UndefinedEncoder, "no encoder defined for type #{oid_name.inspect} format #{format}"
|
63
|
+
end
|
62
64
|
end
|
63
65
|
|
66
|
+
private_constant :UndefinedDefault
|
67
|
+
|
64
68
|
# Change the mechanism that is used to encode ruby array values
|
65
69
|
#
|
66
70
|
# Possible values:
|
@@ -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
|