pg 1.5.9-x64-mingw32 → 1.6.0.rc1-x64-mingw32

Sign up to get free protection for your applications and to get access to all the features.
@@ -133,6 +133,154 @@ pg_bin_dec_to_base64(t_pg_coder *conv, const char *val, int len, int tuple, int
133
133
  return out_value;
134
134
  }
135
135
 
136
+ /*
137
+ * Maximum number of array subscripts (arbitrary limit)
138
+ */
139
+ #define MAXDIM 6
140
+
141
+ /*
142
+ * Document-class: PG::BinaryDecoder::Array < PG::CompositeDecoder
143
+ *
144
+ * This is a decoder class for conversion of binary array types.
145
+ *
146
+ * It returns an Array with possibly an arbitrary number of sub-Arrays.
147
+ * All values are decoded according to the #elements_type accessor.
148
+ * Sub-arrays are decoded recursively.
149
+ *
150
+ * This decoder simply ignores any dimension decorations preceding the array values.
151
+ * It returns all array values as regular ruby Array with a zero based index, regardless of the index given in the dimension decoration.
152
+ *
153
+ * An array decoder which respects dimension decorations is waiting to be implemented.
154
+ *
155
+ */
156
+ static VALUE
157
+ pg_bin_dec_array(t_pg_coder *conv, const char *input_line, int len, int tuple, int field, int enc_idx)
158
+ {
159
+ t_pg_composite_coder *this = (t_pg_composite_coder *)conv;
160
+ t_pg_coder_dec_func dec_func = pg_coder_dec_func(this->elem, this->comp.format);
161
+
162
+ /* Current field */
163
+ VALUE field_str;
164
+
165
+ int32_t nitems32;
166
+ int i;
167
+ int ndim;
168
+ int nitems;
169
+ int flags;
170
+ int dim;
171
+ int dim_sizes[MAXDIM];
172
+ VALUE arrays[MAXDIM];
173
+ char *output_ptr;
174
+ const char *cur_ptr;
175
+ const char *line_end_ptr;
176
+ char *end_capa_ptr;
177
+
178
+ /* Allocate a new string with embedded capacity and realloc later with
179
+ * exponential growing size when needed. */
180
+ PG_RB_STR_NEW( field_str, output_ptr, end_capa_ptr );
181
+
182
+ /* set pointer variables for loop */
183
+ cur_ptr = input_line;
184
+ line_end_ptr = input_line + len;
185
+
186
+ /* read number of dimensions */
187
+ if (line_end_ptr - cur_ptr < 4 ) goto length_error;
188
+ ndim = read_nbo32(cur_ptr);
189
+ if (ndim < 0 || ndim > MAXDIM) {
190
+ rb_raise( rb_eArgError, "unsupported number of array dimensions: %d", ndim );
191
+ }
192
+ cur_ptr += 4;
193
+
194
+ /* read flags */
195
+ if (line_end_ptr - cur_ptr < 4 ) goto length_error;
196
+ flags = read_nbo32(cur_ptr);
197
+ if (flags != 0 && flags != 1) {
198
+ rb_raise( rb_eArgError, "unsupported binary array flags: %d", flags );
199
+ }
200
+ cur_ptr += 4;
201
+
202
+ /* ignore element OID */
203
+ if (line_end_ptr - cur_ptr < 4 ) goto length_error;
204
+ cur_ptr += 4;
205
+
206
+ nitems32 = ndim == 0 ? 0 : 1;
207
+ for (i = 0; i < ndim; i++) {
208
+ int64_t prod;
209
+
210
+ /* read size of dimensions and ignore lower bound */
211
+ if (line_end_ptr - cur_ptr < 8 ) goto length_error;
212
+ dim_sizes[i] = read_nbo32(cur_ptr);
213
+ prod = (int64_t) nitems32 * (int64_t) dim_sizes[i];
214
+ nitems32 = (int32_t) prod;
215
+ if (dim_sizes[i] < 0 || (int64_t) nitems32 != prod) {
216
+ rb_raise( rb_eArgError, "unsupported array size: %" PRId64, prod );
217
+ }
218
+ cur_ptr += 8;
219
+ }
220
+ nitems = (int)nitems32;
221
+
222
+ dim = 0;
223
+ arrays[dim] = rb_ary_new2(ndim == 0 ? 0 : dim_sizes[dim]);
224
+ for (i = 0; i < nitems; i++) {
225
+ int input_len;
226
+
227
+ /* traverse dimensions down */
228
+ while (dim < ndim - 1) {
229
+ dim++;
230
+ arrays[dim] = rb_ary_new2(dim_sizes[dim]);
231
+ rb_ary_push(arrays[dim - 1], arrays[dim]);
232
+ }
233
+
234
+ /* read element length */
235
+ if (line_end_ptr - cur_ptr < 4 ) goto length_error;
236
+ input_len = read_nbo32(cur_ptr);
237
+ cur_ptr += 4;
238
+
239
+ /* convert and put element into array */
240
+ if (input_len < 0) {
241
+ if (input_len != -1) goto length_error;
242
+ /* NULL indicator */
243
+ rb_ary_push(arrays[dim], Qnil);
244
+ } else {
245
+ VALUE field_value;
246
+ if (line_end_ptr - cur_ptr < input_len ) goto length_error;
247
+
248
+ /* copy input data to field_str */
249
+ PG_RB_STR_ENSURE_CAPA( field_str, input_len, output_ptr, end_capa_ptr );
250
+ memcpy(output_ptr, cur_ptr, input_len);
251
+ cur_ptr += input_len;
252
+ output_ptr += input_len;
253
+ /* convert field_str through the type map */
254
+ rb_str_set_len( field_str, output_ptr - RSTRING_PTR(field_str) );
255
+ field_value = dec_func(this->elem, RSTRING_PTR(field_str), input_len, tuple, field, enc_idx);
256
+
257
+ rb_ary_push(arrays[dim], field_value);
258
+
259
+ if( field_value == field_str ){
260
+ /* Our output string will be send to the user, so we can not reuse
261
+ * it for the next field. */
262
+ PG_RB_STR_NEW( field_str, output_ptr, end_capa_ptr );
263
+ }
264
+ }
265
+
266
+ /* Reset the pointer to the start of the output/buffer string. */
267
+ output_ptr = RSTRING_PTR(field_str);
268
+
269
+ /* traverse dimensions up */
270
+ while (RARRAY_LEN(arrays[dim]) >= dim_sizes[dim] && dim > 0) {
271
+ dim--;
272
+ }
273
+ }
274
+
275
+ if (cur_ptr < line_end_ptr)
276
+ rb_raise( rb_eArgError, "trailing data after binary array data at position: %ld", (long)(cur_ptr - input_line) + 1 );
277
+
278
+ return arrays[0];
279
+
280
+ length_error:
281
+ rb_raise( rb_eArgError, "premature end of binary array data at position: %ld", (long)(cur_ptr - input_line) + 1 );
282
+ }
283
+
136
284
  #define PG_INT64_MIN (-0x7FFFFFFFFFFFFFFFL - 1)
