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.h CHANGED
@@ -24,7 +24,6 @@
24
24
  #if defined(HAVE_RUBY_ENCODING_H) && HAVE_RUBY_ENCODING_H
25
25
  # include "ruby/encoding.h"
26
26
  # define M17N_SUPPORTED
27
- # define ASSOCIATE_INDEX( obj, index_holder ) rb_enc_associate_index((obj), pg_enc_get_index((index_holder)))
28
27
  # ifdef HAVE_RB_ENCDB_ALIAS
29
28
  extern int rb_encdb_alias(const char *, const char *);
30
29
  # define ENC_ALIAS(name, orig) rb_encdb_alias((name), (orig))
@@ -35,8 +34,28 @@
35
34
  extern int rb_enc_alias(const char *alias, const char *orig); /* declaration missing in Ruby 1.9.1 */
36
35
  # define ENC_ALIAS(name, orig) rb_enc_alias((name), (orig))
37
36
  # endif
37
+
38
+
39
+ # if !defined(ENCODING_SET_INLINED)
40
+ /* Rubinius doesn't define ENCODING_SET_INLINED, so we fall back to the more
41
+ * portable version.
42
+ */
43
+ # define PG_ENCODING_SET_NOCHECK(obj,i) \
44
+ do { \
45
+ rb_enc_set_index((obj), (i)); \
46
+ } while(0)
47
+ # else
48
+ # define PG_ENCODING_SET_NOCHECK(obj,i) \
49
+ do { \
50
+ if ((i) < ENCODING_INLINE_MAX) \
51
+ ENCODING_SET_INLINED((obj), (i)); \
52
+ else \
53
+ rb_enc_set_index((obj), (i)); \
54
+ } while(0)
55
+ # endif
56
+
38
57
  #else
39
- # define ASSOCIATE_INDEX( obj, index_holder ) /* nothing */
58
+ # define PG_ENCODING_SET_NOCHECK(obj,i) /* nothing */
40
59
  #endif
41
60
 
42
61
  #if RUBY_VM != 1
@@ -66,6 +85,11 @@
66
85
  # include "ruby/io.h"
67
86
  #endif
68
87
 
88
+ #ifdef RUBINIUS
89
+ /* Workaround for wrong FIXNUM_MAX definition */
90
+ typedef intptr_t native_int;
91
+ #endif
92
+
69
93
  #ifndef timeradd
70
94
  #define timeradd(a, b, result) \
