pg 0.18.0.pre20141117110243 → 0.18.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  * pg_column_map.c - PG::ColumnMap class extension
3
- * $Id$
3
+ * $Id: pg_type_map.c,v c99d26015e3c 2014/12/12 20:58:25 lars $
4
4
  *
5
5
  */
6
6
 
@@ -74,29 +74,6 @@ pg_typemap_s_allocate( VALUE klass )
74
74
  return self;
75
75
  }
76
76
 
77
- static VALUE
78
- pg_typemap_fit_to_result_ext( VALUE self, VALUE result )
79
- {
80
- t_typemap *this = DATA_PTR( self );
81
-
82
- if ( !rb_obj_is_kind_of(result, rb_cPGresult) ) {
83
- rb_raise( rb_eTypeError, "wrong argument type %s (expected kind of PG::Result)",
84
- rb_obj_classname( result ) );
85
- }
86
-
87
- return this->funcs.fit_to_result( self, result );
88
- }
89
-
90
- static VALUE
91
- pg_typemap_fit_to_query_ext( VALUE self, VALUE params )
92
- {
93
- t_typemap *this = DATA_PTR( self );
94
-
95
- Check_Type( params, T_ARRAY);
96
-
97
- return this->funcs.fit_to_query( self, params );
98
- }
99
-
100
77
  /*
101
78
  * call-seq:
102
79
  * res.default_type_map = typemap
@@ -174,8 +151,6 @@ init_pg_type_map()
174
151
  */
175
152
  rb_cTypeMap = rb_define_class_under( rb_mPG, "TypeMap", rb_cObject );
176
153
  rb_define_alloc_func( rb_cTypeMap, pg_typemap_s_allocate );
177
- rb_define_method( rb_cTypeMap, "fit_to_result", pg_typemap_fit_to_result_ext, 1 );
178
- rb_define_method( rb_cTypeMap, "fit_to_query", pg_typemap_fit_to_query_ext, 1 );
179
154
 
180
155
  rb_mDefaultTypeMappable = rb_define_module_under( rb_cTypeMap, "DefaultTypeMappable");
181
156
  rb_define_method( rb_mDefaultTypeMappable, "default_type_map=", pg_typemap_default_type_map_set, 1 );
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  * pg_type_map_all_strings.c - PG::TypeMapAllStrings class extension
3
- * $Id$
3
+ * $Id: pg_type_map_all_strings.c,v c53f993a4254 2014/12/12 21:57:29 lars $
4
4
  *
5
5
  * This is the default typemap.
6
6
  *
@@ -97,7 +97,7 @@ init_pg_type_map_all_strings()
97
97
  * Document-class: PG::TypeMapAllStrings < PG::TypeMap
98
98
  *
99
99
  * This type map casts all values received from the database server to Strings
100
- * and sends all values to the server after conversion to String by +#to_str+ .
100
+ * and sends all values to the server after conversion to String by +#to_s+ .
101
101
  * That means, it is hard coded to PG::TextEncoder::String for value encoding
102
102
  * and to PG::TextDecoder::String for text format respectivly PG::BinaryDecoder::Bytea
103
103
  * for binary format received from the server.
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  * pg_type_map_by_class.c - PG::TypeMapByClass class extension
3
- * $Id$
3
+ * $Id: pg_type_map_by_class.c,v eeb8a82c5328 2014/11/10 19:34:02 lars $
4
4
  *
5
5
  * This type map can be used to select value encoders based on the class
6
6
  * of the given value to be send.
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  * pg_column_map.c - PG::ColumnMap class extension
3
- * $Id$
3
+ * $Id: pg_type_map_by_column.c,v d369d31e8fe3 2014/10/22 08:47:29 lars $
4
4
  *
5
5
  */
6
6
 
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  * pg_type_map_by_mri_type.c - PG::TypeMapByMriType class extension
3
- * $Id$
3
+ * $Id: pg_type_map_by_mri_type.c,v 27987dbd0b32 2014/11/07 20:55:52 lars $
4
4
  *
5
5
  * This type map can be used to select value encoders based on the MRI-internal
6
6
  * value type code.
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  * pg_type_map_by_oid.c - PG::TypeMapByOid class extension
3
- * $Id$
3
+ * $Id: pg_type_map_by_oid.c,v c99d26015e3c 2014/12/12 20:58:25 lars $
4
4
  *
5
5
  */
6
6
 
