pg 0.18.0 → 1.1.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (80) hide show
  1. checksums.yaml +5 -5
  2. checksums.yaml.gz.sig +0 -0
  3. data/BSDL +2 -2
  4. data/ChangeLog +1221 -4
  5. data/History.rdoc +200 -0
  6. data/Manifest.txt +5 -18
  7. data/README-Windows.rdoc +15 -26
  8. data/README.rdoc +27 -10
  9. data/Rakefile +33 -24
  10. data/Rakefile.cross +57 -39
  11. data/ext/errorcodes.def +37 -0
  12. data/ext/errorcodes.rb +1 -1
  13. data/ext/errorcodes.txt +16 -1
  14. data/ext/extconf.rb +29 -35
  15. data/ext/gvl_wrappers.c +4 -0
  16. data/ext/gvl_wrappers.h +27 -39
  17. data/ext/pg.c +27 -53
  18. data/ext/pg.h +66 -83
  19. data/ext/pg_binary_decoder.c +75 -6
  20. data/ext/pg_binary_encoder.c +14 -12
  21. data/ext/pg_coder.c +83 -13
  22. data/ext/pg_connection.c +627 -351
  23. data/ext/pg_copy_coder.c +44 -9
  24. data/ext/pg_result.c +364 -134
  25. data/ext/pg_text_decoder.c +605 -46
  26. data/ext/pg_text_encoder.c +95 -76
  27. data/ext/pg_tuple.c +541 -0
  28. data/ext/pg_type_map.c +20 -13
  29. data/ext/pg_type_map_by_column.c +7 -7
  30. data/ext/pg_type_map_by_mri_type.c +2 -2
  31. data/ext/pg_type_map_in_ruby.c +4 -7
  32. data/ext/util.c +7 -7
  33. data/ext/util.h +3 -3
  34. data/lib/pg/basic_type_mapping.rb +105 -45
  35. data/lib/pg/binary_decoder.rb +22 -0
  36. data/lib/pg/coder.rb +1 -1
  37. data/lib/pg/connection.rb +109 -39
  38. data/lib/pg/constants.rb +1 -1
  39. data/lib/pg/exceptions.rb +1 -1
  40. data/lib/pg/result.rb +11 -6
  41. data/lib/pg/text_decoder.rb +25 -20
  42. data/lib/pg/text_encoder.rb +43 -1
  43. data/lib/pg/tuple.rb +30 -0
  44. data/lib/pg/type_map_by_column.rb +1 -1
  45. data/lib/pg.rb +21 -11
  46. data/spec/helpers.rb +50 -25
  47. data/spec/pg/basic_type_mapping_spec.rb +287 -30
  48. data/spec/pg/connection_spec.rb +695 -282
  49. data/spec/pg/connection_sync_spec.rb +41 -0
  50. data/spec/pg/result_spec.rb +59 -17
  51. data/spec/pg/tuple_spec.rb +280 -0
  52. data/spec/pg/type_map_by_class_spec.rb +3 -3
  53. data/spec/pg/type_map_by_column_spec.rb +1 -1
  54. data/spec/pg/type_map_by_mri_type_spec.rb +2 -2
  55. data/spec/pg/type_map_by_oid_spec.rb +1 -1
  56. data/spec/pg/type_map_in_ruby_spec.rb +1 -1
  57. data/spec/pg/type_map_spec.rb +1 -1
  58. data/spec/pg/type_spec.rb +319 -35
  59. data/spec/pg_spec.rb +2 -2
  60. data.tar.gz.sig +0 -0
  61. metadata +68 -68
  62. metadata.gz.sig +0 -0
  63. data/sample/array_insert.rb +0 -20
  64. data/sample/async_api.rb +0 -106
  65. data/sample/async_copyto.rb +0 -39
  66. data/sample/async_mixed.rb +0 -56
  67. data/sample/check_conn.rb +0 -21
  68. data/sample/copyfrom.rb +0 -81
  69. data/sample/copyto.rb +0 -19
  70. data/sample/cursor.rb +0 -21
  71. data/sample/disk_usage_report.rb +0 -186
  72. data/sample/issue-119.rb +0 -94
  73. data/sample/losample.rb +0 -69
  74. data/sample/minimal-testcase.rb +0 -17
  75. data/sample/notify_wait.rb +0 -72
  76. data/sample/pg_statistics.rb +0 -294
  77. data/sample/replication_monitor.rb +0 -231
  78. data/sample/test_binary_values.rb +0 -33
  79. data/sample/wal_shipper.rb +0 -434
  80. data/sample/warehouse_partitions.rb +0 -320
