pg 0.18.4 → 1.4.3

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 +5 -5
  2. checksums.yaml.gz.sig +0 -0
  3. data/.appveyor.yml +36 -0
  4. data/.gems +6 -0
  5. data/.github/workflows/binary-gems.yml +86 -0
  6. data/.github/workflows/source-gem.yml +129 -0
  7. data/.gitignore +13 -0
  8. data/.hgsigs +34 -0
  9. data/.hgtags +41 -0
  10. data/.irbrc +23 -0
  11. data/.pryrc +23 -0
  12. data/.tm_properties +21 -0
  13. data/.travis.yml +49 -0
  14. data/BSDL +2 -2
  15. data/Gemfile +14 -0
  16. data/History.rdoc +436 -4
  17. data/Manifest.txt +8 -21
  18. data/README-Windows.rdoc +4 -4
  19. data/README.ja.rdoc +1 -2
  20. data/README.rdoc +67 -17
  21. data/Rakefile +32 -144
  22. data/Rakefile.cross +70 -69
  23. data/certs/ged.pem +24 -0
  24. data/certs/larskanis-2022.pem +26 -0
  25. data/ext/errorcodes.def +109 -0
  26. data/ext/errorcodes.rb +1 -1
  27. data/ext/errorcodes.txt +35 -2
  28. data/ext/extconf.rb +119 -54
  29. data/ext/gvl_wrappers.c +8 -0
  30. data/ext/gvl_wrappers.h +44 -33
  31. data/ext/pg.c +213 -171
  32. data/ext/pg.h +92 -98
  33. data/ext/pg_binary_decoder.c +82 -15
  34. data/ext/pg_binary_encoder.c +20 -19
  35. data/ext/pg_coder.c +175 -39
  36. data/ext/pg_connection.c +1730 -1135
  37. data/ext/pg_copy_coder.c +94 -27
  38. data/ext/pg_record_coder.c +521 -0
  39. data/ext/pg_result.c +640 -221
  40. data/ext/pg_text_decoder.c +606 -40
  41. data/ext/pg_text_encoder.c +250 -99
  42. data/ext/pg_tuple.c +569 -0
  43. data/ext/pg_type_map.c +55 -15
  44. data/ext/pg_type_map_all_strings.c +19 -5
  45. data/ext/pg_type_map_by_class.c +54 -24
  46. data/ext/pg_type_map_by_column.c +73 -34
  47. data/ext/pg_type_map_by_mri_type.c +48 -19
  48. data/ext/pg_type_map_by_oid.c +55 -25
  49. data/ext/pg_type_map_in_ruby.c +51 -20
  50. data/ext/{util.c → pg_util.c} +12 -12
  51. data/ext/{util.h → pg_util.h} +2 -2
  52. data/lib/pg/basic_type_map_based_on_result.rb +47 -0
  53. data/lib/pg/basic_type_map_for_queries.rb +193 -0
  54. data/lib/pg/basic_type_map_for_results.rb +81 -0
  55. data/lib/pg/basic_type_registry.rb +301 -0
  56. data/lib/pg/binary_decoder.rb +23 -0
  57. data/lib/pg/coder.rb +24 -3
  58. data/lib/pg/connection.rb +723 -65
  59. data/lib/pg/constants.rb +2 -1
  60. data/lib/pg/exceptions.rb +9 -2
  61. data/lib/pg/result.rb +24 -7
  62. data/lib/pg/text_decoder.rb +24 -22
  63. data/lib/pg/text_encoder.rb +40 -8
  64. data/lib/pg/tuple.rb +30 -0
  65. data/lib/pg/type_map_by_column.rb +3 -2
  66. data/lib/pg/version.rb +4 -0
  67. data/lib/pg.rb +61 -36
  68. data/misc/openssl-pg-segfault.rb +31 -0
  69. data/misc/postgres/History.txt +9 -0
  70. data/misc/postgres/Manifest.txt +5 -0
  71. data/misc/postgres/README.txt +21 -0
  72. data/misc/postgres/Rakefile +21 -0
  73. data/misc/postgres/lib/postgres.rb +16 -0
  74. data/misc/ruby-pg/History.txt +9 -0
  75. data/misc/ruby-pg/Manifest.txt +5 -0
  76. data/misc/ruby-pg/README.txt +21 -0
  77. data/misc/ruby-pg/Rakefile +21 -0
  78. data/misc/ruby-pg/lib/ruby/pg.rb +16 -0
  79. data/pg.gemspec +32 -0
  80. data/rakelib/task_extension.rb +46 -0
  81. data/sample/array_insert.rb +1 -1
  82. data/sample/async_api.rb +4 -8
  83. data/sample/async_copyto.rb +1 -1
  84. data/sample/async_mixed.rb +1 -1
  85. data/sample/check_conn.rb +1 -1
  86. data/sample/copydata.rb +71 -0
  87. data/sample/copyfrom.rb +1 -1
  88. data/sample/copyto.rb +1 -1
  89. data/sample/cursor.rb +1 -1
  90. data/sample/disk_usage_report.rb +6 -15
  91. data/sample/issue-119.rb +2 -2
  92. data/sample/losample.rb +1 -1
  93. data/sample/minimal-testcase.rb +2 -2
  94. data/sample/notify_wait.rb +1 -1
  95. data/sample/pg_statistics.rb +6 -15
  96. data/sample/replication_monitor.rb +9 -18
  97. data/sample/test_binary_values.rb +1 -1
  98. data/sample/wal_shipper.rb +2 -2
  99. data/sample/warehouse_partitions.rb +8 -17
  100. data.tar.gz.sig +0 -0
  101. metadata +79 -225
  102. metadata.gz.sig +0 -0
  103. data/ChangeLog +0 -5911
  104. data/lib/pg/basic_type_mapping.rb +0 -399
  105. data/spec/data/expected_trace.out +0 -26
  106. data/spec/data/random_binary_data +0 -0
  107. data/spec/helpers.rb +0 -355
  108. data/spec/pg/basic_type_mapping_spec.rb +0 -251
  109. data/spec/pg/connection_spec.rb +0 -1544
  110. data/spec/pg/result_spec.rb +0 -449
  111. data/spec/pg/type_map_by_class_spec.rb +0 -138
  112. data/spec/pg/type_map_by_column_spec.rb +0 -222
  113. data/spec/pg/type_map_by_mri_type_spec.rb +0 -136
  114. data/spec/pg/type_map_by_oid_spec.rb +0 -149
  115. data/spec/pg/type_map_in_ruby_spec.rb +0 -164
  116. data/spec/pg/type_map_spec.rb +0 -22
  117. data/spec/pg/type_spec.rb +0 -697
  118. data/spec/pg_spec.rb +0 -50
