pg 1.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. checksums.yaml +7 -0
  2. checksums.yaml.gz.sig +3 -0
  3. data.tar.gz.sig +0 -0
  4. data/.gemtest +0 -0
  5. data/BSDL +22 -0
  6. data/ChangeLog +6595 -0
  7. data/Contributors.rdoc +46 -0
  8. data/History.rdoc +492 -0
  9. data/LICENSE +56 -0
  10. data/Manifest.txt +72 -0
  11. data/POSTGRES +23 -0
  12. data/README-OS_X.rdoc +68 -0
  13. data/README-Windows.rdoc +56 -0
  14. data/README.ja.rdoc +14 -0
  15. data/README.rdoc +178 -0
  16. data/Rakefile +215 -0
  17. data/Rakefile.cross +298 -0
  18. data/ext/errorcodes.def +968 -0
  19. data/ext/errorcodes.rb +45 -0
  20. data/ext/errorcodes.txt +478 -0
  21. data/ext/extconf.rb +94 -0
  22. data/ext/gvl_wrappers.c +17 -0
  23. data/ext/gvl_wrappers.h +241 -0
  24. data/ext/pg.c +640 -0
  25. data/ext/pg.h +365 -0
  26. data/ext/pg_binary_decoder.c +229 -0
  27. data/ext/pg_binary_encoder.c +162 -0
  28. data/ext/pg_coder.c +549 -0
  29. data/ext/pg_connection.c +4252 -0
  30. data/ext/pg_copy_coder.c +596 -0
  31. data/ext/pg_errors.c +95 -0
  32. data/ext/pg_result.c +1501 -0
  33. data/ext/pg_text_decoder.c +981 -0
  34. data/ext/pg_text_encoder.c +682 -0
  35. data/ext/pg_tuple.c +541 -0
  36. data/ext/pg_type_map.c +166 -0
  37. data/ext/pg_type_map_all_strings.c +116 -0
  38. data/ext/pg_type_map_by_class.c +239 -0
  39. data/ext/pg_type_map_by_column.c +312 -0
  40. data/ext/pg_type_map_by_mri_type.c +284 -0
  41. data/ext/pg_type_map_by_oid.c +355 -0
  42. data/ext/pg_type_map_in_ruby.c +299 -0
  43. data/ext/util.c +149 -0
  44. data/ext/util.h +65 -0
  45. data/ext/vc/pg.sln +26 -0
  46. data/ext/vc/pg_18/pg.vcproj +216 -0
  47. data/ext/vc/pg_19/pg_19.vcproj +209 -0
  48. data/lib/pg.rb +74 -0
  49. data/lib/pg/basic_type_mapping.rb +459 -0
  50. data/lib/pg/binary_decoder.rb +22 -0
  51. data/lib/pg/coder.rb +83 -0
  52. data/lib/pg/connection.rb +291 -0
  53. data/lib/pg/constants.rb +11 -0
  54. data/lib/pg/exceptions.rb +11 -0
  55. data/lib/pg/result.rb +31 -0
  56. data/lib/pg/text_decoder.rb +47 -0
  57. data/lib/pg/text_encoder.rb +69 -0
  58. data/lib/pg/tuple.rb +30 -0
  59. data/lib/pg/type_map_by_column.rb +15 -0
  60. data/spec/data/expected_trace.out +26 -0
  61. data/spec/data/random_binary_data +0 -0
  62. data/spec/helpers.rb +380 -0
  63. data/spec/pg/basic_type_mapping_spec.rb +508 -0
  64. data/spec/pg/connection_spec.rb +1872 -0
  65. data/spec/pg/connection_sync_spec.rb +41 -0
  66. data/spec/pg/result_spec.rb +491 -0
  67. data/spec/pg/tuple_spec.rb +280 -0
  68. data/spec/pg/type_map_by_class_spec.rb +138 -0
  69. data/spec/pg/type_map_by_column_spec.rb +222 -0
  70. data/spec/pg/type_map_by_mri_type_spec.rb +136 -0
  71. data/spec/pg/type_map_by_oid_spec.rb +149 -0
  72. data/spec/pg/type_map_in_ruby_spec.rb +164 -0
  73. data/spec/pg/type_map_spec.rb +22 -0
  74. data/spec/pg/type_spec.rb +949 -0
  75. data/spec/pg_spec.rb +50 -0
  76. metadata +322 -0
  77. metadata.gz.sig +0 -0