data/ext/pg_tuple.c ADDED
@@ -0,0 +1,541 @@
1
+ #include "pg.h"
2
+
3
+ /********************************************************************
4
+ *
5
+ * Document-class: PG::Tuple
6
+ *
7
+ * The class to represent one query result tuple (row).
8
+ * An instance of this class can be created by PG::Result#tuple .
9
+ *
10
+ * All field values of the tuple are retrieved on demand from the underlying PGresult object and converted to a Ruby object.
11
+ * Subsequent access to the same field returns the same object, since they are cached when materialized.
12
+ * Each PG::Tuple holds a reference to the related PG::Result object, but gets detached, when all fields are materialized.
13
+ *
14
+ * Example:
15
+ * require 'pg'
16
+ * conn = PG.connect(:dbname => 'test')
17
+ * res = conn.exec('VALUES(1,2), (3,4)')
18
+ * t0 = res.tuple(0) # => #<PG::Tuple column1: "1", column2: "2">
19
+ * t1 = res.tuple(1) # => #<PG::Tuple column1: "3", column2: "4">
20
+ * t1[0] # => "3"
21
+ * t1["column2"] # => "4"
22
+ */
23
+
24
+ static VALUE rb_cPG_Tuple;
25
+
26
+ typedef struct {
27
+ /* PG::Result object this tuple was retrieved from.
28
+ * Qnil when all fields are materialized.
29
+ */
30
+ VALUE result;
31
+
32
+ /* Store the typemap of the result.
33
+ * It's not enough to reference the PG::TypeMap object through the result,
34
+ * since it could be exchanged after the tuple has been created.
35
+ */
36
+ VALUE typemap;
37
+
38
+ /* Hash with maps field names to index into values[]
39
+ * Shared between all instances retrieved from one PG::Result.
40
+ */
41
+ VALUE field_map;
42
+
43
+ /* Row number within the result set. */
44
+ int row_num;
45
+
46
+ /* Number of fields in the result set. */
47
+ int num_fields;
48
+
49
+ /* Materialized values.
50
+ * And in case of dup column names, a field_names Array subsequently.
51
+ */
52
+ VALUE values[0];
53
+ } t_pg_tuple;
54
+
55
+ static inline VALUE
56
+ pg_tuple_get_field_names( t_pg_tuple *this )
57
+ {
58
+ if( this->num_fields != (int)RHASH_SIZE(this->field_map) ){
59
+ return this->values[this->num_fields];
60
+ } else {
61
+ return Qfalse;
62
+ }
63
+ }
64
+
65
+ static void
66
+ pg_tuple_gc_mark( t_pg_tuple *this )
67
+ {
68
+ int i;
69
+
70
+ if( !this ) return;
71
+ rb_gc_mark( this->result );
72
+ rb_gc_mark( this->typemap );
73
+ rb_gc_mark( this->field_map );
74
+
75
+ for( i = 0; i < this->num_fields; i++ ){
76
+ rb_gc_mark( this->values[i] );
77
+ }
78
+ rb_gc_mark( pg_tuple_get_field_names(this) );
79
+ }
80
+
81
+ static void
82
+ pg_tuple_gc_free( t_pg_tuple *this )
83
+ {
84
+ if( !this ) return;
85
+ xfree(this);
86
+ }
87
+
88
+ static size_t
89
+ pg_tuple_memsize( t_pg_tuple *this )
90
+ {
91
+ if( this==NULL ) return 0;
92
+ return sizeof(*this) + sizeof(*this->values) * this->num_fields;
93
+ }
94
+
95
+ static const rb_data_type_t pg_tuple_type = {
96
+ "pg",
97
+ {
98
+ (void (*)(void*))pg_tuple_gc_mark,
99
+ (void (*)(void*))pg_tuple_gc_free,
100
+ (size_t (*)(const void *))pg_tuple_memsize,
101
+ },
102
+ 0, 0,
103
+ #ifdef RUBY_TYPED_FREE_IMMEDIATELY
104
+ RUBY_TYPED_FREE_IMMEDIATELY,
105
+ #endif
106
+ };
107
+
108
+ /*
109
+ * Document-method: allocate
110
+ *
111
+ * call-seq:
112
+ * PG::VeryTuple.allocate -> obj
113
+ */
114
+ static VALUE
115
+ pg_tuple_s_allocate( VALUE klass )
116
+ {
117
+ return TypedData_Wrap_Struct( klass, &pg_tuple_type, NULL );
118
+ }
119
+
120
+ VALUE
121
+ pg_tuple_new(VALUE result, int row_num)
122
+ {
123
+ t_pg_tuple *this;
124
+ VALUE self = pg_tuple_s_allocate( rb_cPG_Tuple );
125
+ t_pg_result *p_result = pgresult_get_this(result);
126
+ int num_fields = p_result->nfields;
127
+ int i;
128
+ VALUE field_map = p_result->field_map;
129
+ int dup_names = num_fields != (int)RHASH_SIZE(field_map);
130
+
131
+ this = (t_pg_tuple *)xmalloc(
132
+ sizeof(*this) +
133
+ sizeof(*this->values) * num_fields +
134
+ sizeof(*this->values) * (dup_names ? 1 : 0));
135
+ RTYPEDDATA_DATA(self) = this;
136
+
137
+ this->result = result;
138
+ this->typemap = p_result->typemap;
139
+ this->field_map = field_map;
140
+ this->row_num = row_num;
141
+ this->num_fields = num_fields;
142
+
143
+ for( i = 0; i < num_fields; i++ ){
144
+ this->values[i] = Qundef;
145
+ }
146
+
147
+ if( dup_names ){
148
+ /* Some of the column names are duplicated -> we need the keys as Array in addition.
149
+ * Store it behind the values to save the space in the common case of no dups.
150
+ */
151
+ this->values[num_fields] = rb_obj_freeze(rb_ary_new4(num_fields, p_result->fnames));
152
+ }
153
+
154
+ return self;
155
+ }
156
+
157
+ static inline t_pg_tuple *
158
+ pg_tuple_get_this( VALUE self )
159
+ {
160
+ t_pg_tuple *this;
161
+ TypedData_Get_Struct(self, t_pg_tuple, &pg_tuple_type, this);
162
+ if (this == NULL)
163
+ rb_raise(rb_eTypeError, "tuple is empty");
164
+
165
+ return this;
166
+ }
167
+
168
+ static VALUE
169
+ pg_tuple_materialize_field(t_pg_tuple *this, int col)
170
+ {
171
+ VALUE value = this->values[col];
172
+
173
+ if( value == Qundef ){
174
+ t_typemap *p_typemap = DATA_PTR( this->typemap );
175
+
176
+ pgresult_get(this->result); /* make sure we have a valid PGresult object */
177
+ value = p_typemap->funcs.typecast_result_value(p_typemap, this->result, this->row_num, col);
178
+ this->values[col] = value;
179
+ }
180
+
181
+ return value;
182
+ }
183
+
184
+ static void
185
+ pg_tuple_detach(t_pg_tuple *this)
186
+ {
187
+ this->result = Qnil;
188
+ this->typemap = Qnil;
189
+ this->row_num = -1;
190
+ }
191
+
192
+ static void
193
+ pg_tuple_materialize(t_pg_tuple *this)
194
+ {
195
+ int field_num;
196
+ for(field_num = 0; field_num < this->num_fields; field_num++) {
197
+ pg_tuple_materialize_field(this, field_num);
198
+ }
199
+
200
+ pg_tuple_detach(this);
201
+ }
202
+
203
+ /*
204
+ * call-seq:
205
+ * tup.fetch(key) → value
206
+ * tup.fetch(key, default) → value
207
+ * tup.fetch(key) { |key| block } → value
208
+ *
209
+ * Returns a field value by either column index or column name.
210
+ *
211
+ * An integer +key+ is interpreted as column index.
212
+ * Negative values of index count from the end of the array.
213
+ *
214
+ * A string +key+ is interpreted as column name.
215
+ *
216
+ * If the key can't be found, there are several options:
217
+ * With no other arguments, it will raise a IndexError exception;
218
+ * if default is given, then that will be returned;
219
+ * if the optional code block is specified, then that will be run and its result returned.
220
+ */
221
+ static VALUE
222
+ pg_tuple_fetch(int argc, VALUE *argv, VALUE self)
223
+ {
224
+ VALUE key;
225
+ long block_given;
226
+ VALUE index;
227
+ int field_num;
228
+ t_pg_tuple *this = pg_tuple_get_this(self);
229
+
230
+ rb_check_arity(argc, 1, 2);
231
+ key = argv[0];
232
+
233
+ block_given = rb_block_given_p();
234
+ if (block_given && argc == 2) {
235
+ rb_warn("block supersedes default value argument");
236
+ }
237
+
238
+ switch(rb_type(key)){
239
+ case T_FIXNUM:
240
+ case T_BIGNUM:
241
+ field_num = NUM2INT(key);
242
+ if ( field_num < 0 )
243
+ field_num = this->num_fields + field_num;
244
+ if ( field_num < 0 || field_num >= this->num_fields ){
245
+ if (block_given) return rb_yield(key);
246
+ if (argc == 1) rb_raise( rb_eIndexError, "Index %d is out of range", field_num );
247
+ return argv[1];
248
+ }
249
+ break;
250
+ default:
251
+ index = rb_hash_aref(this->field_map, key);
252
+
253
+ if (index == Qnil) {
254
+ if (block_given) return rb_yield(key);
255
+ if (argc == 1) rb_raise( rb_eKeyError, "column not found" );
256
+ return argv[1];
257
+ }
258
+
259
+ field_num = NUM2INT(index);
260
+ }
261
+
262
+ return pg_tuple_materialize_field(this, field_num);
263
+ }
264
+
265
+ /*
266
+ * call-seq:
267
+ * res[ name ] -> value
268
+ *
269
+ * Returns field _name_.
270
+ */
271
+ static VALUE
272
+ pg_tuple_aref(VALUE self, VALUE key)
273
+ {
274
+ VALUE index;
275
+ int field_num;
276
+ t_pg_tuple *this = pg_tuple_get_this(self);
277
+
278
+ switch(rb_type(key)){
279
+ case T_FIXNUM:
280
+ case T_BIGNUM:
281
+ field_num = NUM2INT(key);
282
+ if ( field_num < 0 )
283
+ field_num = this->num_fields + field_num;
284
+ if ( field_num < 0 || field_num >= this->num_fields )
285
+ return Qnil;
286
+ break;
287
+ default:
288
+ index = rb_hash_aref(this->field_map, key);
289
+ if( index == Qnil ) return Qnil;
290
+ field_num = NUM2INT(index);
291
+ }
292
+
293
+ return pg_tuple_materialize_field(this, field_num);
294
+ }
295
+
296
+ static VALUE
297
+ pg_tuple_num_fields_for_enum(VALUE self, VALUE args, VALUE eobj)
298
+ {
299
+ t_pg_tuple *this = pg_tuple_get_this(self);
300
+ return INT2NUM(this->num_fields);
301
+ }
302
+
303
+ static int
304
+ pg_tuple_yield_key_value(VALUE key, VALUE index, VALUE _this)
305
+ {
306
+ t_pg_tuple *this = (t_pg_tuple *)_this;
307
+ VALUE value = pg_tuple_materialize_field(this, NUM2INT(index));
308
+ rb_yield_values(2, key, value);
309
+ return ST_CONTINUE;
310
+ }
311
+
312
+ /*
313
+ * call-seq:
314
+ * tup.each{ |key, value| ... }
315
+ *
316
+ * Invokes block for each field name and value in the tuple.
317
+ */
318
+ static VALUE
319
+ pg_tuple_each(VALUE self)
320
+ {
321
+ t_pg_tuple *this = pg_tuple_get_this(self);
322
+ VALUE field_names;
323
+
324
+ RETURN_SIZED_ENUMERATOR(self, 0, NULL, pg_tuple_num_fields_for_enum);
325
+
326
+ field_names = pg_tuple_get_field_names(this);
327
+
328
+ if( field_names == Qfalse ){
329
+ rb_hash_foreach(this->field_map, pg_tuple_yield_key_value, (VALUE)this);
330
+ } else {
331
+ int i;
332
+ for( i = 0; i < this->num_fields; i++ ){
333
+ VALUE value = pg_tuple_materialize_field(this, i);
334
+ rb_yield_values(2, RARRAY_AREF(field_names, i), value);
335
+ }
336
+ }
337
+
338
+ pg_tuple_detach(this);
339
+ return self;
340
+ }
341
+
342
+ /*
343
+ * call-seq:
344
+ * tup.each_value{ |value| ... }
345
+ *
346
+ * Invokes block for each field value in the tuple.
347
+ */
348
+ static VALUE
349
+ pg_tuple_each_value(VALUE self)
350
+ {
351
+ t_pg_tuple *this = pg_tuple_get_this(self);
352
+ int field_num;
353
+
354
+ RETURN_SIZED_ENUMERATOR(self, 0, NULL, pg_tuple_num_fields_for_enum);
355
+
356
+ for(field_num = 0; field_num < this->num_fields; field_num++) {
357
+ VALUE value = pg_tuple_materialize_field(this, field_num);
358
+ rb_yield(value);
359
+ }
360
+
361
+ pg_tuple_detach(this);
362
+ return self;
363
+ }
364
+
365
+
366
+ /*
367
+ * call-seq:
368
+ * tup.values -> Array
369
+ *
370
+ * Returns the values of this tuple as Array.
371
+ * +res.tuple(i).values+ is equal to +res.tuple_values(i)+ .
372
+ */
373
+ static VALUE
374
+ pg_tuple_values(VALUE self)
375
+ {
376
+ t_pg_tuple *this = pg_tuple_get_this(self);
377
+
378
+ pg_tuple_materialize(this);
379
+ return rb_ary_new4(this->num_fields, &this->values[0]);
380
+ }
381
+
382
+ static VALUE
383
+ pg_tuple_field_map(VALUE self)
384
+ {
385
+ t_pg_tuple *this = pg_tuple_get_this(self);
386
+ return this->field_map;
387
+ }
388
+
389
+ static VALUE
390
+ pg_tuple_field_names(VALUE self)
391
+ {
392
+ t_pg_tuple *this = pg_tuple_get_this(self);
393
+ return pg_tuple_get_field_names(this);
394
+ }
395
+
396
+ /*
397
+ * call-seq:
398
+ * tup.length → integer
399
+ *
400
+ * Returns number of fields of this tuple.
401
+ */
402
+ static VALUE
403
+ pg_tuple_length(VALUE self)
404
+ {
405
+ t_pg_tuple *this = pg_tuple_get_this(self);
406
+ return INT2NUM(this->num_fields);
407
+ }
408
+
409
+ /*
410
+ * call-seq:
411
+ * tup.index(key) → integer
412
+ *
413
+ * Returns the field number which matches the given column name.
414
+ */
415
+ static VALUE
416
+ pg_tuple_index(VALUE self, VALUE key)
417
+ {
418
+ t_pg_tuple *this = pg_tuple_get_this(self);
419
+ return rb_hash_aref(this->field_map, key);
420
+ }
421
+
422
+
423
+ static VALUE
424
+ pg_tuple_dump(VALUE self)
425
+ {
426
+ VALUE field_names;
427
+ VALUE values;
428
+ VALUE a;
429
+ t_pg_tuple *this = pg_tuple_get_this(self);
430
+
431
+ pg_tuple_materialize(this);
432
+
433
+ field_names = pg_tuple_get_field_names(this);
434
+ if( field_names == Qfalse )
435
+ field_names = rb_funcall(this->field_map, rb_intern("keys"), 0);
436
+
437
+ values = rb_ary_new4(this->num_fields, &this->values[0]);
438
+ a = rb_ary_new3(2, field_names, values);
439
+
440
+ if (FL_TEST(self, FL_EXIVAR)) {
441
+ rb_copy_generic_ivar(a, self);
442
+ FL_SET(a, FL_EXIVAR);
443
+ }
444
+
445
+ return a;
446
+ }
447
+
448
+ static VALUE
449
+ pg_tuple_load(VALUE self, VALUE a)
450
+ {
451
+ int num_fields;
452
+ int i;
453
+ t_pg_tuple *this;
454
+ VALUE values;
455
+ VALUE field_names;
456
+ VALUE field_map;
457
+ int dup_names;
458
+
459
+ rb_check_frozen(self);
460
+ rb_check_trusted(self);
461
+
462
+ TypedData_Get_Struct(self, t_pg_tuple, &pg_tuple_type, this);
463
+ if (this)
464
+ rb_raise(rb_eTypeError, "tuple is not empty");
465
+
466
+ Check_Type(a, T_ARRAY);
467
+ if (RARRAY_LEN(a) != 2)
468
+ rb_raise(rb_eTypeError, "expected an array of 2 elements");
469
+
470
+ field_names = RARRAY_AREF(a, 0);
471
+ Check_Type(field_names, T_ARRAY);
472
+ rb_obj_freeze(field_names);
473
+ values = RARRAY_AREF(a, 1);
474
+ Check_Type(values, T_ARRAY);
475
+ num_fields = RARRAY_LEN(values);
476
+
477
+ if (RARRAY_LEN(field_names) != num_fields)
478
+ rb_raise(rb_eTypeError, "different number of fields and values");
479
+
480
+ field_map = rb_hash_new();
481
+ for( i = 0; i < num_fields; i++ ){
482
+ rb_hash_aset(field_map, RARRAY_AREF(field_names, i), INT2FIX(i));
483
+ }
484
+ rb_obj_freeze(field_map);
485
+
486
+ dup_names = num_fields != (int)RHASH_SIZE(field_map);
487
+
488
+ this = (t_pg_tuple *)xmalloc(
489
+ sizeof(*this) +
490
+ sizeof(*this->values) * num_fields +
491
+ sizeof(*this->values) * (dup_names ? 1 : 0));
492
+ RTYPEDDATA_DATA(self) = this;
493
+
494
+ this->result = Qnil;
495
+ this->typemap = Qnil;
496
+ this->row_num = -1;
497
+ this->num_fields = num_fields;
498
+ this->field_map = field_map;
499
+
500
+ for( i = 0; i < num_fields; i++ ){
501
+ VALUE v = RARRAY_AREF(values, i);
502
+ if( v == Qundef )
503
+ rb_raise(rb_eTypeError, "field %d is not materialized", i);
504
+ this->values[i] = v;
505
+ }
506
+
507
+ if( dup_names ){
508
+ this->values[num_fields] = field_names;
509
+ }
510
+
511
+ if (FL_TEST(a, FL_EXIVAR)) {
512
+ rb_copy_generic_ivar(self, a);
513
+ FL_SET(self, FL_EXIVAR);
514
+ }
515
+
516
+ return self;
517
+ }
518
+
519
+ void
520
+ init_pg_tuple()
521
+ {
522
+ rb_cPG_Tuple = rb_define_class_under( rb_mPG, "Tuple", rb_cObject );
523
+ rb_define_alloc_func( rb_cPG_Tuple, pg_tuple_s_allocate );
524
+ rb_include_module(rb_cPG_Tuple, rb_mEnumerable);
525
+
526
+ rb_define_method(rb_cPG_Tuple, "fetch", pg_tuple_fetch, -1);
527
+ rb_define_method(rb_cPG_Tuple, "[]", pg_tuple_aref, 1);
528
+ rb_define_method(rb_cPG_Tuple, "each", pg_tuple_each, 0);
529
+ rb_define_method(rb_cPG_Tuple, "each_value", pg_tuple_each_value, 0);
530
+ rb_define_method(rb_cPG_Tuple, "values", pg_tuple_values, 0);
531
+ rb_define_method(rb_cPG_Tuple, "length", pg_tuple_length, 0);
532
+ rb_define_alias(rb_cPG_Tuple, "size", "length");
533
+ rb_define_method(rb_cPG_Tuple, "index", pg_tuple_index, 1);
534
+
535
+ rb_define_private_method(rb_cPG_Tuple, "field_map", pg_tuple_field_map, 0);
536
+ rb_define_private_method(rb_cPG_Tuple, "field_names", pg_tuple_field_names, 0);
537
+
538
+ /* methods for marshaling */
539
+ rb_define_private_method(rb_cPG_Tuple, "marshal_dump", pg_tuple_dump, 0);
540
+ rb_define_private_method(rb_cPG_Tuple, "marshal_load", pg_tuple_load, 1);
541
+ }
data/ext/pg_type_map.c CHANGED
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  * pg_column_map.c - PG::ColumnMap class extension
3
- * $Id: pg_type_map.c,v c99d26015e3c 2014/12/12 20:58:25 lars $
3
+ * $Id: pg_type_map.c,v 2af122820861 2017/01/14 19:56:36 lars $
4
4
  *