data/ext/pg_tuple.c ADDED
@@ -0,0 +1,569 @@
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_ptr( 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
+ static VALUE f = Qfalse;
62
+ return &f;
63
+ }
64
+ }
65
+
66
+ static inline VALUE
67
+ pg_tuple_get_field_names( t_pg_tuple *this )
68
+ {
69
+ return *pg_tuple_get_field_names_ptr(this);
70
+ }
71
+
72
+ static void
73
+ pg_tuple_gc_mark( void *_this )
74
+ {
75
+ t_pg_tuple *this = (t_pg_tuple *)_this;
76
+ int i;
77
+
78
+ if( !this ) return;
79
+ rb_gc_mark_movable( this->result );
80
+ rb_gc_mark_movable( this->typemap );
81
+ rb_gc_mark_movable( this->field_map );
82
+
83
+ for( i = 0; i < this->num_fields; i++ ){
84
+ rb_gc_mark_movable( this->values[i] );
85
+ }
86
+ rb_gc_mark_movable( pg_tuple_get_field_names(this) );
87
+ }
88
+
89
+ static void
90
+ pg_tuple_gc_compact( void *_this )
91
+ {
92
+ t_pg_tuple *this = (t_pg_tuple *)_this;
93
+ int i;
94
+
95
+ if( !this ) return;
96
+ pg_gc_location( this->result );
97
+ pg_gc_location( this->typemap );
98
+ pg_gc_location( this->field_map );
99
+
100
+ for( i = 0; i < this->num_fields; i++ ){
101
+ pg_gc_location( this->values[i] );
102
+ }
103
+ pg_gc_location( *pg_tuple_get_field_names_ptr(this) );
104
+ }
105
+
106
+ static void
107
+ pg_tuple_gc_free( void *_this )
108
+ {
109
+ t_pg_tuple *this = (t_pg_tuple *)_this;
110
+ if( !this ) return;
111
+ xfree(this);
112
+ }
113
+
114
+ static size_t
115
+ pg_tuple_memsize( const void *_this )
116
+ {
117
+ const t_pg_tuple *this = (const t_pg_tuple *)_this;
118
+ if( this==NULL ) return 0;
119
+ return sizeof(*this) + sizeof(*this->values) * this->num_fields;
120
+ }
121
+
122
+ static const rb_data_type_t pg_tuple_type = {
123
+ "PG::Tuple",
124
+ {
125
+ pg_tuple_gc_mark,
126
+ pg_tuple_gc_free,
127
+ pg_tuple_memsize,
128
+ pg_compact_callback(pg_tuple_gc_compact),
129
+ },
130
+ 0, 0,
131
+ RUBY_TYPED_FREE_IMMEDIATELY,
132
+ };
133
+
134
+ /*
135
+ * Document-method: allocate
136
+ *
137
+ * call-seq:
138
+ * PG::VeryTuple.allocate -> obj
139
+ */
140
+ static VALUE
141
+ pg_tuple_s_allocate( VALUE klass )
142
+ {
143
+ return TypedData_Wrap_Struct( klass, &pg_tuple_type, NULL );
144
+ }
145
+
146
+ VALUE
147
+ pg_tuple_new(VALUE result, int row_num)
148
+ {
149
+ t_pg_tuple *this;
150
+ VALUE self = pg_tuple_s_allocate( rb_cPG_Tuple );
151
+ t_pg_result *p_result = pgresult_get_this(result);
152
+ int num_fields = p_result->nfields;
153
+ int i;
154
+ VALUE field_map = p_result->field_map;
155
+ int dup_names = num_fields != (int)RHASH_SIZE(field_map);
156
+
157
+ this = (t_pg_tuple *)xmalloc(
158
+ sizeof(*this) +
159
+ sizeof(*this->values) * num_fields +
160
+ sizeof(*this->values) * (dup_names ? 1 : 0));
161
+
162
+ this->result = result;
163
+ this->typemap = p_result->typemap;
164
+ this->field_map = field_map;
165
+ this->row_num = row_num;
166
+ this->num_fields = num_fields;
167
+
168
+ for( i = 0; i < num_fields; i++ ){
169
+ this->values[i] = Qundef;
170
+ }
171
+
172
+ if( dup_names ){
173
+ /* Some of the column names are duplicated -> we need the keys as Array in addition.
174
+ * Store it behind the values to save the space in the common case of no dups.
175
+ */
176
+ this->values[num_fields] = rb_obj_freeze(rb_ary_new4(num_fields, p_result->fnames));
177
+ }
178
+
179
+ RTYPEDDATA_DATA(self) = this;
180
+
181
+ return self;
182
+ }
183
+
184
+ static inline t_pg_tuple *
185
+ pg_tuple_get_this( VALUE self )
186
+ {
187
+ t_pg_tuple *this;
188
+ TypedData_Get_Struct(self, t_pg_tuple, &pg_tuple_type, this);
189
+ if (this == NULL)
190
+ rb_raise(rb_eTypeError, "tuple is empty");
191
+
192
+ return this;
193
+ }
194
+
195
+ static VALUE
196
+ pg_tuple_materialize_field(t_pg_tuple *this, int col)
197
+ {
198
+ VALUE value = this->values[col];
199
+
200
+ if( value == Qundef ){
201
+ t_typemap *p_typemap = RTYPEDDATA_DATA( this->typemap );
202
+
203
+ pgresult_get(this->result); /* make sure we have a valid PGresult object */
204
+ value = p_typemap->funcs.typecast_result_value(p_typemap, this->result, this->row_num, col);
205
+ this->values[col] = value;
206
+ }
207
+
208
+ return value;
209
+ }
210
+
211
+ static void
212
+ pg_tuple_detach(t_pg_tuple *this)
213
+ {
214
+ this->result = Qnil;
215
+ this->typemap = Qnil;
216
+ this->row_num = -1;
217
+ }
218
+
219
+ static void
220
+ pg_tuple_materialize(t_pg_tuple *this)
221
+ {
222
+ int field_num;
223
+ for(field_num = 0; field_num < this->num_fields; field_num++) {
224
+ pg_tuple_materialize_field(this, field_num);
225
+ }
226
+
227
+ pg_tuple_detach(this);
228
+ }
229
+
230
+ /*
231
+ * call-seq:
232
+ * tup.fetch(key) → value
233
+ * tup.fetch(key, default) → value
234
+ * tup.fetch(key) { |key| block } → value
235
+ *
236
+ * Returns a field value by either column index or column name.
237
+ *
238
+ * An integer +key+ is interpreted as column index.
239
+ * Negative values of index count from the end of the array.
240
+ *
241
+ * Depending on Result#field_name_type= a string or symbol +key+ is interpreted as column name.
242
+ *
243
+ * If the key can't be found, there are several options:
244
+ * With no other arguments, it will raise a IndexError exception;
245
+ * if default is given, then that will be returned;
246
+ * if the optional code block is specified, then that will be run and its result returned.
247
+ */
248
+ static VALUE
249
+ pg_tuple_fetch(int argc, VALUE *argv, VALUE self)
250
+ {
251
+ VALUE key;
252
+ long block_given;
253
+ VALUE index;
254
+ int field_num;
255
+ t_pg_tuple *this = pg_tuple_get_this(self);
256
+
257
+ rb_check_arity(argc, 1, 2);
258
+ key = argv[0];
259
+
260
+ block_given = rb_block_given_p();
261
+ if (block_given && argc == 2) {
262
+ rb_warn("block supersedes default value argument");
263
+ }
264
+
265
+ switch(rb_type(key)){
266
+ case T_FIXNUM:
267
+ case T_BIGNUM:
268
+ field_num = NUM2INT(key);
269
+ if ( field_num < 0 )
270
+ field_num = this->num_fields + field_num;
271
+ if ( field_num < 0 || field_num >= this->num_fields ){
272
+ if (block_given) return rb_yield(key);
273
+ if (argc == 1) rb_raise( rb_eIndexError, "Index %d is out of range", field_num );
274
+ return argv[1];
275
+ }
276
+ break;
277
+ default:
278
+ index = rb_hash_aref(this->field_map, key);
279
+
280
+ if (index == Qnil) {
281
+ if (block_given) return rb_yield(key);
282
+ if (argc == 1) rb_raise( rb_eKeyError, "column not found" );
283
+ return argv[1];
284
+ }
285
+
286
+ field_num = NUM2INT(index);
287
+ }
288
+
289
+ return pg_tuple_materialize_field(this, field_num);
290
+ }
291
+
292
+ /*
293
+ * call-seq:
294
+ * tup[ key ] -> value
295
+ *
296
+ * Returns a field value by either column index or column name.
297
+ *
298
+ * An integer +key+ is interpreted as column index.
299
+ * Negative values of index count from the end of the array.
300
+ *
301
+ * Depending on Result#field_name_type= a string or symbol +key+ is interpreted as column name.
302
+ *
303
+ * If the key can't be found, it returns +nil+ .
304
+ */
305
+ static VALUE
306
+ pg_tuple_aref(VALUE self, VALUE key)
307
+ {
308
+ VALUE index;
309
+ int field_num;
310
+ t_pg_tuple *this = pg_tuple_get_this(self);
311
+
312
+ switch(rb_type(key)){
313
+ case T_FIXNUM:
314
+ case T_BIGNUM:
315
+ field_num = NUM2INT(key);
316
+ if ( field_num < 0 )
317
+ field_num = this->num_fields + field_num;
318
+ if ( field_num < 0 || field_num >= this->num_fields )
319
+ return Qnil;
320
+ break;
321
+ default:
322
+ index = rb_hash_aref(this->field_map, key);
323
+ if( index == Qnil ) return Qnil;
324
+ field_num = NUM2INT(index);
325
+ }
326
+
327
+ return pg_tuple_materialize_field(this, field_num);
328
+ }
329
+
330
+ static VALUE
331
+ pg_tuple_num_fields_for_enum(VALUE self, VALUE args, VALUE eobj)
332
+ {
333
+ t_pg_tuple *this = pg_tuple_get_this(self);
334
+ return INT2NUM(this->num_fields);
335
+ }
336
+
337
+ static int
338
+ pg_tuple_yield_key_value(VALUE key, VALUE index, VALUE _this)
339
+ {
340
+ t_pg_tuple *this = (t_pg_tuple *)_this;
341
+ VALUE value = pg_tuple_materialize_field(this, NUM2INT(index));
342
+ rb_yield_values(2, key, value);
343
+ return ST_CONTINUE;
344
+ }
345
+
346
+ /*
347
+ * call-seq:
348
+ * tup.each{ |key, value| ... }
349
+ *
350
+ * Invokes block for each field name and value in the tuple.
351
+ */
352
+ static VALUE
353
+ pg_tuple_each(VALUE self)
354
+ {
355
+ t_pg_tuple *this = pg_tuple_get_this(self);
356
+ VALUE field_names;
357
+
358
+ RETURN_SIZED_ENUMERATOR(self, 0, NULL, pg_tuple_num_fields_for_enum);
359
+
360
+ field_names = pg_tuple_get_field_names(this);
361
+
362
+ if( field_names == Qfalse ){
363
+ rb_hash_foreach(this->field_map, pg_tuple_yield_key_value, (VALUE)this);
364
+ } else {
365
+ int i;
366
+ for( i = 0; i < this->num_fields; i++ ){
367
+ VALUE value = pg_tuple_materialize_field(this, i);
368
+ rb_yield_values(2, RARRAY_AREF(field_names, i), value);
369
+ }
370
+ }
371
+
372
+ pg_tuple_detach(this);
373
+ return self;
374
+ }
375
+
376
+ /*
377
+ * call-seq:
378
+ * tup.each_value{ |value| ... }
379
+ *
380
+ * Invokes block for each field value in the tuple.
381
+ */
382
+ static VALUE
383
+ pg_tuple_each_value(VALUE self)
384
+ {
385
+ t_pg_tuple *this = pg_tuple_get_this(self);
386
+ int field_num;
387
+
388
+ RETURN_SIZED_ENUMERATOR(self, 0, NULL, pg_tuple_num_fields_for_enum);
389
+
390
+ for(field_num = 0; field_num < this->num_fields; field_num++) {
391
+ VALUE value = pg_tuple_materialize_field(this, field_num);
392
+ rb_yield(value);
393
+ }
394
+
395
+ pg_tuple_detach(this);
396
+ return self;
397
+ }
398
+
399
+
400
+ /*
401
+ * call-seq:
402
+ * tup.values -> Array
403
+ *
404
+ * Returns the values of this tuple as Array.
405
+ * +res.tuple(i).values+ is equal to +res.tuple_values(i)+ .
406
+ */
407
+ static VALUE
408
+ pg_tuple_values(VALUE self)
409
+ {
410
+ t_pg_tuple *this = pg_tuple_get_this(self);
411
+
412
+ pg_tuple_materialize(this);
413
+ return rb_ary_new4(this->num_fields, &this->values[0]);
414
+ }
415
+
416
+ static VALUE
417
+ pg_tuple_field_map(VALUE self)
418
+ {
419
+ t_pg_tuple *this = pg_tuple_get_this(self);
420
+ return this->field_map;
421
+ }
422
+
423
+ static VALUE
424
+ pg_tuple_field_names(VALUE self)
425
+ {
426
+ t_pg_tuple *this = pg_tuple_get_this(self);
427
+ return pg_tuple_get_field_names(this);
428
+ }
429
+
430
+ /*
431
+ * call-seq:
432
+ * tup.length → integer
433
+ *
434
+ * Returns number of fields of this tuple.
435
+ */
436
+ static VALUE
437
+ pg_tuple_length(VALUE self)
438
+ {
439
+ t_pg_tuple *this = pg_tuple_get_this(self);
440
+ return INT2NUM(this->num_fields);
441
+ }
442
+
443
+ /*
444
+ * call-seq:
445
+ * tup.index(key) → integer
446
+ *
447
+ * Returns the field number which matches the given column name.
448
+ */
449
+ static VALUE
450
+ pg_tuple_index(VALUE self, VALUE key)
451
+ {
452
+ t_pg_tuple *this = pg_tuple_get_this(self);
453
+ return rb_hash_aref(this->field_map, key);
454
+ }
455
+
456
+
457
+ static VALUE
458
+ pg_tuple_dump(VALUE self)
459
+ {
460
+ VALUE field_names;
461
+ VALUE values;
462
+ VALUE a;
463
+ t_pg_tuple *this = pg_tuple_get_this(self);
464
+
465
+ pg_tuple_materialize(this);
466
+
467
+ field_names = pg_tuple_get_field_names(this);
468
+ if( field_names == Qfalse )
469
+ field_names = rb_funcall(this->field_map, rb_intern("keys"), 0);
470
+
471
+ values = rb_ary_new4(this->num_fields, &this->values[0]);
472
+ a = rb_ary_new3(2, field_names, values);
473
+
474
+ rb_copy_generic_ivar(a, self);
475
+
476
+ return a;
477
+ }
478
+
479
+ static VALUE
480
+ pg_tuple_load(VALUE self, VALUE a)
481
+ {
482
+ int num_fields;
483
+ int i;
484
+ t_pg_tuple *this;
485
+ VALUE values;
486
+ VALUE field_names;
487
+ VALUE field_map;
488
+ int dup_names;
489
+
490
+ rb_check_frozen(self);
491
+
492
+ TypedData_Get_Struct(self, t_pg_tuple, &pg_tuple_type, this);
493
+ if (this)
494
+ rb_raise(rb_eTypeError, "tuple is not empty");
495
+
496
+ Check_Type(a, T_ARRAY);
497
+ if (RARRAY_LEN(a) != 2)
498
+ rb_raise(rb_eTypeError, "expected an array of 2 elements");
499
+
500
+ field_names = RARRAY_AREF(a, 0);
501
+ Check_Type(field_names, T_ARRAY);
502
+ rb_obj_freeze(field_names);
503
+ values = RARRAY_AREF(a, 1);
504
+ Check_Type(values, T_ARRAY);
505
+ num_fields = RARRAY_LENINT(values);
506
+
507
+ if (RARRAY_LENINT(field_names) != num_fields)
508
+ rb_raise(rb_eTypeError, "different number of fields and values");
509
+
510
+ field_map = rb_hash_new();
511
+ for( i = 0; i < num_fields; i++ ){
512
+ rb_hash_aset(field_map, RARRAY_AREF(field_names, i), INT2FIX(i));
513
+ }
514
+ rb_obj_freeze(field_map);
515
+
516
+ dup_names = num_fields != (int)RHASH_SIZE(field_map);
517
+
518
+ this = (t_pg_tuple *)xmalloc(
519
+ sizeof(*this) +
520
+ sizeof(*this->values) * num_fields +
521
+ sizeof(*this->values) * (dup_names ? 1 : 0));
522
+
523
+ this->result = Qnil;
524
+ this->typemap = Qnil;
525
+ this->row_num = -1;
526
+ this->num_fields = num_fields;
527
+ this->field_map = field_map;
528
+
529
+ for( i = 0; i < num_fields; i++ ){
530
+ VALUE v = RARRAY_AREF(values, i);
531
+ if( v == Qundef )
532
+ rb_raise(rb_eTypeError, "field %d is not materialized", i);
533
+ this->values[i] = v;
534
+ }
535
+
536
+ if( dup_names ){
537
+ this->values[num_fields] = field_names;
538
+ }
539
+
540
+ RTYPEDDATA_DATA(self) = this;
541
+
542
+ rb_copy_generic_ivar(self, a);
543
+
544
+ return self;
545
+ }
546
+
547
+ void
548
+ init_pg_tuple()
549
+ {
550
+ rb_cPG_Tuple = rb_define_class_under( rb_mPG, "Tuple", rb_cObject );
551
+ rb_define_alloc_func( rb_cPG_Tuple, pg_tuple_s_allocate );
552
+ rb_include_module(rb_cPG_Tuple, rb_mEnumerable);
553
+
554
+ rb_define_method(rb_cPG_Tuple, "fetch", pg_tuple_fetch, -1);
555
+ rb_define_method(rb_cPG_Tuple, "[]", pg_tuple_aref, 1);
556
+ rb_define_method(rb_cPG_Tuple, "each", pg_tuple_each, 0);
557
+ rb_define_method(rb_cPG_Tuple, "each_value", pg_tuple_each_value, 0);
558
+ rb_define_method(rb_cPG_Tuple, "values", pg_tuple_values, 0);
559
+ rb_define_method(rb_cPG_Tuple, "length", pg_tuple_length, 0);
560
+ rb_define_alias(rb_cPG_Tuple, "size", "length");
561
+ rb_define_method(rb_cPG_Tuple, "index", pg_tuple_index, 1);
562
+
563
+ rb_define_private_method(rb_cPG_Tuple, "field_map", pg_tuple_field_map, 0);
564
+ rb_define_private_method(rb_cPG_Tuple, "field_names", pg_tuple_field_names, 0);
565
+
566
+ /* methods for marshaling */
567
+ rb_define_private_method(rb_cPG_Tuple, "marshal_dump", pg_tuple_dump, 0);
568
+ rb_define_private_method(rb_cPG_Tuple, "marshal_load", pg_tuple_load, 1);
569
+ }
data/ext/pg_type_map.c CHANGED
@@ -1,56 +1,97 @@
1
1
  /*
2
2
  * pg_column_map.c - PG::ColumnMap class extension
3
- * $Id: pg_type_map.c,v fcf731d3dff7 2015/09/08 12:25:06 jfali $
3
+ * $Id$
4
4
  *
5
5
  */