@@ -0,0 +1,162 @@
1
+ /*
2
+ * pg_column_map.c - PG::ColumnMap class extension
3
+ * $Id: pg_binary_encoder.c,v e61a06f1f5ed 2015/12/25 21:14:21 lars $
4
+ *
5
+ */
6
+
7
+ #include "pg.h"
8
+ #include "util.h"
9
+ #ifdef HAVE_INTTYPES_H
10
+ #include <inttypes.h>
11
+ #endif
12
+
13
+ VALUE rb_mPG_BinaryEncoder;
14
+
15
+
16
+ /*
17
+ * Document-class: PG::BinaryEncoder::Boolean < PG::SimpleEncoder
18
+ *
19
+ * This is the encoder class for the PostgreSQL boolean type.
20
+ *
21
+ * It accepts true and false. Other values will raise an exception.
22
+ *
23
+ */
24
+ static int
25
+ pg_bin_enc_boolean(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate, int enc_idx)
26
+ {
27
+ char mybool;
28
+ switch(value){
29
+ case Qtrue : mybool = 1; break;
30
+ case Qfalse : mybool = 0; break;
31
+ default :
32
+ rb_raise( rb_eTypeError, "wrong data for binary boolean converter" );
33
+ }
34
+ if(out) *out = mybool;
35
+ return 1;
36
+ }
37
+
38
+ /*
39
+ * Document-class: PG::BinaryEncoder::Int2 < PG::SimpleEncoder
40
+ *
41
+ * This is the encoder class for the PostgreSQL int2 type.
42
+ *
43
+ * Non-Number values are expected to have method +to_i+ defined.
44
+ *
45
+ */
46
+ static int
47
+ pg_bin_enc_int2(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate, int enc_idx)
48
+ {
49
+ if(out){
50
+ write_nbo16(NUM2INT(*intermediate), out);
51
+ }else{
52
+ *intermediate = pg_obj_to_i(value);
53
+ }
54
+ return 2;
55
+ }
56
+
57
+ /*
58
+ * Document-class: PG::BinaryEncoder::Int2 < PG::SimpleEncoder
59
+ *
60
+ * This is the encoder class for the PostgreSQL int4 type.
61
+ *
62
+ * Non-Number values are expected to have method +to_i+ defined.
63
+ *
64
+ */
65
+ static int
66
+ pg_bin_enc_int4(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate, int enc_idx)
67
+ {
68
+ if(out){
69
+ write_nbo32(NUM2LONG(*intermediate), out);
70
+ }else{
71
+ *intermediate = pg_obj_to_i(value);
72
+ }
73
+ return 4;
74
+ }
75
+
76
+ /*
77
+ * Document-class: PG::BinaryEncoder::Int2 < PG::SimpleEncoder
78
+ *
79
+ * This is the encoder class for the PostgreSQL int8 type.
80
+ *
81
+ * Non-Number values are expected to have method +to_i+ defined.
82
+ *
83
+ */
84
+ static int
85
+ pg_bin_enc_int8(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate, int enc_idx)
86
+ {
87
+ if(out){
88
+ write_nbo64(NUM2LL(*intermediate), out);
89
+ }else{
90
+ *intermediate = pg_obj_to_i(value);
91
+ }
92
+ return 8;
93
+ }
94
+
95
+ /*
96
+ * Document-class: PG::BinaryEncoder::FromBase64 < PG::CompositeEncoder
97
+ *
98
+ * This is an encoder class for conversion of base64 encoded data
99
+ * to it's binary representation.
100
+ *
101
+ */
102
+ static int
103
+ pg_bin_enc_from_base64(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate, int enc_idx)
104
+ {
105
+ int strlen;
106
+ VALUE subint;
107
+ t_pg_composite_coder *this = (t_pg_composite_coder *)conv;
108
+ t_pg_coder_enc_func enc_func = pg_coder_enc_func(this->elem);
109
+
110
+ if(out){
111
+ /* Second encoder pass, if required */
112
+ strlen = enc_func(this->elem, value, out, intermediate, enc_idx);
113
+ strlen = base64_decode( out, out, strlen );
114
+
115
+ return strlen;
116
+ } else {
117
+ /* First encoder pass */
118
+ strlen = enc_func(this->elem, value, NULL, &subint, enc_idx);
119
+
120
+ if( strlen == -1 ){
121
+ /* Encoded string is returned in subint */
122
+ VALUE out_str;
123
+
124
+ strlen = RSTRING_LENINT(subint);
125
+ out_str = rb_str_new(NULL, BASE64_DECODED_SIZE(strlen));
126
+
127
+ strlen = base64_decode( RSTRING_PTR(out_str), RSTRING_PTR(subint), strlen);
128
+ rb_str_set_len( out_str, strlen );
129
+ *intermediate = out_str;
130
+
131
+ return -1;
132
+ } else {
133
+ *intermediate = subint;
134
+
135
+ return BASE64_DECODED_SIZE(strlen);
136
+ }
137
+ }
138
+ }
139
+
140
+ void
141
+ init_pg_binary_encoder()
142
+ {
143
+ /* This module encapsulates all encoder classes with binary output format */
144
+ rb_mPG_BinaryEncoder = rb_define_module_under( rb_mPG, "BinaryEncoder" );
145
+
146
+ /* Make RDoc aware of the encoder classes... */
147
+ /* dummy = rb_define_class_under( rb_mPG_BinaryEncoder, "Boolean", rb_cPG_SimpleEncoder ); */
148
+ pg_define_coder( "Boolean", pg_bin_enc_boolean, rb_cPG_SimpleEncoder, rb_mPG_BinaryEncoder );
149
+ /* dummy = rb_define_class_under( rb_mPG_BinaryEncoder, "Int2", rb_cPG_SimpleEncoder ); */
150
+ pg_define_coder( "Int2", pg_bin_enc_int2, rb_cPG_SimpleEncoder, rb_mPG_BinaryEncoder );
151
+ /* dummy = rb_define_class_under( rb_mPG_BinaryEncoder, "Int4", rb_cPG_SimpleEncoder ); */
152
+ pg_define_coder( "Int4", pg_bin_enc_int4, rb_cPG_SimpleEncoder, rb_mPG_BinaryEncoder );
153
+ /* dummy = rb_define_class_under( rb_mPG_BinaryEncoder, "Int8", rb_cPG_SimpleEncoder ); */
154
+ pg_define_coder( "Int8", pg_bin_enc_int8, rb_cPG_SimpleEncoder, rb_mPG_BinaryEncoder );
155
+ /* dummy = rb_define_class_under( rb_mPG_BinaryEncoder, "String", rb_cPG_SimpleEncoder ); */
156
+ pg_define_coder( "String", pg_coder_enc_to_s, rb_cPG_SimpleEncoder, rb_mPG_BinaryEncoder );
157
+ /* dummy = rb_define_class_under( rb_mPG_BinaryEncoder, "Bytea", rb_cPG_SimpleEncoder ); */
158
+ pg_define_coder( "Bytea", pg_coder_enc_to_s, rb_cPG_SimpleEncoder, rb_mPG_BinaryEncoder );
159
+
160
+ /* dummy = rb_define_class_under( rb_mPG_BinaryEncoder, "FromBase64", rb_cPG_CompositeEncoder ); */
161
+ pg_define_coder( "FromBase64", pg_bin_enc_from_base64, rb_cPG_CompositeEncoder, rb_mPG_BinaryEncoder );
162
+ }
@@ -0,0 +1,549 @@
1
+ /*
2
+ * pg_coder.c - PG::Coder class extension
3
+ *
4
+ */
5
+
6
+ #include "pg.h"
7
+
8
+ VALUE rb_cPG_Coder;
9
+ VALUE rb_cPG_SimpleCoder;
10
+ VALUE rb_cPG_SimpleEncoder;
11
+ VALUE rb_cPG_SimpleDecoder;
12
+ VALUE rb_cPG_CompositeCoder;
13
+ VALUE rb_cPG_CompositeEncoder;
14
+ VALUE rb_cPG_CompositeDecoder;
15
+ VALUE rb_mPG_BinaryFormatting;
16
+ static ID s_id_encode;
17
+ static ID s_id_decode;
18
+ static ID s_id_CFUNC;
19
+
20
+ static VALUE
21
+ pg_coder_allocate( VALUE klass )
22
+ {
23
+ rb_raise( rb_eTypeError, "PG::Coder cannot be instantiated directly");
24
+ }
25
+
26
+ void
27
+ pg_coder_init_encoder( VALUE self )
28
+ {
29
+ t_pg_coder *this = DATA_PTR( self );
30
+ VALUE klass = rb_class_of(self);
31
+ if( rb_const_defined( klass, s_id_CFUNC ) ){
32
+ VALUE cfunc = rb_const_get( klass, s_id_CFUNC );
33
+ this->enc_func = DATA_PTR(cfunc);
34
+ } else {
35
+ this->enc_func = NULL;
36
+ }
37
+ this->dec_func = NULL;
38
+ this->coder_obj = self;
39
+ this->oid = 0;
40
+ this->format = 0;
41
+ this->flags = 0;
42
+ rb_iv_set( self, "@name", Qnil );
43
+ }
44
+
45
+ void
46
+ pg_coder_init_decoder( VALUE self )
47
+ {
48
+ t_pg_coder *this = DATA_PTR( self );
49
+ VALUE klass = rb_class_of(self);
50
+ this->enc_func = NULL;
51
+ if( rb_const_defined( klass, s_id_CFUNC ) ){
52
+ VALUE cfunc = rb_const_get( klass, s_id_CFUNC );
53
+ this->dec_func = DATA_PTR(cfunc);
54
+ } else {
55
+ this->dec_func = NULL;
56
+ }
57
+ this->coder_obj = self;
58
+ this->oid = 0;
59
+ this->format = 0;
60
+ this->flags = 0;
61
+ rb_iv_set( self, "@name", Qnil );
62
+ }
63
+
64
+ static VALUE
65
+ pg_simple_encoder_allocate( VALUE klass )
66
+ {
67
+ t_pg_coder *this;
68
+ VALUE self = Data_Make_Struct( klass, t_pg_coder, NULL, -1, this );
69
+ pg_coder_init_encoder( self );
70
+ return self;
71
+ }
72
+
73
+ static VALUE
74
+ pg_composite_encoder_allocate( VALUE klass )
75
+ {
76
+ t_pg_composite_coder *this;
77
+ VALUE self = Data_Make_Struct( klass, t_pg_composite_coder, NULL, -1, this );
78
+ pg_coder_init_encoder( self );
79
+ this->elem = NULL;
80
+ this->needs_quotation = 1;
81
+ this->delimiter = ',';
82
+ rb_iv_set( self, "@elements_type", Qnil );
83
+ return self;
84
+ }
85
+
86
+ static VALUE
87
+ pg_simple_decoder_allocate( VALUE klass )
88
+ {
89
+ t_pg_coder *this;
90
+ VALUE self = Data_Make_Struct( klass, t_pg_coder, NULL, -1, this );
91
+ pg_coder_init_decoder( self );
92
+ return self;
93
+ }
94
+
95
+ static VALUE
96
+ pg_composite_decoder_allocate( VALUE klass )
97
+ {
98
+ t_pg_composite_coder *this;
99
+ VALUE self = Data_Make_Struct( klass, t_pg_composite_coder, NULL, -1, this );
100
+ pg_coder_init_decoder( self );
101
+ this->elem = NULL;
102
+ this->needs_quotation = 1;
103
+ this->delimiter = ',';
104
+ rb_iv_set( self, "@elements_type", Qnil );
105
+ return self;
106
+ }
107
+
108
+ /*
109
+ * call-seq:
110
+ * coder.encode( value [, encoding] )
111
+ *
112
+ * Encodes the given Ruby object into string representation, without
113
+ * sending data to/from the database server.
114
+ *
115
+ * A nil value is passed through.
116
+ *
117
+ */
118
+ static VALUE
119
+ pg_coder_encode(int argc, VALUE *argv, VALUE self)
120
+ {
121
+ VALUE res;
122
+ VALUE intermediate;
123
+ VALUE value;
124
+ int len, len2;
125
+ int enc_idx;
126
+ t_pg_coder *this = DATA_PTR(self);
127
+
128
+ if(argc < 1 || argc > 2){
129
+ rb_raise(rb_eArgError, "wrong number of arguments (%i for 1..2)", argc);
130
+ }else if(argc == 1){
131
+ enc_idx = rb_ascii8bit_encindex();
132
+ }else{
133
+ enc_idx = rb_to_encoding_index(argv[1]);
134
+ }
135
+ value = argv[0];
136
+
137
+ if( NIL_P(value) )
138
+ return Qnil;
139
+
140
+ if( !this->enc_func ){
141
+ rb_raise(rb_eRuntimeError, "no encoder function defined");
142
+ }
143
+
144
+ len = this->enc_func( this, value, NULL, &intermediate, enc_idx );
145
+
146
+ if( len == -1 ){
147
+ /* The intermediate value is a String that can be used directly. */
148
+ OBJ_INFECT(intermediate, value);
149
+ return intermediate;
150
+ }
151
+
152
+ res = rb_str_new(NULL, len);
153
+ PG_ENCODING_SET_NOCHECK(res, enc_idx);
154
+ len2 = this->enc_func( this, value, RSTRING_PTR(res), &intermediate, enc_idx );
155
+ if( len < len2 ){
156
+ rb_bug("%s: result length of first encoder run (%i) is less than second run (%i)",
157
+ rb_obj_classname( self ), len, len2 );
158
+ }
159
+ rb_str_set_len( res, len2 );
160
+ OBJ_INFECT(res, value);
161
+
162
+ RB_GC_GUARD(intermediate);
163
+
164
+ return res;
165
+ }
166
+
167
+ /*
168
+ * call-seq:
169
+ * coder.decode( string, tuple=nil, field=nil )
170
+ *
171
+ * Decodes the given string representation into a Ruby object, without
172
+ * sending data to/from the database server.
173
+ *
174
+ * A nil value is passed through and non String values are expected to have
175
+ * #to_str defined.
176
+ *
177
+ */
178
+ static VALUE
179
+ pg_coder_decode(int argc, VALUE *argv, VALUE self)
180
+ {
181
+ char *val;
182
+ int tuple = -1;
183
+ int field = -1;
184
+ VALUE res;
185
+ t_pg_coder *this = DATA_PTR(self);
186
+
187
+ if(argc < 1 || argc > 3){
188
+ rb_raise(rb_eArgError, "wrong number of arguments (%i for 1..3)", argc);
189
+ }else if(argc >= 3){
190
+ tuple = NUM2INT(argv[1]);
191
+ field = NUM2INT(argv[2]);
192
+ }
193
+
194
+ if( NIL_P(argv[0]) )
195
+ return Qnil;
196
+
197
+ if( this->format == 0 ){
198
+ val = StringValueCStr(argv[0]);
199
+ }else{
200
+ val = StringValuePtr(argv[0]);
201
+ }
202
+ if( !this->dec_func ){
203
+ rb_raise(rb_eRuntimeError, "no decoder function defined");
204
+ }
205
+
206
+ res = this->dec_func(this, val, RSTRING_LEN(argv[0]), tuple, field, ENCODING_GET(argv[0]));
207
+ OBJ_INFECT(res, argv[0]);
208
+
209
+ return res;
210
+ }
211
+
212
+ /*
213
+ * call-seq:
214
+ * coder.oid = Integer
215
+ *
216
+ * Specifies the type OID that is sent alongside with an encoded
217
+ * query parameter value.
218
+ *
219
+ * The default is +0+.
220
+ */
221
+ static VALUE
222
+ pg_coder_oid_set(VALUE self, VALUE oid)
223
+ {
224
+ t_pg_coder *this = DATA_PTR(self);
225
+ this->oid = NUM2UINT(oid);
226
+ return oid;
227
+ }
228
+
229
+ /*
230
+ * call-seq:
231
+ * coder.oid -> Integer
232
+ *
233
+ * The type OID that is sent alongside with an encoded
234
+ * query parameter value.
235
+ */
236
+ static VALUE
237
+ pg_coder_oid_get(VALUE self)
238
+ {
239
+ t_pg_coder *this = DATA_PTR(self);
240
+ return UINT2NUM(this->oid);
241
+ }
242
+
243
+ /*
244
+ * call-seq:
245
+ * coder.format = Integer
246
+ *
247
+ * Specifies the format code that is sent alongside with an encoded
248
+ * query parameter value.
249
+ *
250
+ * The default is +0+.
251
+ */
252
+ static VALUE
253
+ pg_coder_format_set(VALUE self, VALUE format)
254
+ {
255
+ t_pg_coder *this = DATA_PTR(self);
256
+ this->format = NUM2INT(format);
257
+ return format;
258
+ }
259
+
260
+ /*
261
+ * call-seq:
262
+ * coder.format -> Integer
263
+ *
264
+ * The format code that is sent alongside with an encoded
265
+ * query parameter value.
266
+ */
267
+ static VALUE
268
+ pg_coder_format_get(VALUE self)
269
+ {
270
+ t_pg_coder *this = DATA_PTR(self);
271
+ return INT2NUM(this->format);
272
+ }
273
+
274
+ /*
275
+ * call-seq:
276
+ * coder.flags = Integer
277
+ *
278
+ * Set coder specific bitwise OR-ed flags.
279
+ * See the particular en- or decoder description for available flags.
280
+ *
281
+ * The default is +0+.
282
+ */
283
+ static VALUE
284
+ pg_coder_flags_set(VALUE self, VALUE flags)
285
+ {
286
+ t_pg_coder *this = DATA_PTR(self);
287
+ this->flags = NUM2INT(flags);
288
+ return flags;
289
+ }
290
+
291
+ /*
292
+ * call-seq:
293
+ * coder.flags -> Integer
294
+ *
295
+ * Get current bitwise OR-ed coder flags.
296
+ */
297
+ static VALUE
298
+ pg_coder_flags_get(VALUE self)
299
+ {
300
+ t_pg_coder *this = DATA_PTR(self);
301
+ return INT2NUM(this->flags);
302
+ }
303
+
304
+ /*
305
+ * call-seq:
306
+ * coder.needs_quotation = Boolean
307
+ *
308
+ * Specifies whether the assigned #elements_type requires quotation marks to
309
+ * be transferred safely. Encoding with #needs_quotation=false is somewhat
310
+ * faster.
311
+ *
312
+ * The default is +true+. This option is ignored for decoding of values.
313
+ */
314
+ static VALUE
315
+ pg_coder_needs_quotation_set(VALUE self, VALUE needs_quotation)
316
+ {
317
+ t_pg_composite_coder *this = DATA_PTR(self);
318
+ this->needs_quotation = RTEST(needs_quotation);
319
+ return needs_quotation;
320
+ }
321
+
322
+ /*
323
+ * call-seq:
324
+ * coder.needs_quotation -> Boolean
325
+ *
326
+ * Specifies whether the assigned #elements_type requires quotation marks to
327
+ * be transferred safely.
328
+ */
329
+ static VALUE
330
+ pg_coder_needs_quotation_get(VALUE self)
331
+ {
332
+ t_pg_composite_coder *this = DATA_PTR(self);
333
+ return this->needs_quotation ? Qtrue : Qfalse;
334
+ }
335
+
336
+ /*
337
+ * call-seq:
338
+ * coder.delimiter = String
339
+ *
340
+ * Specifies the character that separates values within the composite type.
341
+ * The default is a comma.
342
+ * This must be a single one-byte character.
343
+ */
344
+ static VALUE
345
+ pg_coder_delimiter_set(VALUE self, VALUE delimiter)
346
+ {
347
+ t_pg_composite_coder *this = DATA_PTR(self);
348
+ StringValue(delimiter);
349
+ if(RSTRING_LEN(delimiter) != 1)
350
+ rb_raise( rb_eArgError, "delimiter size must be one byte");
351
+ this->delimiter = *RSTRING_PTR(delimiter);
352
+ return delimiter;
353
+ }
354
+
355
+ /*
356
+ * call-seq:
357
+ * coder.delimiter -> String
358
+ *
359
+ * The character that separates values within the composite type.
360
+ */
361
+ static VALUE
362
+ pg_coder_delimiter_get(VALUE self)
363
+ {
364
+ t_pg_composite_coder *this = DATA_PTR(self);
365
+ return rb_str_new(&this->delimiter, 1);
366
+ }
367
+
368
+ /*
369
+ * call-seq:
370
+ * coder.elements_type = coder
371
+ *
372
+ * Specifies the PG::Coder object that is used to encode or decode
373
+ * the single elementes of this composite type.
374
+ *
375
+ * If set to +nil+ all values are encoded and decoded as String objects.
376
+ */
377
+ static VALUE
378
+ pg_coder_elements_type_set(VALUE self, VALUE elem_type)
379
+ {
380
+ t_pg_composite_coder *this = DATA_PTR( self );
381
+
382
+ if ( NIL_P(elem_type) ){
383
+ this->elem = NULL;
384
+ } else if ( rb_obj_is_kind_of(elem_type, rb_cPG_Coder) ){
385
+ this->elem = DATA_PTR( elem_type );
386
+ } else {
387
+ rb_raise( rb_eTypeError, "wrong elements type %s (expected some kind of PG::Coder)",
388
+ rb_obj_classname( elem_type ) );
389
+ }
390
+
391
+ rb_iv_set( self, "@elements_type", elem_type );
392
+ return elem_type;
393
+ }
394
+
395
+ void
396
+ pg_define_coder( const char *name, void *func, VALUE base_klass, VALUE nsp )
397
+ {
398
+ VALUE cfunc_obj = Data_Wrap_Struct( rb_cObject, NULL, NULL, func );
399
+ VALUE coder_klass = rb_define_class_under( nsp, name, base_klass );
400
+ if( nsp==rb_mPG_BinaryEncoder || nsp==rb_mPG_BinaryDecoder )
401
+ rb_include_module( coder_klass, rb_mPG_BinaryFormatting );
402
+
403
+ rb_define_const( coder_klass, "CFUNC", cfunc_obj );
404
+
405
+ RB_GC_GUARD(cfunc_obj);
406
+ }
407
+
408
+
409
+ static int
410
+ pg_text_enc_in_ruby(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate, int enc_idx)
411
+ {
412
+ int arity = rb_obj_method_arity(conv->coder_obj, s_id_encode);
413
+ if( arity == 1 ){
414
+ VALUE out_str = rb_funcall( conv->coder_obj, s_id_encode, 1, value );
415
+ StringValue( out_str );
416
+ *intermediate = rb_str_export_to_enc(out_str, rb_enc_from_index(enc_idx));
417
+ }else{
418
+ VALUE enc = rb_enc_from_encoding(rb_enc_from_index(enc_idx));
419
+ VALUE out_str = rb_funcall( conv->coder_obj, s_id_encode, 2, value, enc );
420
+ StringValue( out_str );
421
+ *intermediate = out_str;
422
+ }
423
+ return -1;
424
+ }
425
+
426
+ t_pg_coder_enc_func
427
+ pg_coder_enc_func(t_pg_coder *this)
428
+ {
429
+ if( this ){
430
+ if( this->enc_func ){
431
+ return this->enc_func;
432
+ }else{
433
+ return pg_text_enc_in_ruby;
434
+ }
435
+ }else{
436
+ /* no element encoder defined -> use std to_str conversion */
437
+ return pg_coder_enc_to_s;
438
+ }
439
+ }
440
+
441
+ static VALUE
442
+ pg_text_dec_in_ruby(t_pg_coder *this, const char *val, int len, int tuple, int field, int enc_idx)
443
+ {
444
+ VALUE string = pg_text_dec_string(this, val, len, tuple, field, enc_idx);
445
+ return rb_funcall( this->coder_obj, s_id_decode, 3, string, INT2NUM(tuple), INT2NUM(field) );
446
+ }
447
+
448
+ static VALUE
449
+ pg_bin_dec_in_ruby(t_pg_coder *this, const char *val, int len, int tuple, int field, int enc_idx)
450
+ {
451
+ VALUE string = pg_bin_dec_bytea(this, val, len, tuple, field, enc_idx);
452
+ return rb_funcall( this->coder_obj, s_id_decode, 3, string, INT2NUM(tuple), INT2NUM(field) );
453
+ }
454
+
455
+ t_pg_coder_dec_func
456
+ pg_coder_dec_func(t_pg_coder *this, int binary)
457
+ {
458
+ if( this ){
459
+ if( this->dec_func ){
460
+ return this->dec_func;
461
+ }else{
462
+ return binary ? pg_bin_dec_in_ruby : pg_text_dec_in_ruby;
463
+ }
464
+ }else{
465
+ /* no element decoder defined -> use std String conversion */
466
+ return binary ? pg_bin_dec_bytea : pg_text_dec_string;
467
+ }
468
+ }
469
+
470
+
471
+ void
472
+ init_pg_coder()
473
+ {
474
+ s_id_encode = rb_intern("encode");
475
+ s_id_decode = rb_intern("decode");
476
+ s_id_CFUNC = rb_intern("CFUNC");
477
+
478
+ /* Document-class: PG::Coder < Object
479
+ *
480
+ * This is the base class for all type cast encoder and decoder classes.
481
+ *
482
+ * It can be used for implicit type casts by a PG::TypeMap or to
483
+ * convert single values to/from their string representation by #encode
484
+ * and #decode.
485
+ *
486
+ * Ruby +nil+ values are not handled by encoders, but are always transmitted
487
+ * as SQL +NULL+ value. Vice versa SQL +NULL+ values are not handled by decoders,
488
+ * but are always returned as a +nil+ value.
489
+ */
490
+ rb_cPG_Coder = rb_define_class_under( rb_mPG, "Coder", rb_cObject );
491
+ rb_define_alloc_func( rb_cPG_Coder, pg_coder_allocate );
492
+ rb_define_method( rb_cPG_Coder, "oid=", pg_coder_oid_set, 1 );
493
+ rb_define_method( rb_cPG_Coder, "oid", pg_coder_oid_get, 0 );
494
+ rb_define_method( rb_cPG_Coder, "format=", pg_coder_format_set, 1 );
495
+ rb_define_method( rb_cPG_Coder, "format", pg_coder_format_get, 0 );
496
+ rb_define_method( rb_cPG_Coder, "flags=", pg_coder_flags_set, 1 );
497
+ rb_define_method( rb_cPG_Coder, "flags", pg_coder_flags_get, 0 );
498
+
499
+ /* define flags to be used with PG::Coder#flags= */
500
+ rb_define_const( rb_cPG_Coder, "TIMESTAMP_DB_UTC", INT2NUM(PG_CODER_TIMESTAMP_DB_UTC));
501
+ rb_define_const( rb_cPG_Coder, "TIMESTAMP_DB_LOCAL", INT2NUM(PG_CODER_TIMESTAMP_DB_LOCAL));
502
+ rb_define_const( rb_cPG_Coder, "TIMESTAMP_APP_UTC", INT2NUM(PG_CODER_TIMESTAMP_APP_UTC));
503
+ rb_define_const( rb_cPG_Coder, "TIMESTAMP_APP_LOCAL", INT2NUM(PG_CODER_TIMESTAMP_APP_LOCAL));
504
+ rb_define_const( rb_cPG_Coder, "FORMAT_ERROR_MASK", INT2NUM(PG_CODER_FORMAT_ERROR_MASK));
505
+ rb_define_const( rb_cPG_Coder, "FORMAT_ERROR_TO_RAISE", INT2NUM(PG_CODER_FORMAT_ERROR_TO_RAISE));
506
+ rb_define_const( rb_cPG_Coder, "FORMAT_ERROR_TO_STRING", INT2NUM(PG_CODER_FORMAT_ERROR_TO_STRING));
507
+ rb_define_const( rb_cPG_Coder, "FORMAT_ERROR_TO_PARTIAL", INT2NUM(PG_CODER_FORMAT_ERROR_TO_PARTIAL));
508
+
509
+ /*
510
+ * Name of the coder or the corresponding data type.
511
+ *
512
+ * This accessor is only used in PG::Coder#inspect .
513
+ */
514
+ rb_define_attr( rb_cPG_Coder, "name", 1, 1 );
515
+ rb_define_method( rb_cPG_Coder, "encode", pg_coder_encode, -1 );
516
+ rb_define_method( rb_cPG_Coder, "decode", pg_coder_decode, -1 );
517
+
518
+ /* Document-class: PG::SimpleCoder < PG::Coder */
519
+ rb_cPG_SimpleCoder = rb_define_class_under( rb_mPG, "SimpleCoder", rb_cPG_Coder );
520
+
521
+ /* Document-class: PG::SimpleEncoder < PG::SimpleCoder */
522
+ rb_cPG_SimpleEncoder = rb_define_class_under( rb_mPG, "SimpleEncoder", rb_cPG_SimpleCoder );
523
+ rb_define_alloc_func( rb_cPG_SimpleEncoder, pg_simple_encoder_allocate );
524
+ /* Document-class: PG::SimpleDecoder < PG::SimpleCoder */
525
+ rb_cPG_SimpleDecoder = rb_define_class_under( rb_mPG, "SimpleDecoder", rb_cPG_SimpleCoder );
526
+ rb_define_alloc_func( rb_cPG_SimpleDecoder, pg_simple_decoder_allocate );
527
+
528
+ /* Document-class: PG::CompositeCoder < PG::Coder
529
+ *
530
+ * This is the base class for all type cast classes of PostgreSQL types,
531
+ * that are made up of some sub type.
532
+ */
533
+ rb_cPG_CompositeCoder = rb_define_class_under( rb_mPG, "CompositeCoder", rb_cPG_Coder );
534
+ rb_define_method( rb_cPG_CompositeCoder, "elements_type=", pg_coder_elements_type_set, 1 );
535
+ rb_define_attr( rb_cPG_CompositeCoder, "elements_type", 1, 0 );
536
+ rb_define_method( rb_cPG_CompositeCoder, "needs_quotation=", pg_coder_needs_quotation_set, 1 );
537
+ rb_define_method( rb_cPG_CompositeCoder, "needs_quotation?", pg_coder_needs_quotation_get, 0 );
538
+ rb_define_method( rb_cPG_CompositeCoder, "delimiter=", pg_coder_delimiter_set, 1 );
539
+ rb_define_method( rb_cPG_CompositeCoder, "delimiter", pg_coder_delimiter_get, 0 );
540
+
541
+ /* Document-class: PG::CompositeEncoder < PG::CompositeCoder */
542
+ rb_cPG_CompositeEncoder = rb_define_class_under( rb_mPG, "CompositeEncoder", rb_cPG_CompositeCoder );
543
+ rb_define_alloc_func( rb_cPG_CompositeEncoder, pg_composite_encoder_allocate );
544
+ /* Document-class: PG::CompositeDecoder < PG::CompositeCoder */
545
+ rb_cPG_CompositeDecoder = rb_define_class_under( rb_mPG, "CompositeDecoder", rb_cPG_CompositeCoder );
546
+ rb_define_alloc_func( rb_cPG_CompositeDecoder, pg_composite_decoder_allocate );
547
+
548
+ rb_mPG_BinaryFormatting = rb_define_module_under( rb_cPG_Coder, "BinaryFormatting");
549
+ }