pg 1.3.0.rc2-x64-mingw-ucrt

Sign up to get free protection for your applications and to get access to all the features.
Files changed (111) hide show
  1. checksums.yaml +7 -0
  2. checksums.yaml.gz.sig +3 -0
  3. data/.appveyor.yml +36 -0
  4. data/.gems +6 -0
  5. data/.gemtest +0 -0
  6. data/.github/workflows/binary-gems.yml +85 -0
  7. data/.github/workflows/source-gem.yml +130 -0
  8. data/.gitignore +13 -0
  9. data/.hgsigs +34 -0
  10. data/.hgtags +41 -0
  11. data/.irbrc +23 -0
  12. data/.pryrc +23 -0
  13. data/.tm_properties +21 -0
  14. data/.travis.yml +49 -0
  15. data/BSDL +22 -0
  16. data/Contributors.rdoc +46 -0
  17. data/Gemfile +14 -0
  18. data/History.rdoc +648 -0
  19. data/LICENSE +56 -0
  20. data/Manifest.txt +72 -0
  21. data/POSTGRES +23 -0
  22. data/README-OS_X.rdoc +68 -0
  23. data/README-Windows.rdoc +56 -0
  24. data/README.ja.rdoc +13 -0
  25. data/README.rdoc +214 -0
  26. data/Rakefile +106 -0
  27. data/Rakefile.cross +300 -0
  28. data/certs/ged.pem +24 -0
  29. data/ext/errorcodes.def +1040 -0
  30. data/ext/errorcodes.rb +45 -0
  31. data/ext/errorcodes.txt +496 -0
  32. data/ext/extconf.rb +165 -0
  33. data/ext/gvl_wrappers.c +21 -0
  34. data/ext/gvl_wrappers.h +264 -0
  35. data/ext/pg.c +732 -0
  36. data/ext/pg.h +385 -0
  37. data/ext/pg_binary_decoder.c +229 -0
  38. data/ext/pg_binary_encoder.c +163 -0
  39. data/ext/pg_coder.c +615 -0
  40. data/ext/pg_connection.c +4415 -0
  41. data/ext/pg_copy_coder.c +628 -0
  42. data/ext/pg_errors.c +95 -0
  43. data/ext/pg_record_coder.c +519 -0
  44. data/ext/pg_result.c +1683 -0
  45. data/ext/pg_text_decoder.c +987 -0
  46. data/ext/pg_text_encoder.c +814 -0
  47. data/ext/pg_tuple.c +575 -0
  48. data/ext/pg_type_map.c +199 -0
  49. data/ext/pg_type_map_all_strings.c +129 -0
  50. data/ext/pg_type_map_by_class.c +269 -0
  51. data/ext/pg_type_map_by_column.c +349 -0
  52. data/ext/pg_type_map_by_mri_type.c +313 -0
  53. data/ext/pg_type_map_by_oid.c +385 -0
  54. data/ext/pg_type_map_in_ruby.c +330 -0
  55. data/ext/pg_util.c +149 -0
  56. data/ext/pg_util.h +65 -0
  57. data/ext/vc/pg.sln +26 -0
  58. data/ext/vc/pg_18/pg.vcproj +216 -0
  59. data/ext/vc/pg_19/pg_19.vcproj +209 -0
  60. data/lib/3.1/pg_ext.so +0 -0
  61. data/lib/pg/basic_type_map_based_on_result.rb +47 -0
  62. data/lib/pg/basic_type_map_for_queries.rb +193 -0
  63. data/lib/pg/basic_type_map_for_results.rb +81 -0
  64. data/lib/pg/basic_type_registry.rb +296 -0
  65. data/lib/pg/binary_decoder.rb +23 -0
  66. data/lib/pg/coder.rb +104 -0
  67. data/lib/pg/connection.rb +813 -0
  68. data/lib/pg/constants.rb +12 -0
  69. data/lib/pg/exceptions.rb +12 -0
  70. data/lib/pg/result.rb +43 -0
  71. data/lib/pg/text_decoder.rb +46 -0
  72. data/lib/pg/text_encoder.rb +59 -0
  73. data/lib/pg/tuple.rb +30 -0
  74. data/lib/pg/type_map_by_column.rb +16 -0
  75. data/lib/pg/version.rb +4 -0
  76. data/lib/pg.rb +87 -0
  77. data/lib/x64-mingw-ucrt/libpq.dll +0 -0
  78. data/misc/openssl-pg-segfault.rb +31 -0
  79. data/misc/postgres/History.txt +9 -0
  80. data/misc/postgres/Manifest.txt +5 -0
  81. data/misc/postgres/README.txt +21 -0
  82. data/misc/postgres/Rakefile +21 -0
  83. data/misc/postgres/lib/postgres.rb +16 -0
  84. data/misc/ruby-pg/History.txt +9 -0
  85. data/misc/ruby-pg/Manifest.txt +5 -0
  86. data/misc/ruby-pg/README.txt +21 -0
  87. data/misc/ruby-pg/Rakefile +21 -0
  88. data/misc/ruby-pg/lib/ruby/pg.rb +16 -0
  89. data/pg.gemspec +32 -0
  90. data/sample/array_insert.rb +20 -0
  91. data/sample/async_api.rb +106 -0
  92. data/sample/async_copyto.rb +39 -0
  93. data/sample/async_mixed.rb +56 -0
  94. data/sample/check_conn.rb +21 -0
  95. data/sample/copydata.rb +71 -0
  96. data/sample/copyfrom.rb +81 -0
  97. data/sample/copyto.rb +19 -0
  98. data/sample/cursor.rb +21 -0
  99. data/sample/disk_usage_report.rb +177 -0
  100. data/sample/issue-119.rb +94 -0
  101. data/sample/losample.rb +69 -0
  102. data/sample/minimal-testcase.rb +17 -0
  103. data/sample/notify_wait.rb +72 -0
  104. data/sample/pg_statistics.rb +285 -0
  105. data/sample/replication_monitor.rb +222 -0
  106. data/sample/test_binary_values.rb +33 -0
  107. data/sample/wal_shipper.rb +434 -0
  108. data/sample/warehouse_partitions.rb +311 -0
  109. data.tar.gz.sig +0 -0
  110. metadata +188 -0
  111. metadata.gz.sig +0 -0
