pg 0.18.0.pre20141117110243-x64-mingw32 → 0.18.0-x64-mingw32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/ChangeLog +294 -1
- data/History.rdoc +2 -1
- data/Manifest.txt +3 -1
- data/Rakefile +17 -0
- data/ext/pg.c +1 -0
- data/ext/pg.h +1 -0
- data/ext/pg_connection.c +4 -4
- data/ext/pg_copy_coder.c +24 -4
- data/ext/pg_text_decoder.c +2 -4
- data/ext/pg_text_encoder.c +27 -38
- data/ext/pg_type_map.c +0 -25
- data/ext/pg_type_map_all_strings.c +1 -1
- data/ext/pg_type_map_by_oid.c +7 -25
- data/ext/pg_type_map_in_ruby.c +302 -0
- data/lib/2.0/pg_ext.so +0 -0
- data/lib/2.1/pg_ext.so +0 -0
- data/lib/2.2/pg_ext.so +0 -0
- data/lib/pg.rb +1 -1
- data/lib/pg/basic_type_mapping.rb +25 -3
- data/lib/pg/connection.rb +1 -1
- data/lib/x64-mingw32/libpq.dll +0 -0
- data/spec/pg/basic_type_mapping_spec.rb +3 -3
- data/spec/pg/type_map_by_class_spec.rb +1 -1
- data/spec/pg/type_map_by_oid_spec.rb +1 -6
- data/spec/pg/type_map_in_ruby_spec.rb +164 -0
- data/spec/pg/type_map_spec.rb +0 -17
- data/spec/pg/type_spec.rb +5 -9
- metadata +9 -5
- metadata.gz.sig +0 -0
data/ext/pg_text_decoder.c
CHANGED
@@ -313,8 +313,8 @@ pg_text_dec_identifier(t_pg_coder *conv, char *val, int len, int tuple, int fiel
|
|
313
313
|
VALUE elem;
|
314
314
|
int word_index = 0;
|
315
315
|
int index;
|
316
|
-
/*
|
317
|
-
char
|
316
|
+
/* Use a buffer of the same length, as that will be the worst case */
|
317
|
+
char word[len + 1];
|
318
318
|
|
319
319
|
/* The current character in the input string. */
|
320
320
|
char c;
|
@@ -356,8 +356,6 @@ pg_text_dec_identifier(t_pg_coder *conv, char *val, int len, int tuple, int fiel
|
|
356
356
|
elem = dec_func(conv, word, word_index, tuple, field, enc_idx);
|
357
357
|
rb_ary_push(array, elem);
|
358
358
|
|
359
|
-
free(word);
|
360
|
-
|
361
359
|
return array;
|
362
360
|
}
|
363
361
|
|
data/ext/pg_text_encoder.c
CHANGED
@@ -47,8 +47,8 @@
|
|
47
47
|
VALUE rb_mPG_TextEncoder;
|
48
48
|
static ID s_id_encode;
|
49
49
|
static ID s_id_to_i;
|
50
|
-
static VALUE hash_false_values;
|
51
50
|
|
51
|
+
static int pg_text_enc_integer(t_pg_coder *this, VALUE value, char *out, VALUE *intermediate);
|
52
52
|
|
53
53
|
VALUE
|
54
54
|
pg_obj_to_i( VALUE value )
|
@@ -68,38 +68,37 @@ pg_obj_to_i( VALUE value )
|
|
68
68
|
*
|
69
69
|
* This is the encoder class for the PostgreSQL bool type.
|
70
70
|
*
|
71
|
-
* Ruby
|
72
|
-
*
|
73
|
-
* Any other
|
71
|
+
* Ruby value false is encoded as SQL +FALSE+ value.
|
72
|
+
* Ruby value true is encoded as SQL +TRUE+ value.
|
73
|
+
* Any other value is sent as it's string representation.
|
74
74
|
*
|
75
75
|
*/
|
76
76
|
static int
|
77
|
-
pg_text_enc_boolean(t_pg_coder *
|
77
|
+
pg_text_enc_boolean(t_pg_coder *this, VALUE value, char *out, VALUE *intermediate)
|
78
78
|
{
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
*out = 't';
|
100
|
-
}
|
79
|
+
switch( TYPE(value) ){
|
80
|
+
case T_FALSE:
|
81
|
+
if(out) *out = 'f';
|
82
|
+
return 1;
|
83
|
+
case T_TRUE:
|
84
|
+
if(out) *out = 't';
|
85
|
+
return 1;
|
86
|
+
case T_FIXNUM:
|
87
|
+
case T_BIGNUM:
|
88
|
+
if( NUM2LONG(value) == 0 ){
|
89
|
+
if(out) *out = '0';
|
90
|
+
return 1;
|
91
|
+
} else if( NUM2LONG(value) == 1 ){
|
92
|
+
if(out) *out = '1';
|
93
|
+
return 1;
|
94
|
+
} else {
|
95
|
+
return pg_text_enc_integer(this, value, out, intermediate);
|
96
|
+
}
|
97
|
+
default:
|
98
|
+
return pg_coder_enc_to_s(this, value, out, intermediate);
|
101
99
|
}
|
102
|
-
|
100
|
+
/* never reached */
|
101
|
+
return 0;
|
103
102
|
}
|
104
103
|
|
105
104
|
|
@@ -638,16 +637,6 @@ init_pg_text_encoder()
|
|
638
637
|
s_id_encode = rb_intern("encode");
|
639
638
|
s_id_to_i = rb_intern("to_i");
|
640
639
|
|
641
|
-
hash_false_values = rb_hash_new();
|
642
|
-
rb_gc_register_address( &hash_false_values );
|
643
|
-
rb_hash_aset( hash_false_values, rb_str_new2( "0" ), Qtrue );
|
644
|
-
rb_hash_aset( hash_false_values, rb_str_new2( "f" ), Qtrue );
|
645
|
-
rb_hash_aset( hash_false_values, rb_str_new2( "F" ), Qtrue );
|
646
|
-
rb_hash_aset( hash_false_values, rb_str_new2( "false" ), Qtrue );
|
647
|
-
rb_hash_aset( hash_false_values, rb_str_new2( "FALSE" ), Qtrue );
|
648
|
-
rb_hash_aset( hash_false_values, rb_str_new2( "off" ), Qtrue );
|
649
|
-
rb_hash_aset( hash_false_values, rb_str_new2( "OFF" ), Qtrue );
|
650
|
-
|
651
640
|
/* This module encapsulates all encoder classes with text output format */
|
652
641
|
rb_mPG_TextEncoder = rb_define_module_under( rb_mPG, "TextEncoder" );
|
653
642
|
|
data/ext/pg_type_map.c
CHANGED
@@ -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 );
|
@@ -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 +#
|
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.
|
data/ext/pg_type_map_by_oid.c
CHANGED
@@ -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
|
-
|
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.
|
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
|
-
|
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
|
-
|
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, "
|
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$
|
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
|
+
}
|