pg 1.0.0 → 1.5.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/.appveyor.yml +42 -0
- data/.gems +6 -0
- data/.github/workflows/binary-gems.yml +117 -0
- data/.github/workflows/source-gem.yml +141 -0
- data/.gitignore +22 -0
- data/.hgsigs +34 -0
- data/.hgtags +41 -0
- data/.irbrc +23 -0
- data/.pryrc +23 -0
- data/.tm_properties +21 -0
- data/.travis.yml +49 -0
- data/Gemfile +14 -0
- data/History.md +884 -0
- data/Manifest.txt +8 -3
- data/README-Windows.rdoc +4 -4
- data/README.ja.md +300 -0
- data/README.md +286 -0
- data/Rakefile +38 -138
- data/Rakefile.cross +63 -63
- data/certs/ged.pem +24 -0
- data/certs/larskanis-2022.pem +26 -0
- data/certs/larskanis-2023.pem +24 -0
- data/ext/errorcodes.def +80 -0
- data/ext/errorcodes.rb +1 -1
- data/ext/errorcodes.txt +22 -2
- data/ext/extconf.rb +106 -25
- data/ext/gvl_wrappers.c +4 -0
- data/ext/gvl_wrappers.h +23 -0
- data/ext/pg.c +213 -155
- data/ext/pg.h +89 -23
- data/ext/pg_binary_decoder.c +162 -16
- data/ext/pg_binary_encoder.c +238 -13
- data/ext/pg_coder.c +159 -35
- data/ext/pg_connection.c +1557 -972
- data/ext/pg_copy_coder.c +364 -38
- data/ext/pg_errors.c +1 -1
- data/ext/pg_record_coder.c +522 -0
- data/ext/pg_result.c +708 -215
- data/ext/pg_text_decoder.c +627 -43
- data/ext/pg_text_encoder.c +206 -62
- data/ext/pg_tuple.c +572 -0
- data/ext/pg_type_map.c +45 -11
- data/ext/pg_type_map_all_strings.c +21 -7
- data/ext/pg_type_map_by_class.c +59 -27
- data/ext/pg_type_map_by_column.c +80 -37
- data/ext/pg_type_map_by_mri_type.c +49 -20
- data/ext/pg_type_map_by_oid.c +62 -29
- data/ext/pg_type_map_in_ruby.c +56 -22
- data/ext/{util.c → pg_util.c} +12 -12
- data/ext/{util.h → pg_util.h} +2 -2
- data/lib/pg/basic_type_map_based_on_result.rb +67 -0
- data/lib/pg/basic_type_map_for_queries.rb +198 -0
- data/lib/pg/basic_type_map_for_results.rb +104 -0
- data/lib/pg/basic_type_registry.rb +299 -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/coder.rb +36 -13
- data/lib/pg/connection.rb +749 -70
- data/lib/pg/exceptions.rb +16 -2
- data/lib/pg/result.rb +14 -2
- data/lib/pg/text_decoder/date.rb +18 -0
- data/lib/pg/text_decoder/inet.rb +9 -0
- data/lib/pg/text_decoder/json.rb +14 -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 +12 -0
- data/lib/pg/text_encoder/inet.rb +28 -0
- data/lib/pg/text_encoder/json.rb +14 -0
- data/lib/pg/text_encoder/numeric.rb +9 -0
- data/lib/pg/text_encoder/timestamp.rb +24 -0
- data/lib/pg/tuple.rb +30 -0
- data/lib/pg/type_map_by_column.rb +3 -2
- data/lib/pg/version.rb +4 -0
- data/lib/pg.rb +96 -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/pg.gemspec +34 -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/translation/.po4a-version +7 -0
- data/translation/po/all.pot +936 -0
- data/translation/po/ja.po +1036 -0
- data/translation/po4a.cfg +12 -0
- data.tar.gz.sig +0 -0
- metadata +147 -219
- metadata.gz.sig +0 -0
- data/ChangeLog +0 -6595
- data/History.rdoc +0 -422
- data/README.ja.rdoc +0 -14
- data/README.rdoc +0 -167
- data/lib/pg/basic_type_mapping.rb +0 -426
- data/lib/pg/constants.rb +0 -11
- data/lib/pg/text_decoder.rb +0 -51
- data/lib/pg/text_encoder.rb +0 -35
- data/spec/data/expected_trace.out +0 -26
- data/spec/data/random_binary_data +0 -0
- data/spec/helpers.rb +0 -348
- data/spec/pg/basic_type_mapping_spec.rb +0 -305
- data/spec/pg/connection_spec.rb +0 -1719
- data/spec/pg/result_spec.rb +0 -456
- data/spec/pg/type_map_by_class_spec.rb +0 -138
- data/spec/pg/type_map_by_column_spec.rb +0 -222
- 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 -777
- data/spec/pg_spec.rb +0 -50
data/ext/pg_text_encoder.c
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/*
|
|
2
2
|
* pg_text_encoder.c - PG::TextEncoder module
|
|
3
|
-
* $Id
|
|
3
|
+
* $Id$
|
|
4
4
|
*
|
|
5
5
|
*/
|
|
6
6
|
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
|
|
42
42
|
|
|
43
43
|
#include "pg.h"
|
|
44
|
-
#include "
|
|
44
|
+
#include "pg_util.h"
|
|
45
45
|
#ifdef HAVE_INTTYPES_H
|
|
46
46
|
#include <inttypes.h>
|
|
47
47
|
#endif
|
|
@@ -50,6 +50,9 @@
|
|
|
50
50
|
VALUE rb_mPG_TextEncoder;
|
|
51
51
|
static ID s_id_encode;
|
|
52
52
|
static ID s_id_to_i;
|
|
53
|
+
static ID s_id_to_s;
|
|
54
|
+
static ID s_cBigDecimal;
|
|
55
|
+
static VALUE s_str_F;
|
|
53
56
|
|
|
54
57
|
static int pg_text_enc_integer(t_pg_coder *this, VALUE value, char *out, VALUE *intermediate, int enc_idx);
|
|
55
58
|
|
|
@@ -125,11 +128,29 @@ pg_coder_enc_to_s(t_pg_coder *this, VALUE value, char *out, VALUE *intermediate,
|
|
|
125
128
|
return -1;
|
|
126
129
|
}
|
|
127
130
|
|
|
131
|
+
static int
|
|
132
|
+
count_leading_zero_bits(unsigned long long x)
|
|
133
|
+
{
|
|
134
|
+
#if defined(__GNUC__) || defined(__clang__)
|
|
135
|
+
return __builtin_clzll(x);
|
|
136
|
+
#elif defined(_MSC_VER)
|
|
137
|
+
DWORD r = 0;
|
|
138
|
+
_BitScanForward64(&r, x);
|
|
139
|
+
return (int)r;
|
|
140
|
+
#else
|
|
141
|
+
unsigned int a;
|
|
142
|
+
for(a=0; a < sizeof(unsigned long long) * 8; a++){
|
|
143
|
+
if( x & (1 << (sizeof(unsigned long long) * 8 - 1))) return a;
|
|
144
|
+
x <<= 1;
|
|
145
|
+
}
|
|
146
|
+
return a;
|
|
147
|
+
#endif
|
|
148
|
+
}
|
|
128
149
|
|
|
129
150
|
/*
|
|
130
151
|
* Document-class: PG::TextEncoder::Integer < PG::SimpleEncoder
|
|
131
152
|
*
|
|
132
|
-
* This is the encoder class for the PostgreSQL
|
|
153
|
+
* This is the encoder class for the PostgreSQL integer types.
|
|
133
154
|
*
|
|
134
155
|
* Non-Integer values are expected to have method +to_i+ defined.
|
|
135
156
|
*
|
|
@@ -144,20 +165,23 @@ pg_text_enc_integer(t_pg_coder *this, VALUE value, char *out, VALUE *intermediat
|
|
|
144
165
|
char *start = out;
|
|
145
166
|
int len;
|
|
146
167
|
int neg = 0;
|
|
147
|
-
long long
|
|
168
|
+
long long sll = NUM2LL(*intermediate);
|
|
169
|
+
unsigned long long ll;
|
|
148
170
|
|
|
149
|
-
if (
|
|
150
|
-
/*
|
|
151
|
-
* as a positive integer,
|
|
171
|
+
if (sll < 0) {
|
|
172
|
+
/* Avoid problems with the most negative integer not being representable
|
|
173
|
+
* as a positive integer, by using unsigned long long for encoding.
|
|
152
174
|
*/
|
|
153
|
-
ll = -
|
|
175
|
+
ll = -sll;
|
|
154
176
|
neg = 1;
|
|
177
|
+
} else {
|
|
178
|
+
ll = sll;
|
|
155
179
|
}
|
|
156
180
|
|
|
157
181
|
/* Compute the result string backwards. */
|
|
158
182
|
do {
|
|
159
|
-
long long remainder;
|
|
160
|
-
long long oldval = ll;
|
|
183
|
+
unsigned long long remainder;
|
|
184
|
+
unsigned long long oldval = ll;
|
|
161
185
|
|
|
162
186
|
ll /= 10;
|
|
163
187
|
remainder = oldval - ll * 10;
|
|
@@ -167,7 +191,7 @@ pg_text_enc_integer(t_pg_coder *this, VALUE value, char *out, VALUE *intermediat
|
|
|
167
191
|
if (neg)
|
|
168
192
|
*out++ = '-';
|
|
169
193
|
|
|
170
|
-
len = out - start;
|
|
194
|
+
len = (int)(out - start);
|
|
171
195
|
|
|
172
196
|
/* Reverse string. */
|
|
173
197
|
out--;
|
|
@@ -184,45 +208,17 @@ pg_text_enc_integer(t_pg_coder *this, VALUE value, char *out, VALUE *intermediat
|
|
|
184
208
|
}else{
|
|
185
209
|
*intermediate = pg_obj_to_i(value);
|
|
186
210
|
if(TYPE(*intermediate) == T_FIXNUM){
|
|
187
|
-
int len;
|
|
188
211
|
long long sll = NUM2LL(*intermediate);
|
|
189
|
-
long long ll = sll < 0 ? -sll : sll;
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
if( ll < 100 ){
|
|
193
|
-
len = ll < 10 ? 1 : 2;
|
|
194
|
-
}else{
|
|
195
|
-
len = ll < 1000 ? 3 : 4;
|
|
196
|
-
}
|
|
197
|
-
}else{
|
|
198
|
-
if( ll < 1000000 ){
|
|
199
|
-
len = ll < 100000 ? 5 : 6;
|
|
200
|
-
}else{
|
|
201
|
-
len = ll < 10000000 ? 7 : 8;
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
}else{
|
|
205
|
-
if( ll < 1000000000000LL ){
|
|
206
|
-
if( ll < 10000000000LL ){
|
|
207
|
-
len = ll < 1000000000LL ? 9 : 10;
|
|
208
|
-
}else{
|
|
209
|
-
len = ll < 100000000000LL ? 11 : 12;
|
|
210
|
-
}
|
|
211
|
-
}else{
|
|
212
|
-
if( ll < 100000000000000LL ){
|
|
213
|
-
len = ll < 10000000000000LL ? 13 : 14;
|
|
214
|
-
}else{
|
|
215
|
-
return pg_coder_enc_to_s(this, *intermediate, NULL, intermediate, enc_idx);
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
return sll < 0 ? len+1 : len;
|
|
212
|
+
unsigned long long ll = sll < 0 ? -sll : sll;
|
|
213
|
+
int len = (sizeof(unsigned long long) * 8 - count_leading_zero_bits(ll)) / 3;
|
|
214
|
+
return sll < 0 ? len+2 : len+1;
|
|
220
215
|
}else{
|
|
221
216
|
return pg_coder_enc_to_s(this, *intermediate, NULL, intermediate, enc_idx);
|
|
222
217
|
}
|
|
223
218
|
}
|
|
224
219
|
}
|
|
225
220
|
|
|
221
|
+
#define MAX_DOUBLE_DIGITS 16
|
|
226
222
|
|
|
227
223
|
/*
|
|
228
224
|
* Document-class: PG::TextEncoder::Float < PG::SimpleEncoder
|
|
@@ -235,6 +231,12 @@ pg_text_enc_float(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate,
|
|
|
235
231
|
{
|
|
236
232
|
if(out){
|
|
237
233
|
double dvalue = NUM2DBL(value);
|
|
234
|
+
int len = 0;
|
|
235
|
+
int neg = 0;
|
|
236
|
+
int exp2i, exp10i, i;
|
|
237
|
+
unsigned long long ll, remainder, oldval;
|
|
238
|
+
VALUE intermediate;
|
|
239
|
+
|
|
238
240
|
/* Cast to the same strings as value.to_s . */
|
|
239
241
|
if( isinf(dvalue) ){
|
|
240
242
|
if( dvalue < 0 ){
|
|
@@ -248,12 +250,143 @@ pg_text_enc_float(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate,
|
|
|
248
250
|
memcpy( out, "NaN", 3);
|
|
249
251
|
return 3;
|
|
250
252
|
}
|
|
251
|
-
|
|
253
|
+
|
|
254
|
+
/*
|
|
255
|
+
* The following computation is roughly a conversion kind of
|
|
256
|
+
* sprintf( out, "%.16E", dvalue);
|
|
257
|
+
*/
|
|
258
|
+
|
|
259
|
+
/* write the algebraic sign */
|
|
260
|
+
if( dvalue < 0 ) {
|
|
261
|
+
dvalue = -dvalue;
|
|
262
|
+
*out++ = '-';
|
|
263
|
+
neg++;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/* retrieve the power of 2 exponent */
|
|
267
|
+
frexp(dvalue, &exp2i);
|
|
268
|
+
/* compute the power of 10 exponent */
|
|
269
|
+
exp10i = (int)floor(exp2i * 0.30102999566398114); /* Math.log(2)/Math.log(10) */
|
|
270
|
+
/* move the decimal point, so that we get an integer of MAX_DOUBLE_DIGITS decimal digits */
|
|
271
|
+
ll = (unsigned long long)(dvalue * pow(10, MAX_DOUBLE_DIGITS - 1 - exp10i) + 0.5);
|
|
272
|
+
|
|
273
|
+
/* avoid leading zeros due to inaccuracy of deriving exp10i from exp2i */
|
|
274
|
+
/* otherwise we would print "09.0" instead of "9.0" */
|
|
275
|
+
if( ll < 1000000000000000 ){ /* pow(10, MAX_DOUBLE_DIGITS-1) */
|
|
276
|
+
exp10i--;
|
|
277
|
+
ll *= 10;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
if( exp10i <= -5 || exp10i >= 15 ) {
|
|
281
|
+
/* Write the float in exponent format (1.23e45) */
|
|
282
|
+
|
|
283
|
+
/* write fraction digits from right to left */
|
|
284
|
+
for( i = MAX_DOUBLE_DIGITS; i > 1; i--){
|
|
285
|
+
oldval = ll;
|
|
286
|
+
ll /= 10;
|
|
287
|
+
remainder = oldval - ll * 10;
|
|
288
|
+
/* omit trailing zeros */
|
|
289
|
+
if(remainder != 0 || len ) {
|
|
290
|
+
out[i] = '0' + remainder;
|
|
291
|
+
len++;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/* write decimal point */
|
|
296
|
+
if( len ){
|
|
297
|
+
out[1] = '.';
|
|
298
|
+
len++;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/* write remaining single digit left to the decimal point */
|
|
302
|
+
oldval = ll;
|
|
303
|
+
ll /= 10;
|
|
304
|
+
remainder = oldval - ll * 10;
|
|
305
|
+
out[0] = '0' + remainder;
|
|
306
|
+
len++;
|
|
307
|
+
|
|
308
|
+
/* write exponent */
|
|
309
|
+
out[len++] = 'e';
|
|
310
|
+
intermediate = INT2NUM(exp10i);
|
|
311
|
+
|
|
312
|
+
return neg + len + pg_text_enc_integer(conv, Qnil, out + len, &intermediate, enc_idx);
|
|
313
|
+
} else {
|
|
314
|
+
/* write the float in non exponent format (0.001234 or 123450.0) */
|
|
315
|
+
|
|
316
|
+
/* write digits from right to left */
|
|
317
|
+
int lz = exp10i < 0 ? 0 : exp10i;
|
|
318
|
+
for( i = MAX_DOUBLE_DIGITS - (exp10i < 0 ? exp10i : 0); i >= 0; i-- ){
|
|
319
|
+
oldval = ll;
|
|
320
|
+
ll /= 10;
|
|
321
|
+
remainder = oldval - ll * 10;
|
|
322
|
+
/* write decimal point */
|
|
323
|
+
if( i - 1 == lz ){
|
|
324
|
+
out[i--] = '.';
|
|
325
|
+
len++;
|
|
326
|
+
}
|
|
327
|
+
/* if possible then omit trailing zeros */
|
|
328
|
+
if(remainder != 0 || len || i - 2 == lz) {
|
|
329
|
+
out[i] = '0' + remainder;
|
|
330
|
+
len++;
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
return neg + len;
|
|
334
|
+
}
|
|
252
335
|
}else{
|
|
253
|
-
return
|
|
336
|
+
return 1 /*sign*/ + MAX_DOUBLE_DIGITS + 1 /*dot*/ + 1 /*e*/ + 1 /*exp sign*/ + 3 /*exp digits*/;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
/*
|
|
342
|
+
* Document-class: PG::TextEncoder::Numeric < PG::SimpleEncoder
|
|
343
|
+
*
|
|
344
|
+
* This is the encoder class for the PostgreSQL numeric types.
|
|
345
|
+
*
|
|
346
|
+
* It converts Integer, Float and BigDecimal objects.
|
|
347
|
+
* All other objects are expected to respond to +to_s+.
|
|
348
|
+
*/
|
|
349
|
+
static int
|
|
350
|
+
pg_text_enc_numeric(t_pg_coder *this, VALUE value, char *out, VALUE *intermediate, int enc_idx)
|
|
351
|
+
{
|
|
352
|
+
switch(TYPE(value)){
|
|
353
|
+
case T_FIXNUM:
|
|
354
|
+
case T_BIGNUM:
|
|
355
|
+
return pg_text_enc_integer(this, value, out, intermediate, enc_idx);
|
|
356
|
+
case T_FLOAT:
|
|
357
|
+
return pg_text_enc_float(this, value, out, intermediate, enc_idx);
|
|
358
|
+
default:
|
|
359
|
+
if(out){ /* second pass */
|
|
360
|
+
rb_bug("unexpected value type: %d", TYPE(value));
|
|
361
|
+
} else { /* first pass */
|
|
362
|
+
if( rb_obj_is_kind_of(value, s_cBigDecimal) ){
|
|
363
|
+
/* value.to_s('F') */
|
|
364
|
+
*intermediate = rb_funcall(value, s_id_to_s, 1, s_str_F);
|
|
365
|
+
return -1; /* no second pass */
|
|
366
|
+
} else {
|
|
367
|
+
return pg_coder_enc_to_s(this, value, NULL, intermediate, enc_idx);
|
|
368
|
+
/* no second pass */
|
|
369
|
+
}
|
|
370
|
+
}
|
|
254
371
|
}
|
|
255
372
|
}
|
|
256
373
|
|
|
374
|
+
/* called per autoload when TextEncoder::Numeric is used */
|
|
375
|
+
static VALUE
|
|
376
|
+
init_pg_text_encoder_numeric(VALUE rb_mPG_TextDecoder)
|
|
377
|
+
{
|
|
378
|
+
s_str_F = rb_str_freeze(rb_str_new_cstr("F"));
|
|
379
|
+
rb_global_variable(&s_str_F);
|
|
380
|
+
rb_require("bigdecimal");
|
|
381
|
+
s_cBigDecimal = rb_const_get(rb_cObject, rb_intern("BigDecimal"));
|
|
382
|
+
|
|
383
|
+
/* dummy = rb_define_class_under( rb_mPG_TextEncoder, "Numeric", rb_cPG_SimpleEncoder ); */
|
|
384
|
+
pg_define_coder( "Numeric", pg_text_enc_numeric, rb_cPG_SimpleEncoder, rb_mPG_TextEncoder );
|
|
385
|
+
|
|
386
|
+
return Qnil;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
|
|
257
390
|
static const char hextab[] = {
|
|
258
391
|
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
|
|
259
392
|
};
|
|
@@ -261,13 +394,16 @@ static const char hextab[] = {
|
|
|
261
394
|
/*
|
|
262
395
|
* Document-class: PG::TextEncoder::Bytea < PG::SimpleEncoder
|
|
263
396
|
*
|
|
264
|
-
* This is an encoder class for the PostgreSQL bytea type
|
|
265
|
-
* or newer.
|
|
397
|
+
* This is an encoder class for the PostgreSQL +bytea+ type.
|
|
266
398
|
*
|
|
267
399
|
* The binary String is converted to hexadecimal representation for transmission
|
|
268
400
|
* in text format. For query bind parameters it is recommended to use
|
|
269
|
-
* PG::BinaryEncoder::Bytea
|
|
270
|
-
* CPU usage.
|
|
401
|
+
* PG::BinaryEncoder::Bytea or the hash form <tt>{value: binary_string, format: 1}</tt> instead,
|
|
402
|
+
* in order to decrease network traffic and CPU usage.
|
|
403
|
+
* See PG::Connection#exec_params for using the hash form.
|
|
404
|
+
*
|
|
405
|
+
* This encoder is particular useful when PG::TextEncoder::CopyRow is used with the COPY command.
|
|
406
|
+
* 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.
|
|
271
407
|
*
|
|
272
408
|
*/
|
|
273
409
|
static int
|
|
@@ -286,11 +422,11 @@ pg_text_enc_bytea(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate,
|
|
|
286
422
|
*optr++ = hextab[c >> 4];
|
|
287
423
|
*optr++ = hextab[c & 0xf];
|
|
288
424
|
}
|
|
289
|
-
return optr - out;
|
|
425
|
+
return (int)(optr - out);
|
|
290
426
|
}else{
|
|
291
427
|
*intermediate = rb_obj_as_string(value);
|
|
292
428
|
/* The output starts with "\x" and each character is converted to hex. */
|
|
293
|
-
return 2 +
|
|
429
|
+
return 2 + RSTRING_LENINT(*intermediate) * 2;
|
|
294
430
|
}
|
|
295
431
|
}
|
|
296
432
|
|
|
@@ -468,20 +604,19 @@ pg_text_enc_array(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate,
|
|
|
468
604
|
static char *
|
|
469
605
|
quote_identifier( VALUE value, VALUE out_string, char *current_out ){
|
|
470
606
|
char *p_in = RSTRING_PTR(value);
|
|
471
|
-
char *ptr1;
|
|
472
607
|
size_t strlen = RSTRING_LEN(value);
|
|
608
|
+
char *p_inend = p_in + strlen;
|
|
473
609
|
char *end_capa = current_out;
|
|
474
610
|
|
|
475
611
|
PG_RB_STR_ENSURE_CAPA( out_string, strlen + 2, current_out, end_capa );
|
|
476
612
|
*current_out++ = '"';
|
|
477
|
-
for(
|
|
478
|
-
char c = *
|
|
613
|
+
for(; p_in != p_inend; p_in++) {
|
|
614
|
+
char c = *p_in;
|
|
479
615
|
if (c == '"'){
|
|
480
|
-
|
|
481
|
-
PG_RB_STR_ENSURE_CAPA( out_string, p_in - ptr1 + strlen + 1, current_out, end_capa );
|
|
616
|
+
PG_RB_STR_ENSURE_CAPA( out_string, p_inend - p_in + 2, current_out, end_capa );
|
|
482
617
|
*current_out++ = '"';
|
|
483
618
|
} else if (c == 0){
|
|
484
|
-
|
|
619
|
+
rb_raise(rb_eArgError, "string contains null byte");
|
|
485
620
|
}
|
|
486
621
|
*current_out++ = c;
|
|
487
622
|
}
|
|
@@ -494,8 +629,8 @@ quote_identifier( VALUE value, VALUE out_string, char *current_out ){
|
|
|
494
629
|
static char *
|
|
495
630
|
pg_text_enc_array_identifier(VALUE value, VALUE string, char *out, int enc_idx)
|
|
496
631
|
{
|
|
497
|
-
|
|
498
|
-
|
|
632
|
+
long i;
|
|
633
|
+
long nr_elems;
|
|
499
634
|
|
|
500
635
|
Check_Type(value, T_ARRAY);
|
|
501
636
|
nr_elems = RARRAY_LEN(value);
|
|
@@ -521,7 +656,8 @@ pg_text_enc_array_identifier(VALUE value, VALUE string, char *out, int enc_idx)
|
|
|
521
656
|
*
|
|
522
657
|
* This is the encoder class for PostgreSQL identifiers.
|
|
523
658
|
*
|
|
524
|
-
* An Array value can be used for "schema.table.column"
|
|
659
|
+
* An Array value can be used for identifiers of the kind "schema.table.column".
|
|
660
|
+
* This ensures that each element is properly quoted:
|
|
525
661
|
* PG::TextEncoder::Identifier.new.encode(['schema', 'table', 'column'])
|
|
526
662
|
* => '"schema"."table"."column"'
|
|
527
663
|
*
|
|
@@ -589,7 +725,13 @@ quote_literal_buffer( void *_this, char *p_in, int strlen, char *p_out ){
|
|
|
589
725
|
*
|
|
590
726
|
* This is the encoder class for PostgreSQL literals.
|
|
591
727
|
*
|
|
592
|
-
* A literal is quoted and escaped by the
|
|
728
|
+
* A literal is quoted and escaped by the <tt>'</tt> character, so that it can be inserted into SQL queries.
|
|
729
|
+
* It works equal to PG::Connection#escape_literal, but integrates into the type cast system of ruby-pg.
|
|
730
|
+
*
|
|
731
|
+
* Both expressions have the same result:
|
|
732
|
+
* conn.escape_literal(PG::TextEncoder::Array.new.encode(["v1","v2"])) # => "'{v1,v2}'"
|
|
733
|
+
* PG::TextEncoder::QuotedLiteral.new(elements_type: PG::TextEncoder::Array.new).encode(["v1","v2"]) # => "'{v1,v2}'"
|
|
734
|
+
* While escape_literal requires a intermediate ruby string allocation, QuotedLiteral encodes the values directly to the result string.
|
|
593
735
|
*
|
|
594
736
|
*/
|
|
595
737
|
static int
|
|
@@ -652,13 +794,15 @@ pg_text_enc_to_base64(t_pg_coder *conv, VALUE value, char *out, VALUE *intermedi
|
|
|
652
794
|
|
|
653
795
|
|
|
654
796
|
void
|
|
655
|
-
init_pg_text_encoder()
|
|
797
|
+
init_pg_text_encoder(void)
|
|
656
798
|
{
|
|
657
799
|
s_id_encode = rb_intern("encode");
|
|
658
800
|
s_id_to_i = rb_intern("to_i");
|
|
801
|
+
s_id_to_s = rb_intern("to_s");
|
|
659
802
|
|
|
660
803
|
/* This module encapsulates all encoder classes with text output format */
|
|
661
804
|
rb_mPG_TextEncoder = rb_define_module_under( rb_mPG, "TextEncoder" );
|
|
805
|
+
rb_define_private_method(rb_singleton_class(rb_mPG_TextEncoder), "init_numeric", init_pg_text_encoder_numeric, 0);
|
|
662
806
|
|
|
663
807
|
/* Make RDoc aware of the encoder classes... */
|
|
664
808
|
/* dummy = rb_define_class_under( rb_mPG_TextEncoder, "Boolean", rb_cPG_SimpleEncoder ); */
|