pg 1.1.4

Sign up to get free protection for your applications and to get access to all the features.
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
+ }