pg 0.17.1 → 1.2.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (86) hide show
  1. checksums.yaml +5 -5
  2. checksums.yaml.gz.sig +0 -0
  3. data/BSDL +2 -2
  4. data/ChangeLog +0 -3506
  5. data/History.rdoc +308 -0
  6. data/Manifest.txt +35 -19
  7. data/README-Windows.rdoc +17 -28
  8. data/README.ja.rdoc +1 -2
  9. data/README.rdoc +113 -14
  10. data/Rakefile +67 -30
  11. data/Rakefile.cross +109 -83
  12. data/ext/errorcodes.def +101 -0
  13. data/ext/errorcodes.rb +1 -1
  14. data/ext/errorcodes.txt +33 -2
  15. data/ext/extconf.rb +55 -58
  16. data/ext/gvl_wrappers.c +4 -0
  17. data/ext/gvl_wrappers.h +27 -39
  18. data/ext/pg.c +262 -130
  19. data/ext/pg.h +266 -54
  20. data/ext/pg_binary_decoder.c +229 -0
  21. data/ext/pg_binary_encoder.c +163 -0
  22. data/ext/pg_coder.c +561 -0
  23. data/ext/pg_connection.c +1689 -990
  24. data/ext/pg_copy_coder.c +599 -0
  25. data/ext/pg_errors.c +6 -0
  26. data/ext/pg_record_coder.c +491 -0
  27. data/ext/pg_result.c +897 -164
  28. data/ext/pg_text_decoder.c +987 -0
  29. data/ext/pg_text_encoder.c +814 -0
  30. data/ext/pg_tuple.c +549 -0
  31. data/ext/pg_type_map.c +166 -0
  32. data/ext/pg_type_map_all_strings.c +116 -0
  33. data/ext/pg_type_map_by_class.c +244 -0
  34. data/ext/pg_type_map_by_column.c +313 -0
  35. data/ext/pg_type_map_by_mri_type.c +284 -0
  36. data/ext/pg_type_map_by_oid.c +356 -0
  37. data/ext/pg_type_map_in_ruby.c +299 -0
  38. data/ext/pg_util.c +149 -0
  39. data/ext/pg_util.h +65 -0
  40. data/lib/pg/basic_type_mapping.rb +522 -0
  41. data/lib/pg/binary_decoder.rb +23 -0
  42. data/lib/pg/coder.rb +104 -0
  43. data/lib/pg/connection.rb +153 -41
  44. data/lib/pg/constants.rb +2 -1
  45. data/lib/pg/exceptions.rb +2 -1
  46. data/lib/pg/result.rb +33 -6
  47. data/lib/pg/text_decoder.rb +46 -0
  48. data/lib/pg/text_encoder.rb +59 -0
  49. data/lib/pg/tuple.rb +30 -0
  50. data/lib/pg/type_map_by_column.rb +16 -0
  51. data/lib/pg.rb +29 -9
  52. data/spec/{lib/helpers.rb → helpers.rb} +151 -64
  53. data/spec/pg/basic_type_mapping_spec.rb +630 -0
  54. data/spec/pg/connection_spec.rb +1180 -477
  55. data/spec/pg/connection_sync_spec.rb +41 -0
  56. data/spec/pg/result_spec.rb +456 -120
  57. data/spec/pg/tuple_spec.rb +333 -0
  58. data/spec/pg/type_map_by_class_spec.rb +138 -0
  59. data/spec/pg/type_map_by_column_spec.rb +226 -0
  60. data/spec/pg/type_map_by_mri_type_spec.rb +136 -0
  61. data/spec/pg/type_map_by_oid_spec.rb +149 -0
  62. data/spec/pg/type_map_in_ruby_spec.rb +164 -0
  63. data/spec/pg/type_map_spec.rb +22 -0
  64. data/spec/pg/type_spec.rb +1123 -0
  65. data/spec/pg_spec.rb +26 -20
  66. data.tar.gz.sig +0 -0
  67. metadata +148 -91
  68. metadata.gz.sig +0 -0
  69. data/sample/array_insert.rb +0 -20
  70. data/sample/async_api.rb +0 -106
  71. data/sample/async_copyto.rb +0 -39
  72. data/sample/async_mixed.rb +0 -56
  73. data/sample/check_conn.rb +0 -21
  74. data/sample/copyfrom.rb +0 -81
  75. data/sample/copyto.rb +0 -19
  76. data/sample/cursor.rb +0 -21
  77. data/sample/disk_usage_report.rb +0 -186
  78. data/sample/issue-119.rb +0 -94
  79. data/sample/losample.rb +0 -69
  80. data/sample/minimal-testcase.rb +0 -17
  81. data/sample/notify_wait.rb +0 -72
  82. data/sample/pg_statistics.rb +0 -294
  83. data/sample/replication_monitor.rb +0 -231
  84. data/sample/test_binary_values.rb +0 -33
  85. data/sample/wal_shipper.rb +0 -434
  86. data/sample/warehouse_partitions.rb +0 -320
