pg 0.18.4 → 0.19.0.pre20160409114042
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
- data/ChangeLog +303 -5
- data/README.rdoc +2 -2
- data/Rakefile +10 -10
- data/Rakefile.cross +6 -6
- data/ext/errorcodes.def +16 -0
- data/ext/errorcodes.txt +5 -1
- data/ext/extconf.rb +6 -1
- data/ext/pg.h +6 -3
- data/ext/pg_binary_encoder.c +8 -8
- data/ext/pg_coder.c +30 -9
- data/ext/pg_connection.c +200 -74
- data/ext/pg_copy_coder.c +34 -4
- data/ext/pg_result.c +2 -2
- data/ext/pg_text_encoder.c +62 -42
- data/lib/pg.rb +2 -2
- data/lib/pg/basic_type_mapping.rb +30 -5
- data/lib/pg/connection.rb +46 -6
- data/lib/pg/result.rb +6 -2
- data/spec/helpers.rb +6 -9
- data/spec/pg/connection_spec.rb +130 -23
- data/spec/pg/type_map_by_class_spec.rb +1 -1
- data/spec/pg/type_map_by_mri_type_spec.rb +1 -1
- data/spec/pg/type_spec.rb +82 -2
- metadata +11 -13
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/.gemtest +0 -0
- metadata.gz.sig +0 -0
data/ext/pg_copy_coder.c
CHANGED
@@ -167,9 +167,15 @@ pg_copycoder_type_map_get(VALUE self)
|
|
167
167
|
* conn.put_copy_data ["string2", 42, true]
|
168
168
|
* end
|
169
169
|
* This creates +my_table+ and inserts two rows.
|
170
|
+
*
|
171
|
+
* It is possible to manually assign a type encoder for each column per PG::TypeMapByColumn,
|
172
|
+
* or to make use of PG::BasicTypeMapBasedOnResult to assign them based on the table OIDs.
|
173
|
+
*
|
174
|
+
* See also PG::TextDecoder::CopyRow for the decoding direction with
|
175
|
+
* PG::Connection#get_copy_data .
|
170
176
|
*/
|
171
177
|
static int
|
172
|
-
pg_text_enc_copy_row(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate)
|
178
|
+
pg_text_enc_copy_row(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate, int enc_idx)
|
173
179
|
{
|
174
180
|
t_pg_copycoder *this = (t_pg_copycoder *)conv;
|
175
181
|
t_pg_coder_enc_func enc_func;
|
@@ -184,6 +190,7 @@ pg_text_enc_copy_row(t_pg_coder *conv, VALUE value, char *out, VALUE *intermedia
|
|
184
190
|
|
185
191
|
/* Allocate a new string with embedded capacity and realloc exponential when needed. */
|
186
192
|
PG_RB_STR_NEW( *intermediate, current_out, end_capa_ptr );
|
193
|
+
PG_ENCODING_SET_NOCHECK(*intermediate, enc_idx);
|
187
194
|
|
188
195
|
for( i=0; i<RARRAY_LEN(value); i++){
|
189
196
|
char *ptr1;
|
@@ -211,7 +218,7 @@ pg_text_enc_copy_row(t_pg_coder *conv, VALUE value, char *out, VALUE *intermedia
|
|
211
218
|
enc_func = pg_coder_enc_func(p_elem_coder);
|
212
219
|
|
213
220
|
/* 1st pass for retiving the required memory space */
|
214
|
-
strlen = enc_func(p_elem_coder, entry, NULL, &subint);
|
221
|
+
strlen = enc_func(p_elem_coder, entry, NULL, &subint, enc_idx);
|
215
222
|
|
216
223
|
if( strlen == -1 ){
|
217
224
|
/* we can directly use String value in subint */
|
@@ -234,7 +241,7 @@ pg_text_enc_copy_row(t_pg_coder *conv, VALUE value, char *out, VALUE *intermedia
|
|
234
241
|
PG_RB_STR_ENSURE_CAPA( *intermediate, strlen * 2, current_out, end_capa_ptr );
|
235
242
|
|
236
243
|
/* Place the unescaped string at current output position. */
|
237
|
-
strlen = enc_func(p_elem_coder, entry, current_out, &subint);
|
244
|
+
strlen = enc_func(p_elem_coder, entry, current_out, &subint, enc_idx);
|
238
245
|
|
239
246
|
ptr1 = current_out;
|
240
247
|
ptr2 = current_out + strlen;
|
@@ -301,15 +308,38 @@ GetDecimalFromHex(char hex)
|
|
301
308
|
* strings by PG::TextDecoder::String.
|
302
309
|
*
|
303
310
|
* Example with default type map ( TypeMapAllStrings ):
|
311
|
+
* conn.exec("CREATE TABLE my_table AS VALUES('astring', 7, FALSE), ('string2', 42, TRUE) ")
|
312
|
+
*
|
304
313
|
* deco = PG::TextDecoder::CopyRow.new
|
305
314
|
* conn.copy_data "COPY my_table TO STDOUT", deco do
|
306
315
|
* while row=conn.get_copy_data
|
307
316
|
* p row
|
308
317
|
* end
|
309
318
|
* end
|
310
|
-
* This prints all rows of +my_table+
|
319
|
+
* This prints all rows of +my_table+ :
|
311
320
|
* ["astring", "7", "f"]
|
312
321
|
* ["string2", "42", "t"]
|
322
|
+
*
|
323
|
+
* Example with column based type map:
|
324
|
+
* tm = PG::TypeMapByColumn.new( [
|
325
|
+
* PG::TextDecoder::String.new,
|
326
|
+
* PG::TextDecoder::Integer.new,
|
327
|
+
* PG::TextDecoder::Boolean.new] )
|
328
|
+
* deco = PG::TextDecoder::CopyRow.new( type_map: tm )
|
329
|
+
* conn.copy_data "COPY my_table TO STDOUT", deco do
|
330
|
+
* while row=conn.get_copy_data
|
331
|
+
* p row
|
332
|
+
* end
|
333
|
+
* end
|
334
|
+
* This prints the rows with type casted columns:
|
335
|
+
* ["astring", 7, false]
|
336
|
+
* ["string2", 42, true]
|
337
|
+
*
|
338
|
+
* Instead of manually assigning a type decoder for each column, PG::BasicTypeMapForResults
|
339
|
+
* can be used to assign them based on the table OIDs.
|
340
|
+
*
|
341
|
+
* See also PG::TextEncoder::CopyRow for the encoding direction with
|
342
|
+
* PG::Connection#put_copy_data .
|
313
343
|
*/
|
314
344
|
/*
|
315
345
|
* Parse the current line into separate attributes (fields),
|
data/ext/pg_result.c
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
/*
|
2
2
|
* pg_result.c - PG::Result class extension
|
3
|
-
* $Id: pg_result.c,v
|
3
|
+
* $Id: pg_result.c,v 982082c0d77b 2016/01/31 19:28:55 ged $
|
4
4
|
*
|
5
5
|
*/
|
6
6
|
|
@@ -288,7 +288,7 @@ static void pgresult_init_fnames(VALUE self)
|
|
288
288
|
*
|
289
289
|
* Example:
|
290
290
|
* require 'pg'
|
291
|
-
* conn =
|
291
|
+
* conn = PG.connect(:dbname => 'test')
|
292
292
|
* res = conn.exec('SELECT 1 AS a, 2 AS b, NULL AS c')
|
293
293
|
* res.getvalue(0,0) # '1'
|
294
294
|
* res[0]['b'] # '2'
|
data/ext/pg_text_encoder.c
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
/*
|
2
2
|
* pg_text_encoder.c - PG::TextEncoder module
|
3
|
-
* $Id: pg_text_encoder.c,v
|
3
|
+
* $Id: pg_text_encoder.c,v e61a06f1f5ed 2015/12/25 21:14:21 lars $
|
4
4
|
*
|
5
5
|
*/
|
6
6
|
|
@@ -28,6 +28,7 @@
|
|
28
28
|
* intermediate - Pointer to a VALUE that might be set by the encoding function to some
|
29
29
|
* value in the first call that can be retrieved later in the second call.
|
30
30
|
* This VALUE is not yet initialized by the caller.
|
31
|
+
* enc_idx - Index of the output Encoding that strings should be converted to.
|
31
32
|
*
|
32
33
|
* Returns:
|
33
34
|
* >= 0 - If out==NULL the encoder function must return the expected output buffer size.
|
@@ -50,7 +51,7 @@ VALUE rb_mPG_TextEncoder;
|
|
50
51
|
static ID s_id_encode;
|
51
52
|
static ID s_id_to_i;
|
52
53
|
|
53
|
-
static int pg_text_enc_integer(t_pg_coder *this, VALUE value, char *out, VALUE *intermediate);
|
54
|
+
static int pg_text_enc_integer(t_pg_coder *this, VALUE value, char *out, VALUE *intermediate, int enc_idx);
|
54
55
|
|
55
56
|
VALUE
|
56
57
|
pg_obj_to_i( VALUE value )
|
@@ -76,7 +77,7 @@ pg_obj_to_i( VALUE value )
|
|
76
77
|
*
|
77
78
|
*/
|
78
79
|
static int
|
79
|
-
pg_text_enc_boolean(t_pg_coder *this, VALUE value, char *out, VALUE *intermediate)
|
80
|
+
pg_text_enc_boolean(t_pg_coder *this, VALUE value, char *out, VALUE *intermediate, int enc_idx)
|
80
81
|
{
|
81
82
|
switch( TYPE(value) ){
|
82
83
|
case T_FALSE:
|
@@ -94,10 +95,10 @@ pg_text_enc_boolean(t_pg_coder *this, VALUE value, char *out, VALUE *intermediat
|
|
94
95
|
if(out) *out = '1';
|
95
96
|
return 1;
|
96
97
|
} else {
|
97
|
-
return pg_text_enc_integer(this, value, out, intermediate);
|
98
|
+
return pg_text_enc_integer(this, value, out, intermediate, enc_idx);
|
98
99
|
}
|
99
100
|
default:
|
100
|
-
return pg_coder_enc_to_s(this, value, out, intermediate);
|
101
|
+
return pg_coder_enc_to_s(this, value, out, intermediate, enc_idx);
|
101
102
|
}
|
102
103
|
/* never reached */
|
103
104
|
return 0;
|
@@ -113,9 +114,14 @@ pg_text_enc_boolean(t_pg_coder *this, VALUE value, char *out, VALUE *intermediat
|
|
113
114
|
*
|
114
115
|
*/
|
115
116
|
int
|
116
|
-
pg_coder_enc_to_s(t_pg_coder *this, VALUE value, char *out, VALUE *intermediate)
|
117
|
+
pg_coder_enc_to_s(t_pg_coder *this, VALUE value, char *out, VALUE *intermediate, int enc_idx)
|
117
118
|
{
|
118
|
-
|
119
|
+
VALUE str = rb_obj_as_string(value);
|
120
|
+
if( ENCODING_GET(str) == enc_idx ){
|
121
|
+
*intermediate = str;
|
122
|
+
}else{
|
123
|
+
*intermediate = rb_str_export_to_enc(str, rb_enc_from_index(enc_idx));
|
124
|
+
}
|
119
125
|
return -1;
|
120
126
|
}
|
121
127
|
|
@@ -129,11 +135,11 @@ pg_coder_enc_to_s(t_pg_coder *this, VALUE value, char *out, VALUE *intermediate)
|
|
129
135
|
*
|
130
136
|
*/
|
131
137
|
static int
|
132
|
-
pg_text_enc_integer(t_pg_coder *this, VALUE value, char *out, VALUE *intermediate)
|
138
|
+
pg_text_enc_integer(t_pg_coder *this, VALUE value, char *out, VALUE *intermediate, int enc_idx)
|
133
139
|
{
|
134
140
|
if(out){
|
135
141
|
if(TYPE(*intermediate) == T_STRING){
|
136
|
-
return pg_coder_enc_to_s(this, value, out, intermediate);
|
142
|
+
return pg_coder_enc_to_s(this, value, out, intermediate, enc_idx);
|
137
143
|
}else{
|
138
144
|
char *start = out;
|
139
145
|
int len;
|
@@ -206,13 +212,13 @@ pg_text_enc_integer(t_pg_coder *this, VALUE value, char *out, VALUE *intermediat
|
|
206
212
|
if( ll < 100000000000000LL ){
|
207
213
|
len = ll < 10000000000000LL ? 13 : 14;
|
208
214
|
}else{
|
209
|
-
return pg_coder_enc_to_s(this, *intermediate, NULL, intermediate);
|
215
|
+
return pg_coder_enc_to_s(this, *intermediate, NULL, intermediate, enc_idx);
|
210
216
|
}
|
211
217
|
}
|
212
218
|
}
|
213
219
|
return sll < 0 ? len+1 : len;
|
214
220
|
}else{
|
215
|
-
return pg_coder_enc_to_s(this, *intermediate, NULL, intermediate);
|
221
|
+
return pg_coder_enc_to_s(this, *intermediate, NULL, intermediate, enc_idx);
|
216
222
|
}
|
217
223
|
}
|
218
224
|
}
|
@@ -225,7 +231,7 @@ pg_text_enc_integer(t_pg_coder *this, VALUE value, char *out, VALUE *intermediat
|
|
225
231
|
*
|
226
232
|
*/
|
227
233
|
static int
|
228
|
-
pg_text_enc_float(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate)
|
234
|
+
pg_text_enc_float(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate, int enc_idx)
|
229
235
|
{
|
230
236
|
if(out){
|
231
237
|
double dvalue = NUM2DBL(value);
|
@@ -265,7 +271,7 @@ static const char hextab[] = {
|
|
265
271
|
*
|
266
272
|
*/
|
267
273
|
static int
|
268
|
-
pg_text_enc_bytea(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate)
|
274
|
+
pg_text_enc_bytea(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate, int enc_idx)
|
269
275
|
{
|
270
276
|
if(out){
|
271
277
|
size_t strlen = RSTRING_LEN(*intermediate);
|
@@ -344,13 +350,13 @@ quote_array_buffer( void *_this, char *p_in, int strlen, char *p_out ){
|
|
344
350
|
}
|
345
351
|
|
346
352
|
static char *
|
347
|
-
quote_string(t_pg_coder *this, VALUE value, VALUE string, char *current_out, int with_quote, t_quote_func quote_buffer, void *func_data)
|
353
|
+
quote_string(t_pg_coder *this, VALUE value, VALUE string, char *current_out, int with_quote, t_quote_func quote_buffer, void *func_data, int enc_idx)
|
348
354
|
{
|
349
355
|
int strlen;
|
350
356
|
VALUE subint;
|
351
357
|
t_pg_coder_enc_func enc_func = pg_coder_enc_func(this);
|
352
358
|
|
353
|
-
strlen = enc_func(this, value, NULL, &subint);
|
359
|
+
strlen = enc_func(this, value, NULL, &subint, enc_idx);
|
354
360
|
|
355
361
|
if( strlen == -1 ){
|
356
362
|
/* we can directly use String value in subint */
|
@@ -376,20 +382,20 @@ quote_string(t_pg_coder *this, VALUE value, VALUE string, char *current_out, int
|
|
376
382
|
current_out = pg_rb_str_ensure_capa( string, 2 * strlen + 2, current_out, NULL );
|
377
383
|
|
378
384
|
/* Place the unescaped string at current output position. */
|
379
|
-
strlen = enc_func(this, value, current_out, &subint);
|
385
|
+
strlen = enc_func(this, value, current_out, &subint, enc_idx);
|
380
386
|
|
381
387
|
current_out += quote_buffer( func_data, current_out, strlen, current_out );
|
382
388
|
}else{
|
383
389
|
/* size of the unquoted string */
|
384
390
|
current_out = pg_rb_str_ensure_capa( string, strlen, current_out, NULL );
|
385
|
-
current_out += enc_func(this, value, current_out, &subint);
|
391
|
+
current_out += enc_func(this, value, current_out, &subint, enc_idx);
|
386
392
|
}
|
387
393
|
}
|
388
394
|
return current_out;
|
389
395
|
}
|
390
396
|
|
391
397
|
static char *
|
392
|
-
write_array(t_pg_composite_coder *this, VALUE value, char *current_out, VALUE string, int quote)
|
398
|
+
write_array(t_pg_composite_coder *this, VALUE value, char *current_out, VALUE string, int quote, int enc_idx)
|
393
399
|
{
|
394
400
|
int i;
|
395
401
|
|
@@ -407,7 +413,7 @@ write_array(t_pg_composite_coder *this, VALUE value, char *current_out, VALUE st
|
|
407
413
|
|
408
414
|
switch(TYPE(entry)){
|
409
415
|
case T_ARRAY:
|
410
|
-
current_out = write_array(this, entry, current_out, string, quote);
|
416
|
+
current_out = write_array(this, entry, current_out, string, quote, enc_idx);
|
411
417
|
break;
|
412
418
|
case T_NIL:
|
413
419
|
current_out = pg_rb_str_ensure_capa( string, 4, current_out, NULL );
|
@@ -417,7 +423,7 @@ write_array(t_pg_composite_coder *this, VALUE value, char *current_out, VALUE st
|
|
417
423
|
*current_out++ = 'L';
|
418
424
|
break;
|
419
425
|
default:
|
420
|
-
current_out = quote_string( this->elem, entry, string, current_out, quote, quote_array_buffer, this );
|
426
|
+
current_out = quote_string( this->elem, entry, string, current_out, quote, quote_array_buffer, this, enc_idx );
|
421
427
|
}
|
422
428
|
}
|
423
429
|
current_out = pg_rb_str_ensure_capa( string, 1, current_out, NULL );
|
@@ -439,21 +445,23 @@ write_array(t_pg_composite_coder *this, VALUE value, char *current_out, VALUE st
|
|
439
445
|
*
|
440
446
|
*/
|
441
447
|
static int
|
442
|
-
pg_text_enc_array(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate)
|
448
|
+
pg_text_enc_array(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate, int enc_idx)
|
443
449
|
{
|
444
450
|
char *end_ptr;
|
445
451
|
t_pg_composite_coder *this = (t_pg_composite_coder *)conv;
|
446
452
|
|
447
453
|
if( TYPE(value) == T_ARRAY){
|
448
|
-
|
454
|
+
VALUE out_str = rb_str_new(NULL, 0);
|
455
|
+
PG_ENCODING_SET_NOCHECK(out_str, enc_idx);
|
449
456
|
|
450
|
-
end_ptr = write_array(this, value, RSTRING_PTR(
|
457
|
+
end_ptr = write_array(this, value, RSTRING_PTR(out_str), out_str, this->needs_quotation, enc_idx);
|
451
458
|
|
452
|
-
rb_str_set_len(
|
459
|
+
rb_str_set_len( out_str, end_ptr - RSTRING_PTR(out_str) );
|
460
|
+
*intermediate = out_str;
|
453
461
|
|
454
462
|
return -1;
|
455
463
|
} else {
|
456
|
-
return pg_coder_enc_to_s( conv, value, out, intermediate );
|
464
|
+
return pg_coder_enc_to_s( conv, value, out, intermediate, enc_idx );
|
457
465
|
}
|
458
466
|
}
|
459
467
|
|
@@ -484,7 +492,7 @@ quote_identifier( VALUE value, VALUE out_string, char *current_out ){
|
|
484
492
|
}
|
485
493
|
|
486
494
|
static char *
|
487
|
-
pg_text_enc_array_identifier(VALUE value, VALUE string, char *out)
|
495
|
+
pg_text_enc_array_identifier(VALUE value, VALUE string, char *out, int enc_idx)
|
488
496
|
{
|
489
497
|
int i;
|
490
498
|
int nr_elems;
|
@@ -496,6 +504,9 @@ pg_text_enc_array_identifier(VALUE value, VALUE string, char *out)
|
|
496
504
|
VALUE entry = rb_ary_entry(value, i);
|
497
505
|
|
498
506
|
StringValue(entry);
|
507
|
+
if( ENCODING_GET(entry) != enc_idx ){
|
508
|
+
entry = rb_str_export_to_enc(entry, rb_enc_from_index(enc_idx));
|
509
|
+
}
|
499
510
|
out = quote_identifier(entry, string, out);
|
500
511
|
if( i < nr_elems-1 ){
|
501
512
|
out = pg_rb_str_ensure_capa( string, 1, out, NULL );
|
@@ -517,20 +528,26 @@ pg_text_enc_array_identifier(VALUE value, VALUE string, char *out)
|
|
517
528
|
* This encoder can also be used per PG::Connection#quote_ident .
|
518
529
|
*/
|
519
530
|
int
|
520
|
-
pg_text_enc_identifier(t_pg_coder *this, VALUE value, char *out, VALUE *intermediate)
|
531
|
+
pg_text_enc_identifier(t_pg_coder *this, VALUE value, char *out, VALUE *intermediate, int enc_idx)
|
521
532
|
{
|
533
|
+
VALUE out_str;
|
522
534
|
UNUSED( this );
|
523
535
|
if( TYPE(value) == T_ARRAY){
|
524
|
-
|
525
|
-
out = RSTRING_PTR(
|
526
|
-
out = pg_text_enc_array_identifier(value,
|
536
|
+
out_str = rb_str_new(NULL, 0);
|
537
|
+
out = RSTRING_PTR(out_str);
|
538
|
+
out = pg_text_enc_array_identifier(value, out_str, out, enc_idx);
|
527
539
|
} else {
|
528
540
|
StringValue(value);
|
529
|
-
|
530
|
-
|
531
|
-
|
541
|
+
if( ENCODING_GET(value) != enc_idx ){
|
542
|
+
value = rb_str_export_to_enc(value, rb_enc_from_index(enc_idx));
|
543
|
+
}
|
544
|
+
out_str = rb_str_new(NULL, RSTRING_LEN(value) + 2);
|
545
|
+
out = RSTRING_PTR(out_str);
|
546
|
+
out = quote_identifier(value, out_str, out);
|
532
547
|
}
|
533
|
-
rb_str_set_len(
|
548
|
+
rb_str_set_len( out_str, out - RSTRING_PTR(out_str) );
|
549
|
+
PG_ENCODING_SET_NOCHECK(out_str, enc_idx);
|
550
|
+
*intermediate = out_str;
|
534
551
|
return -1;
|
535
552
|
}
|
536
553
|
|
@@ -576,14 +593,16 @@ quote_literal_buffer( void *_this, char *p_in, int strlen, char *p_out ){
|
|
576
593
|
*
|
577
594
|
*/
|
578
595
|
static int
|
579
|
-
pg_text_enc_quoted_literal(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate)
|
596
|
+
pg_text_enc_quoted_literal(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate, int enc_idx)
|
580
597
|
{
|
581
598
|
t_pg_composite_coder *this = (t_pg_composite_coder *)conv;
|
599
|
+
VALUE out_str = rb_str_new(NULL, 0);
|
600
|
+
PG_ENCODING_SET_NOCHECK(out_str, enc_idx);
|
582
601
|
|
583
|
-
|
584
|
-
out =
|
585
|
-
|
586
|
-
|
602
|
+
out = RSTRING_PTR(out_str);
|
603
|
+
out = quote_string(this->elem, value, out_str, out, this->needs_quotation, quote_literal_buffer, this, enc_idx);
|
604
|
+
rb_str_set_len( out_str, out - RSTRING_PTR(out_str) );
|
605
|
+
*intermediate = out_str;
|
587
606
|
return -1;
|
588
607
|
}
|
589
608
|
|
@@ -594,7 +613,7 @@ pg_text_enc_quoted_literal(t_pg_coder *conv, VALUE value, char *out, VALUE *inte
|
|
594
613
|
*
|
595
614
|
*/
|
596
615
|
static int
|
597
|
-
pg_text_enc_to_base64(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate)
|
616
|
+
pg_text_enc_to_base64(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate, int enc_idx)
|
598
617
|
{
|
599
618
|
int strlen;
|
600
619
|
VALUE subint;
|
@@ -603,13 +622,13 @@ pg_text_enc_to_base64(t_pg_coder *conv, VALUE value, char *out, VALUE *intermedi
|
|
603
622
|
|
604
623
|
if(out){
|
605
624
|
/* Second encoder pass, if required */
|
606
|
-
strlen = enc_func(this->elem, value, out, intermediate);
|
625
|
+
strlen = enc_func(this->elem, value, out, intermediate, enc_idx);
|
607
626
|
base64_encode( out, out, strlen );
|
608
627
|
|
609
628
|
return BASE64_ENCODED_SIZE(strlen);
|
610
629
|
} else {
|
611
630
|
/* First encoder pass */
|
612
|
-
strlen = enc_func(this->elem, value, NULL, &subint);
|
631
|
+
strlen = enc_func(this->elem, value, NULL, &subint, enc_idx);
|
613
632
|
|
614
633
|
if( strlen == -1 ){
|
615
634
|
/* Encoded string is returned in subint */
|
@@ -617,6 +636,7 @@ pg_text_enc_to_base64(t_pg_coder *conv, VALUE value, char *out, VALUE *intermedi
|
|
617
636
|
|
618
637
|
strlen = RSTRING_LENINT(subint);
|
619
638
|
out_str = rb_str_new(NULL, BASE64_ENCODED_SIZE(strlen));
|
639
|
+
PG_ENCODING_SET_NOCHECK(out_str, enc_idx);
|
620
640
|
|
621
641
|
base64_encode( RSTRING_PTR(out_str), RSTRING_PTR(subint), strlen);
|
622
642
|
*intermediate = out_str;
|
data/lib/pg.rb
CHANGED
@@ -10,7 +10,7 @@ rescue LoadError
|
|
10
10
|
|
11
11
|
# Set the PATH environment variable, so that libpq.dll can be found.
|
12
12
|
old_path = ENV['PATH']
|
13
|
-
ENV['PATH'] = "#{File.expand_path("
|
13
|
+
ENV['PATH'] = "#{File.expand_path("..", __FILE__)};#{old_path}"
|
14
14
|
require "#{major_minor}/pg_ext"
|
15
15
|
ENV['PATH'] = old_path
|
16
16
|
else
|
@@ -27,7 +27,7 @@ module PG
|
|
27
27
|
VERSION = '0.18.4'
|
28
28
|
|
29
29
|
# VCS revision
|
30
|
-
REVISION = %q$Revision:
|
30
|
+
REVISION = %q$Revision: b3a270f74fdd $
|
31
31
|
|
32
32
|
class NotAllCopyDataRetrieved < PG::Error
|
33
33
|
end
|
@@ -226,8 +226,8 @@ end
|
|
226
226
|
#
|
227
227
|
# Example:
|
228
228
|
# conn = PG::Connection.new
|
229
|
-
# # Assign a default ruleset for type casts of
|
230
|
-
# conn.
|
229
|
+
# # Assign a default ruleset for type casts of output values.
|
230
|
+
# conn.type_map_for_results = PG::BasicTypeMapForResults.new(conn)
|
231
231
|
# # Execute a query.
|
232
232
|
# res = conn.exec_params( "SELECT $1::INT", ['5'] )
|
233
233
|
# # Retrieve and cast the result value. Value format is 0 (text) and OID is 20. Therefore typecasting
|
@@ -236,8 +236,28 @@ end
|
|
236
236
|
#
|
237
237
|
# PG::TypeMapByOid#fit_to_result(result, false) can be used to generate
|
238
238
|
# a result independent PG::TypeMapByColumn type map, which can subsequently be used
|
239
|
-
# to cast #get_copy_data fields
|
239
|
+
# to cast #get_copy_data fields:
|
240
|
+
#
|
241
|
+
# For the following table:
|
242
|
+
# conn.exec( "CREATE TABLE copytable AS VALUES('a', 123, '{5,4,3}'::INT[])" )
|
243
|
+
#
|
244
|
+
# # Retrieve table OIDs per empty result set.
|
245
|
+
# res = conn.exec( "SELECT * FROM copytable LIMIT 0" )
|
246
|
+
# # Build a type map for common database to ruby type decoders.
|
247
|
+
# btm = PG::BasicTypeMapForResults.new(conn)
|
248
|
+
# # Build a PG::TypeMapByColumn with decoders suitable for copytable.
|
249
|
+
# tm = btm.build_column_map( res )
|
250
|
+
# row_decoder = PG::TextDecoder::CopyRow.new type_map: tm
|
251
|
+
#
|
252
|
+
# conn.copy_data( "COPY copytable TO STDOUT", row_decoder ) do |res|
|
253
|
+
# while row=conn.get_copy_data
|
254
|
+
# p row
|
255
|
+
# end
|
256
|
+
# end
|
257
|
+
# This prints the rows with type casted columns:
|
258
|
+
# ["a", 123, [5, 4, 3]]
|
240
259
|
#
|
260
|
+
# See also PG::BasicTypeMapBasedOnResult for the encoder direction.
|
241
261
|
class PG::BasicTypeMapForResults < PG::TypeMapByOid
|
242
262
|
include PG::BasicTypeRegistry
|
243
263
|
|
@@ -290,12 +310,17 @@ end
|
|
290
310
|
#
|
291
311
|
# # Retrieve table OIDs per empty result set.
|
292
312
|
# res = conn.exec( "SELECT * FROM copytable LIMIT 0" )
|
293
|
-
#
|
313
|
+
# # Build a type map for common ruby to database type encoders.
|
314
|
+
# btm = PG::BasicTypeMapBasedOnResult.new(conn)
|
315
|
+
# # Build a PG::TypeMapByColumn with encoders suitable for copytable.
|
316
|
+
# tm = btm.build_column_map( res )
|
294
317
|
# row_encoder = PG::TextEncoder::CopyRow.new type_map: tm
|
295
318
|
#
|
296
319
|
# conn.copy_data( "COPY copytable FROM STDIN", row_encoder ) do |res|
|
297
320
|
# conn.put_copy_data ['a', 123, [5,4,3]]
|
298
321
|
# end
|
322
|
+
# This inserts a single row into copytable with type casts from ruby to
|
323
|
+
# database types.
|
299
324
|
class PG::BasicTypeMapBasedOnResult < PG::TypeMapByOid
|
300
325
|
include PG::BasicTypeRegistry
|
301
326
|
|
@@ -322,7 +347,7 @@ end
|
|
322
347
|
# Example:
|
323
348
|
# conn = PG::Connection.new
|
324
349
|
# # Assign a default ruleset for type casts of input and output values.
|
325
|
-
# conn.
|
350
|
+
# conn.type_map_for_queries = PG::BasicTypeMapForQueries.new(conn)
|
326
351
|
# # Execute a query. The Integer param value is typecasted internally by PG::BinaryEncoder::Int8.
|
327
352
|
# # The format of the parameter is set to 1 (binary) and the OID of this parameter is set to 20 (int8).
|
328
353
|
# res = conn.exec_params( "SELECT $1", [5] )
|