pg 0.18.0.pre20140820094244 → 0.18.0.pre20141017155815

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/ChangeLog +1573 -2
  5. data/History.rdoc +3 -11
  6. data/Manifest.txt +24 -0
  7. data/README.rdoc +51 -4
  8. data/Rakefile +20 -14
  9. data/Rakefile.cross +39 -32
  10. data/ext/extconf.rb +27 -26
  11. data/ext/pg.c +75 -21
  12. data/ext/pg.h +194 -6
  13. data/ext/pg_binary_decoder.c +160 -0
  14. data/ext/pg_binary_encoder.c +160 -0
  15. data/ext/pg_coder.c +454 -0
  16. data/ext/pg_connection.c +815 -518
  17. data/ext/pg_copy_coder.c +557 -0
  18. data/ext/pg_result.c +258 -103
  19. data/ext/pg_text_decoder.c +424 -0
  20. data/ext/pg_text_encoder.c +608 -0
  21. data/ext/pg_type_map.c +113 -0
  22. data/ext/pg_type_map_all_strings.c +113 -0
  23. data/ext/pg_type_map_by_column.c +254 -0
  24. data/ext/pg_type_map_by_mri_type.c +266 -0
  25. data/ext/pg_type_map_by_oid.c +341 -0
  26. data/ext/util.c +121 -0
  27. data/ext/util.h +63 -0
  28. data/lib/pg.rb +11 -1
  29. data/lib/pg/basic_type_mapping.rb +377 -0
  30. data/lib/pg/coder.rb +74 -0
  31. data/lib/pg/connection.rb +38 -5
  32. data/lib/pg/result.rb +13 -3
  33. data/lib/pg/text_decoder.rb +42 -0
  34. data/lib/pg/text_encoder.rb +27 -0
  35. data/lib/pg/type_map_by_column.rb +15 -0
  36. data/spec/helpers.rb +9 -1
  37. data/spec/pg/basic_type_mapping_spec.rb +251 -0
  38. data/spec/pg/connection_spec.rb +232 -13
  39. data/spec/pg/result_spec.rb +52 -0
  40. data/spec/pg/type_map_by_column_spec.rb +135 -0
  41. data/spec/pg/type_map_by_mri_type_spec.rb +122 -0
  42. data/spec/pg/type_map_by_oid_spec.rb +133 -0
  43. data/spec/pg/type_map_spec.rb +39 -0
  44. data/spec/pg/type_spec.rb +620 -0
  45. metadata +40 -4
  46. metadata.gz.sig +0 -0
