pg 0.17.1 → 0.18.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/ChangeLog +2407 -2
  4. data/History.rdoc +68 -0
  5. data/Manifest.txt +29 -1
  6. data/README-Windows.rdoc +15 -26
  7. data/README.rdoc +52 -2
  8. data/Rakefile +56 -18
  9. data/Rakefile.cross +77 -49
  10. data/ext/extconf.rb +33 -26
  11. data/ext/pg.c +142 -21
  12. data/ext/pg.h +242 -6
  13. data/ext/pg_binary_decoder.c +162 -0
  14. data/ext/pg_binary_encoder.c +162 -0
  15. data/ext/pg_coder.c +479 -0
  16. data/ext/pg_connection.c +858 -553
  17. data/ext/pg_copy_coder.c +561 -0
  18. data/ext/pg_errors.c +6 -0
  19. data/ext/pg_result.c +479 -128
  20. data/ext/pg_text_decoder.c +421 -0
  21. data/ext/pg_text_encoder.c +663 -0
  22. data/ext/pg_type_map.c +159 -0
  23. data/ext/pg_type_map_all_strings.c +116 -0
  24. data/ext/pg_type_map_by_class.c +239 -0
  25. data/ext/pg_type_map_by_column.c +312 -0
  26. data/ext/pg_type_map_by_mri_type.c +284 -0
  27. data/ext/pg_type_map_by_oid.c +355 -0
  28. data/ext/pg_type_map_in_ruby.c +299 -0
  29. data/ext/util.c +149 -0
  30. data/ext/util.h +65 -0
  31. data/lib/pg/basic_type_mapping.rb +399 -0
  32. data/lib/pg/coder.rb +83 -0
  33. data/lib/pg/connection.rb +81 -29
  34. data/lib/pg/result.rb +13 -3
  35. data/lib/pg/text_decoder.rb +44 -0
  36. data/lib/pg/text_encoder.rb +27 -0
  37. data/lib/pg/type_map_by_column.rb +15 -0
  38. data/lib/pg.rb +12 -2
  39. data/spec/{lib/helpers.rb → helpers.rb} +101 -39
  40. data/spec/pg/basic_type_mapping_spec.rb +251 -0
  41. data/spec/pg/connection_spec.rb +516 -218
  42. data/spec/pg/result_spec.rb +216 -112
  43. data/spec/pg/type_map_by_class_spec.rb +138 -0
  44. data/spec/pg/type_map_by_column_spec.rb +222 -0
  45. data/spec/pg/type_map_by_mri_type_spec.rb +136 -0
  46. data/spec/pg/type_map_by_oid_spec.rb +149 -0
  47. data/spec/pg/type_map_in_ruby_spec.rb +164 -0
  48. data/spec/pg/type_map_spec.rb +22 -0
  49. data/spec/pg/type_spec.rb +697 -0
  50. data/spec/pg_spec.rb +24 -18
  51. data.tar.gz.sig +0 -0
  52. metadata +111 -45
  53. metadata.gz.sig +0 -0
