pg 1.6.0.rc1-x86_64-linux

Sign up to get free protection for your applications and to get access to all the features.
Files changed (118) hide show
  1. checksums.yaml +7 -0
  2. checksums.yaml.gz.sig +4 -0
  3. data/BSDL +22 -0
  4. data/Contributors.rdoc +46 -0
  5. data/Gemfile +23 -0
  6. data/History.md +958 -0
  7. data/LICENSE +56 -0
  8. data/Manifest.txt +72 -0
  9. data/POSTGRES +23 -0
  10. data/README-OS_X.rdoc +68 -0
  11. data/README-Windows.rdoc +56 -0
  12. data/README.ja.md +300 -0
  13. data/README.md +286 -0
  14. data/Rakefile +161 -0
  15. data/certs/ged.pem +24 -0
  16. data/certs/kanis@comcard.de.pem +20 -0
  17. data/certs/larskanis-2022.pem +26 -0
  18. data/certs/larskanis-2023.pem +24 -0
  19. data/certs/larskanis-2024.pem +24 -0
  20. data/ext/errorcodes.def +1043 -0
  21. data/ext/errorcodes.rb +45 -0
  22. data/ext/errorcodes.txt +494 -0
  23. data/ext/extconf.rb +282 -0
  24. data/ext/gvl_wrappers.c +32 -0
  25. data/ext/gvl_wrappers.h +297 -0
  26. data/ext/pg.c +703 -0
  27. data/ext/pg.h +390 -0
  28. data/ext/pg_binary_decoder.c +460 -0
  29. data/ext/pg_binary_encoder.c +583 -0
  30. data/ext/pg_cancel_connection.c +360 -0
  31. data/ext/pg_coder.c +622 -0
  32. data/ext/pg_connection.c +4869 -0
  33. data/ext/pg_copy_coder.c +921 -0
  34. data/ext/pg_errors.c +95 -0
  35. data/ext/pg_record_coder.c +522 -0
  36. data/ext/pg_result.c +1764 -0
  37. data/ext/pg_text_decoder.c +1008 -0
  38. data/ext/pg_text_encoder.c +833 -0
  39. data/ext/pg_tuple.c +572 -0
  40. data/ext/pg_type_map.c +200 -0
  41. data/ext/pg_type_map_all_strings.c +130 -0
  42. data/ext/pg_type_map_by_class.c +271 -0
  43. data/ext/pg_type_map_by_column.c +355 -0
  44. data/ext/pg_type_map_by_mri_type.c +313 -0
  45. data/ext/pg_type_map_by_oid.c +388 -0
  46. data/ext/pg_type_map_in_ruby.c +333 -0
  47. data/ext/pg_util.c +149 -0
  48. data/ext/pg_util.h +65 -0
  49. data/ext/vc/pg.sln +26 -0
  50. data/ext/vc/pg_18/pg.vcproj +216 -0
  51. data/ext/vc/pg_19/pg_19.vcproj +209 -0
  52. data/lib/2.7/pg_ext.so +0 -0
  53. data/lib/3.0/pg_ext.so +0 -0
  54. data/lib/3.1/pg_ext.so +0 -0
  55. data/lib/3.2/pg_ext.so +0 -0
  56. data/lib/3.3/pg_ext.so +0 -0
  57. data/lib/pg/basic_type_map_based_on_result.rb +67 -0
  58. data/lib/pg/basic_type_map_for_queries.rb +202 -0
  59. data/lib/pg/basic_type_map_for_results.rb +104 -0
  60. data/lib/pg/basic_type_registry.rb +311 -0
  61. data/lib/pg/binary_decoder/date.rb +9 -0
  62. data/lib/pg/binary_decoder/timestamp.rb +26 -0
  63. data/lib/pg/binary_encoder/timestamp.rb +20 -0
  64. data/lib/pg/cancel_connection.rb +30 -0
  65. data/lib/pg/coder.rb +106 -0
  66. data/lib/pg/connection.rb +1027 -0
  67. data/lib/pg/exceptions.rb +31 -0
  68. data/lib/pg/result.rb +43 -0
  69. data/lib/pg/text_decoder/date.rb +21 -0
  70. data/lib/pg/text_decoder/inet.rb +9 -0
  71. data/lib/pg/text_decoder/json.rb +17 -0
  72. data/lib/pg/text_decoder/numeric.rb +9 -0
  73. data/lib/pg/text_decoder/timestamp.rb +30 -0
  74. data/lib/pg/text_encoder/date.rb +13 -0
  75. data/lib/pg/text_encoder/inet.rb +31 -0
  76. data/lib/pg/text_encoder/json.rb +17 -0
  77. data/lib/pg/text_encoder/numeric.rb +9 -0
  78. data/lib/pg/text_encoder/timestamp.rb +24 -0
  79. data/lib/pg/tuple.rb +30 -0
  80. data/lib/pg/type_map_by_column.rb +16 -0
  81. data/lib/pg/version.rb +4 -0
  82. data/lib/pg.rb +144 -0
  83. data/misc/openssl-pg-segfault.rb +31 -0
  84. data/misc/postgres/History.txt +9 -0
  85. data/misc/postgres/Manifest.txt +5 -0
  86. data/misc/postgres/README.txt +21 -0
  87. data/misc/postgres/Rakefile +21 -0
  88. data/misc/postgres/lib/postgres.rb +16 -0
  89. data/misc/ruby-pg/History.txt +9 -0
  90. data/misc/ruby-pg/Manifest.txt +5 -0
  91. data/misc/ruby-pg/README.txt +21 -0
  92. data/misc/ruby-pg/Rakefile +21 -0
  93. data/misc/ruby-pg/lib/ruby/pg.rb +16 -0
  94. data/pg.gemspec +36 -0
  95. data/ports/x86_64-linux/lib/libpq-ruby-pg.so.1 +0 -0
  96. data/rakelib/task_extension.rb +46 -0
  97. data/sample/array_insert.rb +20 -0
  98. data/sample/async_api.rb +102 -0
  99. data/sample/async_copyto.rb +39 -0
  100. data/sample/async_mixed.rb +56 -0
  101. data/sample/check_conn.rb +21 -0
  102. data/sample/copydata.rb +71 -0
  103. data/sample/copyfrom.rb +81 -0
  104. data/sample/copyto.rb +19 -0
  105. data/sample/cursor.rb +21 -0
  106. data/sample/disk_usage_report.rb +177 -0
  107. data/sample/issue-119.rb +94 -0
  108. data/sample/losample.rb +69 -0
  109. data/sample/minimal-testcase.rb +17 -0
  110. data/sample/notify_wait.rb +72 -0
  111. data/sample/pg_statistics.rb +285 -0
  112. data/sample/replication_monitor.rb +222 -0
  113. data/sample/test_binary_values.rb +33 -0
  114. data/sample/wal_shipper.rb +434 -0
  115. data/sample/warehouse_partitions.rb +311 -0
  116. data.tar.gz.sig +0 -0
  117. metadata +252 -0
  118. metadata.gz.sig +0 -0