6
6
 
7
7
  #include "pg.h"
8
8
 
9
+ void
10
+ pg_typemap_mark( void *_this )
11
+ {
12
+ t_typemap *this = (t_typemap *)_this;
13
+ rb_gc_mark_movable(this->default_typemap);
14
+ }
15
+
16
+ size_t
17
+ pg_typemap_memsize( const void *_this )
18
+ {
19
+ t_typemap *this = (t_typemap *)_this;
20
+ return sizeof(*this);
21
+ }
22
+
23
+ void
24
+ pg_typemap_compact( void *_this )
25
+ {
26
+ t_typemap *this = (t_typemap *)_this;
27
+ pg_gc_location(this->default_typemap);
28
+ }
29
+
30
+ const rb_data_type_t pg_typemap_type = {
31
+ "PG::TypeMap",
32
+ {
33
+ pg_typemap_mark,
34
+ RUBY_TYPED_DEFAULT_FREE,
35
+ pg_typemap_memsize,
36
+ pg_compact_callback(pg_typemap_compact),
37
+ },
38
+ 0,
39
+ 0,
40
+ RUBY_TYPED_FREE_IMMEDIATELY,
41
+ };
42
+
9
43
  VALUE rb_cTypeMap;
10
44
  VALUE rb_mDefaultTypeMappable;
