pg 1.4.6 → 1.6.1
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} +185 -3
- data/Gemfile +12 -3
- data/README-Windows.rdoc +1 -1
- data/README.ja.md +75 -41
- data/README.md +86 -31
- data/Rakefile +95 -14
- data/certs/kanis@comcard.de.pem +20 -0
- data/certs/larskanis-2024.pem +24 -0
- data/ext/errorcodes.def +4 -5
- data/ext/errorcodes.txt +2 -5
- data/ext/extconf.rb +165 -14
- data/ext/gvl_wrappers.c +13 -2
- data/ext/gvl_wrappers.h +33 -0
- data/ext/pg.c +28 -35
- data/ext/pg.h +18 -14
- data/ext/pg_binary_decoder.c +231 -0
- data/ext/pg_binary_encoder.c +427 -0
- data/ext/pg_cancel_connection.c +360 -0
- data/ext/pg_coder.c +70 -12
- data/ext/pg_connection.c +473 -208
- data/ext/pg_copy_coder.c +316 -23
- data/ext/pg_record_coder.c +12 -11
- data/ext/pg_result.c +102 -30
- data/ext/pg_text_decoder.c +31 -10
- data/ext/pg_text_encoder.c +58 -26
- data/ext/pg_tuple.c +36 -33
- data/ext/pg_type_map.c +4 -3
- data/ext/pg_type_map_all_strings.c +3 -3
- data/ext/pg_type_map_by_class.c +6 -4
- data/ext/pg_type_map_by_column.c +9 -4
- data/ext/pg_type_map_by_mri_type.c +1 -1
- data/ext/pg_type_map_by_oid.c +10 -5
- data/ext/pg_type_map_in_ruby.c +6 -3
- data/lib/pg/basic_type_map_based_on_result.rb +21 -1
- data/lib/pg/basic_type_map_for_queries.rb +23 -10
- data/lib/pg/basic_type_map_for_results.rb +26 -3
- data/lib/pg/basic_type_registry.rb +46 -36
- data/lib/pg/binary_decoder/date.rb +9 -0
- data/lib/pg/binary_decoder/timestamp.rb +26 -0
- data/lib/pg/binary_encoder/timestamp.rb +20 -0
- data/lib/pg/cancel_connection.rb +53 -0
- data/lib/pg/coder.rb +18 -14
- data/lib/pg/connection.rb +387 -172
- data/lib/pg/exceptions.rb +6 -0
- data/lib/pg/text_decoder/date.rb +21 -0
- data/lib/pg/text_decoder/inet.rb +9 -0
- data/lib/pg/text_decoder/json.rb +17 -0
- data/lib/pg/text_decoder/numeric.rb +9 -0
- data/lib/pg/text_decoder/timestamp.rb +30 -0
- data/lib/pg/text_encoder/date.rb +13 -0
- data/lib/pg/text_encoder/inet.rb +31 -0
- data/lib/pg/text_encoder/json.rb +17 -0
- data/lib/pg/text_encoder/numeric.rb +9 -0
- data/lib/pg/text_encoder/timestamp.rb +24 -0
- data/lib/pg/version.rb +1 -1
- data/lib/pg.rb +78 -17
- 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 +9 -5
- data/ports/patches/krb5/1.21.3/0001-Allow-static-linking-krb5-library.patch +30 -0
- data/ports/patches/openssl/3.5.1/0001-aarch64-mingw.patch +21 -0
- data/ports/patches/postgresql/17.5/0001-Use-workaround-of-__builtin_setjmp-only-on-MINGW-on-.patch +42 -0
- data/ports/patches/postgresql/17.5/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 +61 -49
- 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 -137
- data/.gitignore +0 -19
- 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/lib/pg/binary_decoder.rb +0 -23
- data/lib/pg/constants.rb +0 -12
- data/lib/pg/text_decoder.rb +0 -46
- data/lib/pg/text_encoder.rb +0 -59
- data/translation/.po4a-version +0 -7
- data/translation/po/all.pot +0 -875
- data/translation/po/ja.po +0 -868
- data/translation/po4a.cfg +0 -9
data/ext/pg_text_encoder.c
CHANGED
@@ -119,6 +119,10 @@ pg_text_enc_boolean(t_pg_coder *this, VALUE value, char *out, VALUE *intermediat
|
|
119
119
|
int
|
120
120
|
pg_coder_enc_to_s(t_pg_coder *this, VALUE value, char *out, VALUE *intermediate, int enc_idx)
|
121
121
|
{
|
122
|
+
/* Attention:
|
123
|
+
* In contrast to all other encoders, the "this" pointer of this encoder can be NULL.
|
124
|
+
* This is because it is used as a fall-back if no encoder is defined.
|
125
|
+
*/
|
122
126
|
VALUE str = rb_obj_as_string(value);
|
123
127
|
if( ENCODING_GET(str) == enc_idx ){
|
124
128
|
*intermediate = str;
|
@@ -227,7 +231,7 @@ pg_text_enc_integer(t_pg_coder *this, VALUE value, char *out, VALUE *intermediat
|
|
227
231
|
*
|
228
232
|
*/
|
229
233
|
static int
|
230
|
-
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)
|
231
235
|
{
|
232
236
|
if(out){
|
233
237
|
double dvalue = NUM2DBL(value);
|
@@ -235,7 +239,6 @@ pg_text_enc_float(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate,
|
|
235
239
|
int neg = 0;
|
236
240
|
int exp2i, exp10i, i;
|
237
241
|
unsigned long long ll, remainder, oldval;
|
238
|
-
VALUE intermediate;
|
239
242
|
|
240
243
|
/* Cast to the same strings as value.to_s . */
|
241
244
|
if( isinf(dvalue) ){
|
@@ -279,6 +282,7 @@ pg_text_enc_float(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate,
|
|
279
282
|
|
280
283
|
if( exp10i <= -5 || exp10i >= 15 ) {
|
281
284
|
/* Write the float in exponent format (1.23e45) */
|
285
|
+
VALUE intermediate;
|
282
286
|
|
283
287
|
/* write fraction digits from right to left */
|
284
288
|
for( i = MAX_DOUBLE_DIGITS; i > 1; i--){
|
@@ -345,6 +349,8 @@ pg_text_enc_float(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate,
|
|
345
349
|
*
|
346
350
|
* It converts Integer, Float and BigDecimal objects.
|
347
351
|
* All other objects are expected to respond to +to_s+.
|
352
|
+
*
|
353
|
+
* As soon as this class is used, it requires the 'bigdecimal' gem.
|
348
354
|
*/
|
349
355
|
static int
|
350
356
|
pg_text_enc_numeric(t_pg_coder *this, VALUE value, char *out, VALUE *intermediate, int enc_idx)
|
@@ -371,6 +377,21 @@ pg_text_enc_numeric(t_pg_coder *this, VALUE value, char *out, VALUE *intermediat
|
|
371
377
|
}
|
372
378
|
}
|
373
379
|
|
380
|
+
/* called per autoload when TextEncoder::Numeric is used */
|
381
|
+
static VALUE
|
382
|
+
init_pg_text_encoder_numeric(VALUE rb_mPG_TextDecoder)
|
383
|
+
{
|
384
|
+
s_str_F = rb_str_freeze(rb_str_new_cstr("F"));
|
385
|
+
rb_global_variable(&s_str_F);
|
386
|
+
rb_funcall(rb_mPG, rb_intern("require_bigdecimal_without_warning"), 0);
|
387
|
+
s_cBigDecimal = rb_const_get(rb_cObject, rb_intern("BigDecimal"));
|
388
|
+
|
389
|
+
/* dummy = rb_define_class_under( rb_mPG_TextEncoder, "Numeric", rb_cPG_SimpleEncoder ); */
|
390
|
+
pg_define_coder( "Numeric", pg_text_enc_numeric, rb_cPG_SimpleEncoder, rb_mPG_TextEncoder );
|
391
|
+
|
392
|
+
return Qnil;
|
393
|
+
}
|
394
|
+
|
374
395
|
|
375
396
|
static const char hextab[] = {
|
376
397
|
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
|
@@ -383,8 +404,12 @@ static const char hextab[] = {
|
|
383
404
|
*
|
384
405
|
* The binary String is converted to hexadecimal representation for transmission
|
385
406
|
* in text format. For query bind parameters it is recommended to use
|
386
|
-
* PG::BinaryEncoder::Bytea
|
387
|
-
* CPU usage.
|
407
|
+
* PG::BinaryEncoder::Bytea or the hash form <tt>{value: binary_string, format: 1}</tt> instead,
|
408
|
+
* in order to decrease network traffic and CPU usage.
|
409
|
+
* See PG::Connection#exec_params for using the hash form.
|
410
|
+
*
|
411
|
+
* This encoder is particular useful when PG::TextEncoder::CopyRow is used with the COPY command.
|
412
|
+
* In this case there's no way to change the format of a single column to binary, so that the data have to be converted to bytea hex representation.
|
388
413
|
*
|
389
414
|
*/
|
390
415
|
static int
|
@@ -418,7 +443,7 @@ quote_array_buffer( void *_this, char *p_in, int strlen, char *p_out ){
|
|
418
443
|
t_pg_composite_coder *this = _this;
|
419
444
|
char *ptr1;
|
420
445
|
char *ptr2;
|
421
|
-
int
|
446
|
+
int backslashes = 0;
|
422
447
|
int needquote;
|
423
448
|
|
424
449
|
/* count data plus backslashes; detect chars needing quotes */
|
@@ -435,7 +460,7 @@ quote_array_buffer( void *_this, char *p_in, int strlen, char *p_out ){
|
|
435
460
|
|
436
461
|
if (ch == '"' || ch == '\\'){
|
437
462
|
needquote = 1;
|
438
|
-
|
463
|
+
backslashes++;
|
439
464
|
} else if (ch == '{' || ch == '}' || ch == this->delimiter ||
|
440
465
|
ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r' || ch == '\v' || ch == '\f'){
|
441
466
|
needquote = 1;
|
@@ -444,12 +469,12 @@ quote_array_buffer( void *_this, char *p_in, int strlen, char *p_out ){
|
|
444
469
|
|
445
470
|
if( needquote ){
|
446
471
|
ptr1 = p_in + strlen;
|
447
|
-
ptr2 = p_out + strlen +
|
472
|
+
ptr2 = p_out + strlen + backslashes + 2;
|
448
473
|
/* Write end quote */
|
449
474
|
*--ptr2 = '"';
|
450
475
|
|
451
476
|
/* Then store the escaped string on the final position, walking
|
452
|
-
* right to left, until all
|
477
|
+
* right to left, until all backslashes are placed. */
|
453
478
|
while( ptr1 != p_in ) {
|
454
479
|
*--ptr2 = *--ptr1;
|
455
480
|
if(*ptr2 == '"' || *ptr2 == '\\'){
|
@@ -458,7 +483,7 @@ quote_array_buffer( void *_this, char *p_in, int strlen, char *p_out ){
|
|
458
483
|
}
|
459
484
|
/* Write start quote */
|
460
485
|
*p_out = '"';
|
461
|
-
return strlen +
|
486
|
+
return strlen + backslashes + 2;
|
462
487
|
} else {
|
463
488
|
if( p_in != p_out )
|
464
489
|
memcpy( p_out, p_in, strlen );
|
@@ -512,7 +537,7 @@ quote_string(t_pg_coder *this, VALUE value, VALUE string, char *current_out, int
|
|
512
537
|
}
|
513
538
|
|
514
539
|
static char *
|
515
|
-
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)
|
516
541
|
{
|
517
542
|
int i;
|
518
543
|
|
@@ -520,6 +545,10 @@ write_array(t_pg_composite_coder *this, VALUE value, char *current_out, VALUE st
|
|
520
545
|
current_out = pg_rb_str_ensure_capa( string, 2, current_out, NULL );
|
521
546
|
*current_out++ = '{';
|
522
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
|
+
|
523
552
|
for( i=0; i<RARRAY_LEN(value); i++){
|
524
553
|
VALUE entry = rb_ary_entry(value, i);
|
525
554
|
|
@@ -529,17 +558,26 @@ write_array(t_pg_composite_coder *this, VALUE value, char *current_out, VALUE st
|
|
529
558
|
}
|
530
559
|
|
531
560
|
switch(TYPE(entry)){
|
532
|
-
case T_ARRAY:
|
533
|
-
current_out = write_array(this, entry, current_out, string, quote, enc_idx);
|
534
|
-
break;
|
535
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
|
+
}
|
536
565
|
current_out = pg_rb_str_ensure_capa( string, 4, current_out, NULL );
|
537
566
|
*current_out++ = 'N';
|
538
567
|
*current_out++ = 'U';
|
539
568
|
*current_out++ = 'L';
|
540
569
|
*current_out++ = 'L';
|
541
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 */
|
542
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
|
+
}
|
543
581
|
current_out = quote_string( this->elem, entry, string, current_out, quote, quote_array_buffer, this, enc_idx );
|
544
582
|
}
|
545
583
|
}
|
@@ -571,7 +609,7 @@ pg_text_enc_array(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate,
|
|
571
609
|
VALUE out_str = rb_str_new(NULL, 0);
|
572
610
|
PG_ENCODING_SET_NOCHECK(out_str, enc_idx);
|
573
611
|
|
574
|
-
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);
|
575
613
|
|
576
614
|
rb_str_set_len( out_str, end_ptr - RSTRING_PTR(out_str) );
|
577
615
|
*intermediate = out_str;
|
@@ -673,22 +711,22 @@ static int
|
|
673
711
|
quote_literal_buffer( void *_this, char *p_in, int strlen, char *p_out ){
|
674
712
|
char *ptr1;
|
675
713
|
char *ptr2;
|
676
|
-
int
|
714
|
+
int backslashes = 0;
|
677
715
|
|
678
716
|
/* count required backlashs */
|
679
717
|
for(ptr1 = p_in; ptr1 != p_in + strlen; ptr1++) {
|
680
718
|
if (*ptr1 == '\''){
|
681
|
-
|
719
|
+
backslashes++;
|
682
720
|
}
|
683
721
|
}
|
684
722
|
|
685
723
|
ptr1 = p_in + strlen;
|
686
|
-
ptr2 = p_out + strlen +
|
724
|
+
ptr2 = p_out + strlen + backslashes + 2;
|
687
725
|
/* Write end quote */
|
688
726
|
*--ptr2 = '\'';
|
689
727
|
|
690
728
|
/* Then store the escaped string on the final position, walking
|
691
|
-
* right to left, until all
|
729
|
+
* right to left, until all backslashes are placed. */
|
692
730
|
while( ptr1 != p_in ) {
|
693
731
|
*--ptr2 = *--ptr1;
|
694
732
|
if(*ptr2 == '\''){
|
@@ -697,7 +735,7 @@ quote_literal_buffer( void *_this, char *p_in, int strlen, char *p_out ){
|
|
697
735
|
}
|
698
736
|
/* Write start quote */
|
699
737
|
*p_out = '\'';
|
700
|
-
return strlen +
|
738
|
+
return strlen + backslashes + 2;
|
701
739
|
}
|
702
740
|
|
703
741
|
|
@@ -780,14 +818,10 @@ init_pg_text_encoder(void)
|
|
780
818
|
s_id_encode = rb_intern("encode");
|
781
819
|
s_id_to_i = rb_intern("to_i");
|
782
820
|
s_id_to_s = rb_intern("to_s");
|
783
|
-
s_str_F = rb_str_freeze(rb_str_new_cstr("F"));
|
784
|
-
rb_global_variable(&s_str_F);
|
785
|
-
rb_require("bigdecimal");
|
786
|
-
s_cBigDecimal = rb_const_get(rb_cObject, rb_intern("BigDecimal"));
|
787
|
-
|
788
821
|
|
789
822
|
/* This module encapsulates all encoder classes with text output format */
|
790
823
|
rb_mPG_TextEncoder = rb_define_module_under( rb_mPG, "TextEncoder" );
|
824
|
+
rb_define_private_method(rb_singleton_class(rb_mPG_TextEncoder), "init_numeric", init_pg_text_encoder_numeric, 0);
|
791
825
|
|
792
826
|
/* Make RDoc aware of the encoder classes... */
|
793
827
|
/* dummy = rb_define_class_under( rb_mPG_TextEncoder, "Boolean", rb_cPG_SimpleEncoder ); */
|
@@ -796,8 +830,6 @@ init_pg_text_encoder(void)
|
|
796
830
|
pg_define_coder( "Integer", pg_text_enc_integer, rb_cPG_SimpleEncoder, rb_mPG_TextEncoder );
|
797
831
|
/* dummy = rb_define_class_under( rb_mPG_TextEncoder, "Float", rb_cPG_SimpleEncoder ); */
|
798
832
|
pg_define_coder( "Float", pg_text_enc_float, rb_cPG_SimpleEncoder, rb_mPG_TextEncoder );
|
799
|
-
/* dummy = rb_define_class_under( rb_mPG_TextEncoder, "Numeric", rb_cPG_SimpleEncoder ); */
|
800
|
-
pg_define_coder( "Numeric", pg_text_enc_numeric, rb_cPG_SimpleEncoder, rb_mPG_TextEncoder );
|
801
833
|
/* dummy = rb_define_class_under( rb_mPG_TextEncoder, "String", rb_cPG_SimpleEncoder ); */
|
802
834
|
pg_define_coder( "String", pg_coder_enc_to_s, rb_cPG_SimpleEncoder, rb_mPG_TextEncoder );
|
803
835
|
/* dummy = rb_define_class_under( rb_mPG_TextEncoder, "Bytea", rb_cPG_SimpleEncoder ); */
|
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,
|
131
|
+
RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | PG_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 )
|
@@ -159,9 +159,9 @@ pg_tuple_new(VALUE result, int row_num)
|
|
159
159
|
sizeof(*this->values) * num_fields +
|
160
160
|
sizeof(*this->values) * (dup_names ? 1 : 0));
|
161
161
|
|
162
|
-
this->result
|
163
|
-
this->typemap
|
164
|
-
this->field_map
|
162
|
+
RB_OBJ_WRITE(self, &this->result, result);
|
163
|
+
RB_OBJ_WRITE(self, &this->typemap, p_result->typemap);
|
164
|
+
RB_OBJ_WRITE(self, &this->field_map, field_map);
|
165
165
|
this->row_num = row_num;
|
166
166
|
this->num_fields = num_fields;
|
167
167
|
|
@@ -173,7 +173,8 @@ pg_tuple_new(VALUE result, int row_num)
|
|
173
173
|
/* Some of the column names are duplicated -> we need the keys as Array in addition.
|
174
174
|
* Store it behind the values to save the space in the common case of no dups.
|
175
175
|
*/
|
176
|
-
|
176
|
+
VALUE keys_array = rb_obj_freeze(rb_ary_new4(num_fields, p_result->fnames));
|
177
|
+
RB_OBJ_WRITE(self, &this->values[num_fields], keys_array);
|
177
178
|
}
|
178
179
|
|
179
180
|
RTYPEDDATA_DATA(self) = this;
|
@@ -193,8 +194,9 @@ pg_tuple_get_this( VALUE self )
|
|
193
194
|
}
|
194
195
|
|
195
196
|
static VALUE
|
196
|
-
pg_tuple_materialize_field(
|
197
|
+
pg_tuple_materialize_field(VALUE self, int col)
|
197
198
|
{
|
199
|
+
t_pg_tuple *this = RTYPEDDATA_DATA( self );
|
198
200
|
VALUE value = this->values[col];
|
199
201
|
|
200
202
|
if( value == Qundef ){
|
@@ -202,29 +204,31 @@ pg_tuple_materialize_field(t_pg_tuple *this, int col)
|
|
202
204
|
|
203
205
|
pgresult_get(this->result); /* make sure we have a valid PGresult object */
|
204
206
|
value = p_typemap->funcs.typecast_result_value(p_typemap, this->result, this->row_num, col);
|
205
|
-
this->values[col]
|
207
|
+
RB_OBJ_WRITE(self, &this->values[col], value);
|
206
208
|
}
|
207
209
|
|
208
210
|
return value;
|
209
211
|
}
|
210
212
|
|
211
213
|
static void
|
212
|
-
pg_tuple_detach(
|
214
|
+
pg_tuple_detach(VALUE self)
|
213
215
|
{
|
214
|
-
this
|
215
|
-
this->
|
216
|
+
t_pg_tuple *this = RTYPEDDATA_DATA( self );
|
217
|
+
RB_OBJ_WRITE(self, &this->result, Qnil);
|
218
|
+
RB_OBJ_WRITE(self, &this->typemap, Qnil);
|
216
219
|
this->row_num = -1;
|
217
220
|
}
|
218
221
|
|
219
222
|
static void
|
220
|
-
pg_tuple_materialize(
|
223
|
+
pg_tuple_materialize(VALUE self)
|
221
224
|
{
|
225
|
+
t_pg_tuple *this = RTYPEDDATA_DATA( self );
|
222
226
|
int field_num;
|
223
227
|
for(field_num = 0; field_num < this->num_fields; field_num++) {
|
224
|
-
pg_tuple_materialize_field(
|
228
|
+
pg_tuple_materialize_field(self, field_num);
|
225
229
|
}
|
226
230
|
|
227
|
-
pg_tuple_detach(
|
231
|
+
pg_tuple_detach(self);
|
228
232
|
}
|
229
233
|
|
230
234
|
/*
|
@@ -286,7 +290,7 @@ pg_tuple_fetch(int argc, VALUE *argv, VALUE self)
|
|
286
290
|
field_num = NUM2INT(index);
|
287
291
|
}
|
288
292
|
|
289
|
-
return pg_tuple_materialize_field(
|
293
|
+
return pg_tuple_materialize_field(self, field_num);
|
290
294
|
}
|
291
295
|
|
292
296
|
/*
|
@@ -324,7 +328,7 @@ pg_tuple_aref(VALUE self, VALUE key)
|
|
324
328
|
field_num = NUM2INT(index);
|
325
329
|
}
|
326
330
|
|
327
|
-
return pg_tuple_materialize_field(
|
331
|
+
return pg_tuple_materialize_field(self, field_num);
|
328
332
|
}
|
329
333
|
|
330
334
|
static VALUE
|
@@ -335,10 +339,9 @@ pg_tuple_num_fields_for_enum(VALUE self, VALUE args, VALUE eobj)
|
|
335
339
|
}
|
336
340
|
|
337
341
|
static int
|
338
|
-
pg_tuple_yield_key_value(VALUE key, VALUE index, VALUE
|
342
|
+
pg_tuple_yield_key_value(VALUE key, VALUE index, VALUE self)
|
339
343
|
{
|
340
|
-
|
341
|
-
VALUE value = pg_tuple_materialize_field(this, NUM2INT(index));
|
344
|
+
VALUE value = pg_tuple_materialize_field(self, NUM2INT(index));
|
342
345
|
rb_yield_values(2, key, value);
|
343
346
|
return ST_CONTINUE;
|
344
347
|
}
|
@@ -360,16 +363,16 @@ pg_tuple_each(VALUE self)
|
|
360
363
|
field_names = pg_tuple_get_field_names(this);
|
361
364
|
|
362
365
|
if( field_names == Qfalse ){
|
363
|
-
rb_hash_foreach(this->field_map, pg_tuple_yield_key_value,
|
366
|
+
rb_hash_foreach(this->field_map, pg_tuple_yield_key_value, self);
|
364
367
|
} else {
|
365
368
|
int i;
|
366
369
|
for( i = 0; i < this->num_fields; i++ ){
|
367
|
-
VALUE value = pg_tuple_materialize_field(
|
370
|
+
VALUE value = pg_tuple_materialize_field(self, i);
|
368
371
|
rb_yield_values(2, RARRAY_AREF(field_names, i), value);
|
369
372
|
}
|
370
373
|
}
|
371
374
|
|
372
|
-
pg_tuple_detach(
|
375
|
+
pg_tuple_detach(self);
|
373
376
|
return self;
|
374
377
|
}
|
375
378
|
|
@@ -388,11 +391,11 @@ pg_tuple_each_value(VALUE self)
|
|
388
391
|
RETURN_SIZED_ENUMERATOR(self, 0, NULL, pg_tuple_num_fields_for_enum);
|
389
392
|
|
390
393
|
for(field_num = 0; field_num < this->num_fields; field_num++) {
|
391
|
-
VALUE value = pg_tuple_materialize_field(
|
394
|
+
VALUE value = pg_tuple_materialize_field(self, field_num);
|
392
395
|
rb_yield(value);
|
393
396
|
}
|
394
397
|
|
395
|
-
pg_tuple_detach(
|
398
|
+
pg_tuple_detach(self);
|
396
399
|
return self;
|
397
400
|
}
|
398
401
|
|
@@ -409,7 +412,7 @@ pg_tuple_values(VALUE self)
|
|
409
412
|
{
|
410
413
|
t_pg_tuple *this = pg_tuple_get_this(self);
|
411
414
|
|
412
|
-
pg_tuple_materialize(
|
415
|
+
pg_tuple_materialize(self);
|
413
416
|
return rb_ary_new4(this->num_fields, &this->values[0]);
|
414
417
|
}
|
415
418
|
|
@@ -462,7 +465,7 @@ pg_tuple_dump(VALUE self)
|
|
462
465
|
VALUE a;
|
463
466
|
t_pg_tuple *this = pg_tuple_get_this(self);
|
464
467
|
|
465
|
-
pg_tuple_materialize(
|
468
|
+
pg_tuple_materialize(self);
|
466
469
|
|
467
470
|
field_names = pg_tuple_get_field_names(this);
|
468
471
|
if( field_names == Qfalse )
|
@@ -520,26 +523,26 @@ pg_tuple_load(VALUE self, VALUE a)
|
|
520
523
|
sizeof(*this->values) * num_fields +
|
521
524
|
sizeof(*this->values) * (dup_names ? 1 : 0));
|
522
525
|
|
523
|
-
this->result
|
524
|
-
this->typemap
|
526
|
+
RB_OBJ_WRITE(self, &this->result, Qnil);
|
527
|
+
RB_OBJ_WRITE(self, &this->typemap, Qnil);
|
525
528
|
this->row_num = -1;
|
526
529
|
this->num_fields = num_fields;
|
527
|
-
this->field_map
|
530
|
+
RB_OBJ_WRITE(self, &this->field_map, field_map);
|
528
531
|
|
529
532
|
for( i = 0; i < num_fields; i++ ){
|
530
533
|
VALUE v = RARRAY_AREF(values, i);
|
531
534
|
if( v == Qundef )
|
532
535
|
rb_raise(rb_eTypeError, "field %d is not materialized", i);
|
533
|
-
this->values[i]
|
536
|
+
RB_OBJ_WRITE(self, &this->values[i], v);
|
534
537
|
}
|
535
538
|
|
536
539
|
if( dup_names ){
|
537
|
-
this->values[num_fields]
|
540
|
+
RB_OBJ_WRITE(self, &this->values[num_fields], field_names);
|
538
541
|
}
|
539
542
|
|
540
543
|
RTYPEDDATA_DATA(self) = this;
|
541
544
|
|
542
|
-
|
545
|
+
rb_copy_generic_ivar(self, a);
|
543
546
|
|
544
547
|
return self;
|
545
548
|
}
|
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,
|
40
|
+
RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | PG_RUBY_TYPED_FROZEN_SHAREABLE,
|
41
41
|
};
|
42
42
|
|
43
43
|
VALUE rb_cTypeMap;
|
@@ -132,9 +132,10 @@ pg_typemap_default_type_map_set(VALUE self, VALUE typemap)
|
|
132
132
|
t_typemap *tm;
|
133
133
|
UNUSED(tm);
|
134
134
|
|
135
|
+
rb_check_frozen(self);
|
135
136
|
/* Check type of method param */
|
136
137
|
TypedData_Get_Struct(typemap, t_typemap, &pg_typemap_type, tm);
|
137
|
-
this->default_typemap
|
138
|
+
RB_OBJ_WRITE(self, &this->default_typemap, typemap);
|
138
139
|
|
139
140
|
return typemap;
|
140
141
|
}
|
@@ -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,
|
21
|
+
RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | PG_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_funcall( rb_cTypeMapAllStrings, rb_intern("new"), 0 );
|
128
|
+
pg_typemap_all_strings = rb_obj_freeze( rb_funcall( rb_cTypeMapAllStrings, rb_intern("new"), 0 ));
|
129
129
|
rb_gc_register_address( &pg_typemap_all_strings );
|
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,
|
160
|
+
RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | PG_RUBY_TYPED_FROZEN_SHAREABLE,
|
161
161
|
};
|
162
162
|
|
163
163
|
static VALUE
|
@@ -173,12 +173,12 @@ pg_tmbk_s_allocate( VALUE klass )
|
|
173
173
|
this->typemap.funcs.typecast_result_value = pg_typemap_result_value;
|
174
174
|
this->typemap.funcs.typecast_query_param = pg_tmbk_typecast_query_param;
|
175
175
|
this->typemap.funcs.typecast_copy_get = pg_typemap_typecast_copy_get;
|
176
|
-
this->typemap.default_typemap
|
176
|
+
RB_OBJ_WRITE(self, &this->typemap.default_typemap, pg_typemap_all_strings);
|
177
177
|
|
178
178
|
/* We need to store self in the this-struct, because pg_tmbk_typecast_query_param(),
|
179
179
|
* is called with the this-pointer only. */
|
180
180
|
this->self = self;
|
181
|
-
this->klass_to_coder
|
181
|
+
RB_OBJ_WRITE(self, &this->klass_to_coder, rb_hash_new());
|
182
182
|
|
183
183
|
/* The cache is properly initialized by TypedData_Make_Struct(). */
|
184
184
|
|
@@ -205,6 +205,8 @@ pg_tmbk_aset( VALUE self, VALUE klass, VALUE coder )
|
|
205
205
|
{
|
206
206
|
t_tmbk *this = RTYPEDDATA_DATA( self );
|
207
207
|
|
208
|
+
rb_check_frozen(self);
|
209
|
+
|
208
210
|
if(NIL_P(coder)){
|
209
211
|
rb_hash_delete( this->klass_to_coder, klass );
|
210
212
|
}else{
|
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,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,
|
236
|
+
RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | PG_RUBY_TYPED_FROZEN_SHAREABLE,
|
236
237
|
};
|
237
238
|
|
238
239
|
static VALUE
|
@@ -266,13 +267,14 @@ pg_tmbc_init(VALUE self, VALUE conv_ary)
|
|
266
267
|
t_tmbc *this;
|
267
268
|
int conv_ary_len;
|
268
269
|
|
270
|
+
rb_check_frozen(self);
|
269
271
|
Check_Type(conv_ary, T_ARRAY);
|
270
272
|
conv_ary_len = RARRAY_LENINT(conv_ary);
|
271
273
|
this = xmalloc(sizeof(t_tmbc) + sizeof(struct pg_tmbc_converter) * conv_ary_len);
|
272
274
|
/* Set nfields to 0 at first, so that GC mark function doesn't access uninitialized memory. */
|
273
275
|
this->nfields = 0;
|
274
276
|
this->typemap.funcs = pg_tmbc_funcs;
|
275
|
-
this->typemap.default_typemap
|
277
|
+
RB_OBJ_WRITE(self, &this->typemap.default_typemap, pg_typemap_all_strings);
|
276
278
|
RTYPEDDATA_DATA(self) = this;
|
277
279
|
|
278
280
|
for(i=0; i<conv_ary_len; i++)
|
@@ -283,8 +285,11 @@ pg_tmbc_init(VALUE self, VALUE conv_ary)
|
|
283
285
|
/* no type cast */
|
284
286
|
this->convs[i].cconv = NULL;
|
285
287
|
} else {
|
288
|
+
t_pg_coder *p_coder;
|
286
289
|
/* Check argument type and store the coder pointer */
|
287
|
-
TypedData_Get_Struct(obj, t_pg_coder, &pg_coder_type,
|
290
|
+
TypedData_Get_Struct(obj, t_pg_coder, &pg_coder_type, p_coder);
|
291
|
+
RB_OBJ_WRITTEN(self, Qnil, p_coder->coder_obj);
|
292
|
+
this->convs[i].cconv = p_coder;
|
288
293
|
}
|
289
294
|
}
|
290
295
|
|
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,
|
197
|
+
RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | PG_RUBY_TYPED_FROZEN_SHAREABLE,
|
198
198
|
};
|
199
199
|
|
200
200
|
static VALUE
|
@@ -212,11 +212,11 @@ pg_tmbo_s_allocate( VALUE klass )
|
|
212
212
|
this->typemap.funcs.typecast_result_value = pg_tmbo_result_value;
|
213
213
|
this->typemap.funcs.typecast_query_param = pg_typemap_typecast_query_param;
|
214
214
|
this->typemap.funcs.typecast_copy_get = pg_typemap_typecast_copy_get;
|
215
|
-
this->typemap.default_typemap
|
215
|
+
RB_OBJ_WRITE(self, &this->typemap.default_typemap, pg_typemap_all_strings);
|
216
216
|
this->max_rows_for_online_lookup = 10;
|
217
217
|
|
218
218
|
for( i=0; i<2; i++){
|
219
|
-
this->format[i].oid_to_coder
|
219
|
+
RB_OBJ_WRITE(self, &this->format[i].oid_to_coder, rb_hash_new());
|
220
220
|
}
|
221
221
|
|
222
222
|
return self;
|
@@ -242,6 +242,7 @@ pg_tmbo_add_coder( VALUE self, VALUE coder )
|
|
242
242
|
t_pg_coder *p_coder;
|
243
243
|
struct pg_tmbo_oid_cache_entry *p_ce;
|
244
244
|
|
245
|
+
rb_check_frozen(self);
|
245
246
|
TypedData_Get_Struct(coder, t_pg_coder, &pg_coder_type, p_coder);
|
246
247
|
|
247
248
|
if( p_coder->format < 0 || p_coder->format > 1 )
|
@@ -276,6 +277,7 @@ pg_tmbo_rm_coder( VALUE self, VALUE format, VALUE oid )
|
|
276
277
|
int i_format = NUM2INT(format);
|
277
278
|
struct pg_tmbo_oid_cache_entry *p_ce;
|
278
279
|
|
280
|
+
rb_check_frozen(self);
|
279
281
|
if( i_format < 0 || i_format > 1 )
|
280
282
|
rb_raise(rb_eArgError, "invalid format code %d", i_format);
|
281
283
|
|
@@ -313,11 +315,14 @@ pg_tmbo_coders( VALUE self )
|
|
313
315
|
* The type map will do Hash lookups for each result value, if the number of rows
|
314
316
|
* is below or equal +number+.
|
315
317
|
*
|
318
|
+
* Default is 10.
|
319
|
+
*
|
316
320
|
*/
|
317
321
|
static VALUE
|
318
322
|
pg_tmbo_max_rows_for_online_lookup_set( VALUE self, VALUE value )
|
319
323
|
{
|
320
324
|
t_tmbo *this = RTYPEDDATA_DATA( self );
|
325
|
+
rb_check_frozen(self);
|
321
326
|
this->max_rows_for_online_lookup = NUM2INT(value);
|
322
327
|
return value;
|
323
328
|
}
|
@@ -338,7 +343,7 @@ pg_tmbo_max_rows_for_online_lookup_get( VALUE self )
|
|
338
343
|
* typemap.build_column_map( result )
|
339
344
|
*
|
340
345
|
* This builds a PG::TypeMapByColumn that fits to the given PG::Result object
|
341
|
-
* based on it's type OIDs.
|
346
|
+
* based on it's type OIDs and binary/text format.
|
342
347
|
*
|
343
348
|
*/
|
344
349
|
static VALUE
|