pg 0.18.1 → 0.19.0
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 +3 -3
- data.tar.gz.sig +0 -0
- data/BSDL +2 -2
- data/ChangeLog +1004 -4
- data/History.rdoc +66 -0
- data/README-Windows.rdoc +15 -26
- data/README.rdoc +16 -9
- data/Rakefile +26 -16
- data/Rakefile.cross +42 -21
- data/ext/errorcodes.def +16 -0
- data/ext/errorcodes.txt +5 -1
- data/ext/extconf.rb +14 -2
- data/ext/gvl_wrappers.h +4 -0
- data/ext/pg.c +5 -4
- data/ext/pg.h +15 -2
- data/ext/pg_binary_decoder.c +3 -1
- data/ext/pg_binary_encoder.c +14 -12
- data/ext/pg_coder.c +30 -9
- data/ext/pg_connection.c +241 -115
- data/ext/pg_copy_coder.c +34 -4
- data/ext/pg_result.c +5 -5
- data/ext/pg_text_decoder.c +9 -10
- data/ext/pg_text_encoder.c +93 -73
- data/ext/pg_type_map.c +7 -7
- data/ext/pg_type_map_by_column.c +7 -7
- data/ext/pg_type_map_by_mri_type.c +2 -2
- data/ext/pg_type_map_in_ruby.c +4 -7
- data/ext/util.c +3 -3
- data/ext/util.h +1 -1
- data/lib/pg.rb +3 -3
- data/lib/pg/basic_type_mapping.rb +69 -42
- data/lib/pg/connection.rb +84 -34
- data/lib/pg/result.rb +6 -2
- data/lib/pg/text_decoder.rb +12 -3
- data/lib/pg/text_encoder.rb +8 -0
- data/spec/helpers.rb +7 -10
- data/spec/pg/basic_type_mapping_spec.rb +58 -4
- data/spec/pg/connection_spec.rb +251 -34
- 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 +144 -32
- metadata +65 -52
- 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'
|
@@ -863,7 +863,7 @@ pgresult_each_row(VALUE self)
|
|
863
863
|
num_fields = PQnfields(this->pgresult);
|
864
864
|
|
865
865
|
for ( row = 0; row < num_rows; row++ ) {
|
866
|
-
VALUE row_values
|
866
|
+
PG_VARIABLE_LENGTH_ARRAY(VALUE, row_values, num_fields, PG_MAX_COLUMNS)
|
867
867
|
|
868
868
|
/* populate the row */
|
869
869
|
for ( field = 0; field < num_fields; field++ ) {
|
@@ -892,7 +892,7 @@ pgresult_values(VALUE self)
|
|
892
892
|
VALUE results = rb_ary_new2( num_rows );
|
893
893
|
|
894
894
|
for ( row = 0; row < num_rows; row++ ) {
|
895
|
-
VALUE row_values
|
895
|
+
PG_VARIABLE_LENGTH_ARRAY(VALUE, row_values, num_fields, PG_MAX_COLUMNS)
|
896
896
|
|
897
897
|
/* populate the row */
|
898
898
|
for ( field = 0; field < num_fields; field++ ) {
|
@@ -1176,7 +1176,7 @@ pgresult_stream_each_row(VALUE self)
|
|
1176
1176
|
}
|
1177
1177
|
|
1178
1178
|
for ( row = 0; row < ntuples; row++ ) {
|
1179
|
-
VALUE row_values
|
1179
|
+
PG_VARIABLE_LENGTH_ARRAY(VALUE, row_values, nfields, PG_MAX_COLUMNS)
|
1180
1180
|
int field;
|
1181
1181
|
|
1182
1182
|
/* populate the row */
|
data/ext/pg_text_decoder.c
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
/*
|
2
2
|
* pg_text_decoder.c - PG::TextDecoder module
|
3
|
-
* $Id: pg_text_decoder.c,v
|
3
|
+
* $Id: pg_text_decoder.c,v fcf731d3dff7 2015/09/08 12:25:06 jfali $
|
4
4
|
*
|
5
5
|
*/
|
6
6
|
|
@@ -30,7 +30,9 @@
|
|
30
30
|
|
31
31
|
#include "pg.h"
|
32
32
|
#include "util.h"
|
33
|
+
#ifdef HAVE_INTTYPES_H
|
33
34
|
#include <inttypes.h>
|
35
|
+
#endif
|
34
36
|
|
35
37
|
VALUE rb_mPG_TextDecoder;
|
36
38
|
static ID s_id_decode;
|
@@ -293,7 +295,7 @@ pg_text_dec_array(t_pg_coder *conv, char *val, int len, int tuple, int field, in
|
|
293
295
|
}
|
294
296
|
|
295
297
|
/*
|
296
|
-
* Document-class: PG::TextDecoder::Identifier < PG::
|
298
|
+
* Document-class: PG::TextDecoder::Identifier < PG::SimpleDecoder
|
297
299
|
*
|
298
300
|
* This is the decoder class for PostgreSQL identifiers.
|
299
301
|
*
|
@@ -305,16 +307,13 @@ pg_text_dec_array(t_pg_coder *conv, char *val, int len, int tuple, int field, in
|
|
305
307
|
static VALUE
|
306
308
|
pg_text_dec_identifier(t_pg_coder *conv, char *val, int len, int tuple, int field, int enc_idx)
|
307
309
|
{
|
308
|
-
t_pg_composite_coder *this = (t_pg_composite_coder *)conv;
|
309
|
-
t_pg_coder_dec_func dec_func = pg_coder_dec_func(this->elem, 0);
|
310
|
-
|
311
310
|
/* Return value: array */
|
312
311
|
VALUE array;
|
313
312
|
VALUE elem;
|
314
313
|
int word_index = 0;
|
315
314
|
int index;
|
316
315
|
/* Use a buffer of the same length, as that will be the worst case */
|
317
|
-
char word
|
316
|
+
PG_VARIABLE_LENGTH_ARRAY(char, word, len + 1, NAMEDATALEN)
|
318
317
|
|
319
318
|
/* The current character in the input string. */
|
320
319
|
char c;
|
@@ -331,7 +330,7 @@ pg_text_dec_identifier(t_pg_coder *conv, char *val, int len, int tuple, int fiel
|
|
331
330
|
if(c == '.' && openQuote < 2 ) {
|
332
331
|
word[word_index] = 0;
|
333
332
|
|
334
|
-
elem =
|
333
|
+
elem = pg_text_dec_string(conv, word, word_index, tuple, field, enc_idx);
|
335
334
|
rb_ary_push(array, elem);
|
336
335
|
|
337
336
|
openQuote = 0;
|
@@ -353,7 +352,7 @@ pg_text_dec_identifier(t_pg_coder *conv, char *val, int len, int tuple, int fiel
|
|
353
352
|
}
|
354
353
|
|
355
354
|
word[word_index] = 0;
|
356
|
-
elem =
|
355
|
+
elem = pg_text_dec_string(conv, word, word_index, tuple, field, enc_idx);
|
357
356
|
rb_ary_push(array, elem);
|
358
357
|
|
359
358
|
return array;
|
@@ -412,11 +411,11 @@ init_pg_text_decoder()
|
|
412
411
|
pg_define_coder( "String", pg_text_dec_string, rb_cPG_SimpleDecoder, rb_mPG_TextDecoder );
|
413
412
|
/* dummy = rb_define_class_under( rb_mPG_TextDecoder, "Bytea", rb_cPG_SimpleDecoder ); */
|
414
413
|
pg_define_coder( "Bytea", pg_text_dec_bytea, rb_cPG_SimpleDecoder, rb_mPG_TextDecoder );
|
414
|
+
/* dummy = rb_define_class_under( rb_mPG_TextDecoder, "Identifier", rb_cPG_SimpleDecoder ); */
|
415
|
+
pg_define_coder( "Identifier", pg_text_dec_identifier, rb_cPG_SimpleDecoder, rb_mPG_TextDecoder );
|
415
416
|
|
416
417
|
/* dummy = rb_define_class_under( rb_mPG_TextDecoder, "Array", rb_cPG_CompositeDecoder ); */
|
417
418
|
pg_define_coder( "Array", pg_text_dec_array, rb_cPG_CompositeDecoder, rb_mPG_TextDecoder );
|
418
|
-
/* dummy = rb_define_class_under( rb_mPG_TextDecoder, "Identifier", rb_cPG_CompositeDecoder ); */
|
419
|
-
pg_define_coder( "Identifier", pg_text_dec_identifier, rb_cPG_CompositeDecoder, rb_mPG_TextDecoder );
|
420
419
|
/* dummy = rb_define_class_under( rb_mPG_TextDecoder, "FromBase64", rb_cPG_CompositeDecoder ); */
|
421
420
|
pg_define_coder( "FromBase64", pg_text_dec_from_base64, rb_cPG_CompositeDecoder, rb_mPG_TextDecoder );
|
422
421
|
}
|
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.
|
@@ -41,14 +42,16 @@
|
|
41
42
|
|
42
43
|
#include "pg.h"
|
43
44
|
#include "util.h"
|
45
|
+
#ifdef HAVE_INTTYPES_H
|
44
46
|
#include <inttypes.h>
|
47
|
+
#endif
|
45
48
|
#include <math.h>
|
46
49
|
|
47
50
|
VALUE rb_mPG_TextEncoder;
|
48
51
|
static ID s_id_encode;
|
49
52
|
static ID s_id_to_i;
|
50
53
|
|
51
|
-
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);
|
52
55
|
|
53
56
|
VALUE
|
54
57
|
pg_obj_to_i( VALUE value )
|
@@ -74,7 +77,7 @@ pg_obj_to_i( VALUE value )
|
|
74
77
|
*
|
75
78
|
*/
|
76
79
|
static int
|
77
|
-
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)
|
78
81
|
{
|
79
82
|
switch( TYPE(value) ){
|
80
83
|
case T_FALSE:
|
@@ -92,10 +95,10 @@ pg_text_enc_boolean(t_pg_coder *this, VALUE value, char *out, VALUE *intermediat
|
|
92
95
|
if(out) *out = '1';
|
93
96
|
return 1;
|
94
97
|
} else {
|
95
|
-
return pg_text_enc_integer(this, value, out, intermediate);
|
98
|
+
return pg_text_enc_integer(this, value, out, intermediate, enc_idx);
|
96
99
|
}
|
97
100
|
default:
|
98
|
-
return pg_coder_enc_to_s(this, value, out, intermediate);
|
101
|
+
return pg_coder_enc_to_s(this, value, out, intermediate, enc_idx);
|
99
102
|
}
|
100
103
|
/* never reached */
|
101
104
|
return 0;
|
@@ -111,9 +114,14 @@ pg_text_enc_boolean(t_pg_coder *this, VALUE value, char *out, VALUE *intermediat
|
|
111
114
|
*
|
112
115
|
*/
|
113
116
|
int
|
114
|
-
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)
|
115
118
|
{
|
116
|
-
|
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
|
+
}
|
117
125
|
return -1;
|
118
126
|
}
|
119
127
|
|
@@ -127,11 +135,11 @@ pg_coder_enc_to_s(t_pg_coder *this, VALUE value, char *out, VALUE *intermediate)
|
|
127
135
|
*
|
128
136
|
*/
|
129
137
|
static int
|
130
|
-
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)
|
131
139
|
{
|
132
140
|
if(out){
|
133
141
|
if(TYPE(*intermediate) == T_STRING){
|
134
|
-
return pg_coder_enc_to_s(this, value, out, intermediate);
|
142
|
+
return pg_coder_enc_to_s(this, value, out, intermediate, enc_idx);
|
135
143
|
}else{
|
136
144
|
char *start = out;
|
137
145
|
int len;
|
@@ -204,13 +212,13 @@ pg_text_enc_integer(t_pg_coder *this, VALUE value, char *out, VALUE *intermediat
|
|
204
212
|
if( ll < 100000000000000LL ){
|
205
213
|
len = ll < 10000000000000LL ? 13 : 14;
|
206
214
|
}else{
|
207
|
-
return pg_coder_enc_to_s(this, *intermediate, NULL, intermediate);
|
215
|
+
return pg_coder_enc_to_s(this, *intermediate, NULL, intermediate, enc_idx);
|
208
216
|
}
|
209
217
|
}
|
210
218
|
}
|
211
219
|
return sll < 0 ? len+1 : len;
|
212
220
|
}else{
|
213
|
-
return pg_coder_enc_to_s(this, *intermediate, NULL, intermediate);
|
221
|
+
return pg_coder_enc_to_s(this, *intermediate, NULL, intermediate, enc_idx);
|
214
222
|
}
|
215
223
|
}
|
216
224
|
}
|
@@ -223,7 +231,7 @@ pg_text_enc_integer(t_pg_coder *this, VALUE value, char *out, VALUE *intermediat
|
|
223
231
|
*
|
224
232
|
*/
|
225
233
|
static int
|
226
|
-
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)
|
227
235
|
{
|
228
236
|
if(out){
|
229
237
|
double dvalue = NUM2DBL(value);
|
@@ -263,7 +271,7 @@ static const char hextab[] = {
|
|
263
271
|
*
|
264
272
|
*/
|
265
273
|
static int
|
266
|
-
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)
|
267
275
|
{
|
268
276
|
if(out){
|
269
277
|
size_t strlen = RSTRING_LEN(*intermediate);
|
@@ -299,7 +307,7 @@ quote_array_buffer( void *_this, char *p_in, int strlen, char *p_out ){
|
|
299
307
|
/* count data plus backslashes; detect chars needing quotes */
|
300
308
|
if (strlen == 0)
|
301
309
|
needquote = 1; /* force quotes for empty string */
|
302
|
-
else if (strlen == 4 &&
|
310
|
+
else if (strlen == 4 && rbpg_strncasecmp(p_in, "NULL", strlen) == 0)
|
303
311
|
needquote = 1; /* force quotes for literal NULL */
|
304
312
|
else
|
305
313
|
needquote = 0;
|
@@ -342,13 +350,13 @@ quote_array_buffer( void *_this, char *p_in, int strlen, char *p_out ){
|
|
342
350
|
}
|
343
351
|
|
344
352
|
static char *
|
345
|
-
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)
|
346
354
|
{
|
347
355
|
int strlen;
|
348
356
|
VALUE subint;
|
349
357
|
t_pg_coder_enc_func enc_func = pg_coder_enc_func(this);
|
350
358
|
|
351
|
-
strlen = enc_func(this, value, NULL, &subint);
|
359
|
+
strlen = enc_func(this, value, NULL, &subint, enc_idx);
|
352
360
|
|
353
361
|
if( strlen == -1 ){
|
354
362
|
/* we can directly use String value in subint */
|
@@ -374,20 +382,20 @@ quote_string(t_pg_coder *this, VALUE value, VALUE string, char *current_out, int
|
|
374
382
|
current_out = pg_rb_str_ensure_capa( string, 2 * strlen + 2, current_out, NULL );
|
375
383
|
|
376
384
|
/* Place the unescaped string at current output position. */
|
377
|
-
strlen = enc_func(this, value, current_out, &subint);
|
385
|
+
strlen = enc_func(this, value, current_out, &subint, enc_idx);
|
378
386
|
|
379
387
|
current_out += quote_buffer( func_data, current_out, strlen, current_out );
|
380
388
|
}else{
|
381
389
|
/* size of the unquoted string */
|
382
390
|
current_out = pg_rb_str_ensure_capa( string, strlen, current_out, NULL );
|
383
|
-
current_out += enc_func(this, value, current_out, &subint);
|
391
|
+
current_out += enc_func(this, value, current_out, &subint, enc_idx);
|
384
392
|
}
|
385
393
|
}
|
386
394
|
return current_out;
|
387
395
|
}
|
388
396
|
|
389
397
|
static char *
|
390
|
-
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)
|
391
399
|
{
|
392
400
|
int i;
|
393
401
|
|
@@ -405,7 +413,7 @@ write_array(t_pg_composite_coder *this, VALUE value, char *current_out, VALUE st
|
|
405
413
|
|
406
414
|
switch(TYPE(entry)){
|
407
415
|
case T_ARRAY:
|
408
|
-
current_out = write_array(this, entry, current_out, string, quote);
|
416
|
+
current_out = write_array(this, entry, current_out, string, quote, enc_idx);
|
409
417
|
break;
|
410
418
|
case T_NIL:
|
411
419
|
current_out = pg_rb_str_ensure_capa( string, 4, current_out, NULL );
|
@@ -415,7 +423,7 @@ write_array(t_pg_composite_coder *this, VALUE value, char *current_out, VALUE st
|
|
415
423
|
*current_out++ = 'L';
|
416
424
|
break;
|
417
425
|
default:
|
418
|
-
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 );
|
419
427
|
}
|
420
428
|
}
|
421
429
|
current_out = pg_rb_str_ensure_capa( string, 1, current_out, NULL );
|
@@ -437,57 +445,54 @@ write_array(t_pg_composite_coder *this, VALUE value, char *current_out, VALUE st
|
|
437
445
|
*
|
438
446
|
*/
|
439
447
|
static int
|
440
|
-
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)
|
441
449
|
{
|
442
450
|
char *end_ptr;
|
443
451
|
t_pg_composite_coder *this = (t_pg_composite_coder *)conv;
|
444
452
|
|
445
453
|
if( TYPE(value) == T_ARRAY){
|
446
|
-
|
454
|
+
VALUE out_str = rb_str_new(NULL, 0);
|
455
|
+
PG_ENCODING_SET_NOCHECK(out_str, enc_idx);
|
447
456
|
|
448
|
-
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);
|
449
458
|
|
450
|
-
rb_str_set_len(
|
459
|
+
rb_str_set_len( out_str, end_ptr - RSTRING_PTR(out_str) );
|
460
|
+
*intermediate = out_str;
|
451
461
|
|
452
462
|
return -1;
|
453
463
|
} else {
|
454
|
-
return pg_coder_enc_to_s( conv, value, out, intermediate );
|
464
|
+
return pg_coder_enc_to_s( conv, value, out, intermediate, enc_idx );
|
455
465
|
}
|
456
466
|
}
|
457
467
|
|
458
|
-
static
|
459
|
-
|
468
|
+
static char *
|
469
|
+
quote_identifier( VALUE value, VALUE out_string, char *current_out ){
|
470
|
+
char *p_in = RSTRING_PTR(value);
|
460
471
|
char *ptr1;
|
461
|
-
|
462
|
-
|
472
|
+
size_t strlen = RSTRING_LEN(value);
|
473
|
+
char *end_capa = current_out;
|
463
474
|
|
464
|
-
|
475
|
+
PG_RB_STR_ENSURE_CAPA( out_string, strlen + 2, current_out, end_capa );
|
476
|
+
*current_out++ = '"';
|
465
477
|
for(ptr1 = p_in; ptr1 != p_in + strlen; ptr1++) {
|
466
|
-
|
467
|
-
|
478
|
+
char c = *ptr1;
|
479
|
+
if (c == '"'){
|
480
|
+
strlen++;
|
481
|
+
PG_RB_STR_ENSURE_CAPA( out_string, p_in - ptr1 + strlen + 1, current_out, end_capa );
|
482
|
+
*current_out++ = '"';
|
483
|
+
} else if (c == 0){
|
484
|
+
break;
|
468
485
|
}
|
486
|
+
*current_out++ = c;
|
469
487
|
}
|
488
|
+
PG_RB_STR_ENSURE_CAPA( out_string, 1, current_out, end_capa );
|
489
|
+
*current_out++ = '"';
|
470
490
|
|
471
|
-
|
472
|
-
ptr2 = p_out + strlen + backslashs + 2;
|
473
|
-
/* Write end quote */
|
474
|
-
*--ptr2 = '"';
|
475
|
-
|
476
|
-
/* Then store the escaped string on the final position, walking
|
477
|
-
* right to left, until all backslashs are placed. */
|
478
|
-
while( ptr1 != p_in ) {
|
479
|
-
*--ptr2 = *--ptr1;
|
480
|
-
if(*ptr2 == '"'){
|
481
|
-
*--ptr2 = '"';
|
482
|
-
}
|
483
|
-
}
|
484
|
-
/* Write start quote */
|
485
|
-
*p_out = '"';
|
486
|
-
return strlen + backslashs + 2;
|
491
|
+
return current_out;
|
487
492
|
}
|
488
493
|
|
489
494
|
static char *
|
490
|
-
pg_text_enc_array_identifier(
|
495
|
+
pg_text_enc_array_identifier(VALUE value, VALUE string, char *out, int enc_idx)
|
491
496
|
{
|
492
497
|
int i;
|
493
498
|
int nr_elems;
|
@@ -498,7 +503,11 @@ pg_text_enc_array_identifier(t_pg_composite_coder *this, VALUE value, VALUE stri
|
|
498
503
|
for( i=0; i<nr_elems; i++){
|
499
504
|
VALUE entry = rb_ary_entry(value, i);
|
500
505
|
|
501
|
-
|
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
|
+
}
|
510
|
+
out = quote_identifier(entry, string, out);
|
502
511
|
if( i < nr_elems-1 ){
|
503
512
|
out = pg_rb_str_ensure_capa( string, 1, out, NULL );
|
504
513
|
*out++ = '.';
|
@@ -508,29 +517,37 @@ pg_text_enc_array_identifier(t_pg_composite_coder *this, VALUE value, VALUE stri
|
|
508
517
|
}
|
509
518
|
|
510
519
|
/*
|
511
|
-
* Document-class: PG::TextEncoder::Identifier < PG::
|
520
|
+
* Document-class: PG::TextEncoder::Identifier < PG::SimpleEncoder
|
512
521
|
*
|
513
522
|
* This is the encoder class for PostgreSQL identifiers.
|
514
523
|
*
|
515
524
|
* An Array value can be used for "schema.table.column" type identifiers:
|
516
525
|
* PG::TextEncoder::Identifier.new.encode(['schema', 'table', 'column'])
|
517
|
-
* => "schema"."table"."column"
|
526
|
+
* => '"schema"."table"."column"'
|
518
527
|
*
|
528
|
+
* This encoder can also be used per PG::Connection#quote_ident .
|
519
529
|
*/
|
520
|
-
|
521
|
-
pg_text_enc_identifier(t_pg_coder *
|
530
|
+
int
|
531
|
+
pg_text_enc_identifier(t_pg_coder *this, VALUE value, char *out, VALUE *intermediate, int enc_idx)
|
522
532
|
{
|
523
|
-
|
524
|
-
|
525
|
-
*intermediate = rb_str_new(NULL, 0);
|
526
|
-
out = RSTRING_PTR(*intermediate);
|
527
|
-
|
533
|
+
VALUE out_str;
|
534
|
+
UNUSED( this );
|
528
535
|
if( TYPE(value) == T_ARRAY){
|
529
|
-
|
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);
|
530
539
|
} else {
|
531
|
-
|
540
|
+
StringValue(value);
|
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;
|
@@ -651,11 +671,11 @@ init_pg_text_encoder()
|
|
651
671
|
pg_define_coder( "String", pg_coder_enc_to_s, rb_cPG_SimpleEncoder, rb_mPG_TextEncoder );
|
652
672
|
/* dummy = rb_define_class_under( rb_mPG_TextEncoder, "Bytea", rb_cPG_SimpleEncoder ); */
|
653
673
|
pg_define_coder( "Bytea", pg_text_enc_bytea, rb_cPG_SimpleEncoder, rb_mPG_TextEncoder );
|
674
|
+
/* dummy = rb_define_class_under( rb_mPG_TextEncoder, "Identifier", rb_cPG_SimpleEncoder ); */
|
675
|
+
pg_define_coder( "Identifier", pg_text_enc_identifier, rb_cPG_SimpleEncoder, rb_mPG_TextEncoder );
|
654
676
|
|
655
677
|
/* dummy = rb_define_class_under( rb_mPG_TextEncoder, "Array", rb_cPG_CompositeEncoder ); */
|
656
678
|
pg_define_coder( "Array", pg_text_enc_array, rb_cPG_CompositeEncoder, rb_mPG_TextEncoder );
|
657
|
-
/* dummy = rb_define_class_under( rb_mPG_TextEncoder, "Identifier", rb_cPG_CompositeEncoder ); */
|
658
|
-
pg_define_coder( "Identifier", pg_text_enc_identifier, rb_cPG_CompositeEncoder, rb_mPG_TextEncoder );
|
659
679
|
/* dummy = rb_define_class_under( rb_mPG_TextEncoder, "QuotedLiteral", rb_cPG_CompositeEncoder ); */
|
660
680
|
pg_define_coder( "QuotedLiteral", pg_text_enc_quoted_literal, rb_cPG_CompositeEncoder, rb_mPG_TextEncoder );
|
661
681
|
/* dummy = rb_define_class_under( rb_mPG_TextEncoder, "ToBase64", rb_cPG_CompositeEncoder ); */
|