11
45
  static ID s_id_fit_to_query;
12
46
  static ID s_id_fit_to_result;
13
47
 
48
+ NORETURN( VALUE
49
+ pg_typemap_fit_to_result( VALUE self, VALUE result ));
50
+ NORETURN( VALUE
51
+ pg_typemap_fit_to_query( VALUE self, VALUE params ));
52
+ NORETURN( int
53
+ pg_typemap_fit_to_copy_get( VALUE self ));
54
+ NORETURN( VALUE
55
+ pg_typemap_result_value( t_typemap *p_typemap, VALUE result, int tuple, int field ));
56
+ NORETURN( t_pg_coder *
57
+ pg_typemap_typecast_query_param( t_typemap *p_typemap, VALUE param_value, int field ));
58
+ NORETURN( VALUE
59
+ pg_typemap_typecast_copy_get( t_typemap *p_typemap, VALUE field_str, int fieldno, int format, int enc_idx ));
60
+
14
61
  VALUE
15
62
  pg_typemap_fit_to_result( VALUE self, VALUE result )
16
63
  {
17
64
  rb_raise( rb_eNotImpError, "type map %s is not suitable to map result values", rb_obj_classname(self) );
18
- return Qnil;
19
65
  }
20
66
 
21
67
  VALUE
22
68
  pg_typemap_fit_to_query( VALUE self, VALUE params )