5
5
  */
6
6
 
@@ -11,55 +11,62 @@ VALUE rb_mDefaultTypeMappable;
11
11
  static ID s_id_fit_to_query;
12
12
  static ID s_id_fit_to_result;
13
13
 
14
+ NORETURN( VALUE
15
+ pg_typemap_fit_to_result( VALUE self, VALUE result ));
16
+ NORETURN( VALUE
17
+ pg_typemap_fit_to_query( VALUE self, VALUE params ));
18
+ NORETURN( int
19
+ pg_typemap_fit_to_copy_get( VALUE self ));
20
+ NORETURN( VALUE
21
+ pg_typemap_result_value( t_typemap *p_typemap, VALUE result, int tuple, int field ));
22
+ NORETURN( t_pg_coder *
23
+ pg_typemap_typecast_query_param( t_typemap *p_typemap, VALUE param_value, int field ));
24
+ NORETURN( VALUE
25
+ pg_typemap_typecast_copy_get( t_typemap *p_typemap, VALUE field_str, int fieldno, int format, int enc_idx ));
26
+
14
27
  VALUE
15
28
  pg_typemap_fit_to_result( VALUE self, VALUE result )
16
29
  {
17
30
  rb_raise( rb_eNotImpError, "type map %s is not suitable to map result values", rb_obj_classname(self) );
18
- return Qnil;
19
31
  }
