pg 0.17.1-x86-mingw32 → 0.18.0.pre20141017160319-x86-mingw32

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