23
69
  {
24
70
  rb_raise( rb_eNotImpError, "type map %s is not suitable to map query params", rb_obj_classname(self) );
25
- return Qnil;
26
71
  }
27
72
 
28
73
  int
29
74
  pg_typemap_fit_to_copy_get( VALUE self )
30
75
  {
31
76
  rb_raise( rb_eNotImpError, "type map %s is not suitable to map get_copy_data results", rb_obj_classname(self) );
32
- return Qnil;
33
77
  }
34
78
 
35
79
  VALUE
36
80
  pg_typemap_result_value( t_typemap *p_typemap, VALUE result, int tuple, int field )
37
81
  {
38
82
  rb_raise( rb_eNotImpError, "type map is not suitable to map result values" );
39
- return Qnil;
40
83
  }
41
84
 
42
85
  t_pg_coder *
43
86
  pg_typemap_typecast_query_param( t_typemap *p_typemap, VALUE param_value, int field )
44
87
  {
45
88
  rb_raise( rb_eNotImpError, "type map is not suitable to map query params" );
46
- return NULL;
47
89
  }
48
90
 
49
91
  VALUE
50
92
  pg_typemap_typecast_copy_get( t_typemap *p_typemap, VALUE field_str, int fieldno, int format, int enc_idx )
51
93
  {
52
94
  rb_raise( rb_eNotImpError, "type map is not suitable to map get_copy_data results" );
53
- return Qnil;
54
95
  }
