pg 1.0.0 → 1.5.4

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