pg 0.18.0.pre20140820094244 → 0.18.0.pre20141017155815
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 +1573 -2
- data/History.rdoc +3 -11
- data/Manifest.txt +24 -0
- data/README.rdoc +51 -4
- data/Rakefile +20 -14
- data/Rakefile.cross +39 -32
- data/ext/extconf.rb +27 -26
- data/ext/pg.c +75 -21
- data/ext/pg.h +194 -6
- data/ext/pg_binary_decoder.c +160 -0
- data/ext/pg_binary_encoder.c +160 -0
- data/ext/pg_coder.c +454 -0
- data/ext/pg_connection.c +815 -518
- data/ext/pg_copy_coder.c +557 -0
- data/ext/pg_result.c +258 -103
- data/ext/pg_text_decoder.c +424 -0
- data/ext/pg_text_encoder.c +608 -0
- data/ext/pg_type_map.c +113 -0
- data/ext/pg_type_map_all_strings.c +113 -0
- data/ext/pg_type_map_by_column.c +254 -0
- data/ext/pg_type_map_by_mri_type.c +266 -0
- data/ext/pg_type_map_by_oid.c +341 -0
- data/ext/util.c +121 -0
- data/ext/util.h +63 -0
- data/lib/pg.rb +11 -1
- data/lib/pg/basic_type_mapping.rb +377 -0
- data/lib/pg/coder.rb +74 -0
- data/lib/pg/connection.rb +38 -5
- data/lib/pg/result.rb +13 -3
- data/lib/pg/text_decoder.rb +42 -0
- data/lib/pg/text_encoder.rb +27 -0
- data/lib/pg/type_map_by_column.rb +15 -0
- data/spec/helpers.rb +9 -1
- data/spec/pg/basic_type_mapping_spec.rb +251 -0
- data/spec/pg/connection_spec.rb +232 -13
- data/spec/pg/result_spec.rb +52 -0
- data/spec/pg/type_map_by_column_spec.rb +135 -0
- data/spec/pg/type_map_by_mri_type_spec.rb +122 -0
- data/spec/pg/type_map_by_oid_spec.rb +133 -0
- data/spec/pg/type_map_spec.rb +39 -0
- data/spec/pg/type_spec.rb +620 -0
- metadata +40 -4
- metadata.gz.sig +0 -0
data/ext/pg_type_map.c
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
/*
|
2
|
+
* pg_column_map.c - PG::ColumnMap class extension
|
3
|
+
* $Id: pg_type_map.c,v 4227fdc5f0ac 2014/10/07 17:42:09 lars $
|
4
|
+
*
|
5
|
+
*/
|
6
|
+
|
7
|
+
#include "pg.h"
|
8
|
+
|
9
|
+
VALUE rb_cTypeMap;
|
10
|
+
static ID s_id_fit_to_query;
|
11
|
+
static ID s_id_fit_to_result;
|
12
|
+
|
13
|
+
VALUE
|
14
|
+
pg_typemap_fit_to_result( VALUE self, VALUE result )
|
15
|
+
{
|
16
|
+
rb_raise( rb_eNotImpError, "type map %s is not suitable to map result values", rb_obj_classname(self) );
|
17
|
+
return Qnil;
|
18
|
+
}
|
19
|
+
|
20
|
+
VALUE
|
21
|
+
pg_typemap_fit_to_query( VALUE self, VALUE params )
|
22
|
+
{
|
23
|
+
rb_raise( rb_eNotImpError, "type map %s is not suitable to map query params", rb_obj_classname(self) );
|
24
|
+
return Qnil;
|
25
|
+
}
|
26
|
+
|
27
|
+
int
|
28
|
+
pg_typemap_fit_to_copy_get( VALUE self )
|
29
|
+
{
|
30
|
+
rb_raise( rb_eNotImpError, "type map %s is not suitable to map copy_get_data results", rb_obj_classname(self) );
|
31
|
+
return Qnil;
|
32
|
+
}
|
33
|
+
|
34
|
+
VALUE
|
35
|
+
pg_typemap_result_value(VALUE self, int tuple, int field)
|
36
|
+
{
|
37
|
+
rb_raise( rb_eNotImpError, "type map is not suitable to map result values" );
|
38
|
+
return Qnil;
|
39
|
+
}
|
40
|
+
|
41
|
+
t_pg_coder *
|
42
|
+
pg_typemap_typecast_query_param(VALUE self, VALUE param_value, int field)
|
43
|
+
{
|
44
|
+
rb_raise( rb_eNotImpError, "type map %s is not suitable to map query params", rb_obj_classname(self) );
|
45
|
+
return NULL;
|
46
|
+
}
|
47
|
+
|
48
|
+
VALUE
|
49
|
+
pg_typemap_typecast_copy_get( t_typemap *p_typemap, VALUE field_str, int fieldno, int format, int enc_idx )
|
50
|
+
{
|
51
|
+
rb_raise( rb_eNotImpError, "type map is not suitable to map copy_get_data results" );
|
52
|
+
return Qnil;
|
53
|
+
}
|
54
|
+
|
55
|
+
static VALUE
|
56
|
+
pg_typemap_s_allocate( VALUE klass )
|
57
|
+
{
|
58
|
+
VALUE self;
|
59
|
+
t_typemap *this;
|
60
|
+
|
61
|
+
self = Data_Make_Struct( klass, t_typemap, NULL, -1, this );
|
62
|
+
this->fit_to_result = pg_typemap_fit_to_result;
|
63
|
+
this->fit_to_query = pg_typemap_fit_to_query;
|
64
|
+
this->fit_to_copy_get = pg_typemap_fit_to_copy_get;
|
65
|
+
this->typecast_result_value = pg_typemap_result_value;
|
66
|
+
this->typecast_query_param = pg_typemap_typecast_query_param;
|
67
|
+
this->typecast_copy_get = pg_typemap_typecast_copy_get;
|
68
|
+
|
69
|
+
return self;
|
70
|
+
}
|
71
|
+
|
72
|
+
static VALUE
|
73
|
+
pg_typemap_fit_to_result_ext( VALUE self, VALUE result )
|
74
|
+
{
|
75
|
+
t_typemap *this = DATA_PTR( self );
|
76
|
+
|
77
|
+
if ( !rb_obj_is_kind_of(result, rb_cPGresult) ) {
|
78
|
+
rb_raise( rb_eTypeError, "wrong argument type %s (expected kind of PG::Result)",
|
79
|
+
rb_obj_classname( result ) );
|
80
|
+
}
|
81
|
+
|
82
|
+
return this->fit_to_result( self, result );
|
83
|
+
}
|
84
|
+
|
85
|
+
static VALUE
|
86
|
+
pg_typemap_fit_to_query_ext( VALUE self, VALUE params )
|
87
|
+
{
|
88
|
+
t_typemap *this = DATA_PTR( self );
|
89
|
+
|
90
|
+
Check_Type( params, T_ARRAY);
|
91
|
+
|
92
|
+
return this->fit_to_query( self, params );
|
93
|
+
}
|
94
|
+
|
95
|
+
void
|
96
|
+
init_pg_type_map()
|
97
|
+
{
|
98
|
+
s_id_fit_to_query = rb_intern("fit_to_query");
|
99
|
+
s_id_fit_to_result = rb_intern("fit_to_result");
|
100
|
+
|
101
|
+
/*
|
102
|
+
* Document-class: PG::TypeMap < Object
|
103
|
+
*
|
104
|
+
* This is the base class for type maps.
|
105
|
+
* See derived classes for implementations of different type cast strategies
|
106
|
+
* ( PG::TypeMapByColumn, PG::TypeMapByOid ).
|
107
|
+
*
|
108
|
+
*/
|
109
|
+
rb_cTypeMap = rb_define_class_under( rb_mPG, "TypeMap", rb_cObject );
|
110
|
+
rb_define_alloc_func( rb_cTypeMap, pg_typemap_s_allocate );
|
111
|
+
rb_define_method( rb_cTypeMap, "fit_to_result", pg_typemap_fit_to_result_ext, 1 );
|
112
|
+
rb_define_method( rb_cTypeMap, "fit_to_query", pg_typemap_fit_to_query_ext, 1 );
|
113
|
+
}
|
@@ -0,0 +1,113 @@
|
|
1
|
+
/*
|
2
|
+
* pg_type_map_all_strings.c - PG::TypeMapAllStrings class extension
|
3
|
+
* $Id: pg_type_map_all_strings.c,v 4227fdc5f0ac 2014/10/07 17:42:09 lars $
|
4
|
+
*
|
5
|
+
* This is the default typemap.
|
6
|
+
*
|
7
|
+
*/
|
8
|
+
|
9
|
+
#include "pg.h"
|
10
|
+
|
11
|
+
VALUE rb_cTypeMapAllStrings;
|
12
|
+
VALUE pg_default_typemap;
|
13
|
+
|
14
|
+
static VALUE
|
15
|
+
pg_tmas_fit_to_result( VALUE self, VALUE result )
|
16
|
+
{
|
17
|
+
return self;
|
18
|
+
}
|
19
|
+
|
20
|
+
static VALUE
|
21
|
+
pg_tmas_result_value(VALUE result, int tuple, int field)
|
22
|
+
{
|
23
|
+
VALUE ret;
|
24
|
+
char * val;
|
25
|
+
int len;
|
26
|
+
t_pg_result *p_result = pgresult_get_this(result);
|
27
|
+
|
28
|
+
if (PQgetisnull(p_result->pgresult, tuple, field)) {
|
29
|
+
return Qnil;
|
30
|
+
}
|
31
|
+
|
32
|
+
val = PQgetvalue( p_result->pgresult, tuple, field );
|
33
|
+
len = PQgetlength( p_result->pgresult, tuple, field );
|
34
|
+
|
35
|
+
if ( 0 == PQfformat(p_result->pgresult, field) ) {
|
36
|
+
ret = pg_text_dec_string(NULL, val, len, tuple, field, ENCODING_GET(result));
|
37
|
+
} else {
|
38
|
+
ret = pg_bin_dec_bytea(NULL, val, len, tuple, field, ENCODING_GET(result));
|
39
|
+
}
|
40
|
+
|
41
|
+
return ret;
|
42
|
+
}
|
43
|
+
|
44
|
+
static VALUE
|
45
|
+
pg_tmas_fit_to_query( VALUE self, VALUE params )
|
46
|
+
{
|
47
|
+
return self;
|
48
|
+
}
|
49
|
+
|
50
|
+
static t_pg_coder *
|
51
|
+
pg_tmas_typecast_query_param(VALUE self, VALUE param_value, int field)
|
52
|
+
{
|
53
|
+
return NULL;
|
54
|
+
}
|
55
|
+
|
56
|
+
static int
|
57
|
+
pg_tmas_fit_to_copy_get( VALUE self )
|
58
|
+
{
|
59
|
+
/* We can not predict the number of columns for copy */
|
60
|
+
return 0;
|
61
|
+
}
|
62
|
+
|
63
|
+
static VALUE
|
64
|
+
pg_tmas_typecast_copy_get( t_typemap *p_typemap, VALUE field_str, int fieldno, int format, int enc_idx )
|
65
|
+
{
|
66
|
+
if( format == 0 ){
|
67
|
+
PG_ENCODING_SET_NOCHECK( field_str, enc_idx );
|
68
|
+
} else {
|
69
|
+
PG_ENCODING_SET_NOCHECK( field_str, rb_ascii8bit_encindex() );
|
70
|
+
}
|
71
|
+
return field_str;
|
72
|
+
}
|
73
|
+
|
74
|
+
static VALUE
|
75
|
+
pg_tmas_s_allocate( VALUE klass )
|
76
|
+
{
|
77
|
+
t_typemap *this;
|
78
|
+
VALUE self;
|
79
|
+
|
80
|
+
self = Data_Make_Struct( klass, t_typemap, NULL, -1, this );
|
81
|
+
|
82
|
+
this->fit_to_result = pg_tmas_fit_to_result;
|
83
|
+
this->fit_to_query = pg_tmas_fit_to_query;
|
84
|
+
this->fit_to_copy_get = pg_tmas_fit_to_copy_get;
|
85
|
+
this->typecast_result_value = pg_tmas_result_value;
|
86
|
+
this->typecast_query_param = pg_tmas_typecast_query_param;
|
87
|
+
this->typecast_copy_get = pg_tmas_typecast_copy_get;
|
88
|
+
|
89
|
+
return self;
|
90
|
+
}
|
91
|
+
|
92
|
+
|
93
|
+
void
|
94
|
+
init_pg_type_map_all_strings()
|
95
|
+
{
|
96
|
+
/*
|
97
|
+
* Document-class: PG::TypeMapAllStrings < PG::TypeMap
|
98
|
+
*
|
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+ .
|
101
|
+
*
|
102
|
+
* It is suitable for type casting query bind parameters, result values and
|
103
|
+
* COPY IN/OUT data.
|
104
|
+
*
|
105
|
+
* This is the default type map. It is used when type_map is not set or set to +nil+.
|
106
|
+
*
|
107
|
+
*/
|
108
|
+
rb_cTypeMapAllStrings = rb_define_class_under( rb_mPG, "TypeMapAllStrings", rb_cTypeMap );
|
109
|
+
rb_define_alloc_func( rb_cTypeMapAllStrings, pg_tmas_s_allocate );
|
110
|
+
|
111
|
+
pg_default_typemap = rb_funcall( rb_cTypeMapAllStrings, rb_intern("new"), 0 );
|
112
|
+
rb_gc_register_address( &pg_default_typemap );
|
113
|
+
}
|
@@ -0,0 +1,254 @@
|
|
1
|
+
/*
|
2
|
+
* pg_column_map.c - PG::ColumnMap class extension
|
3
|
+
* $Id: pg_type_map_by_column.c,v ec9ef7fb39eb 2014/10/10 18:59:10 lars $
|
4
|
+
*
|
5
|
+
*/
|
6
|
+
|
7
|
+
#include "pg.h"
|
8
|
+
|
9
|
+
static VALUE rb_cTypeMapByColumn;
|
10
|
+
static ID s_id_decode;
|
11
|
+
static ID s_id_encode;
|
12
|
+
|
13
|
+
static VALUE
|
14
|
+
pg_tmbc_fit_to_result( VALUE self, VALUE result )
|
15
|
+
{
|
16
|
+
int nfields;
|
17
|
+
t_tmbc *this = DATA_PTR( self );
|
18
|
+
|
19
|
+
nfields = PQnfields( pgresult_get(result) );
|
20
|
+
if ( this->nfields != nfields ) {
|
21
|
+
rb_raise( rb_eArgError, "number of result fields (%d) does not match number of mapped columns (%d)",
|
22
|
+
nfields, this->nfields );
|
23
|
+
}
|
24
|
+
return self;
|
25
|
+
}
|
26
|
+
|
27
|
+
static VALUE
|
28
|
+
pg_tmbc_fit_to_query( VALUE self, VALUE params )
|
29
|
+
{
|
30
|
+
int nfields;
|
31
|
+
t_tmbc *this = DATA_PTR( self );
|
32
|
+
|
33
|
+
nfields = (int)RARRAY_LEN( params );
|
34
|
+
if ( this->nfields != nfields ) {
|
35
|
+
rb_raise( rb_eArgError, "number of result fields (%d) does not match number of mapped columns (%d)",
|
36
|
+
nfields, this->nfields );
|
37
|
+
}
|
38
|
+
return self;
|
39
|
+
}
|
40
|
+
|
41
|
+
static int
|
42
|
+
pg_tmbc_fit_to_copy_get( VALUE self )
|
43
|
+
{
|
44
|
+
t_tmbc *this = DATA_PTR( self );
|
45
|
+
return this->nfields;
|
46
|
+
}
|
47
|
+
|
48
|
+
|
49
|
+
VALUE
|
50
|
+
pg_tmbc_result_value(VALUE result, int tuple, int field)
|
51
|
+
{
|
52
|
+
char * val;
|
53
|
+
int len;
|
54
|
+
t_pg_coder *p_coder = NULL;
|
55
|
+
t_pg_coder_dec_func dec_func;
|
56
|
+
t_pg_result *p_result = pgresult_get_this(result);
|
57
|
+
t_tmbc *this = (t_tmbc *) p_result->p_typemap;
|
58
|
+
|
59
|
+
if (PQgetisnull(p_result->pgresult, tuple, field)) {
|
60
|
+
return Qnil;
|
61
|
+
}
|
62
|
+
|
63
|
+
val = PQgetvalue( p_result->pgresult, tuple, field );
|
64
|
+
len = PQgetlength( p_result->pgresult, tuple, field );
|
65
|
+
|
66
|
+
if( this ){
|
67
|
+
p_coder = this->convs[field].cconv;
|
68
|
+
|
69
|
+
if( p_coder && p_coder->dec_func ){
|
70
|
+
return p_coder->dec_func(p_coder, val, len, tuple, field, ENCODING_GET(result));
|
71
|
+
}
|
72
|
+
}
|
73
|
+
|
74
|
+
dec_func = pg_coder_dec_func( p_coder, PQfformat(p_result->pgresult, field) );
|
75
|
+
return dec_func( p_coder, val, len, tuple, field, ENCODING_GET(result) );
|
76
|
+
}
|
77
|
+
|
78
|
+
static t_pg_coder *
|
79
|
+
pg_tmbc_typecast_query_param(VALUE self, VALUE param_value, int field)
|
80
|
+
{
|
81
|
+
t_tmbc *this = (t_tmbc *)DATA_PTR(self);
|
82
|
+
|
83
|
+
/* Number of fields were already checked in pg_tmbc_fit_to_query() */
|
84
|
+
t_pg_coder *p_coder = this->convs[field].cconv;
|
85
|
+
|
86
|
+
return p_coder;
|
87
|
+
}
|
88
|
+
|
89
|
+
static VALUE
|
90
|
+
pg_tmbc_typecast_copy_get( t_typemap *p_typemap, VALUE field_str, int fieldno, int format, int enc_idx )
|
91
|
+
{
|
92
|
+
t_tmbc *this = (t_tmbc *) p_typemap;
|
93
|
+
t_pg_coder *p_coder;
|
94
|
+
t_pg_coder_dec_func dec_func;
|
95
|
+
|
96
|
+
if ( fieldno >= this->nfields || fieldno < 0 ) {
|
97
|
+
rb_raise( rb_eArgError, "number of copy fields (%d) exceeds number of mapped columns (%d)",
|
98
|
+
fieldno, this->nfields );
|
99
|
+
}
|
100
|
+
|
101
|
+
p_coder = this->convs[fieldno].cconv;
|
102
|
+
|
103
|
+
dec_func = pg_coder_dec_func( p_coder, format );
|
104
|
+
|
105
|
+
/* Is it a pure String conversion? Then we can directly send field_str to the user. */
|
106
|
+
if( format == 0 && dec_func == pg_text_dec_string ){
|
107
|
+
PG_ENCODING_SET_NOCHECK( field_str, enc_idx );
|
108
|
+
return field_str;
|
109
|
+
}
|
110
|
+
if( format == 1 && dec_func == pg_bin_dec_bytea ){
|
111
|
+
PG_ENCODING_SET_NOCHECK( field_str, rb_ascii8bit_encindex() );
|
112
|
+
return field_str;
|
113
|
+
}
|
114
|
+
|
115
|
+
return dec_func( p_coder, RSTRING_PTR(field_str), RSTRING_LEN(field_str), 0, fieldno, enc_idx );
|
116
|
+
}
|
117
|
+
|
118
|
+
const t_typemap pg_tmbc_default_typemap = {
|
119
|
+
.fit_to_result = pg_tmbc_fit_to_result,
|
120
|
+
.fit_to_query = pg_tmbc_fit_to_query,
|
121
|
+
.fit_to_copy_get = pg_tmbc_fit_to_copy_get,
|
122
|
+
.typecast_result_value = pg_tmbc_result_value,
|
123
|
+
.typecast_query_param = pg_tmbc_typecast_query_param,
|
124
|
+
.typecast_copy_get = pg_tmbc_typecast_copy_get
|
125
|
+
};
|
126
|
+
|
127
|
+
static void
|
128
|
+
pg_tmbc_mark( t_tmbc *this )
|
129
|
+
{
|
130
|
+
int i;
|
131
|
+
|
132
|
+
/* allocated but not initialized ? */
|
133
|
+
if( !this ) return;
|
134
|
+
|
135
|
+
for( i=0; i<this->nfields; i++){
|
136
|
+
t_pg_coder *p_coder = this->convs[i].cconv;
|
137
|
+
if( p_coder )
|
138
|
+
rb_gc_mark(p_coder->coder_obj);
|
139
|
+
}
|
140
|
+
}
|
141
|
+
|
142
|
+
static VALUE
|
143
|
+
pg_tmbc_s_allocate( VALUE klass )
|
144
|
+
{
|
145
|
+
return Data_Wrap_Struct( klass, pg_tmbc_mark, -1, NULL );
|
146
|
+
}
|
147
|
+
|
148
|
+
VALUE
|
149
|
+
pg_tmbc_allocate()
|
150
|
+
{
|
151
|
+
return pg_tmbc_s_allocate(rb_cTypeMapByColumn);
|
152
|
+
}
|
153
|
+
|
154
|
+
/*
|
155
|
+
* call-seq:
|
156
|
+
* PG::TypeMapByColumn.new( coders )
|
157
|
+
*
|
158
|
+
* Builds a new type map and assigns a list of coders for the given column.
|
159
|
+
* +coders+ must be an Array of PG::Coder objects or +nil+ values.
|
160
|
+
* The length of the Array corresponds to
|
161
|
+
* the number of columns or bind parameters this type map is usable for.
|
162
|
+
*
|
163
|
+
* A +nil+ value will cast the given field to a String object.
|
164
|
+
*/
|
165
|
+
static VALUE
|
166
|
+
pg_tmbc_init(VALUE self, VALUE conv_ary)
|
167
|
+
{
|
168
|
+
int i;
|
169
|
+
t_tmbc *this;
|
170
|
+
int conv_ary_len;
|
171
|
+
|
172
|
+
Check_Type(self, T_DATA);
|
173
|
+
Check_Type(conv_ary, T_ARRAY);
|
174
|
+
conv_ary_len = RARRAY_LEN(conv_ary);
|
175
|
+
this = xmalloc(sizeof(t_tmbc) + sizeof(struct pg_tmbc_converter) * conv_ary_len);
|
176
|
+
/* Set nfields to 0 at first, so that GC mark function doesn't access uninitialized memory. */
|
177
|
+
this->nfields = 0;
|
178
|
+
this->typemap = pg_tmbc_default_typemap;
|
179
|
+
DATA_PTR(self) = this;
|
180
|
+
|
181
|
+
for(i=0; i<conv_ary_len; i++)
|
182
|
+
{
|
183
|
+
VALUE obj = rb_ary_entry(conv_ary, i);
|
184
|
+
|
185
|
+
if( obj == Qnil ){
|
186
|
+
/* no type cast */
|
187
|
+
this->convs[i].cconv = NULL;
|
188
|
+
} else if( rb_obj_is_kind_of(obj, rb_cPG_Coder) ){
|
189
|
+
Data_Get_Struct(obj, t_pg_coder, this->convs[i].cconv);
|
190
|
+
} else {
|
191
|
+
rb_raise(rb_eArgError, "argument %d has invalid type %s (should be nil or some kind of PG::Coder)",
|
192
|
+
i+1, rb_obj_classname( obj ));
|
193
|
+
}
|
194
|
+
}
|
195
|
+
|
196
|
+
this->nfields = conv_ary_len;
|
197
|
+
|
198
|
+
return self;
|
199
|
+
}
|
200
|
+
|
201
|
+
/*
|
202
|
+
* call-seq:
|
203
|
+
* typemap.coders -> Array
|
204
|
+
*
|
205
|
+
* Array of PG::Coder objects. The length of the Array corresponds to
|
206
|
+
* the number of columns or bind parameters this type map is usable for.
|
207
|
+
*/
|
208
|
+
static VALUE
|
209
|
+
pg_tmbc_coders(VALUE self)
|
210
|
+
{
|
211
|
+
int i;
|
212
|
+
t_tmbc *this = DATA_PTR( self );
|
213
|
+
VALUE ary_coders = rb_ary_new();
|
214
|
+
|
215
|
+
for( i=0; i<this->nfields; i++){
|
216
|
+
t_pg_coder *conv = this->convs[i].cconv;
|
217
|
+
if( conv ) {
|
218
|
+
rb_ary_push( ary_coders, conv->coder_obj );
|
219
|
+
} else {
|
220
|
+
rb_ary_push( ary_coders, Qnil );
|
221
|
+
}
|
222
|
+
}
|
223
|
+
|
224
|
+
return rb_obj_freeze(ary_coders);
|
225
|
+
}
|
226
|
+
|
227
|
+
void
|
228
|
+
init_pg_type_map_by_column()
|
229
|
+
{
|
230
|
+
s_id_decode = rb_intern("decode");
|
231
|
+
s_id_encode = rb_intern("encode");
|
232
|
+
|
233
|
+
/*
|
234
|
+
* Document-class: PG::TypeMapByColumn < PG::TypeMap
|
235
|
+
*
|
236
|
+
* This type map casts values by a coder assigned per field/column.
|
237
|
+
*
|
238
|
+
* Each PG:TypeMapByColumn has a fixed list of either encoders or decoders,
|
239
|
+
* that is defined at #new . A type map with encoders is usable for type casting
|
240
|
+
* query bind parameters and COPY data for PG::Connection#put_copy_data .
|
241
|
+
* A type map with decoders is usable for type casting of result values and
|
242
|
+
* COPY data from PG::Connection#get_copy_data .
|
243
|
+
*
|
244
|
+
* PG::TypeMapByColumns are in particular useful in conjunction with prepared statements,
|
245
|
+
* since they can be cached alongside with the statement handle.
|
246
|
+
*
|
247
|
+
* This type map strategy is also used internally by PG::TypeMapByOid, when the
|
248
|
+
* number of rows of a result set exceeds a given limit.
|
249
|
+
*/
|
250
|
+
rb_cTypeMapByColumn = rb_define_class_under( rb_mPG, "TypeMapByColumn", rb_cTypeMap );
|
251
|
+
rb_define_alloc_func( rb_cTypeMapByColumn, pg_tmbc_s_allocate );
|
252
|
+
rb_define_method( rb_cTypeMapByColumn, "initialize", pg_tmbc_init, 1 );
|
253
|
+
rb_define_method( rb_cTypeMapByColumn, "coders", pg_tmbc_coders, 0 );
|
254
|
+
}
|