pg 1.1.3 → 1.3.3
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/.appveyor.yml +36 -0
- data/.gems +6 -0
- data/.github/workflows/binary-gems.yml +86 -0
- data/.github/workflows/source-gem.yml +129 -0
- data/.gitignore +13 -0
- data/.hgsigs +34 -0
- data/.hgtags +41 -0
- data/.irbrc +23 -0
- data/.pryrc +23 -0
- data/.tm_properties +21 -0
- data/.travis.yml +49 -0
- data/Gemfile +14 -0
- data/History.rdoc +210 -6
- data/Manifest.txt +3 -3
- data/README-Windows.rdoc +4 -4
- data/README.ja.rdoc +1 -2
- data/README.rdoc +51 -15
- data/Rakefile +31 -140
- data/Rakefile.cross +60 -56
- data/certs/ged.pem +24 -0
- data/certs/larskanis-2022.pem +26 -0
- data/ext/errorcodes.def +76 -0
- data/ext/errorcodes.txt +21 -2
- data/ext/extconf.rb +101 -26
- data/ext/gvl_wrappers.c +4 -0
- data/ext/gvl_wrappers.h +23 -0
- data/ext/pg.c +190 -98
- data/ext/pg.h +42 -17
- data/ext/pg_binary_decoder.c +20 -16
- data/ext/pg_binary_encoder.c +13 -12
- data/ext/pg_coder.c +95 -29
- data/ext/pg_connection.c +1043 -769
- data/ext/pg_copy_coder.c +50 -18
- data/ext/pg_record_coder.c +519 -0
- data/ext/pg_result.c +326 -142
- data/ext/pg_text_decoder.c +15 -9
- data/ext/pg_text_encoder.c +185 -53
- data/ext/pg_tuple.c +61 -27
- data/ext/pg_type_map.c +42 -9
- data/ext/pg_type_map_all_strings.c +19 -5
- data/ext/pg_type_map_by_class.c +54 -24
- data/ext/pg_type_map_by_column.c +73 -34
- data/ext/pg_type_map_by_mri_type.c +48 -19
- data/ext/pg_type_map_by_oid.c +55 -25
- data/ext/pg_type_map_in_ruby.c +51 -20
- data/ext/{util.c → pg_util.c} +7 -7
- data/ext/{util.h → pg_util.h} +0 -0
- data/lib/pg/basic_type_map_based_on_result.rb +47 -0
- data/lib/pg/basic_type_map_for_queries.rb +193 -0
- data/lib/pg/basic_type_map_for_results.rb +81 -0
- data/lib/pg/basic_type_registry.rb +296 -0
- data/lib/pg/binary_decoder.rb +1 -0
- data/lib/pg/coder.rb +23 -2
- data/lib/pg/connection.rb +589 -59
- data/lib/pg/constants.rb +1 -0
- data/lib/pg/exceptions.rb +1 -0
- data/lib/pg/result.rb +13 -1
- data/lib/pg/text_decoder.rb +2 -3
- data/lib/pg/text_encoder.rb +8 -18
- data/lib/pg/type_map_by_column.rb +2 -1
- data/lib/pg/version.rb +4 -0
- data/lib/pg.rb +48 -33
- data/misc/openssl-pg-segfault.rb +31 -0
- data/misc/postgres/History.txt +9 -0
- data/misc/postgres/Manifest.txt +5 -0
- data/misc/postgres/README.txt +21 -0
- data/misc/postgres/Rakefile +21 -0
- data/misc/postgres/lib/postgres.rb +16 -0
- data/misc/ruby-pg/History.txt +9 -0
- data/misc/ruby-pg/Manifest.txt +5 -0
- data/misc/ruby-pg/README.txt +21 -0
- data/misc/ruby-pg/Rakefile +21 -0
- data/misc/ruby-pg/lib/ruby/pg.rb +16 -0
- data/pg.gemspec +32 -0
- data/rakelib/task_extension.rb +46 -0
- data/sample/array_insert.rb +20 -0
- data/sample/async_api.rb +106 -0
- data/sample/async_copyto.rb +39 -0
- data/sample/async_mixed.rb +56 -0
- data/sample/check_conn.rb +21 -0
- data/sample/copydata.rb +71 -0
- data/sample/copyfrom.rb +81 -0
- data/sample/copyto.rb +19 -0
- data/sample/cursor.rb +21 -0
- data/sample/disk_usage_report.rb +177 -0
- data/sample/issue-119.rb +94 -0
- data/sample/losample.rb +69 -0
- data/sample/minimal-testcase.rb +17 -0
- data/sample/notify_wait.rb +72 -0
- data/sample/pg_statistics.rb +285 -0
- data/sample/replication_monitor.rb +222 -0
- data/sample/test_binary_values.rb +33 -0
- data/sample/wal_shipper.rb +434 -0
- data/sample/warehouse_partitions.rb +311 -0
- data.tar.gz.sig +0 -0
- metadata +94 -237
- metadata.gz.sig +0 -0
- data/ChangeLog +0 -6595
- data/lib/pg/basic_type_mapping.rb +0 -459
- data/spec/data/expected_trace.out +0 -26
- data/spec/data/random_binary_data +0 -0
- data/spec/helpers.rb +0 -381
- data/spec/pg/basic_type_mapping_spec.rb +0 -508
- data/spec/pg/connection_spec.rb +0 -1849
- data/spec/pg/connection_sync_spec.rb +0 -41
- data/spec/pg/result_spec.rb +0 -491
- data/spec/pg/tuple_spec.rb +0 -280
- data/spec/pg/type_map_by_class_spec.rb +0 -138
- data/spec/pg/type_map_by_column_spec.rb +0 -222
- data/spec/pg/type_map_by_mri_type_spec.rb +0 -136
- data/spec/pg/type_map_by_oid_spec.rb +0 -149
- data/spec/pg/type_map_in_ruby_spec.rb +0 -164
- data/spec/pg/type_map_spec.rb +0 -22
- data/spec/pg/type_spec.rb +0 -949
- data/spec/pg_spec.rb +0 -50
data/ext/pg_type_map.c
CHANGED
|
@@ -1,11 +1,45 @@
|
|
|
1
1
|
/*
|
|
2
2
|
* pg_column_map.c - PG::ColumnMap class extension
|
|
3
|
-
* $Id
|
|
3
|
+
* $Id$
|
|
4
4
|
*
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
#include "pg.h"
|
|
8
8
|
|
|
9
|
+
void
|
|
10
|
+
pg_typemap_mark( void *_this )
|
|
11
|
+
{
|
|
12
|
+
t_typemap *this = (t_typemap *)_this;
|
|
13
|
+
rb_gc_mark_movable(this->default_typemap);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
size_t
|
|
17
|
+
pg_typemap_memsize( const void *_this )
|
|
18
|
+
{
|
|
19
|
+
t_typemap *this = (t_typemap *)_this;
|
|
20
|
+
return sizeof(*this);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
void
|
|
24
|
+
pg_typemap_compact( void *_this )
|
|
25
|
+
{
|
|
26
|
+
t_typemap *this = (t_typemap *)_this;
|
|
27
|
+
pg_gc_location(this->default_typemap);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const rb_data_type_t pg_typemap_type = {
|
|
31
|
+
"PG::TypeMap",
|
|
32
|
+
{
|
|
33
|
+
pg_typemap_mark,
|
|
34
|
+
RUBY_TYPED_DEFAULT_FREE,
|
|
35
|
+
pg_typemap_memsize,
|
|
36
|
+
pg_compact_callback(pg_typemap_compact),
|
|
37
|
+
},
|
|
38
|
+
0,
|
|
39
|
+
0,
|
|
40
|
+
RUBY_TYPED_FREE_IMMEDIATELY,
|
|
41
|
+
};
|
|
42
|
+
|
|
9
43
|
VALUE rb_cTypeMap;
|
|
10
44
|
VALUE rb_mDefaultTypeMappable;
|
|
11
45
|
static ID s_id_fit_to_query;
|
|
@@ -75,7 +109,7 @@ pg_typemap_s_allocate( VALUE klass )
|
|
|
75
109
|
VALUE self;
|
|
76
110
|
t_typemap *this;
|
|
77
111
|
|
|
78
|
-
self =
|
|
112
|
+
self = TypedData_Make_Struct( klass, t_typemap, &pg_typemap_type, this );
|
|
79
113
|
this->funcs = pg_typemap_funcs;
|
|
80
114
|
|
|
81
115
|
return self;
|
|
@@ -94,13 +128,12 @@ pg_typemap_s_allocate( VALUE klass )
|
|
|
94
128
|
static VALUE
|
|
95
129
|
pg_typemap_default_type_map_set(VALUE self, VALUE typemap)
|
|
96
130
|
{
|
|
97
|
-
t_typemap *this =
|
|
131
|
+
t_typemap *this = RTYPEDDATA_DATA( self );
|
|
132
|
+
t_typemap *tm;
|
|
133
|
+
UNUSED(tm);
|
|
98
134
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
rb_obj_classname( typemap ) );
|
|
102
|
-
}
|
|
103
|
-
Check_Type(typemap, T_DATA);
|
|
135
|
+
/* Check type of method param */
|
|
136
|
+
TypedData_Get_Struct(typemap, t_typemap, &pg_typemap_type, tm);
|
|
104
137
|
this->default_typemap = typemap;
|
|
105
138
|
|
|
106
139
|
return typemap;
|
|
@@ -119,7 +152,7 @@ pg_typemap_default_type_map_set(VALUE self, VALUE typemap)
|
|
|
119
152
|
static VALUE
|
|
120
153
|
pg_typemap_default_type_map_get(VALUE self)
|
|
121
154
|
{
|
|
122
|
-
t_typemap *this =
|
|
155
|
+
t_typemap *this = RTYPEDDATA_DATA( self );
|
|
123
156
|
|
|
124
157
|
return this->default_typemap;
|
|
125
158
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/*
|
|
2
2
|
* pg_type_map_all_strings.c - PG::TypeMapAllStrings class extension
|
|
3
|
-
* $Id
|
|
3
|
+
* $Id$
|
|
4
4
|
*
|
|
5
5
|
* This is the default typemap.
|
|
6
6
|
*
|
|
@@ -8,6 +8,19 @@
|
|
|
8
8
|
|
|
9
9
|
#include "pg.h"
|
|
10
10
|
|
|
11
|
+
static const rb_data_type_t pg_tmas_type = {
|
|
12
|
+
"PG::TypeMapAllStrings",
|
|
13
|
+
{
|
|
14
|
+
pg_typemap_mark,
|
|
15
|
+
RUBY_TYPED_DEFAULT_FREE,
|
|
16
|
+
pg_typemap_memsize,
|
|
17
|
+
pg_compact_callback(pg_typemap_compact),
|
|
18
|
+
},
|
|
19
|
+
&pg_typemap_type,
|
|
20
|
+
0,
|
|
21
|
+
RUBY_TYPED_FREE_IMMEDIATELY,
|
|
22
|
+
};
|
|
23
|
+
|
|
11
24
|
VALUE rb_cTypeMapAllStrings;
|
|
12
25
|
VALUE pg_typemap_all_strings;
|
|
13
26
|
|
|
@@ -33,9 +46,9 @@ pg_tmas_result_value( t_typemap *p_typemap, VALUE result, int tuple, int field )
|
|
|
33
46
|
len = PQgetlength( p_result->pgresult, tuple, field );
|
|
34
47
|
|
|
35
48
|
if ( 0 == PQfformat(p_result->pgresult, field) ) {
|
|
36
|
-
ret = pg_text_dec_string(NULL, val, len, tuple, field,
|
|
49
|
+
ret = pg_text_dec_string(NULL, val, len, tuple, field, p_result->enc_idx);
|
|
37
50
|
} else {
|
|
38
|
-
ret = pg_bin_dec_bytea(NULL, val, len, tuple, field,
|
|
51
|
+
ret = pg_bin_dec_bytea(NULL, val, len, tuple, field, p_result->enc_idx);
|
|
39
52
|
}
|
|
40
53
|
|
|
41
54
|
return ret;
|
|
@@ -63,6 +76,7 @@ pg_tmas_fit_to_copy_get( VALUE self )
|
|
|
63
76
|
static VALUE
|
|
64
77
|
pg_tmas_typecast_copy_get( t_typemap *p_typemap, VALUE field_str, int fieldno, int format, int enc_idx )
|
|
65
78
|
{
|
|
79
|
+
rb_str_modify(field_str);
|
|
66
80
|
if( format == 0 ){
|
|
67
81
|
PG_ENCODING_SET_NOCHECK( field_str, enc_idx );
|
|
68
82
|
} else {
|
|
@@ -77,7 +91,7 @@ pg_tmas_s_allocate( VALUE klass )
|
|
|
77
91
|
t_typemap *this;
|
|
78
92
|
VALUE self;
|
|
79
93
|
|
|
80
|
-
self =
|
|
94
|
+
self = TypedData_Make_Struct( klass, t_typemap, &pg_tmas_type, this );
|
|
81
95
|
|
|
82
96
|
this->funcs.fit_to_result = pg_tmas_fit_to_result;
|
|
83
97
|
this->funcs.fit_to_query = pg_tmas_fit_to_query;
|
|
@@ -99,7 +113,7 @@ init_pg_type_map_all_strings()
|
|
|
99
113
|
* This type map casts all values received from the database server to Strings
|
|
100
114
|
* and sends all values to the server after conversion to String by +#to_s+ .
|
|
101
115
|
* That means, it is hard coded to PG::TextEncoder::String for value encoding
|
|
102
|
-
* and to PG::TextDecoder::String for text format
|
|
116
|
+
* and to PG::TextDecoder::String for text format respectively PG::BinaryDecoder::Bytea
|
|
103
117
|
* for binary format received from the server.
|
|
104
118
|
*
|
|
105
119
|
* It is suitable for type casting query bind parameters, result values and
|
data/ext/pg_type_map_by_class.c
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/*
|
|
2
2
|
* pg_type_map_by_class.c - PG::TypeMapByClass class extension
|
|
3
|
-
* $Id
|
|
3
|
+
* $Id$
|
|
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.
|
|
@@ -10,7 +10,6 @@
|
|
|
10
10
|
#include "pg.h"
|
|
11
11
|
|
|
12
12
|
static VALUE rb_cTypeMapByClass;
|
|
13
|
-
static ID s_id_ancestors;
|
|
14
13
|
|
|
15
14
|
typedef struct {
|
|
16
15
|
t_typemap typemap;
|
|
@@ -28,7 +27,7 @@ typedef struct {
|
|
|
28
27
|
* We use 8 Bits of the klass object id as index to a 256 entry cache.
|
|
29
28
|
* This avoids full lookups in most cases.
|
|
30
29
|
*/
|
|
31
|
-
#define CACHE_LOOKUP(this, klass) ( &this->cache_row[(klass >> 8) & 0xff] )
|
|
30
|
+
#define CACHE_LOOKUP(this, klass) ( &this->cache_row[(((unsigned long)klass) >> 8) & 0xff] )
|
|
32
31
|
|
|
33
32
|
|
|
34
33
|
static t_pg_coder *
|
|
@@ -48,7 +47,7 @@ pg_tmbk_lookup_klass(t_tmbk *this, VALUE klass, VALUE param_value)
|
|
|
48
47
|
|
|
49
48
|
if( NIL_P(obj) ){
|
|
50
49
|
int i;
|
|
51
|
-
VALUE ancestors =
|
|
50
|
+
VALUE ancestors = rb_mod_ancestors( klass );
|
|
52
51
|
|
|
53
52
|
Check_Type( ancestors, T_ARRAY );
|
|
54
53
|
/* Don't look at the first element, it's expected to equal klass. */
|
|
@@ -63,10 +62,10 @@ pg_tmbk_lookup_klass(t_tmbk *this, VALUE klass, VALUE param_value)
|
|
|
63
62
|
if(NIL_P(obj)){
|
|
64
63
|
p_coder = NULL;
|
|
65
64
|
}else if(rb_obj_is_kind_of(obj, rb_cPG_Coder)){
|
|
66
|
-
|
|
65
|
+
TypedData_Get_Struct(obj, t_pg_coder, &pg_coder_type, p_coder);
|
|
67
66
|
}else{
|
|
68
67
|
if( RB_TYPE_P(obj, T_SYMBOL) ){
|
|
69
|
-
/* A
|
|
68
|
+
/* A Symbol: Call the method with this name. */
|
|
70
69
|
obj = rb_funcall(this->self, SYM2ID(obj), 1, param_value);
|
|
71
70
|
}else{
|
|
72
71
|
/* A Proc object (or something that responds to #call). */
|
|
@@ -75,11 +74,9 @@ pg_tmbk_lookup_klass(t_tmbk *this, VALUE klass, VALUE param_value)
|
|
|
75
74
|
|
|
76
75
|
if( NIL_P(obj) ){
|
|
77
76
|
p_coder = NULL;
|
|
78
|
-
}else if( rb_obj_is_kind_of(obj, rb_cPG_Coder) ){
|
|
79
|
-
Data_Get_Struct(obj, t_pg_coder, p_coder);
|
|
80
77
|
}else{
|
|
81
|
-
|
|
82
|
-
|
|
78
|
+
/* Check retrieved coder type */
|
|
79
|
+
TypedData_Get_Struct(obj, t_pg_coder, &pg_coder_type, p_coder);
|
|
83
80
|
}
|
|
84
81
|
|
|
85
82
|
/* We can not cache coders retrieved by ruby code, because we can not anticipate
|
|
@@ -104,7 +101,7 @@ pg_tmbk_typecast_query_param( t_typemap *p_typemap, VALUE param_value, int field
|
|
|
104
101
|
p_coder = pg_tmbk_lookup_klass( this, rb_obj_class(param_value), param_value );
|
|
105
102
|
|
|
106
103
|
if( !p_coder ){
|
|
107
|
-
t_typemap *default_tm =
|
|
104
|
+
t_typemap *default_tm = RTYPEDDATA_DATA( this->typemap.default_typemap );
|
|
108
105
|
return default_tm->funcs.typecast_query_param( default_tm, param_value, field );
|
|
109
106
|
}
|
|
110
107
|
|
|
@@ -114,28 +111,62 @@ pg_tmbk_typecast_query_param( t_typemap *p_typemap, VALUE param_value, int field
|
|
|
114
111
|
static VALUE
|
|
115
112
|
pg_tmbk_fit_to_query( VALUE self, VALUE params )
|
|
116
113
|
{
|
|
117
|
-
t_tmbk *this = (t_tmbk *)
|
|
114
|
+
t_tmbk *this = (t_tmbk *)RTYPEDDATA_DATA(self);
|
|
118
115
|
/* Nothing to check at this typemap, but ensure that the default type map fits. */
|
|
119
|
-
t_typemap *default_tm =
|
|
116
|
+
t_typemap *default_tm = RTYPEDDATA_DATA( this->typemap.default_typemap );
|
|
120
117
|
default_tm->funcs.fit_to_query( this->typemap.default_typemap, params );
|
|
121
118
|
return self;
|
|
122
119
|
}
|
|
123
120
|
|
|
124
121
|
static void
|
|
125
|
-
pg_tmbk_mark(
|
|
122
|
+
pg_tmbk_mark( void *_this )
|
|
123
|
+
{
|
|
124
|
+
t_tmbk *this = (t_tmbk *)_this;
|
|
125
|
+
pg_typemap_mark(&this->typemap);
|
|
126
|
+
rb_gc_mark_movable(this->klass_to_coder);
|
|
127
|
+
rb_gc_mark_movable(this->self);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
static size_t
|
|
131
|
+
pg_tmbk_memsize( const void *_this )
|
|
132
|
+
{
|
|
133
|
+
const t_tmbk *this = (const t_tmbk *)_this;
|
|
134
|
+
return sizeof(*this);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
static void
|
|
138
|
+
pg_tmbk_compact(void *ptr)
|
|
126
139
|
{
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
140
|
+
t_tmbk *this = (t_tmbk *)ptr;
|
|
141
|
+
|
|
142
|
+
pg_typemap_compact(&this->typemap);
|
|
143
|
+
pg_gc_location(this->klass_to_coder);
|
|
144
|
+
pg_gc_location(this->self);
|
|
145
|
+
|
|
146
|
+
/* Clear the cache, to be safe from changes of klass VALUE by GC.compact. */
|
|
147
|
+
memset(&this->cache_row, 0, sizeof(this->cache_row));
|
|
130
148
|
}
|
|
131
149
|
|
|
150
|
+
static const rb_data_type_t pg_tmbk_type = {
|
|
151
|
+
"PG::TypeMapByClass",
|
|
152
|
+
{
|
|
153
|
+
pg_tmbk_mark,
|
|
154
|
+
RUBY_TYPED_DEFAULT_FREE,
|
|
155
|
+
pg_tmbk_memsize,
|
|
156
|
+
pg_compact_callback(pg_tmbk_compact),
|
|
157
|
+
},
|
|
158
|
+
&pg_typemap_type,
|
|
159
|
+
0,
|
|
160
|
+
RUBY_TYPED_FREE_IMMEDIATELY,
|
|
161
|
+
};
|
|
162
|
+
|
|
132
163
|
static VALUE
|
|
133
164
|
pg_tmbk_s_allocate( VALUE klass )
|
|
134
165
|
{
|
|
135
166
|
t_tmbk *this;
|
|
136
167
|
VALUE self;
|
|
137
168
|
|
|
138
|
-
self =
|
|
169
|
+
self = TypedData_Make_Struct( klass, t_tmbk, &pg_tmbk_type, this );
|
|
139
170
|
this->typemap.funcs.fit_to_result = pg_typemap_fit_to_result;
|
|
140
171
|
this->typemap.funcs.fit_to_query = pg_tmbk_fit_to_query;
|
|
141
172
|
this->typemap.funcs.fit_to_copy_get = pg_typemap_fit_to_copy_get;
|
|
@@ -149,7 +180,7 @@ pg_tmbk_s_allocate( VALUE klass )
|
|
|
149
180
|
this->self = self;
|
|
150
181
|
this->klass_to_coder = rb_hash_new();
|
|
151
182
|
|
|
152
|
-
/* The cache is properly initialized by
|
|
183
|
+
/* The cache is properly initialized by TypedData_Make_Struct(). */
|
|
153
184
|
|
|
154
185
|
return self;
|
|
155
186
|
}
|
|
@@ -172,7 +203,7 @@ pg_tmbk_s_allocate( VALUE klass )
|
|
|
172
203
|
static VALUE
|
|
173
204
|
pg_tmbk_aset( VALUE self, VALUE klass, VALUE coder )
|
|
174
205
|
{
|
|
175
|
-
t_tmbk *this =
|
|
206
|
+
t_tmbk *this = RTYPEDDATA_DATA( self );
|
|
176
207
|
|
|
177
208
|
if(NIL_P(coder)){
|
|
178
209
|
rb_hash_delete( this->klass_to_coder, klass );
|
|
@@ -196,7 +227,7 @@ pg_tmbk_aset( VALUE self, VALUE klass, VALUE coder )
|
|
|
196
227
|
static VALUE
|
|
197
228
|
pg_tmbk_aref( VALUE self, VALUE klass )
|
|
198
229
|
{
|
|
199
|
-
t_tmbk *this =
|
|
230
|
+
t_tmbk *this = RTYPEDDATA_DATA( self );
|
|
200
231
|
|
|
201
232
|
return rb_hash_lookup(this->klass_to_coder, klass);
|
|
202
233
|
}
|
|
@@ -210,7 +241,7 @@ pg_tmbk_aref( VALUE self, VALUE klass )
|
|
|
210
241
|
static VALUE
|
|
211
242
|
pg_tmbk_coders( VALUE self )
|
|
212
243
|
{
|
|
213
|
-
t_tmbk *this =
|
|
244
|
+
t_tmbk *this = RTYPEDDATA_DATA( self );
|
|
214
245
|
|
|
215
246
|
return rb_obj_freeze(rb_hash_dup(this->klass_to_coder));
|
|
216
247
|
}
|
|
@@ -218,8 +249,6 @@ pg_tmbk_coders( VALUE self )
|
|
|
218
249
|
void
|
|
219
250
|
init_pg_type_map_by_class()
|
|
220
251
|
{
|
|
221
|
-
s_id_ancestors = rb_intern("ancestors");
|
|
222
|
-
|
|
223
252
|
/*
|
|
224
253
|
* Document-class: PG::TypeMapByClass < PG::TypeMap
|
|
225
254
|
*
|
|
@@ -235,5 +264,6 @@ init_pg_type_map_by_class()
|
|
|
235
264
|
rb_define_method( rb_cTypeMapByClass, "[]=", pg_tmbk_aset, 2 );
|
|
236
265
|
rb_define_method( rb_cTypeMapByClass, "[]", pg_tmbk_aref, 1 );
|
|
237
266
|
rb_define_method( rb_cTypeMapByClass, "coders", pg_tmbk_coders, 0 );
|
|
267
|
+
/* rb_mDefaultTypeMappable = rb_define_module_under( rb_cTypeMap, "DefaultTypeMappable"); */
|
|
238
268
|
rb_include_module( rb_cTypeMapByClass, rb_mDefaultTypeMappable );
|
|
239
269
|
}
|
data/ext/pg_type_map_by_column.c
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/*
|
|
2
2
|
* pg_column_map.c - PG::ColumnMap class extension
|
|
3
|
-
* $Id
|
|
3
|
+
* $Id$
|
|
4
4
|
*
|
|
5
5
|
*/
|
|
6
6
|
|
|
@@ -16,7 +16,7 @@ static VALUE
|
|
|
16
16
|
pg_tmbc_fit_to_result( VALUE self, VALUE result )
|
|
17
17
|
{
|
|
18
18
|
int nfields;
|
|
19
|
-
t_tmbc *this =
|
|
19
|
+
t_tmbc *this = RTYPEDDATA_DATA( self );
|
|
20
20
|
t_typemap *default_tm;
|
|
21
21
|
VALUE sub_typemap;
|
|
22
22
|
|
|
@@ -26,8 +26,8 @@ pg_tmbc_fit_to_result( VALUE self, VALUE result )
|
|
|
26
26
|
nfields, this->nfields );
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
/* Ensure that the default type map fits
|
|
30
|
-
default_tm =
|
|
29
|
+
/* Ensure that the default type map fits equally. */
|
|
30
|
+
default_tm = RTYPEDDATA_DATA( this->typemap.default_typemap );
|
|
31
31
|
sub_typemap = default_tm->funcs.fit_to_result( this->typemap.default_typemap, result );
|
|
32
32
|
|
|
33
33
|
/* Did the default type return the same object ? */
|
|
@@ -42,7 +42,7 @@ pg_tmbc_fit_to_result( VALUE self, VALUE result )
|
|
|
42
42
|
|
|
43
43
|
memcpy( p_new_typemap, this, struct_size );
|
|
44
44
|
p_new_typemap->typemap.default_typemap = sub_typemap;
|
|
45
|
-
|
|
45
|
+
RTYPEDDATA_DATA(new_typemap) = p_new_typemap;
|
|
46
46
|
return new_typemap;
|
|
47
47
|
}
|
|
48
48
|
}
|
|
@@ -51,7 +51,7 @@ static VALUE
|
|
|
51
51
|
pg_tmbc_fit_to_query( VALUE self, VALUE params )
|
|
52
52
|
{
|
|
53
53
|
int nfields;
|
|
54
|
-
t_tmbc *this =
|
|
54
|
+
t_tmbc *this = RTYPEDDATA_DATA( self );
|
|
55
55
|
t_typemap *default_tm;
|
|
56
56
|
|
|
57
57
|
nfields = (int)RARRAY_LEN( params );
|
|
@@ -60,8 +60,8 @@ pg_tmbc_fit_to_query( VALUE self, VALUE params )
|
|
|
60
60
|
nfields, this->nfields );
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
-
/* Ensure that the default type map fits
|
|
64
|
-
default_tm =
|
|
63
|
+
/* Ensure that the default type map fits equally. */
|
|
64
|
+
default_tm = RTYPEDDATA_DATA( this->typemap.default_typemap );
|
|
65
65
|
default_tm->funcs.fit_to_query( this->typemap.default_typemap, params );
|
|
66
66
|
|
|
67
67
|
return self;
|
|
@@ -70,10 +70,10 @@ pg_tmbc_fit_to_query( VALUE self, VALUE params )
|
|
|
70
70
|
static int
|
|
71
71
|
pg_tmbc_fit_to_copy_get( VALUE self )
|
|
72
72
|
{
|
|
73
|
-
t_tmbc *this =
|
|
73
|
+
t_tmbc *this = RTYPEDDATA_DATA( self );
|
|
74
74
|
|
|
75
|
-
/* Ensure that the default type map fits
|
|
76
|
-
t_typemap *default_tm =
|
|
75
|
+
/* Ensure that the default type map fits equally. */
|
|
76
|
+
t_typemap *default_tm = RTYPEDDATA_DATA( this->typemap.default_typemap );
|
|
77
77
|
default_tm->funcs.fit_to_copy_get( this->typemap.default_typemap );
|
|
78
78
|
|
|
79
79
|
return this->nfields;
|
|
@@ -99,15 +99,15 @@ pg_tmbc_result_value( t_typemap *p_typemap, VALUE result, int tuple, int field )
|
|
|
99
99
|
int len = PQgetlength( p_result->pgresult, tuple, field );
|
|
100
100
|
|
|
101
101
|
if( p_coder->dec_func ){
|
|
102
|
-
return p_coder->dec_func(p_coder, val, len, tuple, field,
|
|
102
|
+
return p_coder->dec_func(p_coder, val, len, tuple, field, p_result->enc_idx);
|
|
103
103
|
} else {
|
|
104
104
|
t_pg_coder_dec_func dec_func;
|
|
105
105
|
dec_func = pg_coder_dec_func( p_coder, PQfformat(p_result->pgresult, field) );
|
|
106
|
-
return dec_func(p_coder, val, len, tuple, field,
|
|
106
|
+
return dec_func(p_coder, val, len, tuple, field, p_result->enc_idx);
|
|
107
107
|
}
|
|
108
108
|
}
|
|
109
109
|
|
|
110
|
-
default_tm =
|
|
110
|
+
default_tm = RTYPEDDATA_DATA( this->typemap.default_typemap );
|
|
111
111
|
return default_tm->funcs.typecast_result_value( default_tm, result, tuple, field );
|
|
112
112
|
}
|
|
113
113
|
|
|
@@ -120,7 +120,7 @@ pg_tmbc_typecast_query_param( t_typemap *p_typemap, VALUE param_value, int field
|
|
|
120
120
|
t_pg_coder *p_coder = this->convs[field].cconv;
|
|
121
121
|
|
|
122
122
|
if( !p_coder ){
|
|
123
|
-
t_typemap *default_tm =
|
|
123
|
+
t_typemap *default_tm = RTYPEDDATA_DATA( this->typemap.default_typemap );
|
|
124
124
|
return default_tm->funcs.typecast_query_param( default_tm, param_value, field );
|
|
125
125
|
}
|
|
126
126
|
|
|
@@ -142,7 +142,7 @@ pg_tmbc_typecast_copy_get( t_typemap *p_typemap, VALUE field_str, int fieldno, i
|
|
|
142
142
|
p_coder = this->convs[fieldno].cconv;
|
|
143
143
|
|
|
144
144
|
if( !p_coder ){
|
|
145
|
-
t_typemap *default_tm =
|
|
145
|
+
t_typemap *default_tm = RTYPEDDATA_DATA( this->typemap.default_typemap );
|
|
146
146
|
return default_tm->funcs.typecast_copy_get( default_tm, field_str, fieldno, format, enc_idx );
|
|
147
147
|
}
|
|
148
148
|
|
|
@@ -150,15 +150,17 @@ pg_tmbc_typecast_copy_get( t_typemap *p_typemap, VALUE field_str, int fieldno, i
|
|
|
150
150
|
|
|
151
151
|
/* Is it a pure String conversion? Then we can directly send field_str to the user. */
|
|
152
152
|
if( dec_func == pg_text_dec_string ){
|
|
153
|
+
rb_str_modify(field_str);
|
|
153
154
|
PG_ENCODING_SET_NOCHECK( field_str, enc_idx );
|
|
154
155
|
return field_str;
|
|
155
156
|
}
|
|
156
157
|
if( dec_func == pg_bin_dec_bytea ){
|
|
158
|
+
rb_str_modify(field_str);
|
|
157
159
|
PG_ENCODING_SET_NOCHECK( field_str, rb_ascii8bit_encindex() );
|
|
158
160
|
return field_str;
|
|
159
161
|
}
|
|
160
162
|
|
|
161
|
-
return dec_func( p_coder, RSTRING_PTR(field_str),
|
|
163
|
+
return dec_func( p_coder, RSTRING_PTR(field_str), RSTRING_LENINT(field_str), 0, fieldno, enc_idx );
|
|
162
164
|
}
|
|
163
165
|
|
|
164
166
|
const struct pg_typemap_funcs pg_tmbc_funcs = {
|
|
@@ -171,34 +173,73 @@ const struct pg_typemap_funcs pg_tmbc_funcs = {
|
|
|
171
173
|
};
|
|
172
174
|
|
|
173
175
|
static void
|
|
174
|
-
pg_tmbc_mark(
|
|
176
|
+
pg_tmbc_mark( void *_this )
|
|
175
177
|
{
|
|
178
|
+
t_tmbc *this = (t_tmbc *)_this;
|
|
176
179
|
int i;
|
|
177
180
|
|
|
178
181
|
/* allocated but not initialized ? */
|
|
179
182
|
if( this == (t_tmbc *)&pg_typemap_funcs ) return;
|
|
180
183
|
|
|
181
|
-
|
|
184
|
+
pg_typemap_mark(&this->typemap);
|
|
182
185
|
for( i=0; i<this->nfields; i++){
|
|
183
186
|
t_pg_coder *p_coder = this->convs[i].cconv;
|
|
184
187
|
if( p_coder )
|
|
185
|
-
|
|
188
|
+
rb_gc_mark_movable(p_coder->coder_obj);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
static size_t
|
|
193
|
+
pg_tmbc_memsize( const void *_this )
|
|
194
|
+
{
|
|
195
|
+
const t_tmbc *this = (const t_tmbc *)_this;
|
|
196
|
+
return sizeof(t_tmbc) + sizeof(struct pg_tmbc_converter) * this->nfields;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
static void
|
|
200
|
+
pg_tmbc_compact( void *_this )
|
|
201
|
+
{
|
|
202
|
+
t_tmbc *this = (t_tmbc *)_this;
|
|
203
|
+
int i;
|
|
204
|
+
|
|
205
|
+
/* allocated but not initialized ? */
|
|
206
|
+
if( this == (t_tmbc *)&pg_typemap_funcs ) return;
|
|
207
|
+
|
|
208
|
+
pg_typemap_compact(&this->typemap);
|
|
209
|
+
for( i=0; i<this->nfields; i++){
|
|
210
|
+
t_pg_coder *p_coder = this->convs[i].cconv;
|
|
211
|
+
if( p_coder )
|
|
212
|
+
pg_gc_location(p_coder->coder_obj);
|
|
186
213
|
}
|
|
187
214
|
}
|
|
188
215
|
|
|
189
216
|
static void
|
|
190
|
-
pg_tmbc_free(
|
|
217
|
+
pg_tmbc_free( void *_this )
|
|
191
218
|
{
|
|
219
|
+
t_tmbc *this = (t_tmbc *)_this;
|
|
192
220
|
/* allocated but not initialized ? */
|
|
193
221
|
if( this == (t_tmbc *)&pg_typemap_funcs ) return;
|
|
194
222
|
xfree( this );
|
|
195
223
|
}
|
|
196
224
|
|
|
225
|
+
static const rb_data_type_t pg_tmbc_type = {
|
|
226
|
+
"PG::TypeMapByColumn",
|
|
227
|
+
{
|
|
228
|
+
pg_tmbc_mark,
|
|
229
|
+
pg_tmbc_free,
|
|
230
|
+
pg_tmbc_memsize,
|
|
231
|
+
pg_compact_callback(pg_tmbc_compact),
|
|
232
|
+
},
|
|
233
|
+
&pg_typemap_type,
|
|
234
|
+
0,
|
|
235
|
+
RUBY_TYPED_FREE_IMMEDIATELY,
|
|
236
|
+
};
|
|
237
|
+
|
|
197
238
|
static VALUE
|
|
198
239
|
pg_tmbc_s_allocate( VALUE klass )
|
|
199
240
|
{
|
|
200
241
|
/* Use pg_typemap_funcs as interim struct until #initialize is called. */
|
|
201
|
-
return
|
|
242
|
+
return TypedData_Wrap_Struct( klass, &pg_tmbc_type, (t_tmbc *)&pg_typemap_funcs );
|
|
202
243
|
}
|
|
203
244
|
|
|
204
245
|
VALUE
|
|
@@ -221,19 +262,18 @@ pg_tmbc_allocate()
|
|
|
221
262
|
static VALUE
|
|
222
263
|
pg_tmbc_init(VALUE self, VALUE conv_ary)
|
|
223
264
|
{
|
|
224
|
-
|
|
265
|
+
long i;
|
|
225
266
|
t_tmbc *this;
|
|
226
267
|
int conv_ary_len;
|
|
227
268
|
|
|
228
|
-
Check_Type(self, T_DATA);
|
|
229
269
|
Check_Type(conv_ary, T_ARRAY);
|
|
230
|
-
conv_ary_len =
|
|
270
|
+
conv_ary_len = RARRAY_LENINT(conv_ary);
|
|
231
271
|
this = xmalloc(sizeof(t_tmbc) + sizeof(struct pg_tmbc_converter) * conv_ary_len);
|
|
232
272
|
/* Set nfields to 0 at first, so that GC mark function doesn't access uninitialized memory. */
|
|
233
273
|
this->nfields = 0;
|
|
234
274
|
this->typemap.funcs = pg_tmbc_funcs;
|
|
235
275
|
this->typemap.default_typemap = pg_typemap_all_strings;
|
|
236
|
-
|
|
276
|
+
RTYPEDDATA_DATA(self) = this;
|
|
237
277
|
|
|
238
278
|
for(i=0; i<conv_ary_len; i++)
|
|
239
279
|
{
|
|
@@ -242,11 +282,9 @@ pg_tmbc_init(VALUE self, VALUE conv_ary)
|
|
|
242
282
|
if( obj == Qnil ){
|
|
243
283
|
/* no type cast */
|
|
244
284
|
this->convs[i].cconv = NULL;
|
|
245
|
-
} else if( rb_obj_is_kind_of(obj, rb_cPG_Coder) ){
|
|
246
|
-
Data_Get_Struct(obj, t_pg_coder, this->convs[i].cconv);
|
|
247
285
|
} else {
|
|
248
|
-
|
|
249
|
-
|
|
286
|
+
/* Check argument type and store the coder pointer */
|
|
287
|
+
TypedData_Get_Struct(obj, t_pg_coder, &pg_coder_type, this->convs[i].cconv);
|
|
250
288
|
}
|
|
251
289
|
}
|
|
252
290
|
|
|
@@ -266,7 +304,7 @@ static VALUE
|
|
|
266
304
|
pg_tmbc_coders(VALUE self)
|
|
267
305
|
{
|
|
268
306
|
int i;
|
|
269
|
-
t_tmbc *this =
|
|
307
|
+
t_tmbc *this = RTYPEDDATA_DATA( self );
|
|
270
308
|
VALUE ary_coders = rb_ary_new();
|
|
271
309
|
|
|
272
310
|
for( i=0; i<this->nfields; i++){
|
|
@@ -292,13 +330,13 @@ init_pg_type_map_by_column()
|
|
|
292
330
|
*
|
|
293
331
|
* This type map casts values by a coder assigned per field/column.
|
|
294
332
|
*
|
|
295
|
-
* Each PG
|
|
296
|
-
* that is defined at
|
|
333
|
+
* Each PG::TypeMapByColumn has a fixed list of either encoders or decoders,
|
|
334
|
+
* that is defined at TypeMapByColumn.new . A type map with encoders is usable for type casting
|
|
297
335
|
* query bind parameters and COPY data for PG::Connection#put_copy_data .
|
|
298
336
|
* A type map with decoders is usable for type casting of result values and
|
|
299
337
|
* COPY data from PG::Connection#get_copy_data .
|
|
300
338
|
*
|
|
301
|
-
* PG::
|
|
339
|
+
* PG::TypeMapByColumn objects are in particular useful in conjunction with prepared statements,
|
|
302
340
|
* since they can be cached alongside with the statement handle.
|
|
303
341
|
*
|
|
304
342
|
* This type map strategy is also used internally by PG::TypeMapByOid, when the
|
|
@@ -308,5 +346,6 @@ init_pg_type_map_by_column()
|
|
|
308
346
|
rb_define_alloc_func( rb_cTypeMapByColumn, pg_tmbc_s_allocate );
|
|
309
347
|
rb_define_method( rb_cTypeMapByColumn, "initialize", pg_tmbc_init, 1 );
|
|
310
348
|
rb_define_method( rb_cTypeMapByColumn, "coders", pg_tmbc_coders, 0 );
|
|
349
|
+
/* rb_mDefaultTypeMappable = rb_define_module_under( rb_cTypeMap, "DefaultTypeMappable"); */
|
|
311
350
|
rb_include_module( rb_cTypeMapByColumn, rb_mDefaultTypeMappable );
|
|
312
351
|
}
|