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,583 @@
1
+ /*
2
+ * pg_column_map.c - PG::ColumnMap class extension
3
+ * $Id$
4
+ *
5
+ */
6
+
7
+ #include "pg.h"
8
+ #include "pg_util.h"
9
+ #ifdef HAVE_INTTYPES_H
10
+ #include <inttypes.h>
11
+ #endif
12
+
13
+ VALUE rb_mPG_BinaryEncoder;
14
+ static ID s_id_year;
15
+ static ID s_id_month;
16
+ static ID s_id_day;
17
+
18
+
19
+ /*
20
+ * Document-class: PG::BinaryEncoder::Boolean < PG::SimpleEncoder
21
+ *
22
+ * This is the encoder class for the PostgreSQL boolean type.
23
+ *
24
+ * It accepts true and false. Other values will raise an exception.
25
+ *
26
+ */
27
+ static int
28
+ pg_bin_enc_boolean(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate, int enc_idx)
29
+ {
30
+ char mybool;
31
+ if (value == Qtrue) {
32
+ mybool = 1;
33
+ } else if (value == Qfalse) {
34
+ mybool = 0;
35
+ } else {
36
+ rb_raise( rb_eTypeError, "wrong data for binary boolean converter" );
37
+ }
38
+ if(out) *out = mybool;
39
+ return 1;
40
+ }
41
+
42
+ /*
43
+ * Document-class: PG::BinaryEncoder::Int2 < PG::SimpleEncoder
44
+ *
45
+ * This is the encoder class for the PostgreSQL +int2+ (alias +smallint+) type.
46
+ *
47
+ * Non-Number values are expected to have method +to_i+ defined.
48
+ *
49
+ */
50
+ static int
51
+ pg_bin_enc_int2(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate, int enc_idx)
52
+ {
53
+ if(out){
54
+ write_nbo16(NUM2INT(*intermediate), out);
55
+ }else{
56
+ *intermediate = pg_obj_to_i(value);
57
+ }
58
+ return 2;
59
+ }
60
+
61
+ /*
62
+ * Document-class: PG::BinaryEncoder::Int4 < PG::SimpleEncoder
63
+ *
64
+ * This is the encoder class for the PostgreSQL +int4+ (alias +integer+) type.
65
+ *
66
+ * Non-Number values are expected to have method +to_i+ defined.
67
+ *
68
+ */
69
+ static int
70
+ pg_bin_enc_int4(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate, int enc_idx)
71
+ {
72
+ if(out){
73
+ write_nbo32(NUM2LONG(*intermediate), out);
74
+ }else{
75
+ *intermediate = pg_obj_to_i(value);
76
+ }
77
+ return 4;
78
+ }
79
+
80
+ /*
81
+ * Document-class: PG::BinaryEncoder::Int8 < PG::SimpleEncoder
82
+ *
83
+ * This is the encoder class for the PostgreSQL +int8+ (alias +bigint+) type.
84
+ *
85
+ * Non-Number values are expected to have method +to_i+ defined.
86
+ *
87
+ */
88
+ static int
89
+ pg_bin_enc_int8(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate, int enc_idx)
90
+ {
91
+ if(out){
92
+ write_nbo64(NUM2LL(*intermediate), out);
93
+ }else{
94
+ *intermediate = pg_obj_to_i(value);
95
+ }
96
+ return 8;
97
+ }
98
+
99
+ /*
100
+ * Document-class: PG::BinaryEncoder::Float4 < PG::SimpleEncoder
101
+ *
102
+ * This is the binary encoder class for the PostgreSQL +float4+ type.
103
+ *
104
+ */
105
+ static int
106
+ pg_bin_enc_float4(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate, int enc_idx)
107
+ {
108
+ union {
109
+ float f;
110
+ int32_t i;
111
+ } swap4;
112
+
113
+ if(out){
114
+ swap4.f = NUM2DBL(*intermediate);
115
+ write_nbo32(swap4.i, out);
116
+ }else{
117
+ *intermediate = value;
118
+ }
119
+ return 4;
120
+ }
121
+
122
+ /*
123
+ * Document-class: PG::BinaryEncoder::Float8 < PG::SimpleEncoder
124
+ *
125
+ * This is the binary encoder class for the PostgreSQL +float8+ type.
126
+ *
127
+ */
128
+ static int
129
+ pg_bin_enc_float8(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate, int enc_idx)
130
+ {
131
+ union {
132
+ double f;
133
+ int64_t i;
134
+ } swap8;
135
+
136
+ if(out){
137
+ swap8.f = NUM2DBL(*intermediate);
138
+ write_nbo64(swap8.i, out);
139
+ }else{
140
+ *intermediate = value;
141
+ }
142
+ return 8;
143
+ }
144
+
145
+ #define PG_INT32_MIN (-0x7FFFFFFF-1)
146
+ #define PG_INT32_MAX (0x7FFFFFFF)
147
+ #define PG_INT64_MIN (-0x7FFFFFFFFFFFFFFFL - 1)
148
+ #define PG_INT64_MAX 0x7FFFFFFFFFFFFFFFL
149
+
150
+ /*
151
+ * Document-class: PG::BinaryEncoder::Timestamp < PG::SimpleEncoder
152
+ *
153
+ * This is a encoder class for conversion of Ruby Time objects to PostgreSQL binary timestamps.
154
+ *
155
+ * The following flags can be used to specify timezone interpretation:
156
+ * * +PG::Coder::TIMESTAMP_DB_UTC+ : Send timestamp as UTC time (default)
157
+ * * +PG::Coder::TIMESTAMP_DB_LOCAL+ : Send timestamp as local time (slower)
158
+ *
159
+ * Example:
160
+ * enco = PG::BinaryEncoder::Timestamp.new(flags: PG::Coder::TIMESTAMP_DB_UTC)
161
+ * enco.encode(Time.utc(2000, 1, 1)) # => "\x00\x00\x00\x00\x00\x00\x00\x00"
162
+ *
163
+ * String values are expected to contain a binary data with a length of 8 byte.
164
+ *
165
+ */
166
+ static int
167
+ pg_bin_enc_timestamp(t_pg_coder *this, VALUE value, char *out, VALUE *intermediate, int enc_idx)
168
+ {
169
+ if(out){
170
+ int64_t timestamp;
171
+ struct timespec ts;
172
+
173
+ /* second call -> write data to *out */
174
+ switch(TYPE(*intermediate)){
175
+ case T_STRING:
176
+ return pg_coder_enc_to_s(this, value, out, intermediate, enc_idx);
177
+ case T_TRUE:
178
+ write_nbo64(PG_INT64_MAX, out);
179
+ return 8;
180
+ case T_FALSE:
181
+ write_nbo64(PG_INT64_MIN, out);
182
+ return 8;
183
+ }
184
+
185
+ ts = rb_time_timespec(*intermediate);
186
+ /* PostgreSQL's timestamp is based on year 2000 and Ruby's time is based on 1970.
187
+ * Adjust the 30 years difference. */
188
+ timestamp = ((int64_t)ts.tv_sec - 10957L * 24L * 3600L) * 1000000 + ((int64_t)ts.tv_nsec / 1000);
189
+
190
+ if( this->flags & PG_CODER_TIMESTAMP_DB_LOCAL ) {
191
+ /* send as local time */
192
+ timestamp += NUM2LL(rb_funcall(*intermediate, rb_intern("utc_offset"), 0)) * 1000000;
193
+ }
194
+
195
+ write_nbo64(timestamp, out);
196
+ }else{
197
+ /* first call -> determine the required length */
198
+ if(TYPE(value) == T_STRING){
199
+ char *pstr = RSTRING_PTR(value);
200
+ if(RSTRING_LEN(value) >= 1){
201
+ switch(pstr[0]) {
202
+ case 'I':
203
+ case 'i':
204
+ *intermediate = Qtrue;
205
+ return 8;
206
+ case '-':
207
+ if (RSTRING_LEN(value) >= 2 && (pstr[1] == 'I' || pstr[1] == 'i')) {
208
+ *intermediate = Qfalse;
209
+ return 8;
210
+ }
211
+ }
212
+ }
213
+
214
+ return pg_coder_enc_to_s(this, value, out, intermediate, enc_idx);
215
+ }
216
+
217
+ if( this->flags & PG_CODER_TIMESTAMP_DB_LOCAL ) {
218
+ /* make a local time, so that utc_offset is set */
219
+ value = rb_funcall(value, rb_intern("getlocal"), 0);
220
+ }
221
+ *intermediate = value;
222
+ }
223
+ return 8;
224
+ }
225
+
226
+ #define POSTGRES_EPOCH_JDATE 2451545 /* == date2j(2000, 1, 1) */
227
+ int
228
+ date2j(int year, int month, int day)
229
+ {
230
+ int julian;
231
+ int century;
232
+
233
+ if (month > 2)
234
+ {
235
+ month += 1;
236
+ year += 4800;
237
+ }
238
+ else
239
+ {
240
+ month += 13;
241
+ year += 4799;
242
+ }
243
+
244
+ century = year / 100;
245
+ julian = year * 365 - 32167;
246
+ julian += year / 4 - century + century / 4;
247
+ julian += 7834 * month / 256 + day;
248
+
249
+ return julian;
250
+ } /* date2j() */
251
+
252
+ /*
253
+ * Document-class: PG::BinaryEncoder::Date < PG::SimpleEncoder
254
+ *
255
+ * This is a encoder class for conversion of Ruby Date objects to PostgreSQL binary date.
256
+ *
257
+ * String values are expected to contain a binary data with a length of 4 byte.
258
+ *
259
+ */
260
+ static int
261
+ pg_bin_enc_date(t_pg_coder *this, VALUE value, char *out, VALUE *intermediate, int enc_idx)
262
+ {
263
+ if(out){
264
+ /* second call -> write data to *out */
265
+ switch(TYPE(*intermediate)){
266
+ case T_STRING:
267
+ return pg_coder_enc_to_s(this, value, out, intermediate, enc_idx);
268
+ case T_TRUE:
269
+ write_nbo32(PG_INT32_MAX, out);
270
+ return 4;
271
+ case T_FALSE:
272
+ write_nbo32(PG_INT32_MIN, out);
273
+ return 4;
274
+ } {
275
+ VALUE year = rb_funcall(value, s_id_year, 0);
276
+ VALUE month = rb_funcall(value, s_id_month, 0);
277
+ VALUE day = rb_funcall(value, s_id_day, 0);
278
+ int jday = date2j(NUM2INT(year), NUM2INT(month), NUM2INT(day)) - POSTGRES_EPOCH_JDATE;
279
+ write_nbo32(jday, out);
280
+ }
281
+ }else{
282
+ /* first call -> determine the required length */
283
+ if(TYPE(value) == T_STRING){
284
+ char *pstr = RSTRING_PTR(value);
285
+ if(RSTRING_LEN(value) >= 1){
286
+ switch(pstr[0]) {
287
+ case 'I':
288
+ case 'i':
289
+ *intermediate = Qtrue;
290
+ return 4;
291
+ case '-':
292
+ if (RSTRING_LEN(value) >= 2 && (pstr[1] == 'I' || pstr[1] == 'i')) {
293
+ *intermediate = Qfalse;
294
+ return 4;
295
+ }
296
+ }
297
+ }
298
+
299
+ return pg_coder_enc_to_s(this, value, out, intermediate, enc_idx);
300
+ }
301
+
302
+ *intermediate = value;
303
+ }
304
+ return 4;
305
+ }
306
+
307
+ /*
308
+ * Maximum number of array subscripts (arbitrary limit)
309
+ */
310
+ #define MAXDIM 6
311
+
312
+ /*
313
+ * Document-class: PG::BinaryEncoder::Array < PG::CompositeEncoder
314
+ *
315
+ * This is the encoder class for PostgreSQL array types in binary format.
316
+ *
317
+ * All values are encoded according to the #elements_type
318
+ * accessor. Sub-arrays are encoded recursively.
319
+ *
320
+ * This encoder expects an Array of values or sub-arrays as input.
321
+ * Other values are passed through as byte string without interpretation.
322
+ *
323
+ * The accessors needs_quotation and delimiter are ignored for binary encoding.
324
+ *
325
+ */
326
+ static int
327
+ pg_bin_enc_array(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate, int enc_idx)
328
+ {
329
+ if (TYPE(value) == T_ARRAY) {
330
+ t_pg_composite_coder *this = (t_pg_composite_coder *)conv;
331
+ t_pg_coder_enc_func enc_func = pg_coder_enc_func(this->elem);
332
+ int dim_sizes[MAXDIM];
333
+ int ndim = 1;
334
+ int nitems = 1;
335
+ VALUE el1 = value;
336
+
337
+ if (RARRAY_LEN(value) == 0) {
338
+ nitems = 0;
339
+ ndim = 0;
340
+ dim_sizes[0] = 0;
341
+ } else {
342
+ /* Determine number of dimensions, sizes of dimensions and number of items */
343
+ while(1) {
344
+ VALUE el2;
345
+
346
+ dim_sizes[ndim-1] = RARRAY_LENINT(el1);
347
+ nitems *= dim_sizes[ndim-1];
348
+ el2 = rb_ary_entry(el1, 0);
349
+ if (TYPE(el2) == T_ARRAY) {
350
+ ndim++;
351
+ if (ndim > MAXDIM)
352
+ rb_raise( rb_eArgError, "unsupported number of array dimensions: >%d", ndim );
353
+ } else {
354
+ break;
355
+ }
356
+ el1 = el2;
357
+ }
358
+ }
359
+
360
+ if(out){
361
+ /* Second encoder pass -> write data to `out` */
362
+ int dimpos[MAXDIM];
363
+ VALUE arrays[MAXDIM];
364
+ int dim = 0;
365
+ int item_idx = 0;
366
+ int i;
367
+ char *orig_out = out;
368
+ Oid elem_oid = this->elem ? this->elem->oid : 0;
369
+
370
+ write_nbo32(ndim, out); out += 4;
371
+ write_nbo32(1 /* flags */, out); out += 4;
372
+ write_nbo32(elem_oid, out); out += 4;
373
+ for (i = 0; i < ndim; i++) {
374
+ dimpos[i] = 0;
375
+ write_nbo32(dim_sizes[i], out); out += 4;
376
+ write_nbo32(1 /* offset */, out); out += 4;
377
+ }
378
+ arrays[0] = value;
379
+
380
+ while(1) {
381
+ /* traverse tree down */
382
+ while (dim < ndim - 1) {
383
+ arrays[dim + 1] = rb_ary_entry(arrays[dim], dimpos[dim]);
384
+ dim++;
385
+ }
386
+
387
+ for (i = 0; i < dim_sizes[dim]; i++) {
388
+ VALUE item = rb_ary_entry(arrays[dim], i);
389
+
390
+ if (NIL_P(item)) {
391
+ write_nbo32(-1, out); out += 4;
392
+ } else {
393
+ /* Encoded string is returned in subint */
394
+ int strlen;
395
+ VALUE is_one_pass = rb_ary_entry(*intermediate, item_idx++);
396
+ VALUE subint = rb_ary_entry(*intermediate, item_idx++);
397
+
398
+ if (is_one_pass == Qtrue) {
399
+ strlen = RSTRING_LENINT(subint);
400
+ memcpy( out + 4, RSTRING_PTR(subint), strlen);
401
+ } else {
402
+ strlen = enc_func(this->elem, item, out + 4, &subint, enc_idx);
403
+ }
404
+ write_nbo32(strlen, out);
405
+ out += 4 /* length */ + strlen;
406
+ }
407
+ }
408
+
409
+ /* traverse tree up and go to next sibling array */
410
+ do {
411
+ if (dim > 0) {
412
+ dimpos[dim] = 0;
413
+ dim--;
414
+ dimpos[dim]++;
415
+ } else {
416
+ goto finished2;
417
+ }
418
+ } while (dimpos[dim] >= dim_sizes[dim]);
419
+ }
420
+ finished2:
421
+ return (int)(out - orig_out);
422
+
423
+ } else {
424
+ /* First encoder pass -> determine required buffer space for `out` */
425
+
426
+ int dimpos[MAXDIM];
427
+ VALUE arrays[MAXDIM];
428
+ int dim = 0;
429
+ int item_idx = 0;
430
+ int i;
431
+ int size_sum = 0;
432
+
433
+ *intermediate = rb_ary_new2(nitems);
434
+
435
+ for (i = 0; i < MAXDIM; i++) {
436
+ dimpos[i] = 0;
437
+ }
438
+ arrays[0] = value;
439
+
440
+ while(1) {
441
+
442
+ /* traverse tree down */
443
+ while (dim < ndim - 1) {
444
+ VALUE array = rb_ary_entry(arrays[dim], dimpos[dim]);
445
+ if (TYPE(array) != T_ARRAY) {
446
+ rb_raise( rb_eArgError, "expected Array instead of %+"PRIsVALUE" in dimension %d", array, dim + 1 );
447
+ }
448
+ if (dim_sizes[dim + 1] != RARRAY_LEN(array)) {
449
+ rb_raise( rb_eArgError, "varying number of array elements (%d and %d) in dimension %d", dim_sizes[dim + 1], RARRAY_LENINT(array), dim + 1 );
450
+ }
451
+ arrays[dim + 1] = array;
452
+ dim++;
453
+ }
454
+
455
+ for (i = 0; i < dim_sizes[dim]; i++) {
456
+ VALUE item = rb_ary_entry(arrays[dim], i);
457
+
458
+ if (NIL_P(item)) {
459
+ size_sum += 4 /* length bytes = -1 */;
460
+ } else {
461
+ VALUE subint;
462
+ int strlen = enc_func(this->elem, item, NULL, &subint, enc_idx);
463
+
464
+ /* Gather all intermediate values of elements into an array, which is returned as intermediate for the array encoder */
465
+ if( strlen == -1 ){
466
+ /* Encoded string is returned in subint */
467
+ rb_ary_store(*intermediate, item_idx++, Qtrue);
468
+ rb_ary_store(*intermediate, item_idx++, subint);
469
+
470
+ strlen = RSTRING_LENINT(subint);
471
+ } else {
472
+ /* Two passes necessary */
473
+ rb_ary_store(*intermediate, item_idx++, Qfalse);
474
+ rb_ary_store(*intermediate, item_idx++, subint);
475
+ }
476
+ size_sum += 4 /* length bytes */ + strlen;
477
+ }
478
+ }
479
+
480
+ /* traverse tree up and go to next sibling array */
481
+ do {
482
+ if (dim > 0) {
483
+ dimpos[dim] = 0;
484
+ dim--;
485
+ dimpos[dim]++;
486
+ } else {
487
+ goto finished1;
488
+ }
489
+ } while (dimpos[dim] >= dim_sizes[dim]);
490
+ }
491
+ finished1:;
492
+
493
+ return 4 /* ndim */ + 4 /* flags */ + 4 /* oid */ +
494
+ ndim * (4 /* dim size */ + 4 /* dim offset */) +
495
+ size_sum;
496
+ }
497
+ } else {
498
+ return pg_coder_enc_to_s( conv, value, out, intermediate, enc_idx );
499
+ }
500
+ }
501
+
502
+ /*
503
+ * Document-class: PG::BinaryEncoder::FromBase64 < PG::CompositeEncoder
504
+ *
505
+ * This is an encoder class for conversion of base64 encoded data
506
+ * to it's binary representation.
507
+ *
508
+ */
509
+ static int
510
+ pg_bin_enc_from_base64(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate, int enc_idx)
511
+ {
512
+ int strlen;
513
+ VALUE subint;
514
+ t_pg_composite_coder *this = (t_pg_composite_coder *)conv;
515
+ t_pg_coder_enc_func enc_func = pg_coder_enc_func(this->elem);
516
+
517
+ if(out){
518
+ /* Second encoder pass, if required */
519
+ strlen = enc_func(this->elem, value, out, intermediate, enc_idx);
520
+ strlen = base64_decode( out, out, strlen );
521
+
522
+ return strlen;
523
+ } else {
524
+ /* First encoder pass */
525
+ strlen = enc_func(this->elem, value, NULL, &subint, enc_idx);
526
+
527
+ if( strlen == -1 ){
528
+ /* Encoded string is returned in subint */
529
+ VALUE out_str;
530
+
531
+ strlen = RSTRING_LENINT(subint);
532
+ out_str = rb_str_new(NULL, BASE64_DECODED_SIZE(strlen));
533
+
534
+ strlen = base64_decode( RSTRING_PTR(out_str), RSTRING_PTR(subint), strlen);
535
+ rb_str_set_len( out_str, strlen );
536
+ *intermediate = out_str;
537
+
538
+ return -1;
539
+ } else {
540
+ *intermediate = subint;
541
+
542
+ return BASE64_DECODED_SIZE(strlen);
543
+ }
544
+ }
545
+ }
546
+
547
+ void
548
+ init_pg_binary_encoder(void)
549
+ {
550
+ s_id_year = rb_intern("year");
551
+ s_id_month = rb_intern("month");
552
+ s_id_day = rb_intern("day");
553
+
554
+ /* This module encapsulates all encoder classes with binary output format */
555
+ rb_mPG_BinaryEncoder = rb_define_module_under( rb_mPG, "BinaryEncoder" );
556
+
557
+ /* Make RDoc aware of the encoder classes... */
558
+ /* dummy = rb_define_class_under( rb_mPG_BinaryEncoder, "Boolean", rb_cPG_SimpleEncoder ); */
559
+ pg_define_coder( "Boolean", pg_bin_enc_boolean, rb_cPG_SimpleEncoder, rb_mPG_BinaryEncoder );
560
+ /* dummy = rb_define_class_under( rb_mPG_BinaryEncoder, "Int2", rb_cPG_SimpleEncoder ); */
561
+ pg_define_coder( "Int2", pg_bin_enc_int2, rb_cPG_SimpleEncoder, rb_mPG_BinaryEncoder );
562
+ /* dummy = rb_define_class_under( rb_mPG_BinaryEncoder, "Int4", rb_cPG_SimpleEncoder ); */
563
+ pg_define_coder( "Int4", pg_bin_enc_int4, rb_cPG_SimpleEncoder, rb_mPG_BinaryEncoder );
564
+ /* dummy = rb_define_class_under( rb_mPG_BinaryEncoder, "Int8", rb_cPG_SimpleEncoder ); */
565
+ pg_define_coder( "Int8", pg_bin_enc_int8, rb_cPG_SimpleEncoder, rb_mPG_BinaryEncoder );
566
+ /* dummy = rb_define_class_under( rb_mPG_BinaryEncoder, "Float4", rb_cPG_SimpleEncoder ); */
567
+ pg_define_coder( "Float4", pg_bin_enc_float4, rb_cPG_SimpleEncoder, rb_mPG_BinaryEncoder );
568
+ /* dummy = rb_define_class_under( rb_mPG_BinaryEncoder, "Float8", rb_cPG_SimpleEncoder ); */
569
+ pg_define_coder( "Float8", pg_bin_enc_float8, rb_cPG_SimpleEncoder, rb_mPG_BinaryEncoder );
570
+ /* dummy = rb_define_class_under( rb_mPG_BinaryEncoder, "String", rb_cPG_SimpleEncoder ); */
571
+ pg_define_coder( "String", pg_coder_enc_to_s, rb_cPG_SimpleEncoder, rb_mPG_BinaryEncoder );
572
+ /* dummy = rb_define_class_under( rb_mPG_BinaryEncoder, "Bytea", rb_cPG_SimpleEncoder ); */
573
+ pg_define_coder( "Bytea", pg_coder_enc_to_s, rb_cPG_SimpleEncoder, rb_mPG_BinaryEncoder );
574
+ /* dummy = rb_define_class_under( rb_mPG_BinaryEncoder, "Timestamp", rb_cPG_SimpleEncoder ); */
575
+ pg_define_coder( "Timestamp", pg_bin_enc_timestamp, rb_cPG_SimpleEncoder, rb_mPG_BinaryEncoder );
576
+ /* dummy = rb_define_class_under( rb_mPG_BinaryEncoder, "Date", rb_cPG_SimpleEncoder ); */
577
+ pg_define_coder( "Date", pg_bin_enc_date, rb_cPG_SimpleEncoder, rb_mPG_BinaryEncoder );
578
+
579
+ /* dummy = rb_define_class_under( rb_mPG_BinaryEncoder, "Array", rb_cPG_CompositeEncoder ); */
580
+ pg_define_coder( "Array", pg_bin_enc_array, rb_cPG_CompositeEncoder, rb_mPG_BinaryEncoder );
581
+ /* dummy = rb_define_class_under( rb_mPG_BinaryEncoder, "FromBase64", rb_cPG_CompositeEncoder ); */
582
+ pg_define_coder( "FromBase64", pg_bin_enc_from_base64, rb_cPG_CompositeEncoder, rb_mPG_BinaryEncoder );
583
+ }