data/ext/pg_tuple.c ADDED
@@ -0,0 +1,549 @@
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
+
136
+ this->result = result;
137
+ this->typemap = p_result->typemap;
138
+ this->field_map = field_map;
139
+ this->row_num = row_num;
140
+ this->num_fields = num_fields;
141
+
142
+ for( i = 0; i < num_fields; i++ ){
143
+ this->values[i] = Qundef;
144
+ }
145
+
146
+ if( dup_names ){
147
+ /* Some of the column names are duplicated -> we need the keys as Array in addition.
148
+ * Store it behind the values to save the space in the common case of no dups.
149
+ */
150
+ this->values[num_fields] = rb_obj_freeze(rb_ary_new4(num_fields, p_result->fnames));
151
+ }
152
+
153
+ RTYPEDDATA_DATA(self) = this;
154
+
155
+ return self;
156
+ }
157
+
158
+ static inline t_pg_tuple *
159
+ pg_tuple_get_this( VALUE self )
160
+ {
161
+ t_pg_tuple *this;
162
+ TypedData_Get_Struct(self, t_pg_tuple, &pg_tuple_type, this);
163
+ if (this == NULL)
164
+ rb_raise(rb_eTypeError, "tuple is empty");
165
+
166
+ return this;
167
+ }
168
+
169
+ static VALUE
170
+ pg_tuple_materialize_field(t_pg_tuple *this, int col)
171
+ {
172
+ VALUE value = this->values[col];
173
+
174
+ if( value == Qundef ){
175
+ t_typemap *p_typemap = DATA_PTR( this->typemap );
176
+
177
+ pgresult_get(this->result); /* make sure we have a valid PGresult object */
178
+ value = p_typemap->funcs.typecast_result_value(p_typemap, this->result, this->row_num, col);
179
+ this->values[col] = value;
180
+ }
181
+
182
+ return value;
183
+ }
184
+
185
+ static void
186
+ pg_tuple_detach(t_pg_tuple *this)
187
+ {
188
+ this->result = Qnil;
189
+ this->typemap = Qnil;
190
+ this->row_num = -1;
191
+ }
192
+
193
+ static void
194
+ pg_tuple_materialize(t_pg_tuple *this)
195
+ {
196
+ int field_num;
197
+ for(field_num = 0; field_num < this->num_fields; field_num++) {
198
+ pg_tuple_materialize_field(this, field_num);
199
+ }
200
+
201
+ pg_tuple_detach(this);
202
+ }
203
+
204
+ /*
205
+ * call-seq:
206
+ * tup.fetch(key) → value
207
+ * tup.fetch(key, default) → value
208
+ * tup.fetch(key) { |key| block } → value
209
+ *
210
+ * Returns a field value by either column index or column name.
211
+ *
212
+ * An integer +key+ is interpreted as column index.
213
+ * Negative values of index count from the end of the array.
214
+ *
215
+ * Depending on Result#field_name_type= a string or symbol +key+ is interpreted as column name.
216
+ *
217
+ * If the key can't be found, there are several options:
218
+ * With no other arguments, it will raise a IndexError exception;
219
+ * if default is given, then that will be returned;
220
+ * if the optional code block is specified, then that will be run and its result returned.
221
+ */
222
+ static VALUE
223
+ pg_tuple_fetch(int argc, VALUE *argv, VALUE self)
224
+ {
225
+ VALUE key;
226
+ long block_given;
227
+ VALUE index;
228
+ int field_num;
229
+ t_pg_tuple *this = pg_tuple_get_this(self);
230
+
231
+ rb_check_arity(argc, 1, 2);
232
+ key = argv[0];
233
+
234
+ block_given = rb_block_given_p();
235
+ if (block_given && argc == 2) {
236
+ rb_warn("block supersedes default value argument");
237
+ }
238
+
239
+ switch(rb_type(key)){
240
+ case T_FIXNUM:
241
+ case T_BIGNUM:
242
+ field_num = NUM2INT(key);
243
+ if ( field_num < 0 )
244
+ field_num = this->num_fields + field_num;
245
+ if ( field_num < 0 || field_num >= this->num_fields ){
246
+ if (block_given) return rb_yield(key);
247
+ if (argc == 1) rb_raise( rb_eIndexError, "Index %d is out of range", field_num );
248
+ return argv[1];
249
+ }
250
+ break;
251
+ default:
252
+ index = rb_hash_aref(this->field_map, key);
253
+
254
+ if (index == Qnil) {
255
+ if (block_given) return rb_yield(key);
256
+ if (argc == 1) rb_raise( rb_eKeyError, "column not found" );
257
+ return argv[1];
258
+ }
259
+
260
+ field_num = NUM2INT(index);
261
+ }
262
+
263
+ return pg_tuple_materialize_field(this, field_num);
264
+ }
265
+
266
+ /*
267
+ * call-seq:
268
+ * tup[ key ] -> value
269
+ *
270
+ * Returns a field value by either column index or column name.
271
+ *
272
+ * An integer +key+ is interpreted as column index.
273
+ * Negative values of index count from the end of the array.
274
+ *
275
+ * Depending on Result#field_name_type= a string or symbol +key+ is interpreted as column name.
276
+ *
277
+ * If the key can't be found, it returns +nil+ .
278
+ */
279
+ static VALUE
280
+ pg_tuple_aref(VALUE self, VALUE key)
281
+ {
282
+ VALUE index;
283
+ int field_num;
284
+ t_pg_tuple *this = pg_tuple_get_this(self);
285
+
286
+ switch(rb_type(key)){
287
+ case T_FIXNUM:
288
+ case T_BIGNUM:
289
+ field_num = NUM2INT(key);
290
+ if ( field_num < 0 )
291
+ field_num = this->num_fields + field_num;
292
+ if ( field_num < 0 || field_num >= this->num_fields )
293
+ return Qnil;
294
+ break;
295
+ default:
296
+ index = rb_hash_aref(this->field_map, key);
297
+ if( index == Qnil ) return Qnil;
298
+ field_num = NUM2INT(index);
299
+ }
300
+
301
+ return pg_tuple_materialize_field(this, field_num);
302
+ }
303
+
304
+ static VALUE
305
+ pg_tuple_num_fields_for_enum(VALUE self, VALUE args, VALUE eobj)
306
+ {
307
+ t_pg_tuple *this = pg_tuple_get_this(self);
308
+ return INT2NUM(this->num_fields);
309
+ }
310
+
311
+ static int
312
+ pg_tuple_yield_key_value(VALUE key, VALUE index, VALUE _this)
313
+ {
314
+ t_pg_tuple *this = (t_pg_tuple *)_this;
315
+ VALUE value = pg_tuple_materialize_field(this, NUM2INT(index));
316
+ rb_yield_values(2, key, value);
317
+ return ST_CONTINUE;
318
+ }
319
+
320
+ /*
321
+ * call-seq:
322
+ * tup.each{ |key, value| ... }
323
+ *
324
+ * Invokes block for each field name and value in the tuple.
325
+ */
326
+ static VALUE
327
+ pg_tuple_each(VALUE self)
328
+ {
329
+ t_pg_tuple *this = pg_tuple_get_this(self);
330
+ VALUE field_names;
331
+
332
+ RETURN_SIZED_ENUMERATOR(self, 0, NULL, pg_tuple_num_fields_for_enum);
333
+
334
+ field_names = pg_tuple_get_field_names(this);
335
+
336
+ if( field_names == Qfalse ){
337
+ rb_hash_foreach(this->field_map, pg_tuple_yield_key_value, (VALUE)this);
338
+ } else {
339
+ int i;
340
+ for( i = 0; i < this->num_fields; i++ ){
341
+ VALUE value = pg_tuple_materialize_field(this, i);
342
+ rb_yield_values(2, RARRAY_AREF(field_names, i), value);
343
+ }
344
+ }
345
+
346
+ pg_tuple_detach(this);
347
+ return self;
348
+ }
349
+
350
+ /*
351
+ * call-seq:
352
+ * tup.each_value{ |value| ... }
353
+ *
354
+ * Invokes block for each field value in the tuple.
355
+ */
356
+ static VALUE
357
+ pg_tuple_each_value(VALUE self)
358
+ {
359
+ t_pg_tuple *this = pg_tuple_get_this(self);
360
+ int field_num;
361
+
362
+ RETURN_SIZED_ENUMERATOR(self, 0, NULL, pg_tuple_num_fields_for_enum);
363
+
364
+ for(field_num = 0; field_num < this->num_fields; field_num++) {
365
+ VALUE value = pg_tuple_materialize_field(this, field_num);
366
+ rb_yield(value);
367
+ }
368
+
369
+ pg_tuple_detach(this);
370
+ return self;
371
+ }
372
+
373
+
374
+ /*
375
+ * call-seq:
376
+ * tup.values -> Array
377
+ *
378
+ * Returns the values of this tuple as Array.
379
+ * +res.tuple(i).values+ is equal to +res.tuple_values(i)+ .
380
+ */
381
+ static VALUE
382
+ pg_tuple_values(VALUE self)
383
+ {
384
+ t_pg_tuple *this = pg_tuple_get_this(self);
385
+
386
+ pg_tuple_materialize(this);
387
+ return rb_ary_new4(this->num_fields, &this->values[0]);
388
+ }
389
+
390
+ static VALUE
391
+ pg_tuple_field_map(VALUE self)
392
+ {
393
+ t_pg_tuple *this = pg_tuple_get_this(self);
394
+ return this->field_map;
395
+ }
396
+
397
+ static VALUE
398
+ pg_tuple_field_names(VALUE self)
399
+ {
400
+ t_pg_tuple *this = pg_tuple_get_this(self);
401
+ return pg_tuple_get_field_names(this);
402
+ }
403
+
404
+ /*
405
+ * call-seq:
406
+ * tup.length → integer
407
+ *
408
+ * Returns number of fields of this tuple.
409
+ */
410
+ static VALUE
411
+ pg_tuple_length(VALUE self)
412
+ {
413
+ t_pg_tuple *this = pg_tuple_get_this(self);
414
+ return INT2NUM(this->num_fields);
415
+ }
416
+
417
+ /*
418
+ * call-seq:
419
+ * tup.index(key) → integer
420
+ *
421
+ * Returns the field number which matches the given column name.
422
+ */
423
+ static VALUE
424
+ pg_tuple_index(VALUE self, VALUE key)
425
+ {
426
+ t_pg_tuple *this = pg_tuple_get_this(self);
427
+ return rb_hash_aref(this->field_map, key);
428
+ }
429
+
430
+
431
+ static VALUE
432
+ pg_tuple_dump(VALUE self)
433
+ {
434
+ VALUE field_names;
435
+ VALUE values;
436
+ VALUE a;
437
+ t_pg_tuple *this = pg_tuple_get_this(self);
438
+
439
+ pg_tuple_materialize(this);
440
+
441
+ field_names = pg_tuple_get_field_names(this);
442
+ if( field_names == Qfalse )
443
+ field_names = rb_funcall(this->field_map, rb_intern("keys"), 0);
444
+
445
+ values = rb_ary_new4(this->num_fields, &this->values[0]);
446
+ a = rb_ary_new3(2, field_names, values);
447
+
448
+ if (FL_TEST(self, FL_EXIVAR)) {
449
+ rb_copy_generic_ivar(a, self);
450
+ FL_SET(a, FL_EXIVAR);
451
+ }
452
+
453
+ return a;
454
+ }
455
+
456
+ static VALUE
457
+ pg_tuple_load(VALUE self, VALUE a)
458
+ {
459
+ int num_fields;
460
+ int i;
461
+ t_pg_tuple *this;
462
+ VALUE values;
463
+ VALUE field_names;
464
+ VALUE field_map;
465
+ int dup_names;
466
+
467
+ rb_check_frozen(self);
468
+
469
+ TypedData_Get_Struct(self, t_pg_tuple, &pg_tuple_type, this);
470
+ if (this)
471
+ rb_raise(rb_eTypeError, "tuple is not empty");
472
+
473
+ Check_Type(a, T_ARRAY);
474
+ if (RARRAY_LEN(a) != 2)
475
+ rb_raise(rb_eTypeError, "expected an array of 2 elements");
476
+
477
+ field_names = RARRAY_AREF(a, 0);
478
+ Check_Type(field_names, T_ARRAY);
479
+ rb_obj_freeze(field_names);
480
+ values = RARRAY_AREF(a, 1);
481
+ Check_Type(values, T_ARRAY);
482
+ num_fields = RARRAY_LEN(values);
483
+
484
+ if (RARRAY_LEN(field_names) != num_fields)
485
+ rb_raise(rb_eTypeError, "different number of fields and values");
486
+
487
+ field_map = rb_hash_new();
488
+ for( i = 0; i < num_fields; i++ ){
489
+ rb_hash_aset(field_map, RARRAY_AREF(field_names, i), INT2FIX(i));
490
+ }
491
+ rb_obj_freeze(field_map);
492
+
493
+ dup_names = num_fields != (int)RHASH_SIZE(field_map);
494
+
495
+ this = (t_pg_tuple *)xmalloc(
496
+ sizeof(*this) +
497
+ sizeof(*this->values) * num_fields +
498
+ sizeof(*this->values) * (dup_names ? 1 : 0));
499
+
500
+ this->result = Qnil;
501
+ this->typemap = Qnil;
502
+ this->row_num = -1;
503
+ this->num_fields = num_fields;
504
+ this->field_map = field_map;
505
+
506
+ for( i = 0; i < num_fields; i++ ){
507
+ VALUE v = RARRAY_AREF(values, i);
508
+ if( v == Qundef )
509
+ rb_raise(rb_eTypeError, "field %d is not materialized", i);
510
+ this->values[i] = v;
511
+ }
512
+
513
+ if( dup_names ){
514
+ this->values[num_fields] = field_names;
515
+ }
516
+
517
+ RTYPEDDATA_DATA(self) = this;
518
+
519
+ if (FL_TEST(a, FL_EXIVAR)) {
520
+ rb_copy_generic_ivar(self, a);
521
+ FL_SET(self, FL_EXIVAR);
522
+ }
523
+
524
+ return self;
525
+ }
526
+
527
+ void
528
+ init_pg_tuple()
529
+ {
530
+ rb_cPG_Tuple = rb_define_class_under( rb_mPG, "Tuple", rb_cObject );
531
+ rb_define_alloc_func( rb_cPG_Tuple, pg_tuple_s_allocate );
532
+ rb_include_module(rb_cPG_Tuple, rb_mEnumerable);
533
+
534
+ rb_define_method(rb_cPG_Tuple, "fetch", pg_tuple_fetch, -1);
535
+ rb_define_method(rb_cPG_Tuple, "[]", pg_tuple_aref, 1);
536
+ rb_define_method(rb_cPG_Tuple, "each", pg_tuple_each, 0);
537
+ rb_define_method(rb_cPG_Tuple, "each_value", pg_tuple_each_value, 0);
538
+ rb_define_method(rb_cPG_Tuple, "values", pg_tuple_values, 0);
539
+ rb_define_method(rb_cPG_Tuple, "length", pg_tuple_length, 0);
540
+ rb_define_alias(rb_cPG_Tuple, "size", "length");
541
+ rb_define_method(rb_cPG_Tuple, "index", pg_tuple_index, 1);
542
+
543
+ rb_define_private_method(rb_cPG_Tuple, "field_map", pg_tuple_field_map, 0);
544
+ rb_define_private_method(rb_cPG_Tuple, "field_names", pg_tuple_field_names, 0);
545
+
546
+ /* methods for marshaling */
547
+ rb_define_private_method(rb_cPG_Tuple, "marshal_dump", pg_tuple_dump, 0);
548
+ rb_define_private_method(rb_cPG_Tuple, "marshal_load", pg_tuple_load, 1);
549
+ }