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.
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+ to stdout:
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 f23dd01bcb52 2014/11/17 10:47:53 kanis $
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 = PGconn.open(:dbname => 'test')
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[num_fields];
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[num_fields];
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[nfields];
1179
+ PG_VARIABLE_LENGTH_ARRAY(VALUE, row_values, nfields, PG_MAX_COLUMNS)
1180
1180
  int field;
1181
1181
 
1182
1182
  /* populate the row */
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  * pg_text_decoder.c - PG::TextDecoder module
3
- * $Id: pg_text_decoder.c,v b7f9daeeba29 2014/11/21 19:53:47 lars $
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::CompositeDecoder
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[len + 1];
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 = dec_func(conv, word, word_index, tuple, field, enc_idx);
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 = dec_func(conv, word, word_index, tuple, field, enc_idx);
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
  }
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  * pg_text_encoder.c - PG::TextEncoder module
3
- * $Id: pg_text_encoder.c,v 1a13e7eafeb7 2014/12/12 20:57:39 lars $
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
- *intermediate = rb_obj_as_string(value);
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 && pg_strncasecmp(p_in, "NULL", strlen) == 0)
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
- *intermediate = rb_str_new(NULL, 0);
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(*intermediate), *intermediate, this->needs_quotation);
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( *intermediate, end_ptr - RSTRING_PTR(*intermediate) );
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 int
459
- quote_identifier_buffer( void *_this, char *p_in, int strlen, char *p_out ){
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
- char *ptr2;
462
- int backslashs = 0;
472
+ size_t strlen = RSTRING_LEN(value);
473
+ char *end_capa = current_out;
463
474
 
464
- /* count required backlashs */
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
- if (*ptr1 == '"'){
467
- backslashs++;
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
- ptr1 = p_in + strlen;
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(t_pg_composite_coder *this, VALUE value, VALUE string, char *out)
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
- out = quote_string(this->elem, entry, string, out, this->needs_quotation, quote_identifier_buffer, this);
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::CompositeEncoder
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
- static int
521
- pg_text_enc_identifier(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate)
530
+ int
531
+ pg_text_enc_identifier(t_pg_coder *this, VALUE value, char *out, VALUE *intermediate, int enc_idx)
522
532
  {
523
- t_pg_composite_coder *this = (t_pg_composite_coder *)conv;
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
- out = pg_text_enc_array_identifier(this, value, *intermediate, out);
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
- out = quote_string(this->elem, value, *intermediate, out, this->needs_quotation, quote_identifier_buffer, this);
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( *intermediate, out - RSTRING_PTR(*intermediate) );
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
- *intermediate = rb_str_new(NULL, 0);
584
- out = RSTRING_PTR(*intermediate);
585
- out = quote_string(this->elem, value, *intermediate, out, this->needs_quotation, quote_literal_buffer, this);
586
- rb_str_set_len( *intermediate, out - RSTRING_PTR(*intermediate) );
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 ); */