@@ -0,0 +1,663 @@
1
+ /*
2
+ * pg_text_encoder.c - PG::TextEncoder module
3
+ * $Id: pg_text_encoder.c,v 4f0bd19e9111 2015/09/24 18:55:11 lars $
4
+ *
5
+ */
6
+
7
+ /*
8
+ *
9
+ * Type casts for encoding Ruby objects to PostgreSQL string representations.
10
+ *
11
+ * Encoder classes are defined with pg_define_coder(). This creates a new coder class and
12
+ * assigns an encoder function. The encoder function can decide between two different options
13
+ * to return the encoded data. It can either return it as a Ruby String object or write the
14
+ * encoded data to a memory space provided by the caller. In the second case, the encoder
15
+ * function is called twice, once for deciding the encoding option and returning the expected
16
+ * data length, and a second time when the requested memory space was made available by the
17
+ * calling function, to do the actual conversion and writing. Parameter intermediate can be
18
+ * used to store data between these two calls.
19
+ *
20
+ * Signature of all type cast encoders is:
21
+ * int encoder_function(t_pg_coder *this, VALUE value, char *out, VALUE *intermediate)
22
+ *
23
+ * Params:
24
+ * this - The data part of the coder object that belongs to the encoder function.
25
+ * value - The Ruby object to cast.
26
+ * out - NULL for the first call,
27
+ * pointer to a buffer with the requested size for the second call.
28
+ * intermediate - Pointer to a VALUE that might be set by the encoding function to some
29
+ * value in the first call that can be retrieved later in the second call.
30
+ * This VALUE is not yet initialized by the caller.
31
+ *
32
+ * Returns:
33
+ * >= 0 - If out==NULL the encoder function must return the expected output buffer size.
34
+ * This can be larger than the size of the second call, but may not be smaller.
35
+ * If out!=NULL the encoder function must return the actually used output buffer size
36
+ * without a termination character.
37
+ * -1 - The encoder function can alternatively return -1 to indicate that no second call
38
+ * is required, but the String value in *intermediate should be used instead.
39
+ */
40
+
41
+
42
+ #include "pg.h"
43
+ #include "util.h"
44
+ #ifdef HAVE_INTTYPES_H
45
+ #include <inttypes.h>
46
+ #endif
47
+ #include <math.h>
48
+
49
+ VALUE rb_mPG_TextEncoder;
50
+ static ID s_id_encode;
51
+ static ID s_id_to_i;
52
+
53
+ static int pg_text_enc_integer(t_pg_coder *this, VALUE value, char *out, VALUE *intermediate);
54
+
55
+ VALUE
56
+ pg_obj_to_i( VALUE value )
57
+ {
58
+ switch (TYPE(value)) {
59
+ case T_FIXNUM:
60
+ case T_FLOAT:
61
+ case T_BIGNUM:
62
+ return value;
63
+ default:
64
+ return rb_funcall(value, s_id_to_i, 0);
65
+ }
66
+ }
67
+
68
+ /*
69
+ * Document-class: PG::TextEncoder::Boolean < PG::SimpleEncoder
70
+ *
71
+ * This is the encoder class for the PostgreSQL bool type.
72
+ *
73
+ * Ruby value false is encoded as SQL +FALSE+ value.
74
+ * Ruby value true is encoded as SQL +TRUE+ value.
75
+ * Any other value is sent as it's string representation.
76
+ *
77
+ */
78
+ static int
79
+ pg_text_enc_boolean(t_pg_coder *this, VALUE value, char *out, VALUE *intermediate)
80
+ {
81
+ switch( TYPE(value) ){
82
+ case T_FALSE:
83
+ if(out) *out = 'f';
84
+ return 1;
85
+ case T_TRUE:
86
+ if(out) *out = 't';
87
+ return 1;
88
+ case T_FIXNUM:
89
+ case T_BIGNUM:
90
+ if( NUM2LONG(value) == 0 ){
91
+ if(out) *out = '0';
92
+ return 1;
93
+ } else if( NUM2LONG(value) == 1 ){
94
+ if(out) *out = '1';
95
+ return 1;
96
+ } else {
97
+ return pg_text_enc_integer(this, value, out, intermediate);
98
+ }
99
+ default:
100
+ return pg_coder_enc_to_s(this, value, out, intermediate);
101
+ }
102
+ /* never reached */
103
+ return 0;
104
+ }
105
+
106
+
107
+ /*
108
+ * Document-class: PG::TextEncoder::String < PG::SimpleEncoder
109
+ *
110
+ * This is the encoder class for the PostgreSQL text types.
111
+ *
112
+ * Non-String values are expected to have method +to_s+ defined.
113
+ *
114
+ */
115
+ int
116
+ pg_coder_enc_to_s(t_pg_coder *this, VALUE value, char *out, VALUE *intermediate)
117
+ {
118
+ *intermediate = rb_obj_as_string(value);
119
+ return -1;
120
+ }
121
+
122
+
123
+ /*
124
+ * Document-class: PG::TextEncoder::Integer < PG::SimpleEncoder
125
+ *
126
+ * This is the encoder class for the PostgreSQL int types.
127
+ *
128
+ * Non-Integer values are expected to have method +to_i+ defined.
129
+ *
130
+ */
131
+ static int
132
+ pg_text_enc_integer(t_pg_coder *this, VALUE value, char *out, VALUE *intermediate)
133
+ {
134
+ if(out){
135
+ if(TYPE(*intermediate) == T_STRING){
136
+ return pg_coder_enc_to_s(this, value, out, intermediate);
137
+ }else{
138
+ char *start = out;
139
+ int len;
140
+ int neg = 0;
141
+ long long ll = NUM2LL(*intermediate);
142
+
143
+ if (ll < 0) {
144
+ /* We don't expect problems with the most negative integer not being representable
145
+ * as a positive integer, because Fixnum is only up to 63 bits.
146
+ */
147
+ ll = -ll;
148
+ neg = 1;
149
+ }
150
+
151
+ /* Compute the result string backwards. */
152
+ do {
153
+ long long remainder;
154
+ long long oldval = ll;
155
+
156
+ ll /= 10;
157
+ remainder = oldval - ll * 10;
158
+ *out++ = '0' + remainder;
159
+ } while (ll != 0);
160
+
161
+ if (neg)
162
+ *out++ = '-';
163
+
164
+ len = out - start;
165
+
166
+ /* Reverse string. */
167
+ out--;
168
+ while (start < out)
169
+ {
170
+ char swap = *start;
171
+
172
+ *start++ = *out;
173
+ *out-- = swap;
174
+ }
175
+
176
+ return len;
177
+ }
178
+ }else{
179
+ *intermediate = pg_obj_to_i(value);
180
+ if(TYPE(*intermediate) == T_FIXNUM){
181
+ int len;
182
+ long long sll = NUM2LL(*intermediate);
183
+ long long ll = sll < 0 ? -sll : sll;
184
+ if( ll < 100000000 ){
185
+ if( ll < 10000 ){
186
+ if( ll < 100 ){
187
+ len = ll < 10 ? 1 : 2;
188
+ }else{
189
+ len = ll < 1000 ? 3 : 4;
190
+ }
191
+ }else{
192
+ if( ll < 1000000 ){
193
+ len = ll < 100000 ? 5 : 6;
194
+ }else{
195
+ len = ll < 10000000 ? 7 : 8;
196
+ }
197
+ }
198
+ }else{
199
+ if( ll < 1000000000000LL ){
200
+ if( ll < 10000000000LL ){
201
+ len = ll < 1000000000LL ? 9 : 10;
202
+ }else{
203
+ len = ll < 100000000000LL ? 11 : 12;
204
+ }
205
+ }else{
206
+ if( ll < 100000000000000LL ){
207
+ len = ll < 10000000000000LL ? 13 : 14;
208
+ }else{
209
+ return pg_coder_enc_to_s(this, *intermediate, NULL, intermediate);
210
+ }
211
+ }
212
+ }
213
+ return sll < 0 ? len+1 : len;
214
+ }else{
215
+ return pg_coder_enc_to_s(this, *intermediate, NULL, intermediate);
216
+ }
217
+ }
218
+ }
219
+
220
+
221
+ /*
222
+ * Document-class: PG::TextEncoder::Float < PG::SimpleEncoder
223
+ *
224
+ * This is the encoder class for the PostgreSQL float types.
225
+ *
226
+ */
227
+ static int
228
+ pg_text_enc_float(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate)
229
+ {
230
+ if(out){
231
+ double dvalue = NUM2DBL(value);
232
+ /* Cast to the same strings as value.to_s . */
233
+ if( isinf(dvalue) ){
234
+ if( dvalue < 0 ){
235
+ memcpy( out, "-Infinity", 9);
236
+ return 9;
237
+ } else {
238
+ memcpy( out, "Infinity", 8);
239
+ return 8;
240
+ }
241
+ } else if (isnan(dvalue)) {
242
+ memcpy( out, "NaN", 3);
243
+ return 3;
244
+ }
245
+ return sprintf( out, "%.16E", dvalue);
246
+ }else{
247
+ return 23;
248
+ }
249
+ }
250
+
251
+ static const char hextab[] = {
252
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
253
+ };
254
+
255
+ /*
256
+ * Document-class: PG::TextEncoder::Bytea < PG::SimpleEncoder
257
+ *
258
+ * This is an encoder class for the PostgreSQL bytea type for server version 9.0
259
+ * or newer.
260
+ *
261
+ * The binary String is converted to hexadecimal representation for transmission
262
+ * in text format. For query bind parameters it is recommended to use
263
+ * PG::BinaryEncoder::Bytea instead, in order to decrease network traffic and
264
+ * CPU usage.
265
+ *
266
+ */
267
+ static int
268
+ pg_text_enc_bytea(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate)
269
+ {
270
+ if(out){
271
+ size_t strlen = RSTRING_LEN(*intermediate);
272
+ char *iptr = RSTRING_PTR(*intermediate);
273
+ char *eptr = iptr + strlen;
274
+ char *optr = out;
275
+ *optr++ = '\\';
276
+ *optr++ = 'x';
277
+
278
+ for( ; iptr < eptr; iptr++ ){
279
+ unsigned char c = *iptr;
280
+ *optr++ = hextab[c >> 4];
281
+ *optr++ = hextab[c & 0xf];
282
+ }
283
+ return optr - out;
284
+ }else{
285
+ *intermediate = rb_obj_as_string(value);
286
+ /* The output starts with "\x" and each character is converted to hex. */
287
+ return 2 + RSTRING_LEN(*intermediate) * 2;
288
+ }
289
+ }
290
+
291
+ typedef int (*t_quote_func)( void *_this, char *p_in, int strlen, char *p_out );
292
+
293
+ static int
294
+ quote_array_buffer( void *_this, char *p_in, int strlen, char *p_out ){
295
+ t_pg_composite_coder *this = _this;
296
+ char *ptr1;
297
+ char *ptr2;
298
+ int backslashs = 0;
299
+ int needquote;
300
+
301
+ /* count data plus backslashes; detect chars needing quotes */
302
+ if (strlen == 0)
303
+ needquote = 1; /* force quotes for empty string */
304
+ else if (strlen == 4 && rbpg_strncasecmp(p_in, "NULL", strlen) == 0)
305
+ needquote = 1; /* force quotes for literal NULL */
306
+ else
307
+ needquote = 0;
308
+
309
+ /* count required backlashs */
310
+ for(ptr1 = p_in; ptr1 != p_in + strlen; ptr1++) {
311
+ char ch = *ptr1;
312
+
313
+ if (ch == '"' || ch == '\\'){
314
+ needquote = 1;
315
+ backslashs++;
316
+ } else if (ch == '{' || ch == '}' || ch == this->delimiter ||
317
+ ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r' || ch == '\v' || ch == '\f'){
318
+ needquote = 1;
319
+ }
320
+ }
321
+
322
+ if( needquote ){
323
+ ptr1 = p_in + strlen;
324
+ ptr2 = p_out + strlen + backslashs + 2;
325
+ /* Write end quote */
326
+ *--ptr2 = '"';
327
+
328
+ /* Then store the escaped string on the final position, walking
329
+ * right to left, until all backslashs are placed. */
330
+ while( ptr1 != p_in ) {
331
+ *--ptr2 = *--ptr1;
332
+ if(*ptr2 == '"' || *ptr2 == '\\'){
333
+ *--ptr2 = '\\';
334
+ }
335
+ }
336
+ /* Write start quote */
337
+ *p_out = '"';
338
+ return strlen + backslashs + 2;
339
+ } else {
340
+ if( p_in != p_out )
341
+ memcpy( p_out, p_in, strlen );
342
+ return strlen;
343
+ }
344
+ }
345
+
346
+ 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)
348
+ {
349
+ int strlen;
350
+ VALUE subint;
351
+ t_pg_coder_enc_func enc_func = pg_coder_enc_func(this);
352
+
353
+ strlen = enc_func(this, value, NULL, &subint);
354
+
355
+ if( strlen == -1 ){
356
+ /* we can directly use String value in subint */
357
+ strlen = RSTRING_LENINT(subint);
358
+
359
+ if(with_quote){
360
+ /* size of string assuming the worst case, that every character must be escaped. */
361
+ current_out = pg_rb_str_ensure_capa( string, strlen * 2 + 2, current_out, NULL );
362
+
363
+ current_out += quote_buffer( func_data, RSTRING_PTR(subint), strlen, current_out );
364
+ } else {
365
+ current_out = pg_rb_str_ensure_capa( string, strlen, current_out, NULL );
366
+ memcpy( current_out, RSTRING_PTR(subint), strlen );
367
+ current_out += strlen;
368
+ }
369
+
370
+ } else {
371
+
372
+ if(with_quote){
373
+ /* size of string assuming the worst case, that every character must be escaped
374
+ * plus two bytes for quotation.
375
+ */
376
+ current_out = pg_rb_str_ensure_capa( string, 2 * strlen + 2, current_out, NULL );
377
+
378
+ /* Place the unescaped string at current output position. */
379
+ strlen = enc_func(this, value, current_out, &subint);
380
+
381
+ current_out += quote_buffer( func_data, current_out, strlen, current_out );
382
+ }else{
383
+ /* size of the unquoted string */
384
+ current_out = pg_rb_str_ensure_capa( string, strlen, current_out, NULL );
385
+ current_out += enc_func(this, value, current_out, &subint);
386
+ }
387
+ }
388
+ return current_out;
389
+ }
390
+
391
+ static char *
392
+ write_array(t_pg_composite_coder *this, VALUE value, char *current_out, VALUE string, int quote)
393
+ {
394
+ int i;
395
+
396
+ /* size of "{}" */
397
+ current_out = pg_rb_str_ensure_capa( string, 2, current_out, NULL );
398
+ *current_out++ = '{';
399
+
400
+ for( i=0; i<RARRAY_LEN(value); i++){
401
+ VALUE entry = rb_ary_entry(value, i);
402
+
403
+ if( i > 0 ){
404
+ current_out = pg_rb_str_ensure_capa( string, 1, current_out, NULL );
405
+ *current_out++ = this->delimiter;
406
+ }
407
+
408
+ switch(TYPE(entry)){
409
+ case T_ARRAY:
410
+ current_out = write_array(this, entry, current_out, string, quote);
411
+ break;
412
+ case T_NIL:
413
+ current_out = pg_rb_str_ensure_capa( string, 4, current_out, NULL );
414
+ *current_out++ = 'N';
415
+ *current_out++ = 'U';
416
+ *current_out++ = 'L';
417
+ *current_out++ = 'L';
418
+ break;
419
+ default:
420
+ current_out = quote_string( this->elem, entry, string, current_out, quote, quote_array_buffer, this );
421
+ }
422
+ }
423
+ current_out = pg_rb_str_ensure_capa( string, 1, current_out, NULL );
424
+ *current_out++ = '}';
425
+ return current_out;
426
+ }
427
+
428
+
429
+ /*
430
+ * Document-class: PG::TextEncoder::Array < PG::CompositeEncoder
431
+ *
432
+ * This is the encoder class for PostgreSQL array types.
433
+ *
434
+ * All values are encoded according to the #elements_type
435
+ * accessor. Sub-arrays are encoded recursively.
436
+ *
437
+ * This encoder expects an Array of values or sub-arrays as input.
438
+ * Other values are passed through as text without interpretation.
439
+ *
440
+ */
441
+ static int
442
+ pg_text_enc_array(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate)
443
+ {
444
+ char *end_ptr;
445
+ t_pg_composite_coder *this = (t_pg_composite_coder *)conv;
446
+
447
+ if( TYPE(value) == T_ARRAY){
448
+ *intermediate = rb_str_new(NULL, 0);
449
+
450
+ end_ptr = write_array(this, value, RSTRING_PTR(*intermediate), *intermediate, this->needs_quotation);
451
+
452
+ rb_str_set_len( *intermediate, end_ptr - RSTRING_PTR(*intermediate) );
453
+
454
+ return -1;
455
+ } else {
456
+ return pg_coder_enc_to_s( conv, value, out, intermediate );
457
+ }
458
+ }
459
+
460
+ static char *
461
+ quote_identifier( VALUE value, VALUE out_string, char *current_out ){
462
+ char *p_in = RSTRING_PTR(value);
463
+ char *ptr1;
464
+ size_t strlen = RSTRING_LEN(value);
465
+ char *end_capa = current_out;
466
+
467
+ PG_RB_STR_ENSURE_CAPA( out_string, strlen + 2, current_out, end_capa );
468
+ *current_out++ = '"';
469
+ for(ptr1 = p_in; ptr1 != p_in + strlen; ptr1++) {
470
+ char c = *ptr1;
471
+ if (c == '"'){
472
+ strlen++;
473
+ PG_RB_STR_ENSURE_CAPA( out_string, p_in - ptr1 + strlen + 1, current_out, end_capa );
474
+ *current_out++ = '"';
475
+ } else if (c == 0){
476
+ break;
477
+ }
478
+ *current_out++ = c;
479
+ }
480
+ PG_RB_STR_ENSURE_CAPA( out_string, 1, current_out, end_capa );
481
+ *current_out++ = '"';
482
+
483
+ return current_out;
484
+ }
485
+
486
+ static char *
487
+ pg_text_enc_array_identifier(VALUE value, VALUE string, char *out)
488
+ {
489
+ int i;
490
+ int nr_elems;
491
+
492
+ Check_Type(value, T_ARRAY);
493
+ nr_elems = RARRAY_LEN(value);
494
+
495
+ for( i=0; i<nr_elems; i++){
496
+ VALUE entry = rb_ary_entry(value, i);
497
+
498
+ StringValue(entry);
499
+ out = quote_identifier(entry, string, out);
500
+ if( i < nr_elems-1 ){
501
+ out = pg_rb_str_ensure_capa( string, 1, out, NULL );
502
+ *out++ = '.';
503
+ }
504
+ }
505
+ return out;
506
+ }
507
+
508
+ /*
509
+ * Document-class: PG::TextEncoder::Identifier < PG::SimpleEncoder
510
+ *
511
+ * This is the encoder class for PostgreSQL identifiers.
512
+ *
513
+ * An Array value can be used for "schema.table.column" type identifiers:
514
+ * PG::TextEncoder::Identifier.new.encode(['schema', 'table', 'column'])
515
+ * => '"schema"."table"."column"'
516
+ *
517
+ * This encoder can also be used per PG::Connection#quote_ident .
518
+ */
519
+ int
520
+ pg_text_enc_identifier(t_pg_coder *this, VALUE value, char *out, VALUE *intermediate)
521
+ {
522
+ UNUSED( this );
523
+ if( TYPE(value) == T_ARRAY){
524
+ *intermediate = rb_str_new(NULL, 0);
525
+ out = RSTRING_PTR(*intermediate);
526
+ out = pg_text_enc_array_identifier(value, *intermediate, out);
527
+ } else {
528
+ StringValue(value);
529
+ *intermediate = rb_str_new(NULL, RSTRING_LEN(value) + 2);
530
+ out = RSTRING_PTR(*intermediate);
531
+ out = quote_identifier(value, *intermediate, out);
532
+ }
533
+ rb_str_set_len( *intermediate, out - RSTRING_PTR(*intermediate) );
534
+ return -1;
535
+ }
536
+
537
+
538
+ static int
539
+ quote_literal_buffer( void *_this, char *p_in, int strlen, char *p_out ){
540
+ char *ptr1;
541
+ char *ptr2;
542
+ int backslashs = 0;
543
+
544
+ /* count required backlashs */
545
+ for(ptr1 = p_in; ptr1 != p_in + strlen; ptr1++) {
546
+ if (*ptr1 == '\''){
547
+ backslashs++;
548
+ }
549
+ }
550
+
551
+ ptr1 = p_in + strlen;
552
+ ptr2 = p_out + strlen + backslashs + 2;
553
+ /* Write end quote */
554
+ *--ptr2 = '\'';
555
+
556
+ /* Then store the escaped string on the final position, walking
557
+ * right to left, until all backslashs are placed. */
558
+ while( ptr1 != p_in ) {
559
+ *--ptr2 = *--ptr1;
560
+ if(*ptr2 == '\''){
561
+ *--ptr2 = '\'';
562
+ }
563
+ }
564
+ /* Write start quote */
565
+ *p_out = '\'';
566
+ return strlen + backslashs + 2;
567
+ }
568
+
569
+
570
+ /*
571
+ * Document-class: PG::TextEncoder::QuotedLiteral < PG::CompositeEncoder
572
+ *
573
+ * This is the encoder class for PostgreSQL literals.
574
+ *
575
+ * A literal is quoted and escaped by the +'+ character.
576
+ *
577
+ */
578
+ static int
579
+ pg_text_enc_quoted_literal(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate)
580
+ {
581
+ t_pg_composite_coder *this = (t_pg_composite_coder *)conv;
582
+
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) );
587
+ return -1;
588
+ }
589
+
590
+ /*
591
+ * Document-class: PG::TextEncoder::ToBase64 < PG::CompositeEncoder
592
+ *
593
+ * This is an encoder class for conversion of binary to base64 data.
594
+ *
595
+ */
596
+ static int
597
+ pg_text_enc_to_base64(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate)
598
+ {
599
+ int strlen;
600
+ VALUE subint;
601
+ t_pg_composite_coder *this = (t_pg_composite_coder *)conv;
602
+ t_pg_coder_enc_func enc_func = pg_coder_enc_func(this->elem);
603
+
604
+ if(out){
605
+ /* Second encoder pass, if required */
606
+ strlen = enc_func(this->elem, value, out, intermediate);
607
+ base64_encode( out, out, strlen );
608
+
609
+ return BASE64_ENCODED_SIZE(strlen);
610
+ } else {
611
+ /* First encoder pass */
612
+ strlen = enc_func(this->elem, value, NULL, &subint);
613
+
614
+ if( strlen == -1 ){
615
+ /* Encoded string is returned in subint */
616
+ VALUE out_str;
617
+
618
+ strlen = RSTRING_LENINT(subint);
619
+ out_str = rb_str_new(NULL, BASE64_ENCODED_SIZE(strlen));
620
+
621
+ base64_encode( RSTRING_PTR(out_str), RSTRING_PTR(subint), strlen);
622
+ *intermediate = out_str;
623
+
624
+ return -1;
625
+ } else {
626
+ *intermediate = subint;
627
+
628
+ return BASE64_ENCODED_SIZE(strlen);
629
+ }
630
+ }
631
+ }
632
+
633
+
634
+ void
635
+ init_pg_text_encoder()
636
+ {
637
+ s_id_encode = rb_intern("encode");
638
+ s_id_to_i = rb_intern("to_i");
639
+
640
+ /* This module encapsulates all encoder classes with text output format */
641
+ rb_mPG_TextEncoder = rb_define_module_under( rb_mPG, "TextEncoder" );
642
+
643
+ /* Make RDoc aware of the encoder classes... */
644
+ /* dummy = rb_define_class_under( rb_mPG_TextEncoder, "Boolean", rb_cPG_SimpleEncoder ); */
645
+ pg_define_coder( "Boolean", pg_text_enc_boolean, rb_cPG_SimpleEncoder, rb_mPG_TextEncoder );
646
+ /* dummy = rb_define_class_under( rb_mPG_TextEncoder, "Integer", rb_cPG_SimpleEncoder ); */
647
+ pg_define_coder( "Integer", pg_text_enc_integer, rb_cPG_SimpleEncoder, rb_mPG_TextEncoder );
648
+ /* dummy = rb_define_class_under( rb_mPG_TextEncoder, "Float", rb_cPG_SimpleEncoder ); */
649
+ pg_define_coder( "Float", pg_text_enc_float, rb_cPG_SimpleEncoder, rb_mPG_TextEncoder );
650
+ /* dummy = rb_define_class_under( rb_mPG_TextEncoder, "String", rb_cPG_SimpleEncoder ); */
651
+ pg_define_coder( "String", pg_coder_enc_to_s, rb_cPG_SimpleEncoder, rb_mPG_TextEncoder );
652
+ /* dummy = rb_define_class_under( rb_mPG_TextEncoder, "Bytea", rb_cPG_SimpleEncoder ); */
653
+ pg_define_coder( "Bytea", pg_text_enc_bytea, rb_cPG_SimpleEncoder, rb_mPG_TextEncoder );
654
+ /* dummy = rb_define_class_under( rb_mPG_TextEncoder, "Identifier", rb_cPG_SimpleEncoder ); */
655
+ pg_define_coder( "Identifier", pg_text_enc_identifier, rb_cPG_SimpleEncoder, rb_mPG_TextEncoder );
656
+
657
+ /* dummy = rb_define_class_under( rb_mPG_TextEncoder, "Array", rb_cPG_CompositeEncoder ); */
658
+ pg_define_coder( "Array", pg_text_enc_array, rb_cPG_CompositeEncoder, rb_mPG_TextEncoder );
659
+ /* dummy = rb_define_class_under( rb_mPG_TextEncoder, "QuotedLiteral", rb_cPG_CompositeEncoder ); */
660
+ pg_define_coder( "QuotedLiteral", pg_text_enc_quoted_literal, rb_cPG_CompositeEncoder, rb_mPG_TextEncoder );
661
+ /* dummy = rb_define_class_under( rb_mPG_TextEncoder, "ToBase64", rb_cPG_CompositeEncoder ); */
662
+ pg_define_coder( "ToBase64", pg_text_enc_to_base64, rb_cPG_CompositeEncoder, rb_mPG_TextEncoder );
663
+ }