20
32
 
21
33
  VALUE
22
34
  pg_typemap_fit_to_query( VALUE self, VALUE params )
23
35
  {
24
36
  rb_raise( rb_eNotImpError, "type map %s is not suitable to map query params", rb_obj_classname(self) );
25
- return Qnil;
26
37
  }
27
38
 
28
39
  int
29
40
  pg_typemap_fit_to_copy_get( VALUE self )
30
41
  {
31
42
  rb_raise( rb_eNotImpError, "type map %s is not suitable to map get_copy_data results", rb_obj_classname(self) );
32
- return Qnil;
33
43
  }
34
44
 
35
45
  VALUE
36
46
  pg_typemap_result_value( t_typemap *p_typemap, VALUE result, int tuple, int field )
37
47
  {
38
48
  rb_raise( rb_eNotImpError, "type map is not suitable to map result values" );
39
- return Qnil;
40
49
  }
41
50
 
42
51
  t_pg_coder *
43
52
  pg_typemap_typecast_query_param( t_typemap *p_typemap, VALUE param_value, int field )
44
53
  {
45
54
  rb_raise( rb_eNotImpError, "type map is not suitable to map query params" );
46
- return NULL;
47
55
  }
48
56
 
49
57
  VALUE
50
58
  pg_typemap_typecast_copy_get( t_typemap *p_typemap, VALUE field_str, int fieldno, int format, int enc_idx )