137
285
  #define PG_INT64_MAX 0x7FFFFFFFFFFFFFFFL
138
286
 
@@ -305,6 +453,8 @@ init_pg_binary_decoder(void)
305
453
  /* dummy = rb_define_class_under( rb_mPG_BinaryDecoder, "Timestamp", rb_cPG_SimpleDecoder ); */
306
454
  pg_define_coder( "Timestamp", pg_bin_dec_timestamp, rb_cPG_SimpleDecoder, rb_mPG_BinaryDecoder );
307
455
 
456
+ /* dummy = rb_define_class_under( rb_mPG_BinaryDecoder, "Array", rb_cPG_CompositeDecoder ); */
457
+ pg_define_coder( "Array", pg_bin_dec_array, rb_cPG_CompositeDecoder, rb_mPG_BinaryDecoder );
308
458
  /* dummy = rb_define_class_under( rb_mPG_BinaryDecoder, "ToBase64", rb_cPG_CompositeDecoder ); */
309
459
  pg_define_coder( "ToBase64", pg_bin_dec_to_base64, rb_cPG_CompositeDecoder, rb_mPG_BinaryDecoder );
310
460
  }
@@ -271,14 +271,13 @@ pg_bin_enc_date(t_pg_coder *this, VALUE value, char *out, VALUE *intermediate, i
271
271
  case T_FALSE:
272
272
  write_nbo32(PG_INT32_MIN, out);
273
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);
274
280
  }
275
-
276
- VALUE year = rb_funcall(value, s_id_year, 0);
277
- VALUE month = rb_funcall(value, s_id_month, 0);
278
- VALUE day = rb_funcall(value, s_id_day, 0);
279
- int jday = date2j(NUM2INT(year), NUM2INT(month), NUM2INT(day)) - POSTGRES_EPOCH_JDATE;
280
- write_nbo32(jday, out);
281
-
282
281
  }else{
283
282
  /* first call -> determine the required length */
284
283
  if(TYPE(value) == T_STRING){
@@ -305,6 +304,201 @@ pg_bin_enc_date(t_pg_coder *this, VALUE value, char *out, VALUE *intermediate, i
305
304
  return 4;
306
305
  }
307
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
+
308
502
  /*
309
503
  * Document-class: PG::BinaryEncoder::FromBase64 < PG::CompositeEncoder
310
504
  *
@@ -382,6 +576,8 @@ init_pg_binary_encoder(void)
382
576
  /* dummy = rb_define_class_under( rb_mPG_BinaryEncoder, "Date", rb_cPG_SimpleEncoder ); */
383
577
  pg_define_coder( "Date", pg_bin_enc_date, rb_cPG_SimpleEncoder, rb_mPG_BinaryEncoder );
384
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 );
385
581
  /* dummy = rb_define_class_under( rb_mPG_BinaryEncoder, "FromBase64", rb_cPG_CompositeEncoder ); */
386
582
  pg_define_coder( "FromBase64", pg_bin_enc_from_base64, rb_cPG_CompositeEncoder, rb_mPG_BinaryEncoder );
387
583
  }