@@ -130,7 +130,7 @@ pg_tmbo_fit_to_result( VALUE self, VALUE result )
130
130
  if( PQntuples( pgresult ) <= this->max_rows_for_online_lookup ){
131
131
  /* Do a hash lookup for each result value in pg_tmbc_result_value() */
132
132
 
133
- /* Did the default type return the same object ? */
133
+ /* Did the default type return the same object ? */
134
134
  if( sub_typemap == this->typemap.default_typemap ){
135
135
  return self;
136
136
  } else {
@@ -306,41 +306,23 @@ pg_tmbo_max_rows_for_online_lookup_get( VALUE self )
306
306
 
307
307
  /*
308
308
  * call-seq:
309
- * typemap.fit_to_result( result, online_lookup = nil )
310
- *
311
- * This is an extended version of PG::TypeMap#fit_to_result that
312
- * allows explicit selection of online lookup ( online_lookup=true )
313
- * or building of a new PG::TypeMapByColumn ( online_lookup=false ).
309
+ * typemap.build_column_map( result )
314
310
  *
311
+ * This builds a PG::TypeMapByColumn that fits to the given PG::Result object
312
+ * based on it's type OIDs.
315
313
  *
316
314
  */
317
315
  static VALUE
318
- pg_tmbo_fit_to_result_ext( int argc, VALUE *argv, VALUE self )
316
+ pg_tmbo_build_column_map( VALUE self, VALUE result )
319
317
  {
320
318
  t_tmbo *this = DATA_PTR( self );
321
- VALUE result;
322
- VALUE online_lookup;
323
-
324
- rb_scan_args(argc, argv, "11", &result, &online_lookup);
325
319
 
326
320
  if ( !rb_obj_is_kind_of(result, rb_cPGresult) ) {
327
321
  rb_raise( rb_eTypeError, "wrong argument type %s (expected kind of PG::Result)",
328
322
  rb_obj_classname( result ) );
329
323
  }
330
324
 
331
- if( NIL_P( online_lookup ) ){
332
- /* call super */
333
- return this->typemap.funcs.fit_to_result(self, result);
334
- } else if( RB_TYPE_P( online_lookup, T_TRUE ) ){
335
- return self;
336
- } else if( RB_TYPE_P( online_lookup, T_FALSE ) ){
337
- PGresult *pgresult = pgresult_get( result );
338
-
339
- return pg_tmbo_build_type_map_for_result2( this, pgresult );
340
- } else {
341
- rb_raise( rb_eArgError, "argument online_lookup %s should be true, false or nil instead",
342
- rb_obj_classname( result ) );
343
- }
325
+ return pg_tmbo_build_type_map_for_result2( this, pgresult_get(result) );
344
326
  }
345
327
 
346
328
 
@@ -368,6 +350,6 @@ init_pg_type_map_by_oid()
368
350
  rb_define_method( rb_cTypeMapByOid, "coders", pg_tmbo_coders, 0 );
369
351
  rb_define_method( rb_cTypeMapByOid, "max_rows_for_online_lookup=", pg_tmbo_max_rows_for_online_lookup_set, 1 );
370
352
  rb_define_method( rb_cTypeMapByOid, "max_rows_for_online_lookup", pg_tmbo_max_rows_for_online_lookup_get, 0 );
371
- rb_define_method( rb_cTypeMapByOid, "fit_to_result", pg_tmbo_fit_to_result_ext, -1 );
353
+ rb_define_method( rb_cTypeMapByOid, "build_column_map", pg_tmbo_build_column_map, 1 );
372
354
  rb_include_module( rb_cTypeMapByOid, rb_mDefaultTypeMappable );
373
355
  }
@@ -0,0 +1,302 @@
1
+ /*
2
+ * pg_type_map_in_ruby.c - PG::TypeMapInRuby class extension
3
+ * $Id: pg_type_map_in_ruby.c,v a38cf53a96f1 2014/12/13 21:59:57 lars $
4
+ *
5
+ */
6
+
7
+ #include "pg.h"
8
+
9
+ VALUE rb_cTypeMapInRuby;
10
+ static VALUE s_id_fit_to_result;
11
+ static VALUE s_id_fit_to_query;
12
+ static VALUE s_id_fit_to_copy_get;
13
+ static VALUE s_id_typecast_result_value;
14
+ static VALUE s_id_typecast_query_param;
15
+ static VALUE s_id_typecast_copy_get;
16
+
17
+ typedef struct {
18
+ t_typemap typemap;
19
+ VALUE self;
20
+ } t_tmir;
21
+
22
+
23
+ /*
24
+ * call-seq:
25
+ * typemap.fit_to_result( result )
26
+ *
27
+ * Check that the type map fits to the result.
28
+ *
29
+ * This method is called, when a type map is assigned to a result.
30
+ * It must return a PG::TypeMap object or raise an Exception.
31
+ * This can be +self+ or some other type map that fits to the result.
32
+ *
33
+ */
34
+ static VALUE
35
+ pg_tmir_fit_to_result( VALUE self, VALUE result )
36
+ {
37
+ t_tmir *this = DATA_PTR( self );
38
+ t_typemap *default_tm;
39
+ t_typemap *p_new_typemap;
40
+ VALUE sub_typemap;
41
+ VALUE new_typemap;
42
+
43
+ if( rb_respond_to(self, s_id_fit_to_result) ){
44
+ new_typemap = rb_funcall( self, s_id_fit_to_result, 1, result );
45
+
46
+ if ( !rb_obj_is_kind_of(new_typemap, rb_cTypeMap) ) {
47
+ rb_raise( rb_eTypeError, "wrong return type from fit_to_result: %s expected kind of PG::TypeMap",
48
+ rb_obj_classname( new_typemap ) );
49
+ }
50
+ Check_Type( new_typemap, T_DATA );
51
+ } else {
52
+ new_typemap = self;
53
+ }
54
+
55
+ /* Ensure that the default type map fits equaly. */
56
+ default_tm = DATA_PTR( this->typemap.default_typemap );
57
+ sub_typemap = default_tm->funcs.fit_to_result( this->typemap.default_typemap, result );
58
+
59
+ if( sub_typemap != this->typemap.default_typemap ){
60
+ new_typemap = rb_obj_dup( new_typemap );
61
+ }
62
+
63
+ p_new_typemap = DATA_PTR(new_typemap);
64
+ p_new_typemap->default_typemap = sub_typemap;
65
+ return new_typemap;
66
+ }
67
+
68
+ static VALUE
69
+ pg_tmir_result_value( t_typemap *p_typemap, VALUE result, int tuple, int field )
70
+ {
71
+ t_tmir *this = (t_tmir *) p_typemap;
72
+
73
+ return rb_funcall( this->self, s_id_typecast_result_value, 3, result, INT2NUM(tuple), INT2NUM(field) );
74
+ }
75
+
76
+ /*
77
+ * call-seq:
78
+ * typemap.typecast_result_value( result, tuple, field )
79
+ *
80
+ * Retrieve and cast a field of the given result.
81
+ *
82
+ * This method implementation uses the #default_type_map to get the
83
+ * field value. It can be derived to change this behaviour.
84
+ *
85
+ * Parameters:
86
+ * * +result+ : The PG::Result received from the database.
87
+ * * +tuple+ : The row number to retrieve.
88
+ * * +field+ : The column number to retrieve.
89
+ *
90
+ * Note: Calling any value retrieving methods of +result+ will result
91
+ * in an (endless) recursion. Instead super() can be used to retrieve
92
+ * the value using the default_typemap.
93
+ *
94
+ */
95
+ static VALUE
96
+ pg_tmir_typecast_result_value( VALUE self, VALUE result, VALUE tuple, VALUE field )
97
+ {
98
+ t_tmir *this = DATA_PTR( self );
99
+ t_typemap *default_tm = DATA_PTR( this->typemap.default_typemap );
100
+ return default_tm->funcs.typecast_result_value( default_tm, result, NUM2INT(tuple), NUM2INT(field) );
101
+ }
102
+
103
+ /*
104
+ * call-seq:
105
+ * typemap.fit_to_query( params )
106
+ *
107
+ * Check that the type map fits to the given user values.
108
+ *
109
+ * This method is called, when a type map is used for sending a query
110
+ * and for encoding of copy data, before the value is casted.
111
+ *
112
+ */
113
+ static VALUE
114
+ pg_tmir_fit_to_query( VALUE self, VALUE params )
115
+ {
116
+ t_tmir *this = DATA_PTR( self );
117
+ t_typemap *default_tm;
118
+
119
+ if( rb_respond_to(self, s_id_fit_to_query) ){
120
+ rb_funcall( self, s_id_fit_to_query, 1, params );
121
+ }
122
+
123
+ /* Ensure that the default type map fits equaly. */
124
+ default_tm = DATA_PTR( this->typemap.default_typemap );
125
+ default_tm->funcs.fit_to_query( this->typemap.default_typemap, params );
126
+
127
+ return self;
128
+ }
129
+
130
+ static t_pg_coder *
131
+ pg_tmir_query_param( t_typemap *p_typemap, VALUE param_value, int field )
132
+ {
133
+ t_tmir *this = (t_tmir *) p_typemap;
134
+
135
+ VALUE coder = rb_funcall( this->self, s_id_typecast_query_param, 2, param_value, INT2NUM(field) );
136
+
137
+ if ( NIL_P(coder) ){
138
+ return NULL;
139
+ } else if( rb_obj_is_kind_of(coder, rb_cPG_Coder) ) {
140
+ return DATA_PTR(coder);
141
+ } else {
142
+ rb_raise( rb_eTypeError, "wrong return type from typecast_query_param: %s expected nil or kind of PG::Coder",
143
+ rb_obj_classname( coder ) );
144
+ }
145
+ }
146
+
147
+ /*
148
+ * call-seq:
149
+ * typemap.typecast_query_param( param_value, field )
150
+ *
151
+ * Cast a field string for transmission to the server.
152
+ *
153
+ * This method implementation uses the #default_type_map to cast param_value.
154
+ * It can be derived to change this behaviour.
155
+ *
156
+ * Parameters:
157
+ * * +param_value+ : The value from the user.
158
+ * * +field+ : The field number from left to right.
159
+ *
160
+ */
161
+ static VALUE
162
+ pg_tmir_typecast_query_param( VALUE self, VALUE param_value, VALUE field )
163
+ {
164
+ t_tmir *this = DATA_PTR( self );
165
+ t_typemap *default_tm = DATA_PTR( this->typemap.default_typemap );
166
+ t_pg_coder *p_coder = default_tm->funcs.typecast_query_param( default_tm, param_value, NUM2INT(field) );
167
+
168
+ return p_coder ? p_coder->coder_obj : Qnil;
169
+ }
170
+
171
+ /* This is to fool rdoc's C parser */
172
+ #if 0
173
+ /*
174
+ * call-seq:
175
+ * typemap.fit_to_copy_get()
176
+ *
177
+ * Check that the type map can be used for PG::Connection#get_copy_data.
178
+ *
179
+ * This method is called, when a type map is used for decoding copy data,
180
+ * before the value is casted.
181
+ *
182
+ */
183
+ static VALUE pg_tmir_fit_to_copy_get_dummy( VALUE self ){}
184
+ #endif
185
+
186
+ static int
187
+ pg_tmir_fit_to_copy_get( VALUE self )
188
+ {
189
+ t_tmir *this = DATA_PTR( self );
190
+ t_typemap *default_tm;
191
+ VALUE num_columns = INT2NUM(0);
192
+
193
+ if( rb_respond_to(self, s_id_fit_to_copy_get) ){
194
+ num_columns = rb_funcall( self, s_id_fit_to_copy_get, 0 );
195
+ }
196
+
197
+ if ( !rb_obj_is_kind_of(num_columns, rb_cInteger) ) {
198
+ rb_raise( rb_eTypeError, "wrong return type from fit_to_copy_get: %s expected kind of Integer",
199
+ rb_obj_classname( num_columns ) );
200
+ }
201
+ /* Ensure that the default type map fits equaly. */
202
+ default_tm = DATA_PTR( this->typemap.default_typemap );
203
+ default_tm->funcs.fit_to_copy_get( this->typemap.default_typemap );
204
+
205
+ return NUM2INT(num_columns);;
206
+ }
207
+
208
+ static VALUE
209
+ pg_tmir_copy_get( t_typemap *p_typemap, VALUE field_str, int fieldno, int format, int enc_idx )
210
+ {
211
+ t_tmir *this = (t_tmir *) p_typemap;
212
+ rb_encoding *p_encoding = rb_enc_from_index(enc_idx);
213
+ VALUE enc = rb_enc_from_encoding(p_encoding);
214
+ /* field_str is reused in-place by pg_text_dec_copy_row(), so we need to make
215
+ * a copy of the string buffer before used in ruby space.
216
+ * This requires rb_str_new() instead of rb_str_dup() for Rubinius.
217
+ */
218
+ VALUE field_str_copy = rb_str_new(RSTRING_PTR(field_str), RSTRING_LEN(field_str));
219
+ PG_ENCODING_SET_NOCHECK(field_str_copy, ENCODING_GET(field_str));
220
+ OBJ_INFECT(field_str_copy, field_str);
221
+
222
+ return rb_funcall( this->self, s_id_typecast_copy_get, 4, field_str_copy, INT2NUM(fieldno), INT2NUM(format), enc );
223
+ }
224
+
225
+ /*
226
+ * call-seq:
227
+ * typemap.typecast_copy_get( field_str, fieldno, format, encoding )
228
+ *
229
+ * Cast a field string received by PG::Connection#get_copy_data.
230
+ *
231
+ * This method implementation uses the #default_type_map to cast field_str.
232
+ * It can be derived to change this behaviour.
233
+ *
234
+ * Parameters:
235
+ * * +field_str+ : The String received from the server.
236
+ * * +fieldno+ : The field number from left to right.
237
+ * * +format+ : The format code (0 = text, 1 = binary)
238
+ * * +encoding+ : The encoding of the connection and encoding the returned
239
+ * value should get.
240
+ *
241
+ */
242
+ static VALUE
243
+ pg_tmir_typecast_copy_get( VALUE self, VALUE field_str, VALUE fieldno, VALUE format, VALUE enc )
244
+ {
245
+ t_tmir *this = DATA_PTR( self );
246
+ t_typemap *default_tm = DATA_PTR( this->typemap.default_typemap );
247
+ int enc_idx = rb_to_encoding_index( enc );
248
+
249
+ return default_tm->funcs.typecast_copy_get( default_tm, field_str, NUM2INT(fieldno), NUM2INT(format), enc_idx );
250
+ }
251
+
252
+ static VALUE
253
+ pg_tmir_s_allocate( VALUE klass )
254
+ {
255
+ t_tmir *this;
256
+ VALUE self;
257
+
258
+ self = Data_Make_Struct( klass, t_tmir, NULL, -1, this );
259
+
260
+ this->typemap.funcs.fit_to_result = pg_tmir_fit_to_result;
261
+ this->typemap.funcs.fit_to_query = pg_tmir_fit_to_query;
262
+ this->typemap.funcs.fit_to_copy_get = pg_tmir_fit_to_copy_get;
263
+ this->typemap.funcs.typecast_result_value = pg_tmir_result_value;
264
+ this->typemap.funcs.typecast_query_param = pg_tmir_query_param;
265
+ this->typemap.funcs.typecast_copy_get = pg_tmir_copy_get;
266
+ this->typemap.default_typemap = pg_typemap_all_strings;
267
+ this->self = self;
268
+
269
+ return self;
270
+ }
271
+
272
+
273
+ void
274
+ init_pg_type_map_in_ruby()
275
+ {
276
+ s_id_fit_to_result = rb_intern("fit_to_result");
277
+ s_id_fit_to_query = rb_intern("fit_to_query");
278
+ s_id_fit_to_copy_get = rb_intern("fit_to_copy_get");
279
+ s_id_typecast_result_value = rb_intern("typecast_result_value");
280
+ s_id_typecast_query_param = rb_intern("typecast_query_param");
281
+ s_id_typecast_copy_get = rb_intern("typecast_copy_get");
282
+
283
+ /*
284
+ * Document-class: PG::TypeMapInRuby < PG::TypeMap
285
+ *
286
+ * This class can be used to implement a type map in ruby, typically as a
287
+ * #default_type_map in a type map chain.
288
+ *
289
+ * This API is EXPERIMENTAL and could change in the future.
290
+ *
291
+ */
292
+ rb_cTypeMapInRuby = rb_define_class_under( rb_mPG, "TypeMapInRuby", rb_cTypeMap );
293
+ rb_define_alloc_func( rb_cTypeMapInRuby, pg_tmir_s_allocate );
294
+ /* rb_define_method( rb_cTypeMapInRuby, "fit_to_result", pg_tmir_fit_to_result, 1 ); */
295
+ /* rb_define_method( rb_cTypeMapInRuby, "fit_to_query", pg_tmir_fit_to_query, 1 ); */
296
+ /* rb_define_method( rb_cTypeMapInRuby, "fit_to_copy_get", pg_tmir_fit_to_copy_get_dummy, 0 ); */
297
+ rb_define_method( rb_cTypeMapInRuby, "typecast_result_value", pg_tmir_typecast_result_value, 3 );
298
+ rb_define_method( rb_cTypeMapInRuby, "typecast_query_param", pg_tmir_typecast_query_param, 2 );
299
+ rb_define_method( rb_cTypeMapInRuby, "typecast_copy_get", pg_tmir_typecast_copy_get, 4 );
300
+ /* rb_mDefaultTypeMappable = rb_define_module_under( rb_cTypeMap, "DefaultTypeMappable"); */
301
+ rb_include_module( rb_cTypeMapInRuby, rb_mDefaultTypeMappable );
302
+ }