pg 1.2.3 → 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/CHANGELOG.md +986 -0
- data/Gemfile +23 -0
- data/README-Windows.rdoc +1 -1
- data/README.ja.md +300 -0
- data/README.md +327 -0
- data/Rakefile +123 -144
- data/certs/ged.pem +24 -0
- data/certs/kanis@comcard.de.pem +20 -0
- data/certs/larskanis-2022.pem +26 -0
- data/certs/larskanis-2023.pem +24 -0
- data/certs/larskanis-2024.pem +24 -0
- data/ext/errorcodes.def +16 -5
- data/ext/errorcodes.rb +0 -0
- data/ext/errorcodes.txt +5 -5
- data/ext/extconf.rb +259 -33
- data/ext/gvl_wrappers.c +17 -2
- data/ext/gvl_wrappers.h +56 -0
- data/ext/pg.c +89 -63
- data/ext/pg.h +31 -8
- data/ext/pg_binary_decoder.c +232 -1
- data/ext/pg_binary_encoder.c +428 -1
- data/ext/pg_cancel_connection.c +360 -0
- data/ext/pg_coder.c +148 -36
- data/ext/pg_connection.c +1365 -817
- data/ext/pg_copy_coder.c +360 -38
- data/ext/pg_errors.c +1 -1
- data/ext/pg_record_coder.c +56 -25
- data/ext/pg_result.c +187 -76
- data/ext/pg_text_decoder.c +32 -11
- data/ext/pg_text_encoder.c +65 -33
- data/ext/pg_tuple.c +84 -61
- data/ext/pg_type_map.c +44 -10
- data/ext/pg_type_map_all_strings.c +17 -3
- data/ext/pg_type_map_by_class.c +54 -27
- data/ext/pg_type_map_by_column.c +74 -31
- data/ext/pg_type_map_by_mri_type.c +48 -19
- data/ext/pg_type_map_by_oid.c +61 -27
- data/ext/pg_type_map_in_ruby.c +55 -21
- data/ext/pg_util.c +2 -2
- data/lib/pg/basic_type_map_based_on_result.rb +67 -0
- data/lib/pg/basic_type_map_for_queries.rb +206 -0
- data/lib/pg/basic_type_map_for_results.rb +104 -0
- data/lib/pg/basic_type_registry.rb +311 -0
- 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 +894 -91
- data/lib/pg/exceptions.rb +20 -1
- 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 +4 -0
- data/lib/pg.rb +109 -39
- 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/misc/yugabyte/Dockerfile +9 -0
- data/misc/yugabyte/docker-compose.yml +28 -0
- data/misc/yugabyte/pg-test.rb +45 -0
- data/pg.gemspec +38 -0
- 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/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 +139 -213
- metadata.gz.sig +0 -0
- data/.gemtest +0 -0
- data/ChangeLog +0 -0
- data/History.rdoc +0 -578
- data/Manifest.txt +0 -73
- data/README.ja.rdoc +0 -13
- data/README.rdoc +0 -213
- data/Rakefile.cross +0 -299
- data/lib/pg/basic_type_mapping.rb +0 -522
- 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/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_text_decoder.c
CHANGED
@@ -43,7 +43,6 @@
|
|
43
43
|
#include <string.h>
|
44
44
|
|
45
45
|
VALUE rb_mPG_TextDecoder;
|
46
|
-
static ID s_id_decode;
|
47
46
|
static ID s_id_Rational;
|
48
47
|
static ID s_id_new;
|
49
48
|
static ID s_id_utc;
|
@@ -164,6 +163,8 @@ pg_text_dec_integer(t_pg_coder *conv, const char *val, int len, int tuple, int f
|
|
164
163
|
* This is a decoder class for conversion of PostgreSQL numeric types
|
165
164
|
* to Ruby BigDecimal objects.
|
166
165
|
*
|
166
|
+
* As soon as this class is used, it requires the 'bigdecimal' gem.
|
167
|
+
*
|
167
168
|
*/
|
168
169
|
static VALUE
|
169
170
|
pg_text_dec_numeric(t_pg_coder *conv, const char *val, int len, int tuple, int field, int enc_idx)
|
@@ -171,6 +172,19 @@ pg_text_dec_numeric(t_pg_coder *conv, const char *val, int len, int tuple, int f
|
|
171
172
|
return rb_funcall(rb_cObject, s_id_BigDecimal, 1, rb_str_new(val, len));
|
172
173
|
}
|
173
174
|
|
175
|
+
/* called per autoload when TextDecoder::Numeric is used */
|
176
|
+
static VALUE
|
177
|
+
init_pg_text_decoder_numeric(VALUE rb_mPG_TextDecoder)
|
178
|
+
{
|
179
|
+
rb_funcall(rb_mPG, rb_intern("require_bigdecimal_without_warning"), 0);
|
180
|
+
s_id_BigDecimal = rb_intern("BigDecimal");
|
181
|
+
|
182
|
+
/* dummy = rb_define_class_under( rb_mPG_TextDecoder, "Numeric", rb_cPG_SimpleDecoder ); */
|
183
|
+
pg_define_coder( "Numeric", pg_text_dec_numeric, rb_cPG_SimpleDecoder, rb_mPG_TextDecoder );
|
184
|
+
|
185
|
+
return Qnil;
|
186
|
+
}
|
187
|
+
|
174
188
|
/*
|
175
189
|
* Document-class: PG::TextDecoder::Float < PG::SimpleDecoder
|
176
190
|
*
|
@@ -799,6 +813,7 @@ static VALUE pg_text_dec_timestamp(t_pg_coder *conv, const char *val, int len, i
|
|
799
813
|
* This is a decoder class for conversion of PostgreSQL inet type
|
800
814
|
* to Ruby IPAddr values.
|
801
815
|
*
|
816
|
+
* As soon as this class is used, it requires the ruby standard library 'ipaddr'.
|
802
817
|
*/
|
803
818
|
static VALUE
|
804
819
|
pg_text_dec_inet(t_pg_coder *conv, const char *val, int len, int tuple, int field, int enc_idx)
|
@@ -854,7 +869,7 @@ pg_text_dec_inet(t_pg_coder *conv, const char *val, int len, int tuple, int fiel
|
|
854
869
|
|
855
870
|
ip_int_native = read_nbo32(dst);
|
856
871
|
|
857
|
-
/* Work around broken IPAddr behavior of
|
872
|
+
/* Work around broken IPAddr behavior of converting portion
|
858
873
|
of address after netmask to 0 */
|
859
874
|
switch (mask) {
|
860
875
|
case 0:
|
@@ -922,8 +937,9 @@ pg_text_dec_inet(t_pg_coder *conv, const char *val, int len, int tuple, int fiel
|
|
922
937
|
return ip;
|
923
938
|
}
|
924
939
|
|
925
|
-
|
926
|
-
|
940
|
+
/* called per autoload when TextDecoder::Inet is used */
|
941
|
+
static VALUE
|
942
|
+
init_pg_text_decoder_inet(VALUE rb_mPG_TextDecoder)
|
927
943
|
{
|
928
944
|
rb_require("ipaddr");
|
929
945
|
s_IPAddr = rb_funcall(rb_cObject, rb_intern("const_get"), 1, rb_str_new2("IPAddr"));
|
@@ -942,14 +958,21 @@ init_pg_text_decoder()
|
|
942
958
|
s_vmasks6 = rb_eval_string("a = [0]*129; a[0] = 0; a[128] = 0xffffffffffffffffffffffffffffffff; 127.downto(1){|i| a[i] = a[i+1] - (1 << (127 - i))}; a.freeze");
|
943
959
|
rb_global_variable(&s_vmasks6);
|
944
960
|
|
945
|
-
|
961
|
+
/* dummy = rb_define_class_under( rb_mPG_TextDecoder, "Inet", rb_cPG_SimpleDecoder ); */
|
962
|
+
pg_define_coder( "Inet", pg_text_dec_inet, rb_cPG_SimpleDecoder, rb_mPG_TextDecoder);
|
963
|
+
|
964
|
+
return Qnil;
|
965
|
+
}
|
966
|
+
|
967
|
+
|
968
|
+
void
|
969
|
+
init_pg_text_decoder(void)
|
970
|
+
{
|
946
971
|
s_id_Rational = rb_intern("Rational");
|
947
972
|
s_id_new = rb_intern("new");
|
948
973
|
s_id_utc = rb_intern("utc");
|
949
974
|
s_id_getlocal = rb_intern("getlocal");
|
950
975
|
|
951
|
-
rb_require("bigdecimal");
|
952
|
-
s_id_BigDecimal = rb_intern("BigDecimal");
|
953
976
|
s_nan = rb_eval_string("0.0/0.0");
|
954
977
|
rb_global_variable(&s_nan);
|
955
978
|
s_pos_inf = rb_eval_string("1.0/0.0");
|
@@ -959,6 +982,8 @@ init_pg_text_decoder()
|
|
959
982
|
|
960
983
|
/* This module encapsulates all decoder classes with text input format */
|
961
984
|
rb_mPG_TextDecoder = rb_define_module_under( rb_mPG, "TextDecoder" );
|
985
|
+
rb_define_private_method(rb_singleton_class(rb_mPG_TextDecoder), "init_inet", init_pg_text_decoder_inet, 0);
|
986
|
+
rb_define_private_method(rb_singleton_class(rb_mPG_TextDecoder), "init_numeric", init_pg_text_decoder_numeric, 0);
|
962
987
|
|
963
988
|
/* Make RDoc aware of the decoder classes... */
|
964
989
|
/* dummy = rb_define_class_under( rb_mPG_TextDecoder, "Boolean", rb_cPG_SimpleDecoder ); */
|
@@ -967,8 +992,6 @@ init_pg_text_decoder()
|
|
967
992
|
pg_define_coder( "Integer", pg_text_dec_integer, rb_cPG_SimpleDecoder, rb_mPG_TextDecoder );
|
968
993
|
/* dummy = rb_define_class_under( rb_mPG_TextDecoder, "Float", rb_cPG_SimpleDecoder ); */
|
969
994
|
pg_define_coder( "Float", pg_text_dec_float, rb_cPG_SimpleDecoder, rb_mPG_TextDecoder );
|
970
|
-
/* dummy = rb_define_class_under( rb_mPG_TextDecoder, "Numeric", rb_cPG_SimpleDecoder ); */
|
971
|
-
pg_define_coder( "Numeric", pg_text_dec_numeric, rb_cPG_SimpleDecoder, rb_mPG_TextDecoder );
|
972
995
|
/* dummy = rb_define_class_under( rb_mPG_TextDecoder, "String", rb_cPG_SimpleDecoder ); */
|
973
996
|
pg_define_coder( "String", pg_text_dec_string, rb_cPG_SimpleDecoder, rb_mPG_TextDecoder );
|
974
997
|
/* dummy = rb_define_class_under( rb_mPG_TextDecoder, "Bytea", rb_cPG_SimpleDecoder ); */
|
@@ -977,8 +1000,6 @@ init_pg_text_decoder()
|
|
977
1000
|
pg_define_coder( "Identifier", pg_text_dec_identifier, rb_cPG_SimpleDecoder, rb_mPG_TextDecoder );
|
978
1001
|
/* dummy = rb_define_class_under( rb_mPG_TextDecoder, "Timestamp", rb_cPG_SimpleDecoder ); */
|
979
1002
|
pg_define_coder( "Timestamp", pg_text_dec_timestamp, rb_cPG_SimpleDecoder, rb_mPG_TextDecoder);
|
980
|
-
/* dummy = rb_define_class_under( rb_mPG_TextDecoder, "Inet", rb_cPG_SimpleDecoder ); */
|
981
|
-
pg_define_coder( "Inet", pg_text_dec_inet, rb_cPG_SimpleDecoder, rb_mPG_TextDecoder);
|
982
1003
|
|
983
1004
|
/* dummy = rb_define_class_under( rb_mPG_TextDecoder, "Array", rb_cPG_CompositeDecoder ); */
|
984
1005
|
pg_define_coder( "Array", pg_text_dec_array, rb_cPG_CompositeDecoder, rb_mPG_TextDecoder );
|
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;
|
@@ -191,7 +195,7 @@ pg_text_enc_integer(t_pg_coder *this, VALUE value, char *out, VALUE *intermediat
|
|
191
195
|
if (neg)
|
192
196
|
*out++ = '-';
|
193
197
|
|
194
|
-
len = out - start;
|
198
|
+
len = (int)(out - start);
|
195
199
|
|
196
200
|
/* Reverse string. */
|
197
201
|
out--;
|
@@ -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) ){
|
@@ -252,7 +255,7 @@ pg_text_enc_float(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate,
|
|
252
255
|
}
|
253
256
|
|
254
257
|
/*
|
255
|
-
* The following
|
258
|
+
* The following computation is roughly a conversion kind of
|
256
259
|
* sprintf( out, "%.16E", dvalue);
|
257
260
|
*/
|
258
261
|
|
@@ -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
|
@@ -403,11 +428,11 @@ pg_text_enc_bytea(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate,
|
|
403
428
|
*optr++ = hextab[c >> 4];
|
404
429
|
*optr++ = hextab[c & 0xf];
|
405
430
|
}
|
406
|
-
return optr - out;
|
431
|
+
return (int)(optr - out);
|
407
432
|
}else{
|
408
433
|
*intermediate = rb_obj_as_string(value);
|
409
434
|
/* The output starts with "\x" and each character is converted to hex. */
|
410
|
-
return 2 +
|
435
|
+
return 2 + RSTRING_LENINT(*intermediate) * 2;
|
411
436
|
}
|
412
437
|
}
|
413
438
|
|
@@ -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;
|
@@ -610,8 +648,8 @@ quote_identifier( VALUE value, VALUE out_string, char *current_out ){
|
|
610
648
|
static char *
|
611
649
|
pg_text_enc_array_identifier(VALUE value, VALUE string, char *out, int enc_idx)
|
612
650
|
{
|
613
|
-
|
614
|
-
|
651
|
+
long i;
|
652
|
+
long nr_elems;
|
615
653
|
|
616
654
|
Check_Type(value, T_ARRAY);
|
617
655
|
nr_elems = RARRAY_LEN(value);
|
@@ -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
|
|
@@ -775,19 +813,15 @@ pg_text_enc_to_base64(t_pg_coder *conv, VALUE value, char *out, VALUE *intermedi
|
|
775
813
|
|
776
814
|
|
777
815
|
void
|
778
|
-
init_pg_text_encoder()
|
816
|
+
init_pg_text_encoder(void)
|
779
817
|
{
|
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()
|
|
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 ); */
|