55
96
 
56
97
  const struct pg_typemap_funcs pg_typemap_funcs = {
@@ -68,7 +109,7 @@ pg_typemap_s_allocate( VALUE klass )
68
109
  VALUE self;
69
110
  t_typemap *this;
70
111
 
71
- self = Data_Make_Struct( klass, t_typemap, NULL, -1, this );
112
+ self = TypedData_Make_Struct( klass, t_typemap, &pg_typemap_type, this );
72
113
  this->funcs = pg_typemap_funcs;
73
114
 
74
115
  return self;
@@ -87,13 +128,12 @@ pg_typemap_s_allocate( VALUE klass )
87
128
  static VALUE
88
129
  pg_typemap_default_type_map_set(VALUE self, VALUE typemap)
89
130
  {
90
- t_typemap *this = DATA_PTR( self );
131
+ t_typemap *this = RTYPEDDATA_DATA( self );
132
+ t_typemap *tm;
133
+ UNUSED(tm);
91
134
 
92
- if ( !rb_obj_is_kind_of(typemap, rb_cTypeMap) ) {
93
- rb_raise( rb_eTypeError, "wrong argument type %s (expected kind of PG::TypeMap)",
94
- rb_obj_classname( typemap ) );
95
- }
96
- Check_Type(typemap, T_DATA);
135
+ /* Check type of method param */
136
+ TypedData_Get_Struct(typemap, t_typemap, &pg_typemap_type, tm);
97
137
  this->default_typemap = typemap;
98
138
 
99
139
  return typemap;
@@ -112,7 +152,7 @@ pg_typemap_default_type_map_set(VALUE self, VALUE typemap)
112
152
  static VALUE
113
153
  pg_typemap_default_type_map_get(VALUE self)
114
154
  {
115
- t_typemap *this = DATA_PTR( self );
155
+ t_typemap *this = RTYPEDDATA_DATA( self );
116
156
 
117
157
  return this->default_typemap;
118
158
  }