pg 0.17.1 → 0.18.4

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