@@ -0,0 +1,349 @@
1
+ /*
2
+ * pg_column_map.c - PG::ColumnMap class extension
3
+ * $Id$
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 pg_tmbc_s_allocate( VALUE klass );
14
+
15
+ static VALUE
16
+ pg_tmbc_fit_to_result( VALUE self, VALUE result )
17
+ {
18
+ int nfields;
19
+ t_tmbc *this = RTYPEDDATA_DATA( self );
20
+ t_typemap *default_tm;
21
+ VALUE sub_typemap;
22
+
23
+ nfields = PQnfields( pgresult_get(result) );
24
+ if ( this->nfields != nfields ) {
25
+ rb_raise( rb_eArgError, "number of result fields (%d) does not match number of mapped columns (%d)",
26
+ nfields, this->nfields );
27
+ }
28
+
29
+ /* Ensure that the default type map fits equally. */
30
+ default_tm = RTYPEDDATA_DATA( this->typemap.default_typemap );
31
+ sub_typemap = default_tm->funcs.fit_to_result( this->typemap.default_typemap, result );
32
+
33
+ /* Did the default type return the same object ? */
34
+ if( sub_typemap == this->typemap.default_typemap ){
35
+ return self;
36
+ } else {
37
+ /* Our default type map built a new object, so we need to propagate it
38
+ * and build a copy of this type map and set it as default there.. */
39
+ VALUE new_typemap = pg_tmbc_s_allocate( rb_cTypeMapByColumn );
40
+ size_t struct_size = sizeof(t_tmbc) + sizeof(struct pg_tmbc_converter) * nfields;
41
+ t_tmbc *p_new_typemap = (t_tmbc *)xmalloc(struct_size);
42
+
43
+ memcpy( p_new_typemap, this, struct_size );
44
+ p_new_typemap->typemap.default_typemap = sub_typemap;
45
+ RTYPEDDATA_DATA(new_typemap) = p_new_typemap;
46
+ return new_typemap;
47
+ }
48
+ }
49
+
50
+ static VALUE
51
+ pg_tmbc_fit_to_query( VALUE self, VALUE params )
52
+ {
53
+ int nfields;
54
+ t_tmbc *this = RTYPEDDATA_DATA( self );
55
+ t_typemap *default_tm;
56
+
57
+ nfields = (int)RARRAY_LEN( params );
58
+ if ( this->nfields != nfields ) {
59
+ rb_raise( rb_eArgError, "number of result fields (%d) does not match number of mapped columns (%d)",
60
+ nfields, this->nfields );
61
+ }
62
+
63
+ /* Ensure that the default type map fits equally. */
64
+ default_tm = RTYPEDDATA_DATA( this->typemap.default_typemap );
65
+ default_tm->funcs.fit_to_query( this->typemap.default_typemap, params );
66
+
67
+ return self;
68
+ }
69
+
70
+ static int
71
+ pg_tmbc_fit_to_copy_get( VALUE self )
72
+ {
73
+ t_tmbc *this = RTYPEDDATA_DATA( self );
74
+
75
+ /* Ensure that the default type map fits equally. */
76
+ t_typemap *default_tm = RTYPEDDATA_DATA( this->typemap.default_typemap );
77
+ default_tm->funcs.fit_to_copy_get( this->typemap.default_typemap );
78
+
79
+ return this->nfields;
80
+ }
81
+
82
+
83
+ VALUE
84
+ pg_tmbc_result_value( t_typemap *p_typemap, VALUE result, int tuple, int field )
85
+ {
86
+ t_pg_coder *p_coder = NULL;
87
+ t_pg_result *p_result = pgresult_get_this(result);
88
+ t_tmbc *this = (t_tmbc *) p_typemap;
89
+ t_typemap *default_tm;
90
+
91
+ if (PQgetisnull(p_result->pgresult, tuple, field)) {
92
+ return Qnil;
93
+ }
94
+
95
+ p_coder = this->convs[field].cconv;
96
+
97
+ if( p_coder ){
98
+ char * val = PQgetvalue( p_result->pgresult, tuple, field );
99
+ int len = PQgetlength( p_result->pgresult, tuple, field );
100
+
101
+ if( p_coder->dec_func ){
102
+ return p_coder->dec_func(p_coder, val, len, tuple, field, p_result->enc_idx);
103
+ } else {
104
+ t_pg_coder_dec_func dec_func;
105
+ dec_func = pg_coder_dec_func( p_coder, PQfformat(p_result->pgresult, field) );
106
+ return dec_func(p_coder, val, len, tuple, field, p_result->enc_idx);
107
+ }
108
+ }
109
+
110
+ default_tm = RTYPEDDATA_DATA( this->typemap.default_typemap );
111
+ return default_tm->funcs.typecast_result_value( default_tm, result, tuple, field );
112
+ }
113
+
114
+ static t_pg_coder *
115
+ pg_tmbc_typecast_query_param( t_typemap *p_typemap, VALUE param_value, int field )
116
+ {
117
+ t_tmbc *this = (t_tmbc *) p_typemap;
118
+
119
+ /* Number of fields were already checked in pg_tmbc_fit_to_query() */
120
+ t_pg_coder *p_coder = this->convs[field].cconv;
121
+
122
+ if( !p_coder ){
123
+ t_typemap *default_tm = RTYPEDDATA_DATA( this->typemap.default_typemap );
124
+ return default_tm->funcs.typecast_query_param( default_tm, param_value, field );
125
+ }
126
+
127
+ return p_coder;
128
+ }
129
+
130
+ static VALUE
131
+ pg_tmbc_typecast_copy_get( t_typemap *p_typemap, VALUE field_str, int fieldno, int format, int enc_idx )
132
+ {
133
+ t_tmbc *this = (t_tmbc *) p_typemap;
134
+ t_pg_coder *p_coder;
135
+ t_pg_coder_dec_func dec_func;
136
+
137
+ if ( fieldno >= this->nfields || fieldno < 0 ) {
138
+ rb_raise( rb_eArgError, "number of copy fields (%d) exceeds number of mapped columns (%d)",
139
+ fieldno, this->nfields );
140
+ }
141
+
142
+ p_coder = this->convs[fieldno].cconv;
143
+
144
+ if( !p_coder ){
145
+ t_typemap *default_tm = RTYPEDDATA_DATA( this->typemap.default_typemap );
146
+ return default_tm->funcs.typecast_copy_get( default_tm, field_str, fieldno, format, enc_idx );
147
+ }
148
+
149
+ dec_func = pg_coder_dec_func( p_coder, format );
150
+
151
+ /* Is it a pure String conversion? Then we can directly send field_str to the user. */
152
+ if( dec_func == pg_text_dec_string ){
153
+ PG_ENCODING_SET_NOCHECK( field_str, enc_idx );
154
+ return field_str;
155
+ }
156
+ if( dec_func == pg_bin_dec_bytea ){
157
+ PG_ENCODING_SET_NOCHECK( field_str, rb_ascii8bit_encindex() );
158
+ return field_str;
159
+ }
160
+
161
+ return dec_func( p_coder, RSTRING_PTR(field_str), RSTRING_LENINT(field_str), 0, fieldno, enc_idx );
162
+ }
163
+
164
+ const struct pg_typemap_funcs pg_tmbc_funcs = {
165
+ pg_tmbc_fit_to_result,
166
+ pg_tmbc_fit_to_query,
167
+ pg_tmbc_fit_to_copy_get,
168
+ pg_tmbc_result_value,
169
+ pg_tmbc_typecast_query_param,
170
+ pg_tmbc_typecast_copy_get
171
+ };
172
+
173
+ static void
174
+ pg_tmbc_mark( void *_this )
175
+ {
176
+ t_tmbc *this = (t_tmbc *)_this;
177
+ int i;
178
+
179
+ /* allocated but not initialized ? */
180
+ if( this == (t_tmbc *)&pg_typemap_funcs ) return;
181
+
182
+ pg_typemap_mark(&this->typemap);
183
+ for( i=0; i<this->nfields; i++){
184
+ t_pg_coder *p_coder = this->convs[i].cconv;
185
+ if( p_coder )
186
+ rb_gc_mark_movable(p_coder->coder_obj);
187
+ }
188
+ }
189
+
190
+ static size_t
191
+ pg_tmbc_memsize( const void *_this )
192
+ {
193
+ const t_tmbc *this = (const t_tmbc *)_this;
194
+ return sizeof(t_tmbc) + sizeof(struct pg_tmbc_converter) * this->nfields;
195
+ }
196
+
197
+ static void
198
+ pg_tmbc_compact( void *_this )
199
+ {
200
+ t_tmbc *this = (t_tmbc *)_this;
201
+ int i;
202
+
203
+ /* allocated but not initialized ? */
204
+ if( this == (t_tmbc *)&pg_typemap_funcs ) return;
205
+
206
+ pg_typemap_compact(&this->typemap);
207
+ for( i=0; i<this->nfields; i++){
208
+ t_pg_coder *p_coder = this->convs[i].cconv;
209
+ if( p_coder )
210
+ pg_gc_location(p_coder->coder_obj);
211
+ }
212
+ }
213
+
214
+ static void
215
+ pg_tmbc_free( void *_this )
216
+ {
217
+ t_tmbc *this = (t_tmbc *)_this;
218
+ /* allocated but not initialized ? */
219
+ if( this == (t_tmbc *)&pg_typemap_funcs ) return;
220
+ xfree( this );
221
+ }
222
+
223
+ static const rb_data_type_t pg_tmbc_type = {
224
+ "PG::TypeMapByColumn",
225
+ {
226
+ pg_tmbc_mark,
227
+ pg_tmbc_free,
228
+ pg_tmbc_memsize,
229
+ pg_compact_callback(pg_tmbc_compact),
230
+ },
231
+ &pg_typemap_type,
232
+ 0,
233
+ RUBY_TYPED_FREE_IMMEDIATELY,
234
+ };
235
+
236
+ static VALUE
237
+ pg_tmbc_s_allocate( VALUE klass )
238
+ {
239
+ /* Use pg_typemap_funcs as interim struct until #initialize is called. */
240
+ return TypedData_Wrap_Struct( klass, &pg_tmbc_type, (t_tmbc *)&pg_typemap_funcs );
241
+ }
242
+
243
+ VALUE
244
+ pg_tmbc_allocate()
245
+ {
246
+ return pg_tmbc_s_allocate(rb_cTypeMapByColumn);
247
+ }
248
+
249
+ /*
250
+ * call-seq:
251
+ * PG::TypeMapByColumn.new( coders )
252
+ *
253
+ * Builds a new type map and assigns a list of coders for the given column.
254
+ * +coders+ must be an Array of PG::Coder objects or +nil+ values.
255
+ * The length of the Array corresponds to
256
+ * the number of columns or bind parameters this type map is usable for.
257
+ *
258
+ * A +nil+ value will forward the given field to the #default_type_map .
259
+ */
260
+ static VALUE
261
+ pg_tmbc_init(VALUE self, VALUE conv_ary)
262
+ {
263
+ long i;
264
+ t_tmbc *this;
265
+ int conv_ary_len;
266
+
267
+ Check_Type(conv_ary, T_ARRAY);
268
+ conv_ary_len = RARRAY_LENINT(conv_ary);
269
+ this = xmalloc(sizeof(t_tmbc) + sizeof(struct pg_tmbc_converter) * conv_ary_len);
270
+ /* Set nfields to 0 at first, so that GC mark function doesn't access uninitialized memory. */
271
+ this->nfields = 0;
272
+ this->typemap.funcs = pg_tmbc_funcs;
273
+ this->typemap.default_typemap = pg_typemap_all_strings;
274
+ RTYPEDDATA_DATA(self) = this;
275
+
276
+ for(i=0; i<conv_ary_len; i++)
277
+ {
278
+ VALUE obj = rb_ary_entry(conv_ary, i);
279
+
280
+ if( obj == Qnil ){
281
+ /* no type cast */
282
+ this->convs[i].cconv = NULL;
283
+ } else {
284
+ /* Check argument type and store the coder pointer */
285
+ TypedData_Get_Struct(obj, t_pg_coder, &pg_coder_type, this->convs[i].cconv);
286
+ }
287
+ }
288
+
289
+ this->nfields = conv_ary_len;
290
+
291
+ return self;
292
+ }
293
+
294
+ /*
295
+ * call-seq:
296
+ * typemap.coders -> Array
297
+ *
298
+ * Array of PG::Coder objects. The length of the Array corresponds to
299
+ * the number of columns or bind parameters this type map is usable for.
300
+ */
301
+ static VALUE
302
+ pg_tmbc_coders(VALUE self)
303
+ {
304
+ int i;
305
+ t_tmbc *this = RTYPEDDATA_DATA( self );
306
+ VALUE ary_coders = rb_ary_new();
307
+
308
+ for( i=0; i<this->nfields; i++){
309
+ t_pg_coder *conv = this->convs[i].cconv;
310
+ if( conv ) {
311
+ rb_ary_push( ary_coders, conv->coder_obj );
312
+ } else {
313
+ rb_ary_push( ary_coders, Qnil );
314
+ }
315
+ }
316
+
317
+ return rb_obj_freeze(ary_coders);
318
+ }
319
+
320
+ void
321
+ init_pg_type_map_by_column()
322
+ {
323
+ s_id_decode = rb_intern("decode");
324
+ s_id_encode = rb_intern("encode");
325
+
326
+ /*
327
+ * Document-class: PG::TypeMapByColumn < PG::TypeMap
328
+ *
329
+ * This type map casts values by a coder assigned per field/column.
330
+ *
331
+ * Each PG::TypeMapByColumn has a fixed list of either encoders or decoders,
332
+ * that is defined at TypeMapByColumn.new . A type map with encoders is usable for type casting
333
+ * query bind parameters and COPY data for PG::Connection#put_copy_data .
334
+ * A type map with decoders is usable for type casting of result values and
335
+ * COPY data from PG::Connection#get_copy_data .
336
+ *
337
+ * PG::TypeMapByColumn objects are in particular useful in conjunction with prepared statements,
338
+ * since they can be cached alongside with the statement handle.
339
+ *
340
+ * This type map strategy is also used internally by PG::TypeMapByOid, when the
341
+ * number of rows of a result set exceeds a given limit.
342
+ */
343
+ rb_cTypeMapByColumn = rb_define_class_under( rb_mPG, "TypeMapByColumn", rb_cTypeMap );
344
+ rb_define_alloc_func( rb_cTypeMapByColumn, pg_tmbc_s_allocate );
345
+ rb_define_method( rb_cTypeMapByColumn, "initialize", pg_tmbc_init, 1 );
346
+ rb_define_method( rb_cTypeMapByColumn, "coders", pg_tmbc_coders, 0 );
347
+ /* rb_mDefaultTypeMappable = rb_define_module_under( rb_cTypeMap, "DefaultTypeMappable"); */
348
+ rb_include_module( rb_cTypeMapByColumn, rb_mDefaultTypeMappable );
349
+ }
@@ -0,0 +1,313 @@
1
+ /*
2
+ * pg_type_map_by_mri_type.c - PG::TypeMapByMriType class extension
3
+ * $Id$
4
+ *
5
+ * This type map can be used to select value encoders based on the MRI-internal
6
+ * value type code.
7
+ *
8
+ */
9
+
10
+ #include "pg.h"
11
+
12
+ static VALUE rb_cTypeMapByMriType;
13
+
14
+ #define FOR_EACH_MRI_TYPE(func) \
15
+ func(T_FIXNUM) \
16
+ func(T_TRUE) \
17
+ func(T_FALSE) \
18
+ func(T_FLOAT) \
19
+ func(T_BIGNUM) \
20
+ func(T_COMPLEX) \
21
+ func(T_RATIONAL) \
22
+ func(T_ARRAY) \
23
+ func(T_STRING) \
24
+ func(T_SYMBOL) \
25
+ func(T_OBJECT) \
26
+ func(T_CLASS) \
27
+ func(T_MODULE) \
28
+ func(T_REGEXP) \
29
+ func(T_HASH) \
30
+ func(T_STRUCT) \
31
+ func(T_FILE) \
32
+ func(T_DATA)
33
+
34
+ #define DECLARE_CODER(type) \
35
+ t_pg_coder *coder_##type; \
36
+ VALUE ask_##type; \
37
+ VALUE coder_obj_##type;
38
+
39
+ typedef struct {
40
+ t_typemap typemap;
41
+ struct pg_tmbmt_converter {
42
+ FOR_EACH_MRI_TYPE( DECLARE_CODER )
43
+ } coders;
44
+ } t_tmbmt;
45
+
46
+
47
+ #define CASE_AND_GET(type) \
48
+ case type: \
49
+ p_coder = this->coders.coder_##type; \
50
+ ask_for_coder = this->coders.ask_##type; \
51
+ break;
52
+
53
+ static t_pg_coder *
54
+ pg_tmbmt_typecast_query_param( t_typemap *p_typemap, VALUE param_value, int field )
55
+ {
56
+ t_tmbmt *this = (t_tmbmt *)p_typemap;
57
+ t_pg_coder *p_coder;
58
+ VALUE ask_for_coder;
59
+
60
+ switch(TYPE(param_value)){
61
+ FOR_EACH_MRI_TYPE( CASE_AND_GET )
62
+ default:
63
+ /* unknown MRI type */
64
+ p_coder = NULL;
65
+ ask_for_coder = Qnil;
66
+ }
67
+
68
+ if( !NIL_P(ask_for_coder) ){
69
+ /* No static Coder object, but proc/method given to ask for the Coder to use. */
70
+ VALUE obj;
71
+
72
+ obj = rb_funcall(ask_for_coder, rb_intern("call"), 1, param_value);
73
+
74
+ /* Check argument type and store the coder pointer */
75
+ TypedData_Get_Struct(obj, t_pg_coder, &pg_coder_type, p_coder);
76
+ }
77
+
78
+ if( !p_coder ){
79
+ t_typemap *default_tm = RTYPEDDATA_DATA( this->typemap.default_typemap );
80
+ return default_tm->funcs.typecast_query_param( default_tm, param_value, field );
81
+ }
82
+
83
+ return p_coder;
84
+ }
85
+
86
+ static VALUE
87
+ pg_tmbmt_fit_to_query( VALUE self, VALUE params )
88
+ {
89
+ t_tmbmt *this = (t_tmbmt *)RTYPEDDATA_DATA(self);
90
+ /* Nothing to check at this typemap, but ensure that the default type map fits. */
91
+ t_typemap *default_tm = RTYPEDDATA_DATA( this->typemap.default_typemap );
92
+ default_tm->funcs.fit_to_query( this->typemap.default_typemap, params );
93
+ return self;
94
+ }
95
+
96
+ #define GC_MARK_AS_USED(type) \
97
+ rb_gc_mark_movable( this->coders.ask_##type ); \
98
+ rb_gc_mark_movable( this->coders.coder_obj_##type );
99
+
100
+ static void
101
+ pg_tmbmt_mark( void *_this )
102
+ {
103
+ t_tmbmt *this = (t_tmbmt *)_this;
104
+ pg_typemap_mark(&this->typemap);
105
+ FOR_EACH_MRI_TYPE( GC_MARK_AS_USED );
106
+ }
107
+
108
+ static size_t
109
+ pg_tmbmt_memsize( const void *_this )
110
+ {
111
+ const t_tmbmt *this = (const t_tmbmt *)_this;
112
+ return sizeof(*this);
113
+ }
114
+
115
+ #define GC_COMPACT(type) \
116
+ pg_gc_location( this->coders.ask_##type ); \
117
+ pg_gc_location( this->coders.coder_obj_##type );
118
+
119
+ static void
120
+ pg_tmbmt_compact( void *_this )
121
+ {
122
+ t_tmbmt *this = (t_tmbmt *)_this;
123
+ pg_typemap_compact(&this->typemap);
124
+ FOR_EACH_MRI_TYPE( GC_COMPACT );
125
+ }
126
+
127
+ static const rb_data_type_t pg_tmbmt_type = {
128
+ "PG::TypeMapByMriType",
129
+ {
130
+ pg_tmbmt_mark,
131
+ RUBY_TYPED_DEFAULT_FREE,
132
+ pg_tmbmt_memsize,
133
+ pg_compact_callback(pg_tmbmt_compact),
134
+ },
135
+ &pg_typemap_type,
136
+ 0,
137
+ RUBY_TYPED_FREE_IMMEDIATELY,
138
+ };
139
+
140
+ #define INIT_VARIABLES(type) \
141
+ this->coders.coder_##type = NULL; \
142
+ this->coders.ask_##type = Qnil; \
143
+ this->coders.coder_obj_##type = Qnil;
144
+
145
+ static VALUE
146
+ pg_tmbmt_s_allocate( VALUE klass )
147
+ {
148
+ t_tmbmt *this;
149
+ VALUE self;
150
+
151
+ self = TypedData_Make_Struct( klass, t_tmbmt, &pg_tmbmt_type, this );
152
+ this->typemap.funcs.fit_to_result = pg_typemap_fit_to_result;
153
+ this->typemap.funcs.fit_to_query = pg_tmbmt_fit_to_query;
154
+ this->typemap.funcs.fit_to_copy_get = pg_typemap_fit_to_copy_get;
155
+ this->typemap.funcs.typecast_result_value = pg_typemap_result_value;
156
+ this->typemap.funcs.typecast_query_param = pg_tmbmt_typecast_query_param;
157
+ this->typemap.funcs.typecast_copy_get = pg_typemap_typecast_copy_get;
158
+ this->typemap.default_typemap = pg_typemap_all_strings;
159
+
160
+ FOR_EACH_MRI_TYPE( INIT_VARIABLES );
161
+
162
+ return self;
163
+ }
164
+
165
+ #define COMPARE_AND_ASSIGN(type) \
166
+ else if(!strcmp(p_mri_type, #type)){ \
167
+ this->coders.coder_obj_##type = coder; \
168
+ if(NIL_P(coder)){ \
169
+ this->coders.coder_##type = NULL; \
170
+ this->coders.ask_##type = Qnil; \
171
+ }else if(rb_obj_is_kind_of(coder, rb_cPG_Coder)){ \
172
+ TypedData_Get_Struct(coder, t_pg_coder, &pg_coder_type, this->coders.coder_##type); \
173
+ this->coders.ask_##type = Qnil; \
174
+ }else if(RB_TYPE_P(coder, T_SYMBOL)){ \
175
+ this->coders.coder_##type = NULL; \
176
+ this->coders.ask_##type = rb_obj_method( self, coder ); \
177
+ }else{ \
178
+ this->coders.coder_##type = NULL; \
179
+ this->coders.ask_##type = coder; \
180
+ } \
181
+ }
182
+
183
+ /*
184
+ * call-seq:
185
+ * typemap.[mri_type] = coder
186
+ *
187
+ * Assigns a new PG::Coder object to the type map. The encoder
188
+ * is registered for type casts of the given +mri_type+ .
189
+ *
190
+ * +coder+ can be one of the following:
191
+ * * +nil+ - Values are forwarded to the #default_type_map .
192
+ * * a PG::Coder - Values are encoded by the given encoder
193
+ * * a Symbol - The method of this type map (or a derivation) that is called for each value to sent.
194
+ * It must return a PG::Coder.
195
+ * * a Proc - The Proc object is called for each value. It must return a PG::Coder.
196
+ *
197
+ * +mri_type+ must be one of the following strings:
198
+ * * +T_FIXNUM+
199
+ * * +T_TRUE+
200
+ * * +T_FALSE+
201
+ * * +T_FLOAT+
202
+ * * +T_BIGNUM+
203
+ * * +T_COMPLEX+
204
+ * * +T_RATIONAL+
205
+ * * +T_ARRAY+
206
+ * * +T_STRING+
207
+ * * +T_SYMBOL+
208
+ * * +T_OBJECT+
209
+ * * +T_CLASS+
210
+ * * +T_MODULE+
211
+ * * +T_REGEXP+
212
+ * * +T_HASH+
213
+ * * +T_STRUCT+
214
+ * * +T_FILE+
215
+ * * +T_DATA+
216
+ */
217
+ static VALUE
218
+ pg_tmbmt_aset( VALUE self, VALUE mri_type, VALUE coder )
219
+ {
220
+ t_tmbmt *this = RTYPEDDATA_DATA( self );
221
+ char *p_mri_type;
222
+
223
+ p_mri_type = StringValueCStr(mri_type);
224
+
225
+ if(0){}
226
+ FOR_EACH_MRI_TYPE( COMPARE_AND_ASSIGN )
227
+ else{
228
+ VALUE mri_type_inspect = rb_inspect( mri_type );
229
+ rb_raise(rb_eArgError, "unknown mri_type %s", StringValueCStr(mri_type_inspect));
230
+ }
231
+
232
+ return self;
233
+ }
234
+
235
+ #define COMPARE_AND_GET(type) \
236
+ else if(!strcmp(p_mri_type, #type)){ \
237
+ coder = this->coders.coder_obj_##type; \
238
+ }
239
+
240
+ /*
241
+ * call-seq:
242
+ * typemap.[mri_type] -> coder
243
+ *
244
+ * Returns the encoder object for the given +mri_type+
245
+ *
246
+ * See #[]= for allowed +mri_type+ .
247
+ */
248
+ static VALUE
249
+ pg_tmbmt_aref( VALUE self, VALUE mri_type )
250
+ {
251
+ VALUE coder;
252
+ t_tmbmt *this = RTYPEDDATA_DATA( self );
253
+ char *p_mri_type;
254
+
255
+ p_mri_type = StringValueCStr(mri_type);
256
+
257
+ if(0){}
258
+ FOR_EACH_MRI_TYPE( COMPARE_AND_GET )
259
+ else{
260
+ VALUE mri_type_inspect = rb_inspect( mri_type );
261
+ rb_raise(rb_eArgError, "unknown mri_type %s", StringValueCStr(mri_type_inspect));
262
+ }
263
+
264
+ return coder;
265
+ }
266
+
267
+ #define ADD_TO_HASH(type) \
268
+ rb_hash_aset( hash_coders, rb_obj_freeze(rb_str_new2(#type)), this->coders.coder_obj_##type );
269
+
270
+
271
+ /*
272
+ * call-seq:
273
+ * typemap.coders -> Hash
274
+ *
275
+ * Returns all mri types and their assigned encoder object.
276
+ */
277
+ static VALUE
278
+ pg_tmbmt_coders( VALUE self )
279
+ {
280
+ t_tmbmt *this = RTYPEDDATA_DATA( self );
281
+ VALUE hash_coders = rb_hash_new();
282
+
283
+ FOR_EACH_MRI_TYPE( ADD_TO_HASH );
284
+
285
+ return rb_obj_freeze(hash_coders);
286
+ }
287
+
288
+ void
289
+ init_pg_type_map_by_mri_type()
290
+ {
291
+ /*
292
+ * Document-class: PG::TypeMapByMriType < PG::TypeMap
293
+ *
294
+ * This type map casts values based on the Ruby object type code of the given value
295
+ * to be sent.
296
+ *
297
+ * This type map is usable for type casting query bind parameters and COPY data
298
+ * for PG::Connection#put_copy_data . Therefore only encoders might be assigned by
299
+ * the #[]= method.
300
+ *
301
+ * _Note_ : This type map is not portable across Ruby implementations and is less flexible
302
+ * than PG::TypeMapByClass.
303
+ * It is kept only for performance comparisons, but PG::TypeMapByClass proved to be equally
304
+ * fast in almost all cases.
305
+ *
306
+ */
307
+ rb_cTypeMapByMriType = rb_define_class_under( rb_mPG, "TypeMapByMriType", rb_cTypeMap );
308
+ rb_define_alloc_func( rb_cTypeMapByMriType, pg_tmbmt_s_allocate );
309
+ rb_define_method( rb_cTypeMapByMriType, "[]=", pg_tmbmt_aset, 2 );
310
+ rb_define_method( rb_cTypeMapByMriType, "[]", pg_tmbmt_aref, 1 );
311
+ rb_define_method( rb_cTypeMapByMriType, "coders", pg_tmbmt_coders, 0 );
312
+ rb_include_module( rb_cTypeMapByMriType, rb_mDefaultTypeMappable );
313
+ }