data/ext/pg_coder.c ADDED
@@ -0,0 +1,454 @@
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
+ static ID s_id_encode;
16
+ static ID s_id_decode;
17
+ static ID s_id_CFUNC;
18
+
19
+ static VALUE
20
+ pg_coder_allocate( VALUE klass )
21
+ {
22
+ rb_raise( rb_eTypeError, "PG::Coder cannot be instantiated directly");
23
+ }
24
+
25
+ void
26
+ pg_coder_init_encoder( VALUE self )
27
+ {
28
+ t_pg_coder *this = DATA_PTR( self );
29
+ VALUE klass = rb_class_of(self);
30
+ if( rb_const_defined( klass, s_id_CFUNC ) ){
31
+ VALUE cfunc = rb_const_get( klass, s_id_CFUNC );
32
+ this->enc_func = DATA_PTR(cfunc);
33
+ } else {
34
+ this->enc_func = NULL;
35
+ }
36
+ this->dec_func = NULL;
37
+ this->coder_obj = self;
38
+ this->oid = 0;
39
+ this->format = 0;
40
+ rb_iv_set( self, "@name", Qnil );
41
+ }
42
+
43
+ void
44
+ pg_coder_init_decoder( VALUE self )
45
+ {
46
+ t_pg_coder *this = DATA_PTR( self );
47
+ VALUE klass = rb_class_of(self);
48
+ this->enc_func = NULL;
49
+ if( rb_const_defined( klass, s_id_CFUNC ) ){
50
+ VALUE cfunc = rb_const_get( klass, s_id_CFUNC );
51
+ this->dec_func = DATA_PTR(cfunc);
52
+ } else {
53
+ this->dec_func = NULL;
54
+ }
55
+ this->coder_obj = self;
56
+ this->oid = 0;
57
+ this->format = 0;
58
+ rb_iv_set( self, "@name", Qnil );
59
+ }
60
+
61
+ static VALUE
62
+ pg_simple_encoder_allocate( VALUE klass )
63
+ {
64
+ t_pg_coder *this;
65
+ VALUE self = Data_Make_Struct( klass, t_pg_coder, NULL, -1, this );
66
+ pg_coder_init_encoder( self );
67
+ return self;
68
+ }
69
+
70
+ static VALUE
71
+ pg_composite_encoder_allocate( VALUE klass )
72
+ {
73
+ t_pg_composite_coder *this;
74
+ VALUE self = Data_Make_Struct( klass, t_pg_composite_coder, NULL, -1, this );
75
+ pg_coder_init_encoder( self );
76
+ this->elem = NULL;
77
+ this->needs_quotation = 1;
78
+ this->delimiter = ',';
79
+ rb_iv_set( self, "@elements_type", Qnil );
80
+ return self;
81
+ }
82
+
83
+ static VALUE
84
+ pg_simple_decoder_allocate( VALUE klass )
85
+ {
86
+ t_pg_coder *this;
87
+ VALUE self = Data_Make_Struct( klass, t_pg_coder, NULL, -1, this );
88
+ pg_coder_init_decoder( self );
89
+ return self;
90
+ }
91
+
92
+ static VALUE
93
+ pg_composite_decoder_allocate( VALUE klass )
94
+ {
95
+ t_pg_composite_coder *this;
96
+ VALUE self = Data_Make_Struct( klass, t_pg_composite_coder, NULL, -1, this );
97
+ pg_coder_init_decoder( self );
98
+ this->elem = NULL;
99
+ this->needs_quotation = 1;
100
+ this->delimiter = ',';
101
+ rb_iv_set( self, "@elements_type", Qnil );
102
+ return self;
103
+ }
104
+
105
+ /*
106
+ * call-seq:
107
+ * coder.encode( value )
108
+ *
109
+ * Encodes the given Ruby object into string representation, without
110
+ * sending data to/from the database server.
111
+ *
112
+ */
113
+ static VALUE
114
+ pg_coder_encode(VALUE self, VALUE value)
115
+ {
116
+ VALUE res;
117
+ VALUE intermediate;
118
+ int len, len2;
119
+ t_pg_coder *this = DATA_PTR(self);
120
+
121
+ if( !this->enc_func ){
122
+ rb_raise(rb_eRuntimeError, "no encoder function defined");
123
+ }
124
+
125
+ len = this->enc_func( this, value, NULL, &intermediate );
126
+
127
+ if( len == -1 ){
128
+ /* The intermediate value is a String that can be used directly. */
129
+ OBJ_INFECT(intermediate, value);
130
+ return intermediate;
131
+ }
132
+
133
+ res = rb_str_new(NULL, len);
134
+ len2 = this->enc_func( this, value, RSTRING_PTR(res), &intermediate);
135
+ if( len < len2 ){
136
+ rb_bug("%s: result length of first encoder run (%i) is less than second run (%i)",
137
+ rb_obj_classname( self ), len, len2 );
138
+ }
139
+ rb_str_set_len( res, len2 );
140
+ OBJ_INFECT(res, value);
141
+
142
+ RB_GC_GUARD(intermediate);
143
+
144
+ return res;
145
+ }
146
+
147
+ /*
148
+ * call-seq:
149
+ * coder.decode( string, tuple=nil, field=nil )
150
+ *
151
+ * Decodes the given string representation into a Ruby object, without
152
+ * sending data to/from the database server.
153
+ *
154
+ */
155
+ static VALUE
156
+ pg_coder_decode(int argc, VALUE *argv, VALUE self)
157
+ {
158
+ char *val;
159
+ VALUE tuple = -1;
160
+ VALUE field = -1;
161
+ VALUE res;
162
+ t_pg_coder *this = DATA_PTR(self);
163
+
164
+ if(argc < 1 || argc > 3){
165
+ rb_raise(rb_eArgError, "wrong number of arguments (%i for 1..3)", argc);
166
+ }else if(argc >= 3){
167
+ tuple = NUM2INT(argv[1]);
168
+ field = NUM2INT(argv[2]);
169
+ }
170
+
171
+ val = StringValuePtr(argv[0]);
172
+ if( !this->dec_func ){
173
+ rb_raise(rb_eRuntimeError, "no decoder function defined");
174
+ }
175
+
176
+ res = this->dec_func(this, val, RSTRING_LEN(argv[0]), tuple, field, ENCODING_GET(argv[0]));
177
+ OBJ_INFECT(res, argv[0]);
178
+
179
+ return res;
180
+ }
181
+
182
+ /*
183
+ * call-seq:
184
+ * coder.oid = Integer
185
+ *
186
+ * Specifies the type OID that is sent alongside with an encoded
187
+ * query parameter value.
188
+ *
189
+ * The default is +0+.
190
+ */
191
+ static VALUE
192
+ pg_coder_oid_set(VALUE self, VALUE oid)
193
+ {
194
+ t_pg_coder *this = DATA_PTR(self);
195
+ this->oid = NUM2UINT(oid);
196
+ return oid;
197
+ }
198
+
199
+ /*
200
+ * call-seq:
201
+ * coder.oid -> Integer
202
+ *
203
+ * The type OID that is sent alongside with an encoded
204
+ * query parameter value.
205
+ */
206
+ static VALUE
207
+ pg_coder_oid_get(VALUE self)
208
+ {
209
+ t_pg_coder *this = DATA_PTR(self);
210
+ return UINT2NUM(this->oid);
211
+ }
212
+
213
+ /*
214
+ * call-seq:
215
+ * coder.format = Integer
216
+ *
217
+ * Specifies the format code that is sent alongside with an encoded
218
+ * query parameter value.
219
+ *
220
+ * The default is +0+.
221
+ */
222
+ static VALUE
223
+ pg_coder_format_set(VALUE self, VALUE format)
224
+ {
225
+ t_pg_coder *this = DATA_PTR(self);
226
+ this->format = NUM2INT(format);
227
+ return format;
228
+ }
229
+
230
+ /*
231
+ * call-seq:
232
+ * coder.format -> Integer
233
+ *
234
+ * The format code that is sent alongside with an encoded
235
+ * query parameter value.
236
+ */
237
+ static VALUE
238
+ pg_coder_format_get(VALUE self)
239
+ {
240
+ t_pg_coder *this = DATA_PTR(self);
241
+ return INT2NUM(this->format);
242
+ }
243
+
244
+ /*
245
+ * call-seq:
246
+ * coder.needs_quotation = Boolean
247
+ *
248
+ * Specifies whether the assigned #elements_type requires quotation marks to
249
+ * be transferred safely. Encoding with #needs_quotation=false is somewhat
250
+ * faster.
251
+ *
252
+ * The default is +true+. This option is ignored for decoding of values.
253
+ */
254
+ static VALUE
255
+ pg_coder_needs_quotation_set(VALUE self, VALUE needs_quotation)
256
+ {
257
+ t_pg_composite_coder *this = DATA_PTR(self);
258
+ this->needs_quotation = RTEST(needs_quotation);
259
+ return needs_quotation;
260
+ }
261
+
262
+ /*
263
+ * call-seq:
264
+ * coder.needs_quotation -> Boolean
265
+ *
266
+ * Specifies whether the assigned #elements_type requires quotation marks to
267
+ * be transferred safely.
268
+ */
269
+ static VALUE
270
+ pg_coder_needs_quotation_get(VALUE self)
271
+ {
272
+ t_pg_composite_coder *this = DATA_PTR(self);
273
+ return this->needs_quotation ? Qtrue : Qfalse;
274
+ }
275
+
276
+ /*
277
+ * call-seq:
278
+ * coder.delimiter = String
279
+ *
280
+ * Specifies the character that separates values within the composite type.
281
+ * The default is a comma.
282
+ * This must be a single one-byte character.
283
+ */
284
+ static VALUE
285
+ pg_coder_delimiter_set(VALUE self, VALUE delimiter)
286
+ {
287
+ t_pg_composite_coder *this = DATA_PTR(self);
288
+ StringValue(delimiter);
289
+ if(RSTRING_LEN(delimiter) != 1)
290
+ rb_raise( rb_eArgError, "delimiter size must be one byte");
291
+ this->delimiter = *RSTRING_PTR(delimiter);
292
+ return delimiter;
293
+ }
294
+
295
+ /*
296
+ * call-seq:
297
+ * coder.delimiter -> String
298
+ *
299
+ * The character that separates values within the composite type.
300
+ */
301
+ static VALUE
302
+ pg_coder_delimiter_get(VALUE self)
303
+ {
304
+ t_pg_composite_coder *this = DATA_PTR(self);
305
+ return rb_str_new(&this->delimiter, 1);
306
+ }
307
+
308
+ /*
309
+ * call-seq:
310
+ * coder.elements_type = coder
311
+ *
312
+ * Specifies the PG::Coder object that is used to encode or decode
313
+ * the single elementes of this composite type.
314
+ *
315
+ * If set to +nil+ all values are encoded and decoded as String objects.
316
+ */
317
+ static VALUE
318
+ pg_coder_elements_type_set(VALUE self, VALUE elem_type)
319
+ {
320
+ t_pg_composite_coder *this = DATA_PTR( self );
321
+
322
+ if ( NIL_P(elem_type) ){
323
+ this->elem = NULL;
324
+ } else if ( rb_obj_is_kind_of(elem_type, rb_cPG_Coder) ){
325
+ this->elem = DATA_PTR( elem_type );
326
+ } else {
327
+ rb_raise( rb_eTypeError, "wrong elements type %s (expected some kind of PG::Coder)",
328
+ rb_obj_classname( elem_type ) );
329
+ }
330
+
331
+ rb_iv_set( self, "@elements_type", elem_type );
332
+ return elem_type;
333
+ }
334
+
335
+ void
336
+ pg_define_coder( const char *name, void *func, VALUE base_klass, VALUE nsp )
337
+ {
338
+ VALUE cfunc_obj = Data_Wrap_Struct( rb_cObject, NULL, NULL, func );
339
+ VALUE coder_klass = rb_define_class_under( nsp, name, base_klass );
340
+ rb_define_const( coder_klass, "CFUNC", cfunc_obj );
341
+
342
+ RB_GC_GUARD(cfunc_obj);
343
+ }
344
+
345
+
346
+ static int
347
+ pg_text_enc_in_ruby(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate)
348
+ {
349
+ *intermediate = rb_funcall( conv->coder_obj, s_id_encode, 1, value );
350
+ StringValue( *intermediate );
351
+ return -1;
352
+ }
353
+
354
+ t_pg_coder_enc_func
355
+ pg_coder_enc_func(t_pg_coder *this)
356
+ {
357
+ if( this ){
358
+ if( this->enc_func ){
359
+ return this->enc_func;
360
+ }else{
361
+ return pg_text_enc_in_ruby;
362
+ }
363
+ }else{
364
+ /* no element encoder defined -> use std to_str conversion */
365
+ return pg_coder_enc_to_s;
366
+ }
367
+ }
368
+
369
+ static VALUE
370
+ pg_text_dec_in_ruby(t_pg_coder *this, char *val, int len, int tuple, int field, int enc_idx)
371
+ {
372
+ VALUE string = pg_text_dec_string(this, val, len, tuple, field, enc_idx);
373
+ return rb_funcall( this->coder_obj, s_id_decode, 3, string, INT2NUM(tuple), INT2NUM(field) );
374
+ }
375
+
376
+ static VALUE
377
+ pg_bin_dec_in_ruby(t_pg_coder *this, char *val, int len, int tuple, int field, int enc_idx)
378
+ {
379
+ VALUE string = pg_bin_dec_bytea(this, val, len, tuple, field, enc_idx);
380
+ return rb_funcall( this->coder_obj, s_id_decode, 3, string, INT2NUM(tuple), INT2NUM(field) );
381
+ }
382
+
383
+ t_pg_coder_dec_func
384
+ pg_coder_dec_func(t_pg_coder *this, int binary)
385
+ {
386
+ if( this ){
387
+ if( this->dec_func ){
388
+ return this->dec_func;
389
+ }else{
390
+ return binary ? pg_bin_dec_in_ruby : pg_text_dec_in_ruby;
391
+ }
392
+ }else{
393
+ /* no element decoder defined -> use std String conversion */
394
+ return binary ? pg_bin_dec_bytea : pg_text_dec_string;
395
+ }
396
+ }
397
+
398
+
399
+ void
400
+ init_pg_coder()
401
+ {
402
+ s_id_encode = rb_intern("encode");
403
+ s_id_decode = rb_intern("decode");
404
+ s_id_CFUNC = rb_intern("CFUNC");
405
+
406
+ /* Document-class: PG::Coder < Object
407
+ *
408
+ * This is the base class for all type cast encoder and decoder classes.
409
+ */
410
+ rb_cPG_Coder = rb_define_class_under( rb_mPG, "Coder", rb_cObject );
411
+ rb_define_alloc_func( rb_cPG_Coder, pg_coder_allocate );
412
+ rb_define_method( rb_cPG_Coder, "oid=", pg_coder_oid_set, 1 );
413
+ rb_define_method( rb_cPG_Coder, "oid", pg_coder_oid_get, 0 );
414
+ rb_define_method( rb_cPG_Coder, "format=", pg_coder_format_set, 1 );
415
+ rb_define_method( rb_cPG_Coder, "format", pg_coder_format_get, 0 );
416
+ /*
417
+ * Name of the coder or the corresponding data type.
418
+ *
419
+ * This accessor is only used in PG::Coder#inspect .
420
+ */
421
+ rb_define_attr( rb_cPG_Coder, "name", 1, 1 );
422
+ rb_define_method( rb_cPG_Coder, "encode", pg_coder_encode, 1 );
423
+ rb_define_method( rb_cPG_Coder, "decode", pg_coder_decode, -1 );
424
+
425
+ /* Document-class: PG::SimpleCoder < PG::Coder */
426
+ rb_cPG_SimpleCoder = rb_define_class_under( rb_mPG, "SimpleCoder", rb_cPG_Coder );
427
+
428
+ /* Document-class: PG::SimpleEncoder < PG::SimpleCoder */
429
+ rb_cPG_SimpleEncoder = rb_define_class_under( rb_mPG, "SimpleEncoder", rb_cPG_SimpleCoder );
430
+ rb_define_alloc_func( rb_cPG_SimpleEncoder, pg_simple_encoder_allocate );
431
+ /* Document-class: PG::SimpleDecoder < PG::SimpleCoder */
432
+ rb_cPG_SimpleDecoder = rb_define_class_under( rb_mPG, "SimpleDecoder", rb_cPG_SimpleCoder );
433
+ rb_define_alloc_func( rb_cPG_SimpleDecoder, pg_simple_decoder_allocate );
434
+
435
+ /* Document-class: PG::CompositeCoder < PG::Coder
436
+ *
437
+ * This is the base class for all type cast classes of PostgreSQL types,
438
+ * that are made up of some sub type.
439
+ */
440
+ rb_cPG_CompositeCoder = rb_define_class_under( rb_mPG, "CompositeCoder", rb_cPG_Coder );
441
+ rb_define_method( rb_cPG_CompositeCoder, "elements_type=", pg_coder_elements_type_set, 1 );
442
+ rb_define_attr( rb_cPG_CompositeCoder, "elements_type", 1, 0 );
443
+ rb_define_method( rb_cPG_CompositeCoder, "needs_quotation=", pg_coder_needs_quotation_set, 1 );
444
+ rb_define_method( rb_cPG_CompositeCoder, "needs_quotation?", pg_coder_needs_quotation_get, 0 );
445
+ rb_define_method( rb_cPG_CompositeCoder, "delimiter=", pg_coder_delimiter_set, 1 );
446
+ rb_define_method( rb_cPG_CompositeCoder, "delimiter", pg_coder_delimiter_get, 0 );
447
+
448
+ /* Document-class: PG::CompositeEncoder < PG::CompositeCoder */
449
+ rb_cPG_CompositeEncoder = rb_define_class_under( rb_mPG, "CompositeEncoder", rb_cPG_CompositeCoder );
450
+ rb_define_alloc_func( rb_cPG_CompositeEncoder, pg_composite_encoder_allocate );
451
+ /* Document-class: PG::CompositeDecoder < PG::CompositeCoder */
452
+ rb_cPG_CompositeDecoder = rb_define_class_under( rb_mPG, "CompositeDecoder", rb_cPG_CompositeCoder );
453
+ rb_define_alloc_func( rb_cPG_CompositeDecoder, pg_composite_decoder_allocate );
454
+ }