51
59
  {
52
60
  rb_raise( rb_eNotImpError, "type map is not suitable to map get_copy_data results" );
53
- return Qnil;
54
61
  }
55
62
 
56
63
  const struct pg_typemap_funcs pg_typemap_funcs = {
57
- .fit_to_result = pg_typemap_fit_to_result,
58
- .fit_to_query = pg_typemap_fit_to_query,
59
- .fit_to_copy_get = pg_typemap_fit_to_copy_get,
60
- .typecast_result_value = pg_typemap_result_value,
61
- .typecast_query_param = pg_typemap_typecast_query_param,
62
- .typecast_copy_get = pg_typemap_typecast_copy_get
64
+ pg_typemap_fit_to_result,
65
+ pg_typemap_fit_to_query,
66
+ pg_typemap_fit_to_copy_get,
67
+ pg_typemap_result_value,
68
+ pg_typemap_typecast_query_param,
69
+ pg_typemap_typecast_copy_get
63
70
  };
64
71
 
65
72
  static VALUE
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  * pg_column_map.c - PG::ColumnMap class extension
3
- * $Id: pg_type_map_by_column.c,v d369d31e8fe3 2014/10/22 08:47:29 lars $
3
+ * $Id: pg_type_map_by_column.c,v fcf731d3dff7 2015/09/08 12:25:06 jfali $
4
4
  *