@@ -0,0 +1,1008 @@
1
+ /*
2
+ * pg_text_decoder.c - PG::TextDecoder module
3
+ * $Id$
4
+ *
5
+ */
6
+
7
+ /*
8
+ *
9
+ * Type casts for decoding PostgreSQL string representations to Ruby objects.
10
+ *
11
+ * Decoder classes are defined with pg_define_coder(). This creates a new coder class and
12
+ * assigns a decoder function.
13
+ *
14
+ * Signature of all type cast decoders is:
15
+ * VALUE decoder_function(t_pg_coder *this, const char *val, int len, int tuple, int field, int enc_idx)
16
+ *
17
+ * Params:
18
+ * this - The data part of the coder object that belongs to the decoder function.
19
+ * val, len - The text or binary data to decode.
20
+ * The caller ensures, that text data (format=0) is zero terminated so that val[len]=0.
21
+ * The memory should be used read-only by the callee.
22
+ * tuple - Row of the value within the result set.
23
+ * field - Column of the value within the result set.
24
+ * enc_idx - Index of the Encoding that any output String should get assigned.
25
+ *
26
+ * Returns:
27
+ * The type casted Ruby object.
28
+ *
29
+ */
30
+
31
+ #include "ruby/version.h"
32
+ #include "pg.h"
33
+ #include "pg_util.h"
34
+ #ifdef HAVE_INTTYPES_H
35
+ #include <inttypes.h>
36
+ #endif
37
+ #include <ctype.h>
38
+ #include <time.h>
39
+ #if !defined(_WIN32)
40
+ #include <arpa/inet.h>
41
+ #include <sys/socket.h>
42
+ #endif
43
+ #include <string.h>
44
+
45
+ VALUE rb_mPG_TextDecoder;
46
+ static ID s_id_Rational;
47
+ static ID s_id_new;
48
+ static ID s_id_utc;
49
+ static ID s_id_getlocal;
50
+ static ID s_id_BigDecimal;
51
+
52
+ static VALUE s_IPAddr;
53
+ static VALUE s_vmasks4;
54
+ static VALUE s_vmasks6;
55
+ static VALUE s_nan, s_pos_inf, s_neg_inf;
56
+ static int use_ipaddr_alloc;
57
+ static ID s_id_lshift;
58
+ static ID s_id_add;
59
+ static ID s_id_mask;
60
+ static ID s_ivar_family;
61
+ static ID s_ivar_addr;
62
+ static ID s_ivar_mask_addr;
63
+
64
+ /*
65
+ * Document-class: PG::TextDecoder::Boolean < PG::SimpleDecoder
66
+ *
67
+ * This is a decoder class for conversion of PostgreSQL boolean type
68
+ * to Ruby true or false values.
69
+ *
70
+ */
71
+ static VALUE
72
+ pg_text_dec_boolean(t_pg_coder *conv, const char *val, int len, int tuple, int field, int enc_idx)
73
+ {
74
+ if (len < 1) {
75
+ rb_raise( rb_eTypeError, "wrong data for text boolean converter in tuple %d field %d", tuple, field);
76
+ }
77
+ return *val == 't' ? Qtrue : Qfalse;
78
+ }
79
+
80
+ /*
81
+ * Document-class: PG::TextDecoder::String < PG::SimpleDecoder
82
+ *
83
+ * This is a decoder class for conversion of PostgreSQL text output to
84
+ * to Ruby String object. The output value will have the character encoding
85
+ * set with PG::Connection#internal_encoding= .
86
+ *
87
+ */
88
+ VALUE
89
+ pg_text_dec_string(t_pg_coder *conv, const char *val, int len, int tuple, int field, int enc_idx)
90
+ {
91
+ VALUE ret = rb_str_new( val, len );
92
+ PG_ENCODING_SET_NOCHECK( ret, enc_idx );
93
+ return ret;
94
+ }
95
+
96
+ /*
97
+ * Document-class: PG::TextDecoder::Integer < PG::SimpleDecoder
98
+ *
99
+ * This is a decoder class for conversion of PostgreSQL integer types
100
+ * to Ruby Integer objects.
101
+ *
102
+ */
103
+ static VALUE
104
+ pg_text_dec_integer(t_pg_coder *conv, const char *val, int len, int tuple, int field, int enc_idx)
105
+ {
106
+ long i;
107
+ int max_len;
108
+
109
+ if( sizeof(i) >= 8 && FIXNUM_MAX >= 1000000000000000000LL ){
110
+ /* 64 bit system can safely handle all numbers up to 18 digits as Fixnum */
111
+ max_len = 18;
112
+ } else if( sizeof(i) >= 4 && FIXNUM_MAX >= 1000000000LL ){
113
+ /* 32 bit system can safely handle all numbers up to 9 digits as Fixnum */
114
+ max_len = 9;
115
+ } else {
116
+ /* unknown -> don't use fast path for int conversion */
117
+ max_len = 0;
118
+ }
119
+
120
+ if( len <= max_len ){
121
+ /* rb_cstr2inum() seems to be slow, so we do the int conversion by hand.
122
+ * This proved to be 40% faster by the following benchmark:
123
+ *
124
+ * conn.type_mapping_for_results = PG::BasicTypeMapForResults.new conn
125
+ * Benchmark.measure do
126
+ * conn.exec("select generate_series(1,1000000)").values }
127
+ * end
128
+ */
129
+ const char *val_pos = val;
130
+ char digit = *val_pos;
131
+ int neg;
132
+ int error = 0;
133
+
134
+ if( digit=='-' ){
135
+ neg = 1;
136
+ i = 0;
137
+ }else if( digit>='0' && digit<='9' ){
138
+ neg = 0;
139
+ i = digit - '0';
140
+ } else {
141
+ error = 1;
142
+ }
143
+
144
+ while (!error && (digit=*++val_pos)) {
145
+ if( digit>='0' && digit<='9' ){
146
+ i = i * 10 + (digit - '0');
147
+ } else {
148
+ error = 1;
149
+ }
150
+ }
151
+
152
+ if( !error ){
153
+ return LONG2FIX(neg ? -i : i);
154
+ }
155
+ }
156
+ /* Fallback to ruby method if number too big or unrecognized. */
157
+ return rb_cstr2inum(val, 10);
158
+ }
159
+
160
+ /*
161
+ * Document-class: PG::TextDecoder::Numeric < PG::SimpleDecoder
162
+ *
163
+ * This is a decoder class for conversion of PostgreSQL numeric types
164
+ * to Ruby BigDecimal objects.
165
+ *
166
+ * As soon as this class is used, it requires the 'bigdecimal' gem.
167
+ *
168
+ */
169
+ static VALUE
170
+ pg_text_dec_numeric(t_pg_coder *conv, const char *val, int len, int tuple, int field, int enc_idx)
171
+ {
172
+ return rb_funcall(rb_cObject, s_id_BigDecimal, 1, rb_str_new(val, len));
173
+ }
174
+
175
+ /* called per autoload when TextDecoder::Numeric is used */
176
+ static VALUE
177
+ init_pg_text_decoder_numeric(VALUE rb_mPG_TextDecoder)
178
+ {
179
+ rb_funcall(rb_mPG, rb_intern("require_bigdecimal_without_warning"), 0);
180
+ s_id_BigDecimal = rb_intern("BigDecimal");
181
+
182
+ /* dummy = rb_define_class_under( rb_mPG_TextDecoder, "Numeric", rb_cPG_SimpleDecoder ); */
183
+ pg_define_coder( "Numeric", pg_text_dec_numeric, rb_cPG_SimpleDecoder, rb_mPG_TextDecoder );
184
+
185
+ return Qnil;
186
+ }
187
+
188
+ /*
189
+ * Document-class: PG::TextDecoder::Float < PG::SimpleDecoder
190
+ *
191
+ * This is a decoder class for conversion of PostgreSQL float4 and float8 types
192
+ * to Ruby Float objects.
193
+ *
194
+ */
195
+ static VALUE
196
+ pg_text_dec_float(t_pg_coder *conv, const char *val, int len, int tuple, int field, int enc_idx)
197
+ {
198
+ switch(*val) {
199
+ case 'N':
200
+ return s_nan;
201
+ case 'I':
202
+ return s_pos_inf;
203
+ case '-':
204
+ if (val[1] == 'I') {
205
+ return s_neg_inf;
206
+ } else {
207
+ return rb_float_new(rb_cstr_to_dbl(val, Qfalse));
208
+ }
209
+ default:
210
+ return rb_float_new(rb_cstr_to_dbl(val, Qfalse));
211
+ }
212
+ }
213
+
214
+ struct pg_blob_initialization {
215
+ char *blob_string;
216
+ size_t length;
217
+ };
218
+
219
+ static VALUE pg_create_blob(VALUE v) {
220
+ struct pg_blob_initialization *bi = (struct pg_blob_initialization *)v;
221
+ return rb_str_new(bi->blob_string, bi->length);
222
+ }
223
+
224
+ static VALUE pg_pq_freemem(VALUE mem) {
225
+ PQfreemem((void *)mem);
226
+ return Qfalse;
227
+ }
228
+
229
+ /*
230
+ * Document-class: PG::TextDecoder::Bytea < PG::SimpleDecoder
231
+ *
232
+ * This is a decoder class for conversion of PostgreSQL bytea type
233
+ * to binary String objects.
234
+ *
235
+ */
236
+ static VALUE
237
+ pg_text_dec_bytea(t_pg_coder *conv, const char *val, int len, int tuple, int field, int enc_idx)
238
+ {
239
+ struct pg_blob_initialization bi;
240
+
241
+ bi.blob_string = (char *)PQunescapeBytea((unsigned char*)val, &bi.length);
242
+ if (bi.blob_string == NULL) {
243
+ rb_raise(rb_eNoMemError, "PQunescapeBytea failure: probably not enough memory");
244
+ }
245
+ return rb_ensure(pg_create_blob, (VALUE)&bi, pg_pq_freemem, (VALUE)bi.blob_string);
246
+ }
247
+
248
+ /*
249
+ * array_isspace() --- a non-locale-dependent isspace()
250
+ *
251
+ * We used to use isspace() for parsing array values, but that has
252
+ * undesirable results: an array value might be silently interpreted
253
+ * differently depending on the locale setting. Now we just hard-wire
254
+ * the traditional ASCII definition of isspace().
255
+ */
256
+ static int
257
+ array_isspace(char ch)
258
+ {
259
+ if (ch == ' ' ||
260
+ ch == '\t' ||
261
+ ch == '\n' ||
262
+ ch == '\r' ||
263
+ ch == '\v' ||
264
+ ch == '\f')
265
+ return 1;
266
+ return 0;
267
+ }
268
+
269
+ static int
270
+ array_isdim(char ch)
271
+ {
272
+ if ( (ch >= '0' && ch <= '9') ||
273
+ (ch == '-') ||
274
+ (ch == '+') ||
275
+ (ch == ':') )
276
+ return 1;
277
+ return 0;
278
+ }
279
+
280
+ static void
281
+ array_parser_error(t_pg_composite_coder *this, const char *text){
282
+ if( (this->comp.flags & PG_CODER_FORMAT_ERROR_MASK) == PG_CODER_FORMAT_ERROR_TO_RAISE ){
283
+ rb_raise( rb_eTypeError, "%s", text );
284
+ }
285
+ }
286
+
287
+ /*
288
+ * Array parser functions are thankfully borrowed from here:
289
+ * https://github.com/dockyard/pg_array_parser
290
+ */
291
+ static VALUE
292
+ read_array_without_dim(t_pg_composite_coder *this, int *index, const char *c_pg_array_string, int array_string_length, char *word, int enc_idx, int tuple, int field, t_pg_coder_dec_func dec_func)
293
+ {
294
+ /* Return value: array */
295
+ VALUE array;
296
+ int word_index = 0;
297
+
298
+ /* The current character in the input string. */
299
+ char c;
300
+
301
+ /* 0: Currently outside a quoted string, current word never quoted
302
+ * 1: Currently inside a quoted string
303
+ * -1: Currently outside a quoted string, current word previously quoted */
304
+ int openQuote = 0;
305
+
306
+ /* Inside quoted input means the next character should be treated literally,
307
+ * instead of being treated as a metacharacter.
308
+ * Outside of quoted input, means that the word shouldn't be pushed to the array,
309
+ * used when the last entry was a subarray (which adds to the array itself). */
310
+ int escapeNext = 0;
311
+
312
+ array = rb_ary_new();
313
+
314
+ /* Special case the empty array, so it doesn't need to be handled manually inside
315
+ * the loop. */
316
+ if(((*index) < array_string_length) && c_pg_array_string[*index] == '}')
317
+ {
318
+ return array;
319
+ }
320
+
321
+ for(;(*index) < array_string_length; ++(*index))
322
+ {
323
+ c = c_pg_array_string[*index];
324
+ if(openQuote < 1)
325
+ {
326
+ if(c == this->delimiter || c == '}')
327
+ {
328
+ if(!escapeNext)
329
+ {
330
+ if(openQuote == 0 && word_index == 4 && !strncmp(word, "NULL", word_index))
331
+ {
332
+ rb_ary_push(array, Qnil);
333
+ }
334
+ else
335
+ {
336
+ VALUE val;
337
+ word[word_index] = 0;
338
+ val = dec_func(this->elem, word, word_index, tuple, field, enc_idx);
339
+ rb_ary_push(array, val);
340
+ }
341
+ }
342
+ if(c == '}')
343
+ {
344
+ return array;
345
+ }
346
+ escapeNext = 0;
347
+ openQuote = 0;
348
+ word_index = 0;
349
+ }
350
+ else if(c == '"')
351
+ {
352
+ openQuote = 1;
353
+ }
354
+ else if(c == '{')
355
+ {
356
+ VALUE subarray;
357
+ (*index)++;
358
+ subarray = read_array_without_dim(this, index, c_pg_array_string, array_string_length, word, enc_idx, tuple, field, dec_func);
359
+ rb_ary_push(array, subarray);
360
+ escapeNext = 1;
361
+ }
362
+ else if(c == 0)
363
+ {
364
+ array_parser_error( this, "premature end of the array string" );
365
+ return array;
366
+ }
367
+ else
368
+ {
369
+ word[word_index] = c;
370
+ word_index++;
371
+ }
372
+ }
373
+ else if (escapeNext) {
374
+ word[word_index] = c;
375
+ word_index++;
376
+ escapeNext = 0;
377
+ }
378
+ else if (c == '\\')
379
+ {
380
+ escapeNext = 1;
381
+ }
382
+ else if (c == '"')
383
+ {
384
+ openQuote = -1;
385
+ }
386
+ else
387
+ {
388
+ word[word_index] = c;
389
+ word_index++;
390
+ }
391
+ }
392
+
393
+ array_parser_error( this, "premature end of the array string" );
394
+ return array;
395
+ }
396
+
397
+ /*
398
+ * Document-class: PG::TextDecoder::Array < PG::CompositeDecoder
399
+ *
400
+ * This is a decoder class for PostgreSQL array types.
401
+ *
402
+ * It returns an Array with possibly an arbitrary number of sub-Arrays.
403
+ * All values are decoded according to the #elements_type accessor.
404
+ * Sub-arrays are decoded recursively.
405
+ *
406
+ * This decoder simply ignores any dimension decorations preceding the array values.
407
+ * It returns all array values as regular ruby Array with a zero based index, regardless of the index given in the dimension decoration.
408
+ *
409
+ * An array decoder which respects dimension decorations is waiting to be implemented.
410
+ *
411
+ */
412
+ static VALUE
413
+ pg_text_dec_array(t_pg_coder *conv, const char *c_pg_array_string, int array_string_length, int tuple, int field, int enc_idx)
414
+ {
415
+ int index = 0;
416
+ int ndim = 0;
417
+ VALUE ret;
418
+ t_pg_composite_coder *this = (t_pg_composite_coder *)conv;
419
+
420
+ /*
421
+ * If the input string starts with dimension info, read and use that.
422
+ * Otherwise, we require the input to be in curly-brace style, and we
423
+ * prescan the input to determine dimensions.
424
+ *
425
+ * Dimension info takes the form of one or more [n] or [m:n] items. The
426
+ * outer loop iterates once per dimension item.
427
+ */
428
+ for (;;)
429
+ {
430
+ /*
431
+ * Note: we currently allow whitespace between, but not within,
432
+ * dimension items.
433
+ */
434
+ while (array_isspace(c_pg_array_string[index]))
435
+ index++;
436
+ if (c_pg_array_string[index] != '[')
437
+ break; /* no more dimension items */
438
+ index++;
439
+
440
+ while (array_isdim(c_pg_array_string[index]))
441
+ index++;
442
+
443
+ if (c_pg_array_string[index] != ']'){
444
+ array_parser_error( this, "missing \"]\" in array dimensions");
445
+ break;
446
+ }
447
+ index++;
448
+
449
+ ndim++;
450
+ }
451
+
452
+ if (ndim == 0)
453
+ {
454
+ /* No array dimensions */
455
+ }
456
+ else
457
+ {
458
+ /* If array dimensions are given, expect '=' operator */
459
+ if (c_pg_array_string[index] != '=') {
460
+ array_parser_error( this, "missing assignment operator");
461
+ index-=2; /* jump back to before "]" so that we don't break behavior to pg < 1.1 */
462
+ }
463
+ index++;
464
+
465
+ while (array_isspace(c_pg_array_string[index]))
466
+ index++;
467
+ }
468
+
469
+ if (c_pg_array_string[index] != '{')
470
+ array_parser_error( this, "array value must start with \"{\" or dimension information");
471
+ index++;
472
+
473
+ if ( index < array_string_length && c_pg_array_string[index] == '}' ) {
474
+ /* avoid buffer allocation for empty array */
475
+ ret = rb_ary_new();
476
+ } else {
477
+ t_pg_coder_dec_func dec_func = pg_coder_dec_func(this->elem, 0);
478
+ /* create a buffer of the same length, as that will be the worst case */
479
+ VALUE buf = rb_str_new(NULL, array_string_length);
480
+ char *word = RSTRING_PTR(buf);
481
+
482
+ ret = read_array_without_dim(this, &index, c_pg_array_string, array_string_length, word, enc_idx, tuple, field, dec_func);
483
+
484
+ RB_GC_GUARD(buf);
485
+ }
486
+
487
+ if (c_pg_array_string[index] != '}' )
488
+ array_parser_error( this, "array value must end with \"}\"");
489
+ index++;
490
+
491
+ /* only whitespace is allowed after the closing brace */
492
+ for(;index < array_string_length; ++index)
493
+ {
494
+ if (!array_isspace(c_pg_array_string[index]))
495
+ array_parser_error( this, "malformed array literal: Junk after closing right brace.");
496
+ }
497
+
498
+ return ret;
499
+ }
500
+
501
+ /*
502
+ * Document-class: PG::TextDecoder::Identifier < PG::SimpleDecoder
503
+ *
504
+ * This is the decoder class for PostgreSQL identifiers.
505
+ *
506
+ * Returns an Array of identifiers:
507
+ * PG::TextDecoder::Identifier.new.decode('schema."table"."column"')
508
+ * => ["schema", "table", "column"]
509
+ *
510
+ */
511
+ static VALUE
512
+ pg_text_dec_identifier(t_pg_coder *conv, const char *val, int len, int tuple, int field, int enc_idx)
513
+ {
514
+ /* Return value: array */
515
+ VALUE array;
516
+ VALUE elem;
517
+ int word_index = 0;
518
+ int index;
519
+ /* Use a buffer of the same length, as that will be the worst case */
520
+ PG_VARIABLE_LENGTH_ARRAY(char, word, len + 1, NAMEDATALEN)
521
+
522
+ /* The current character in the input string. */
523
+ char c;
524
+
525
+ /* 0: Currently outside a quoted string
526
+ * 1: Currently inside a quoted string, last char was a quote
527
+ * 2: Currently inside a quoted string, last char was no quote */
528
+ int openQuote = 0;
529
+
530
+ array = rb_ary_new();
531
+
532
+ for(index = 0; index < len; ++index) {
533
+ c = val[index];
534
+ if(c == '.' && openQuote < 2 ) {
535
+ word[word_index] = 0;
536
+
537
+ elem = pg_text_dec_string(conv, word, word_index, tuple, field, enc_idx);
538
+ rb_ary_push(array, elem);
539
+
540
+ openQuote = 0;
541
+ word_index = 0;
542
+ } else if(c == '"') {
543
+ if (openQuote == 1) {
544
+ word[word_index] = c;
545
+ word_index++;
546
+ openQuote = 2;
547
+ } else if (openQuote == 2){
548
+ openQuote = 1;
549
+ } else {
550
+ openQuote = 2;
551
+ }
552
+ } else {
553
+ word[word_index] = c;
554
+ word_index++;
555
+ }
556
+ }
557
+
558
+ word[word_index] = 0;
559
+ elem = pg_text_dec_string(conv, word, word_index, tuple, field, enc_idx);
560
+ rb_ary_push(array, elem);
561
+
562
+ return array;
563
+ }
564
+
565
+ /*
566
+ * Document-class: PG::TextDecoder::FromBase64 < PG::CompositeDecoder
567
+ *
568
+ * This is a decoder class for conversion of base64 encoded data
569
+ * to it's binary representation. It outputs a binary Ruby String
570
+ * or some other Ruby object, if a #elements_type decoder was defined.
571
+ *
572
+ */
573
+ static VALUE
574
+ pg_text_dec_from_base64(t_pg_coder *conv, const char *val, int len, int tuple, int field, int enc_idx)
575
+ {
576
+ t_pg_composite_coder *this = (t_pg_composite_coder *)conv;
577
+ t_pg_coder_dec_func dec_func = pg_coder_dec_func(this->elem, this->comp.format);
578
+ int decoded_len;
579
+ /* create a buffer of the expected decoded length */
580
+ VALUE out_value = rb_str_new(NULL, BASE64_DECODED_SIZE(len));
581
+
582
+ decoded_len = base64_decode( RSTRING_PTR(out_value), val, len );
583
+ rb_str_set_len(out_value, decoded_len);
584
+
585
+ /* Is it a pure String conversion? Then we can directly send out_value to the user. */
586
+ if( this->comp.format == 0 && dec_func == pg_text_dec_string ){
587
+ PG_ENCODING_SET_NOCHECK( out_value, enc_idx );
588
+ return out_value;
589
+ }
590
+ if( this->comp.format == 1 && dec_func == pg_bin_dec_bytea ){
591
+ PG_ENCODING_SET_NOCHECK( out_value, rb_ascii8bit_encindex() );
592
+ return out_value;
593
+ }
594
+ out_value = dec_func(this->elem, RSTRING_PTR(out_value), decoded_len, tuple, field, enc_idx);
595
+
596
+ return out_value;
597
+ }
598
+
599
+ static inline int char_to_digit(char c)
600
+ {
601
+ return c - '0';
602
+ }
603
+
604
+ static int str2_to_int(const char *str)
605
+ {
606
+ return char_to_digit(str[0]) * 10
607
+ + char_to_digit(str[1]);
608
+ }
609
+
610
+ static int parse_year(const char **str) {
611
+ int year = 0;
612
+ int i;
613
+ const char * p = *str;
614
+
615
+ for(i = 0; isdigit(*p) && i < 7; i++, p++) {
616
+ year = 10 * year + char_to_digit(*p);
617
+ }
618
+
619
+ *str = p;
620
+ return year;
621
+ }
622
+
623
+ #define TZ_NEG 1
624
+ #define TZ_POS 2
625
+
626
+ /*
627
+ * Document-class: PG::TextDecoder::Timestamp < PG::SimpleDecoder
628
+ *
629
+ * This is a decoder class for conversion of PostgreSQL text timestamps
630
+ * to Ruby Time objects.
631
+ *
632
+ * The following flags can be used to specify time interpretation when no timezone is given:
633
+ * * +PG::Coder::TIMESTAMP_DB_UTC+ : Interpret timestamp as UTC time (default)
634
+ * * +PG::Coder::TIMESTAMP_DB_LOCAL+ : Interpret timestamp as local time
635
+ * * +PG::Coder::TIMESTAMP_APP_UTC+ : Return timestamp as UTC time (default)
636
+ * * +PG::Coder::TIMESTAMP_APP_LOCAL+ : Return timestamp as local time
637
+ *
638
+ * Example:
639
+ * deco = PG::TextDecoder::Timestamp.new(flags: PG::Coder::TIMESTAMP_DB_UTC | PG::Coder::TIMESTAMP_APP_LOCAL)
640
+ * deco.decode("2000-01-01 00:00:00") # => 2000-01-01 01:00:00 +0100
641
+ * deco.decode("2000-01-01 00:00:00.123-06") # => 2000-01-01 00:00:00 -0600
642
+ */
643
+ static VALUE pg_text_dec_timestamp(t_pg_coder *conv, const char *val, int len, int tuple, int field, int enc_idx)
644
+ {
645
+ const char *str = val;
646
+ int year, mon, day;
647
+ int hour, min, sec;
648
+ int nsec = 0;
649
+ int tz_given = 0;
650
+ int tz_hour = 0;
651
+ int tz_min = 0;
652
+ int tz_sec = 0;
653
+
654
+ year = parse_year(&str);
655
+
656
+ if ( year > 0
657
+ && str[0] == '-' && isdigit(str[1]) && isdigit(str[2])
658
+ && str[3] == '-' && isdigit(str[4]) && isdigit(str[5])
659
+ && str[6] == ' ' && isdigit(str[7]) && isdigit(str[8])
660
+ && str[9] == ':' && isdigit(str[10]) && isdigit(str[11])
661
+ && str[12] == ':' && isdigit(str[13]) && isdigit(str[14])
662
+ ) {
663
+
664
+ mon = str2_to_int(str+1); str += 3;
665
+ day = str2_to_int(str+1); str += 3;
666
+ hour = str2_to_int(str+1); str += 3;
667
+ min = str2_to_int(str+1); str += 3;
668
+ sec = str2_to_int(str+1); str += 3;
669
+
670
+ if (str[0] == '.' && isdigit(str[1])) {
671
+ /* nano second part, up to 9 digits */
672
+ static const int coef[9] = {
673
+ 100000000, 10000000, 1000000,
674
+ 100000, 10000, 1000, 100, 10, 1
675
+ };
676
+ int i;
677
+
678
+ str++;
679
+ for (i = 0; i < 9 && isdigit(*str); i++)
680
+ {
681
+ nsec += coef[i] * char_to_digit(*str++);
682
+ }
683
+ /* consume digits smaller than nsec */
684
+ while(isdigit(*str)) str++;
685
+ }
686
+
687
+ if ((str[0] == '+' || str[0] == '-') && isdigit(str[1]) && isdigit(str[2])) {
688
+ tz_given = str[0] == '-' ? TZ_NEG : TZ_POS;
689
+ tz_hour = str2_to_int(str+1); str += 3;
690
+
691
+ if (str[0] == ':' && isdigit(str[1]) && isdigit(str[2]))
692
+ {
693
+ tz_min = str2_to_int(str+1); str += 3;
694
+ }
695
+ if (str[0] == ':' && isdigit(str[1]) && isdigit(str[2]))
696
+ {
697
+ tz_sec = str2_to_int(str+1); str += 3;
698
+ }
699
+ }
700
+
701
+ if (str[0] == ' ' && str[1] == 'B' && str[2] == 'C') {
702
+ year = -year + 1;
703
+ str += 3;
704
+ }
705
+
706
+ if (*str == '\0') { /* must have consumed all the string */
707
+ VALUE sec_value;
708
+ VALUE gmt_offset_value;
709
+ VALUE res;
710
+
711
+ #if (RUBY_API_VERSION_MAJOR > 2 || (RUBY_API_VERSION_MAJOR == 2 && RUBY_API_VERSION_MINOR >= 3)) && defined(HAVE_TIMEGM)
712
+ /* Fast path for time conversion */
713
+ struct tm tm;
714
+ struct timespec ts;
715
+ tm.tm_year = year - 1900;
716
+ tm.tm_mon = mon - 1;
717
+ tm.tm_mday = day;
718
+ tm.tm_hour = hour;
719
+ tm.tm_min = min;
720
+ tm.tm_sec = sec;
721
+ tm.tm_isdst = -1;
722
+
723
+ if (tz_given) {
724
+ /* with timezone */
725
+ time_t time = timegm(&tm);
726
+ if (time != -1){
727
+ int gmt_offset;
728
+
729
+ gmt_offset = tz_hour * 3600 + tz_min * 60 + tz_sec;
730
+ if (tz_given == TZ_NEG)
731
+ {
732
+ gmt_offset = - gmt_offset;
733
+ }
734
+ ts.tv_sec = time - gmt_offset;
735
+ ts.tv_nsec = nsec;
736
+ return rb_time_timespec_new(&ts, gmt_offset);
737
+ }
738
+ } else {
739
+ /* without timezone */
740
+ time_t time;
741
+
742
+ if( conv->flags & PG_CODER_TIMESTAMP_DB_LOCAL ) {
743
+ time = mktime(&tm);
744
+ } else {
745
+ time = timegm(&tm);
746
+ }
747
+ if (time != -1){
748
+ ts.tv_sec = time;
749
+ ts.tv_nsec = nsec;
750
+ return rb_time_timespec_new(&ts, conv->flags & PG_CODER_TIMESTAMP_APP_LOCAL ? INT_MAX : INT_MAX-1);
751
+ }
752
+ }
753
+ /* Some libc implementations fail to convert certain values,
754
+ * so that we fall through to the slow path.
755
+ */
756
+ #endif
757
+ if (nsec) {
758
+ int sec_numerator = sec * 1000000 + nsec / 1000;
759
+ int sec_denominator = 1000000;
760
+ sec_value = rb_funcall(Qnil, s_id_Rational, 2,
761
+ INT2NUM(sec_numerator), INT2NUM(sec_denominator));
762
+ } else {
763
+ sec_value = INT2NUM(sec);
764
+ }
765
+
766
+ if (tz_given) {
767
+ /* with timezone */
768
+ int gmt_offset;
769
+
770
+ gmt_offset = tz_hour * 3600 + tz_min * 60 + tz_sec;
771
+ if (tz_given == TZ_NEG)
772
+ {
773
+ gmt_offset = - gmt_offset;
774
+ }
775
+ gmt_offset_value = INT2NUM(gmt_offset);
776
+ } else {
777
+ /* without timezone */
778
+ gmt_offset_value = conv->flags & PG_CODER_TIMESTAMP_DB_LOCAL ? Qnil : INT2NUM(0);
779
+ }
780
+
781
+ res = rb_funcall(rb_cTime, s_id_new, 7,
782
+ INT2NUM(year),
783
+ INT2NUM(mon),
784
+ INT2NUM(day),
785
+ INT2NUM(hour),
786
+ INT2NUM(min),
787
+ sec_value,
788
+ gmt_offset_value);
789
+
790
+ if (tz_given) {
791
+ /* with timezone */
792
+ return res;
793
+ } else {
794
+ /* without timezone */
795
+ if( (conv->flags & PG_CODER_TIMESTAMP_DB_LOCAL) && (conv->flags & PG_CODER_TIMESTAMP_APP_LOCAL) ) {
796
+ return res;
797
+ } else if( conv->flags & PG_CODER_TIMESTAMP_APP_LOCAL ) {
798
+ return rb_funcall(res, s_id_getlocal, 0);
799
+ } else {
800
+ return rb_funcall(res, s_id_utc, 0);
801
+ }
802
+ }
803
+ }
804
+ }
805
+
806
+ /* fall through to string conversion */
807
+ return pg_text_dec_string(conv, val, len, tuple, field, enc_idx);
808
+ }
809
+
810
+ /*
811
+ * Document-class: PG::TextDecoder::Inet < PG::SimpleDecoder
812
+ *
813
+ * This is a decoder class for conversion of PostgreSQL inet type
814
+ * to Ruby IPAddr values.
815
+ *
816
+ * As soon as this class is used, it requires the ruby standard library 'ipaddr'.
817
+ */
818
+ static VALUE
819
+ pg_text_dec_inet(t_pg_coder *conv, const char *val, int len, int tuple, int field, int enc_idx)
820
+ {
821
+ VALUE ip;
822
+ #if defined(_WIN32)
823
+ ip = rb_str_new(val, len);
824
+ ip = rb_class_new_instance(1, &ip, s_IPAddr);
825
+ #else
826
+ VALUE ip_int;
827
+ VALUE vmasks;
828
+ char dst[16];
829
+ char buf[64];
830
+ int af = strchr(val, '.') ? AF_INET : AF_INET6;
831
+ int mask = -1;
832
+
833
+ if (len >= 64) {
834
+ rb_raise(rb_eTypeError, "too long data for text inet converter in tuple %d field %d", tuple, field);
835
+ }
836
+
837
+ if (len >= 4) {
838
+ if (val[len-2] == '/') {
839
+ mask = val[len-1] - '0';
840
+ memcpy(buf, val, len-2);
841
+ buf[len-2] = '\0';
842
+ val = buf;
843
+ } else if (val[len-3] == '/') {
844
+ mask = (val[len-2]- '0')*10 + val[len-1] - '0';
845
+ memcpy(buf, val, len-3);
846
+ buf[len-3] = '\0';
847
+ val = buf;
848
+ } else if (val[len-4] == '/') {
849
+ mask = (val[len-3]- '0')*100 + (val[len-2]- '0')*10 + val[len-1] - '0';
850
+ memcpy(buf, val, len-4);
851
+ buf[len-4] = '\0';
852
+ val = buf;
853
+ }
854
+ }
855
+
856
+ if (1 != inet_pton(af, val, dst)) {
857
+ rb_raise(rb_eTypeError, "wrong data for text inet converter in tuple %d field %d val", tuple, field);
858
+ }
859
+
860
+ if (af == AF_INET) {
861
+ unsigned int ip_int_native;
862
+
863
+ if (mask == -1) {
864
+ mask = 32;
865
+ } else if (mask < 0 || mask > 32) {
866
+ rb_raise(rb_eTypeError, "invalid mask for IPv4: %d", mask);
867
+ }
868
+ vmasks = s_vmasks4;
869
+
870
+ ip_int_native = read_nbo32(dst);
871
+
872
+ /* Work around broken IPAddr behavior of converting portion
873
+ of address after netmask to 0 */
874
+ switch (mask) {
875
+ case 0:
876
+ ip_int_native = 0;
877
+ break;
878
+ case 32:
879
+ /* nothing to do */
880
+ break;
881
+ default:
882
+ ip_int_native &= ~((1UL<<(32-mask))-1);
883
+ break;
884
+ }
885
+
886
+ ip_int = UINT2NUM(ip_int_native);
887
+ } else {
888
+ unsigned long long * dstllp = (unsigned long long *)dst;
889
+ unsigned long long ip_int_native1;
890
+ unsigned long long ip_int_native2;
891
+
892
+ if (mask == -1) {
893
+ mask = 128;
894
+ } else if (mask < 0 || mask > 128) {
895
+ rb_raise(rb_eTypeError, "invalid mask for IPv6: %d", mask);
896
+ }
897
+ vmasks = s_vmasks6;
898
+
899
+ ip_int_native1 = read_nbo64(dstllp);
900
+ dstllp++;
901
+ ip_int_native2 = read_nbo64(dstllp);
902
+
903
+ if (mask == 128) {
904
+ /* nothing to do */
905
+ } else if (mask == 64) {
906
+ ip_int_native2 = 0;
907
+ } else if (mask == 0) {
908
+ ip_int_native1 = 0;
909
+ ip_int_native2 = 0;
910
+ } else if (mask < 64) {
911
+ ip_int_native1 &= ~((1ULL<<(64-mask))-1);
912
+ ip_int_native2 = 0;
913
+ } else {
914
+ ip_int_native2 &= ~((1ULL<<(128-mask))-1);
915
+ }
916
+
917
+ /* 4 Bignum allocations */
918
+ ip_int = ULL2NUM(ip_int_native1);
919
+ ip_int = rb_funcall(ip_int, s_id_lshift, 1, INT2NUM(64));
920
+ ip_int = rb_funcall(ip_int, s_id_add, 1, ULL2NUM(ip_int_native2));
921
+ }
922
+
923
+ if (use_ipaddr_alloc) {
924
+ ip = rb_obj_alloc(s_IPAddr);
925
+ rb_ivar_set(ip, s_ivar_family, INT2NUM(af));
926
+ rb_ivar_set(ip, s_ivar_addr, ip_int);
927
+ rb_ivar_set(ip, s_ivar_mask_addr, RARRAY_AREF(vmasks, mask));
928
+ } else {
929
+ VALUE ip_args[2];
930
+ ip_args[0] = ip_int;
931
+ ip_args[1] = INT2NUM(af);
932
+ ip = rb_class_new_instance(2, ip_args, s_IPAddr);
933
+ ip = rb_funcall(ip, s_id_mask, 1, INT2NUM(mask));
934
+ }
935
+
936
+ #endif
937
+ return ip;
938
+ }
939
+
940
+ /* called per autoload when TextDecoder::Inet is used */
941
+ static VALUE
942
+ init_pg_text_decoder_inet(VALUE rb_mPG_TextDecoder)
943
+ {
944
+ rb_require("ipaddr");
945
+ s_IPAddr = rb_funcall(rb_cObject, rb_intern("const_get"), 1, rb_str_new2("IPAddr"));
946
+ rb_global_variable(&s_IPAddr);
947
+ s_ivar_family = rb_intern("@family");
948
+ s_ivar_addr = rb_intern("@addr");
949
+ s_ivar_mask_addr = rb_intern("@mask_addr");
950
+ s_id_lshift = rb_intern("<<");
951
+ s_id_add = rb_intern("+");
952
+ s_id_mask = rb_intern("mask");
953
+
954
+ use_ipaddr_alloc = RTEST(rb_eval_string("IPAddr.new.instance_variables.sort == [:@addr, :@family, :@mask_addr]"));
955
+
956
+ s_vmasks4 = rb_eval_string("a = [0]*33; a[0] = 0; a[32] = 0xffffffff; 31.downto(1){|i| a[i] = a[i+1] - (1 << (31 - i))}; a.freeze");
957
+ rb_global_variable(&s_vmasks4);
958
+ s_vmasks6 = rb_eval_string("a = [0]*129; a[0] = 0; a[128] = 0xffffffffffffffffffffffffffffffff; 127.downto(1){|i| a[i] = a[i+1] - (1 << (127 - i))}; a.freeze");
959
+ rb_global_variable(&s_vmasks6);
960
+
961
+ /* dummy = rb_define_class_under( rb_mPG_TextDecoder, "Inet", rb_cPG_SimpleDecoder ); */
962
+ pg_define_coder( "Inet", pg_text_dec_inet, rb_cPG_SimpleDecoder, rb_mPG_TextDecoder);
963
+
964
+ return Qnil;
965
+ }
966
+
967
+
968
+ void
969
+ init_pg_text_decoder(void)
970
+ {
971
+ s_id_Rational = rb_intern("Rational");
972
+ s_id_new = rb_intern("new");
973
+ s_id_utc = rb_intern("utc");
974
+ s_id_getlocal = rb_intern("getlocal");
975
+
976
+ s_nan = rb_eval_string("0.0/0.0");
977
+ rb_global_variable(&s_nan);
978
+ s_pos_inf = rb_eval_string("1.0/0.0");
979
+ rb_global_variable(&s_pos_inf);
980
+ s_neg_inf = rb_eval_string("-1.0/0.0");
981
+ rb_global_variable(&s_neg_inf);
982
+
983
+ /* This module encapsulates all decoder classes with text input format */
984
+ rb_mPG_TextDecoder = rb_define_module_under( rb_mPG, "TextDecoder" );
985
+ rb_define_private_method(rb_singleton_class(rb_mPG_TextDecoder), "init_inet", init_pg_text_decoder_inet, 0);
986
+ rb_define_private_method(rb_singleton_class(rb_mPG_TextDecoder), "init_numeric", init_pg_text_decoder_numeric, 0);
987
+
988
+ /* Make RDoc aware of the decoder classes... */
989
+ /* dummy = rb_define_class_under( rb_mPG_TextDecoder, "Boolean", rb_cPG_SimpleDecoder ); */
990
+ pg_define_coder( "Boolean", pg_text_dec_boolean, rb_cPG_SimpleDecoder, rb_mPG_TextDecoder );
991
+ /* dummy = rb_define_class_under( rb_mPG_TextDecoder, "Integer", rb_cPG_SimpleDecoder ); */
992
+ pg_define_coder( "Integer", pg_text_dec_integer, rb_cPG_SimpleDecoder, rb_mPG_TextDecoder );
993
+ /* dummy = rb_define_class_under( rb_mPG_TextDecoder, "Float", rb_cPG_SimpleDecoder ); */
994
+ pg_define_coder( "Float", pg_text_dec_float, rb_cPG_SimpleDecoder, rb_mPG_TextDecoder );
995
+ /* dummy = rb_define_class_under( rb_mPG_TextDecoder, "String", rb_cPG_SimpleDecoder ); */
996
+ pg_define_coder( "String", pg_text_dec_string, rb_cPG_SimpleDecoder, rb_mPG_TextDecoder );
997
+ /* dummy = rb_define_class_under( rb_mPG_TextDecoder, "Bytea", rb_cPG_SimpleDecoder ); */
998
+ pg_define_coder( "Bytea", pg_text_dec_bytea, rb_cPG_SimpleDecoder, rb_mPG_TextDecoder );
999
+ /* dummy = rb_define_class_under( rb_mPG_TextDecoder, "Identifier", rb_cPG_SimpleDecoder ); */
1000
+ pg_define_coder( "Identifier", pg_text_dec_identifier, rb_cPG_SimpleDecoder, rb_mPG_TextDecoder );
1001
+ /* dummy = rb_define_class_under( rb_mPG_TextDecoder, "Timestamp", rb_cPG_SimpleDecoder ); */
1002
+ pg_define_coder( "Timestamp", pg_text_dec_timestamp, rb_cPG_SimpleDecoder, rb_mPG_TextDecoder);
1003
+
1004
+ /* dummy = rb_define_class_under( rb_mPG_TextDecoder, "Array", rb_cPG_CompositeDecoder ); */
1005
+ pg_define_coder( "Array", pg_text_dec_array, rb_cPG_CompositeDecoder, rb_mPG_TextDecoder );
1006
+ /* dummy = rb_define_class_under( rb_mPG_TextDecoder, "FromBase64", rb_cPG_CompositeDecoder ); */
1007
+ pg_define_coder( "FromBase64", pg_text_dec_from_base64, rb_cPG_CompositeDecoder, rb_mPG_TextDecoder );
1008
+ }