71
95
  do { \
@@ -97,10 +121,101 @@
97
121
 
98
122
  #if defined(_WIN32)
99
123
  # include <fcntl.h>
100
- __declspec(dllexport)
101
124
  typedef long suseconds_t;
102
125
  #endif
103
126
 
127
+ /* The data behind each PG::Connection object */
128
+ typedef struct {
129
+ PGconn *pgconn;
130
+
131
+ /* Cached IO object for the socket descriptor */
132
+ VALUE socket_io;
133
+ /* Proc object that receives notices as PG::Result objects */
134
+ VALUE notice_receiver;
135
+ /* Proc object that receives notices as String objects */
136
+ VALUE notice_processor;
137
+ /* Kind of PG::TypeMap object for casting query params */
138
+ VALUE type_map_for_queries;
139
+ /* Kind of PG::TypeMap object for casting result values */
140
+ VALUE type_map_for_results;
141
+ /* IO object internally used for the trace stream */
142
+ VALUE trace_stream;
143
+ /* Cached Encoding object */
144
+ VALUE external_encoding;
145
+ /* Kind of PG::Coder object for casting ruby values to COPY rows */
146
+ VALUE encoder_for_put_copy_data;
147
+ /* Kind of PG::Coder object for casting COPY rows to ruby values */
148
+ VALUE decoder_for_get_copy_data;
149
+
150
+ } t_pg_connection;
151
+
152
+ typedef struct pg_coder t_pg_coder;
153
+ typedef struct pg_typemap t_typemap;
154
+
155
+ /* The data behind each PG::Result object */
156
+ typedef struct {
157
+ PGresult *pgresult;
158
+
159
+ /* The connection object used to build this result */
160
+ VALUE connection;
161
+
162
+ /* The TypeMap used to type cast result values */
163
+ VALUE typemap;
164
+
165
+ /* Pointer to the typemap object data. This is assumed to be
166
+ * always valid.
167
+ */
168
+ t_typemap *p_typemap;
169
+
170
+ /* 0 = PGresult is cleared by PG::Result#clear or by the GC
171
+ * 1 = PGresult is cleared internally by libpq
172
+ */
173
+ int autoclear;
174
+ } t_pg_result;
175
+
176
+
177
+ typedef int (* t_pg_coder_enc_func)(t_pg_coder *, VALUE, char *, VALUE *);
178
+ typedef VALUE (* t_pg_coder_dec_func)(t_pg_coder *, char *, int, int, int, int);
179
+ typedef VALUE (* t_pg_fit_to_result)(VALUE, VALUE);
180
+ typedef VALUE (* t_pg_fit_to_query)(VALUE, VALUE);
181
+ typedef int (* t_pg_fit_to_copy_get)(VALUE);
182
+ typedef VALUE (* t_pg_typecast_result)(VALUE, int, int);
183
+ typedef t_pg_coder *(* t_pg_typecast_query_param)(VALUE, VALUE, int);
184
+ typedef VALUE (* t_pg_typecast_copy_get)( t_typemap *, VALUE, int, int, int );
185
+
186
+ struct pg_coder {
187
+ t_pg_coder_enc_func enc_func;
188
+ t_pg_coder_dec_func dec_func;
189
+ VALUE coder_obj;
190
+ Oid oid;
191
+ int format;
192
+ };
193
+
194
+ typedef struct {
195
+ t_pg_coder comp;
196
+ t_pg_coder *elem;
197
+ int needs_quotation;
198
+ char delimiter;
199
+ } t_pg_composite_coder;
200
+
201
+ struct pg_typemap {
202
+ t_pg_fit_to_result fit_to_result;
203
+ t_pg_fit_to_query fit_to_query;
204
+ t_pg_fit_to_copy_get fit_to_copy_get;
205
+ t_pg_typecast_result typecast_result_value;
206
+ t_pg_typecast_query_param typecast_query_param;
207
+ t_pg_typecast_copy_get typecast_copy_get;
208
+ };
209
+
210
+ typedef struct {
211
+ t_typemap typemap;
212
+ int nfields;
213
+ struct pg_tmbc_converter {
214
+ t_pg_coder *cconv;
215
+ } convs[0];
216
+ } t_tmbc;
217
+
218
+
104
219
  #include "gvl_wrappers.h"
105
220
 
106
221
  /***************************************************************************
@@ -116,7 +231,23 @@ extern VALUE rb_mPGconstants;
116
231
  extern VALUE rb_cPGconn;
117
232
  extern VALUE rb_cPGresult;
118
233
  extern VALUE rb_hErrors;
234
+ extern VALUE rb_cTypeMap;
235
+ extern VALUE rb_cTypeMapAllStrings;
236
+ extern VALUE rb_cPG_Coder;
237
+ extern VALUE rb_cPG_SimpleEncoder;
238
+ extern VALUE rb_cPG_SimpleDecoder;
239
+ extern VALUE rb_cPG_CompositeEncoder;
240
+ extern VALUE rb_cPG_CompositeDecoder;
241
+ extern VALUE rb_cPG_CopyCoder;
242
+ extern VALUE rb_cPG_CopyEncoder;
243
+ extern VALUE rb_cPG_CopyDecoder;
244
+ extern VALUE rb_mPG_TextEncoder;
245
+ extern VALUE rb_mPG_TextDecoder;
246
+ extern VALUE rb_mPG_BinaryEncoder;
247
+ extern VALUE rb_mPG_BinaryDecoder;
248
+ extern const t_typemap pg_tmbc_default_typemap;
119
249
 
250
+ extern VALUE pg_default_typemap;
120
251
 
121
252
  /***************************************************************************
122
253
  * MACROS
@@ -134,19 +265,76 @@ void Init_pg_ext _(( void ));
134
265
  void init_pg_connection _(( void ));
135
266
  void init_pg_result _(( void ));
136
267
  void init_pg_errors _(( void ));
137
- VALUE lookup_error_class _(( const char *sqlstate ));
268
+ void init_pg_type_map _(( void ));
269
+ void init_pg_type_map_all_strings _(( void ));
270
+ void init_pg_type_map_by_column _(( void ));
271
+ void init_pg_type_map_by_mri_type _(( void ));
272
+ void init_pg_type_map_by_oid _(( void ));
273
+ void init_pg_coder _(( void ));
274
+ void init_pg_copycoder _(( void ));
275
+ void init_pg_text_encoder _(( void ));
276
+ void init_pg_text_decoder _(( void ));
277
+ void init_pg_binary_encoder _(( void ));
278
+ void init_pg_binary_decoder _(( void ));
279
+ VALUE lookup_error_class _(( const char * ));
280
+ VALUE pg_bin_dec_bytea _(( t_pg_coder*, char *, int, int, int, int ));
281
+ VALUE pg_text_dec_string _(( t_pg_coder*, char *, int, int, int, int ));
282
+ int pg_coder_enc_to_s _(( t_pg_coder*, VALUE, char *, VALUE *));
283
+ t_pg_coder_enc_func pg_coder_enc_func _(( t_pg_coder* ));
284
+ t_pg_coder_dec_func pg_coder_dec_func _(( t_pg_coder*, int ));
285
+ void pg_define_coder _(( const char *, void *, VALUE, VALUE ));
286
+ VALUE pg_obj_to_i _(( VALUE ));
287
+ VALUE pg_tmbc_allocate _(( void ));
288
+ void pg_coder_init_encoder _(( VALUE ));
289
+ void pg_coder_init_decoder _(( VALUE ));
290
+ char *pg_rb_str_ensure_capa _(( VALUE, long, char *, char ** ));
138
291
 
139
- PGconn *pg_get_pgconn _(( VALUE ));
292
+ #define PG_RB_STR_ENSURE_CAPA( str, expand_len, curr_ptr, end_ptr ) \
293
+ do { \
294
+ if( (curr_ptr) + (expand_len) >= (end_ptr) ) \
295
+ (curr_ptr) = pg_rb_str_ensure_capa( (str), (expand_len), (curr_ptr), &(end_ptr) ); \
296
+ } while(0);
297
+
298
+ #define PG_RB_STR_NEW( str, curr_ptr, end_ptr ) ( \
299
+ (str) = rb_str_new( NULL, 0 ), \
300
+ (curr_ptr) = (end_ptr) = RSTRING_PTR(str) \
301
+ )
302
+
303
+ #define PG_RB_TAINTED_STR_NEW( str, curr_ptr, end_ptr ) ( \
304
+ (str) = rb_tainted_str_new( NULL, 0 ), \
305
+ (curr_ptr) = (end_ptr) = RSTRING_PTR(str) \
306
+ )
307
+
308
+ VALUE pg_typemap_fit_to_result _(( VALUE, VALUE ));
309
+ VALUE pg_typemap_fit_to_query _(( VALUE, VALUE ));
310
+ int pg_typemap_fit_to_copy_get _(( VALUE ));
311
+ VALUE pg_typemap_result_value _(( VALUE, int, int ));
312
+ t_pg_coder *pg_typemap_typecast_query_param _(( VALUE, VALUE, int ));
313
+ VALUE pg_typemap_typecast_copy_get _(( t_typemap *, VALUE, int, int, int ));
314
+
315
+ PGconn *pg_get_pgconn _(( VALUE ));
316
+ t_pg_connection *pg_get_connection _(( VALUE ));
140
317
 
141
318
  VALUE pg_new_result _(( PGresult *, VALUE ));
319
+ VALUE pg_new_result_autoclear _(( PGresult *, VALUE ));
320
+ PGresult* pgresult_get _(( VALUE ));
142
321
  VALUE pg_result_check _(( VALUE ));
143
322
  VALUE pg_result_clear _(( VALUE ));
144
323
 
324
+ /*
325
+ * Fetch the data pointer for the result object
326
+ */
327
+ static inline t_pg_result *
328
+ pgresult_get_this( VALUE self )
329
+ {
330
+ return DATA_PTR(self);
331
+ }
332
+
333
+
145
334
  #ifdef M17N_SUPPORTED
146
335
  rb_encoding * pg_get_pg_encoding_as_rb_encoding _(( int ));
147
336
  rb_encoding * pg_get_pg_encname_as_rb_encoding _(( const char * ));
148
337
  const char * pg_get_rb_encoding_as_pg_encoding _(( rb_encoding * ));
149
- int pg_enc_get_index _(( VALUE ));
150
338
  rb_encoding *pg_conn_enc_get _(( PGconn * ));
151
339
  #endif /* M17N_SUPPORTED */
152
340
 
@@ -0,0 +1,160 @@
1
+ /*
2
+ * pg_column_map.c - PG::ColumnMap class extension
3
+ * $Id: pg_binary_decoder.c,v f786006b25ff 2014/10/12 17:40:31 lars $
4
+ *
5
+ */
6
+
7
+ #include "pg.h"
8
+ #include "util.h"
9
+ #include <inttypes.h>
10
+
11
+ VALUE rb_mPG_BinaryDecoder;
12
+
13
+
14
+ /*
15
+ * Document-class: PG::BinaryDecoder::Boolean < PG::SimpleDecoder
16
+ *
17
+ * This is a decoder class for conversion of PostgreSQL binary bool type
18
+ * to Ruby true or false objects.
19
+ *
20
+ */
21
+ static VALUE
22
+ pg_bin_dec_boolean(t_pg_coder *conv, char *val, int len, int tuple, int field, int enc_idx)
23
+ {
24
+ if (len < 1) {
25
+ rb_raise( rb_eTypeError, "wrong data for binary boolean converter in tuple %d field %d", tuple, field);
26
+ }
27
+ return *val == 0 ? Qfalse : Qtrue;
28
+ }
29
+
30
+ /*
31
+ * Document-class: PG::BinaryDecoder::Integer < PG::SimpleDecoder
32
+ *
33
+ * This is a decoder class for conversion of PostgreSQL binary int2, int4 and int8 types
34
+ * to Ruby Integer objects.
35
+ *
36
+ */
37
+ static VALUE
38
+ pg_bin_dec_integer(t_pg_coder *conv, char *val, int len, int tuple, int field, int enc_idx)
39
+ {
40
+ switch( len ){
41
+ case 2:
42
+ return INT2NUM(read_nbo16(val));
43
+ case 4:
44
+ return LONG2NUM(read_nbo32(val));
45
+ case 8:
46
+ return LL2NUM(read_nbo64(val));
47
+ default:
48
+ rb_raise( rb_eTypeError, "wrong data for binary integer converter in tuple %d field %d length %d", tuple, field, len);
49
+ }
50
+ }
51
+
52
+ /*
53
+ * Document-class: PG::BinaryDecoder::Float < PG::SimpleDecoder
54
+ *
55
+ * This is a decoder class for conversion of PostgreSQL binary float4 and float8 types
56
+ * to Ruby Float objects.
57
+ *
58
+ */
59
+ static VALUE
60
+ pg_bin_dec_float(t_pg_coder *conv, char *val, int len, int tuple, int field, int enc_idx)
61
+ {
62
+ union {
63
+ float f;
64
+ int32_t i;
65
+ } swap4;
66
+ union {
67
+ double f;
68
+ int64_t i;
69
+ } swap8;
70
+
71
+ switch( len ){
72
+ case 4:
73
+ swap4.i = read_nbo32(val);
74
+ return rb_float_new(swap4.f);
75
+ case 8:
76
+ swap8.i = read_nbo64(val);
77
+ return rb_float_new(swap8.f);
78
+ default:
79
+ rb_raise( rb_eTypeError, "wrong data for BinaryFloat converter in tuple %d field %d length %d", tuple, field, len);
80
+ }
81
+ }
82
+
83
+ /*
84
+ * Document-class: PG::BinaryDecoder::Bytea < PG::SimpleDecoder
85
+ *
86
+ * This is a decoder class for conversion of PostgreSQL binary data (bytea)
87
+ * to binary Ruby String objects or some other Ruby object, if a #elements_type
88
+ * decoder was defined.
89
+ *
90
+ */
91
+ VALUE
92
+ pg_bin_dec_bytea(t_pg_coder *conv, char *val, int len, int tuple, int field, int enc_idx)
93
+ {
94
+ VALUE ret;
95
+ ret = rb_tainted_str_new( val, len );
96
+ PG_ENCODING_SET_NOCHECK( ret, rb_ascii8bit_encindex() );
97
+ return ret;
98
+ }
99
+
100
+ /*
101
+ * Document-class: PG::BinaryDecoder::ToBase64 < PG::CompositeDecoder
102
+ *
103
+ * This is a decoder class for conversion of binary (bytea) to base64 data.
104
+ *
105
+ */
106
+ static VALUE
107
+ pg_bin_dec_to_base64(t_pg_coder *conv, char *val, int len, int tuple, int field, int enc_idx)
108
+ {
109
+ t_pg_composite_coder *this = (t_pg_composite_coder *)conv;
110
+ t_pg_coder_dec_func dec_func = pg_coder_dec_func(this->elem, this->comp.format);
111
+ int encoded_len = BASE64_ENCODED_SIZE(len);
112
+ /* create a buffer of the encoded length */
113
+ VALUE out_value = rb_tainted_str_new(NULL, encoded_len);
114
+
115
+ base64_encode( RSTRING_PTR(out_value), val, len );
116
+
117
+ /* Is it a pure String conversion? Then we can directly send out_value to the user. */
118
+ if( this->comp.format == 0 && dec_func == pg_text_dec_string ){
119
+ PG_ENCODING_SET_NOCHECK( out_value, enc_idx );
120
+ return out_value;
121
+ }
122
+ if( this->comp.format == 1 && dec_func == pg_bin_dec_bytea ){
123
+ PG_ENCODING_SET_NOCHECK( out_value, rb_ascii8bit_encindex() );
124
+ return out_value;
125
+ }
126
+ out_value = dec_func(this->elem, RSTRING_PTR(out_value), encoded_len, tuple, field, enc_idx);
127
+
128
+ return out_value;
129
+ }
130
+
131
+ /*
132
+ * Document-class: PG::BinaryDecoder::String < PG::SimpleDecoder
133
+ *
134
+ * This is a decoder class for conversion of PostgreSQL text output to
135
+ * to Ruby String object. The output value will have the character encoding
136
+ * set with PG::Connection#internal_encoding= .
137
+ *
138
+ */
139
+
140
+ void
141
+ init_pg_binary_decoder()
142
+ {
143
+ /* This module encapsulates all decoder classes with binary input format */
144
+ rb_mPG_BinaryDecoder = rb_define_module_under( rb_mPG, "BinaryDecoder" );
145
+
146
+ /* Make RDoc aware of the decoder classes... */
147
+ /* dummy = rb_define_class_under( rb_mPG_BinaryDecoder, "Boolean", rb_cPG_SimpleDecoder ); */
148
+ pg_define_coder( "Boolean", pg_bin_dec_boolean, rb_cPG_SimpleDecoder, rb_mPG_BinaryDecoder );
149
+ /* dummy = rb_define_class_under( rb_mPG_BinaryDecoder, "Integer", rb_cPG_SimpleDecoder ); */
150
+ pg_define_coder( "Integer", pg_bin_dec_integer, rb_cPG_SimpleDecoder, rb_mPG_BinaryDecoder );
151
+ /* dummy = rb_define_class_under( rb_mPG_BinaryDecoder, "Float", rb_cPG_SimpleDecoder ); */
152
+ pg_define_coder( "Float", pg_bin_dec_float, rb_cPG_SimpleDecoder, rb_mPG_BinaryDecoder );
153
+ /* dummy = rb_define_class_under( rb_mPG_BinaryDecoder, "String", rb_cPG_SimpleDecoder ); */
154
+ pg_define_coder( "String", pg_text_dec_string, rb_cPG_SimpleDecoder, rb_mPG_BinaryDecoder );
155
+ /* dummy = rb_define_class_under( rb_mPG_BinaryDecoder, "Bytea", rb_cPG_SimpleDecoder ); */
156
+ pg_define_coder( "Bytea", pg_bin_dec_bytea, rb_cPG_SimpleDecoder, rb_mPG_BinaryDecoder );
157
+
158
+ /* dummy = rb_define_class_under( rb_mPG_BinaryDecoder, "ToBase64", rb_cPG_CompositeDecoder ); */
159
+ pg_define_coder( "ToBase64", pg_bin_dec_to_base64, rb_cPG_CompositeDecoder, rb_mPG_BinaryDecoder );
160
+ }
@@ -0,0 +1,160 @@
1
+ /*
2
+ * pg_column_map.c - PG::ColumnMap class extension
3
+ * $Id: pg_binary_encoder.c,v ac23631c96d9 2014/10/14 11:50:21 lars $
4
+ *
5
+ */
6
+
7
+ #include "pg.h"
8
+ #include "util.h"
9
+ #include <inttypes.h>
10
+
11
+ VALUE rb_mPG_BinaryEncoder;
12
+
13
+
14
+ /*
15
+ * Document-class: PG::BinaryEncoder::Boolean < PG::SimpleEncoder
16
+ *
17
+ * This is the encoder class for the PostgreSQL boolean type.
18
+ *
19
+ * It accepts true and false. Other values will raise an exception.
20
+ *
21
+ */
22
+ static int
23
+ pg_bin_enc_boolean(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate)
24
+ {
25
+ char bool;
26
+ switch(value){
27
+ case Qtrue : bool = 1; break;
28
+ case Qfalse : bool = 0; break;
29
+ default :
30
+ rb_raise( rb_eTypeError, "wrong data for binary boolean converter" );
31
+ }
32
+ if(out) *out = bool;
33
+ return 1;
34
+ }
35
+
36
+ /*
37
+ * Document-class: PG::BinaryEncoder::Int2 < PG::SimpleEncoder
38
+ *
39
+ * This is the encoder class for the PostgreSQL int2 type.
40
+ *
41
+ * Non-Number values are expected to have method +to_i+ defined.
42
+ *
43
+ */
44
+ static int
45
+ pg_bin_enc_int2(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate)
46
+ {
47
+ if(out){
48
+ write_nbo16(NUM2INT(*intermediate), out);
49
+ }else{
50
+ *intermediate = pg_obj_to_i(value);
51
+ }
52
+ return 2;
53
+ }
54
+
55
+ /*
56
+ * Document-class: PG::BinaryEncoder::Int2 < PG::SimpleEncoder
57
+ *
58
+ * This is the encoder class for the PostgreSQL int4 type.
59
+ *
60
+ * Non-Number values are expected to have method +to_i+ defined.
61
+ *
62
+ */
63
+ static int
64
+ pg_bin_enc_int4(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate)
65
+ {
66
+ if(out){
67
+ write_nbo32(NUM2LONG(*intermediate), out);
68
+ }else{
69
+ *intermediate = pg_obj_to_i(value);
70
+ }
71
+ return 4;
72
+ }
73
+
74
+ /*
75
+ * Document-class: PG::BinaryEncoder::Int2 < PG::SimpleEncoder
76
+ *
77
+ * This is the encoder class for the PostgreSQL int8 type.
78
+ *
79
+ * Non-Number values are expected to have method +to_i+ defined.
80
+ *
81
+ */
82
+ static int
83
+ pg_bin_enc_int8(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate)
84
+ {
85
+ if(out){
86
+ write_nbo64(NUM2LL(*intermediate), out);
87
+ }else{
88
+ *intermediate = pg_obj_to_i(value);
89
+ }
90
+ return 8;
91
+ }
92
+
93
+ /*
94
+ * Document-class: PG::BinaryEncoder::FromBase64 < PG::CompositeEncoder
95
+ *
96
+ * This is an encoder class for conversion of base64 encoded data
97
+ * to it's binary representation.
98
+ *
99
+ */
100
+ static int
101
+ pg_bin_enc_from_base64(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate)
102
+ {
103
+ int strlen;
104
+ VALUE subint;
105
+ t_pg_composite_coder *this = (t_pg_composite_coder *)conv;
106
+ t_pg_coder_enc_func enc_func = pg_coder_enc_func(this->elem);
107
+
108
+ if(out){
109
+ /* Second encoder pass, if required */
110
+ strlen = enc_func(this->elem, value, out, intermediate);
111
+ strlen = base64_decode( out, out, strlen );
112
+
113
+ return strlen;
114
+ } else {
115
+ /* First encoder pass */
116
+ strlen = enc_func(this->elem, value, NULL, &subint);
117
+
118
+ if( strlen == -1 ){
119
+ /* Encoded string is returned in subint */
120
+ VALUE out_str;
121
+
122
+ strlen = RSTRING_LENINT(subint);
123
+ out_str = rb_str_new(NULL, BASE64_DECODED_SIZE(strlen));
124
+
125
+ strlen = base64_decode( RSTRING_PTR(out_str), RSTRING_PTR(subint), strlen);
126
+ rb_str_set_len( out_str, strlen );
127
+ *intermediate = out_str;
128
+
129
+ return -1;
130
+ } else {
131
+ *intermediate = subint;
132
+
133
+ return BASE64_DECODED_SIZE(strlen);
134
+ }
135
+ }
136
+ }
137
+
138
+ void
139
+ init_pg_binary_encoder()
140
+ {
141
+ /* This module encapsulates all encoder classes with binary output format */
142
+ rb_mPG_BinaryEncoder = rb_define_module_under( rb_mPG, "BinaryEncoder" );
143
+
144
+ /* Make RDoc aware of the encoder classes... */
145
+ /* dummy = rb_define_class_under( rb_mPG_BinaryEncoder, "Boolean", rb_cPG_SimpleEncoder ); */
146
+ pg_define_coder( "Boolean", pg_bin_enc_boolean, rb_cPG_SimpleEncoder, rb_mPG_BinaryEncoder );
147
+ /* dummy = rb_define_class_under( rb_mPG_BinaryEncoder, "Int2", rb_cPG_SimpleEncoder ); */
148
+ pg_define_coder( "Int2", pg_bin_enc_int2, rb_cPG_SimpleEncoder, rb_mPG_BinaryEncoder );
149
+ /* dummy = rb_define_class_under( rb_mPG_BinaryEncoder, "Int4", rb_cPG_SimpleEncoder ); */
150
+ pg_define_coder( "Int4", pg_bin_enc_int4, rb_cPG_SimpleEncoder, rb_mPG_BinaryEncoder );
151
+ /* dummy = rb_define_class_under( rb_mPG_BinaryEncoder, "Int8", rb_cPG_SimpleEncoder ); */
152
+ pg_define_coder( "Int8", pg_bin_enc_int8, rb_cPG_SimpleEncoder, rb_mPG_BinaryEncoder );
153
+ /* dummy = rb_define_class_under( rb_mPG_BinaryEncoder, "String", rb_cPG_SimpleEncoder ); */
154
+ pg_define_coder( "String", pg_coder_enc_to_s, rb_cPG_SimpleEncoder, rb_mPG_BinaryEncoder );
155
+ /* dummy = rb_define_class_under( rb_mPG_BinaryEncoder, "Bytea", rb_cPG_SimpleEncoder ); */
156
+ pg_define_coder( "Bytea", pg_coder_enc_to_s, rb_cPG_SimpleEncoder, rb_mPG_BinaryEncoder );
157
+
158
+ /* dummy = rb_define_class_under( rb_mPG_BinaryEncoder, "FromBase64", rb_cPG_CompositeEncoder ); */
159
+ pg_define_coder( "FromBase64", pg_bin_enc_from_base64, rb_cPG_CompositeEncoder, rb_mPG_BinaryEncoder );
160
+ }