5
5
  */
6
6
 
@@ -162,12 +162,12 @@ pg_tmbc_typecast_copy_get( t_typemap *p_typemap, VALUE field_str, int fieldno, i
162
162
  }
163
163
 
164
164
  const struct pg_typemap_funcs pg_tmbc_funcs = {
165
- .fit_to_result = pg_tmbc_fit_to_result,
166
- .fit_to_query = pg_tmbc_fit_to_query,
167
- .fit_to_copy_get = pg_tmbc_fit_to_copy_get,
168
- .typecast_result_value = pg_tmbc_result_value,
169
- .typecast_query_param = pg_tmbc_typecast_query_param,
170
- .typecast_copy_get = pg_tmbc_typecast_copy_get
165
+ pg_tmbc_fit_to_result,
166
+ pg_tmbc_fit_to_query,
167
+ pg_tmbc_fit_to_copy_get,
168
+ pg_tmbc_result_value,
169
+ pg_tmbc_typecast_query_param,
170
+ pg_tmbc_typecast_copy_get
171
171
  };
172
172
 
173
173
  static void
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  * pg_type_map_by_mri_type.c - PG::TypeMapByMriType class extension
3
- * $Id: pg_type_map_by_mri_type.c,v 27987dbd0b32 2014/11/07 20:55:52 lars $
3
+ * $Id: pg_type_map_by_mri_type.c,v 1269b8ad77b8 2015/02/06 16:38:23 lars $
4
4
  *
5
5
  * This type map can be used to select value encoders based on the MRI-internal
6
6
  * value type code.
@@ -39,7 +39,7 @@ static VALUE rb_cTypeMapByMriType;
39
39
  typedef struct {
40
40
  t_typemap typemap;
41
41
  struct pg_tmbmt_converter {
42
- FOR_EACH_MRI_TYPE( DECLARE_CODER );
42
+ FOR_EACH_MRI_TYPE( DECLARE_CODER )
43
43
  } coders;
44
44
  } t_tmbmt;
45
45
 
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  * pg_type_map_in_ruby.c - PG::TypeMapInRuby class extension
3
- * $Id: pg_type_map_in_ruby.c,v a38cf53a96f1 2014/12/13 21:59:57 lars $
3
+ * $Id: pg_type_map_in_ruby.c,v 3d89d3aae4fd 2015/01/05 16:19:41 kanis $
4
4
  *
5
5
  */
6
6
 
@@ -212,12 +212,9 @@ pg_tmir_copy_get( t_typemap *p_typemap, VALUE field_str, int fieldno, int format
212
212
  rb_encoding *p_encoding = rb_enc_from_index(enc_idx);
213
213
  VALUE enc = rb_enc_from_encoding(p_encoding);
214
214
  /* field_str is reused in-place by pg_text_dec_copy_row(), so we need to make
215
- * a copy of the string buffer before used in ruby space.
216
- * This requires rb_str_new() instead of rb_str_dup() for Rubinius.
217
- */
218
- VALUE field_str_copy = rb_str_new(RSTRING_PTR(field_str), RSTRING_LEN(field_str));
219
- PG_ENCODING_SET_NOCHECK(field_str_copy, ENCODING_GET(field_str));
220
- OBJ_INFECT(field_str_copy, field_str);
215
+ * a copy of the string buffer for use in ruby space. */
216
+ VALUE field_str_copy = rb_str_dup(field_str);
217
+ rb_str_modify(field_str_copy);
221
218
 
222
219
  return rb_funcall( this->self, s_id_typecast_copy_get, 4, field_str_copy, INT2NUM(fieldno), INT2NUM(format), enc );
223
220
  }