yugabyte_ysql 0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (121) hide show
  1. checksums.yaml +7 -0
  2. data/.appveyor.yml +42 -0
  3. data/.gems +6 -0
  4. data/.gemtest +0 -0
  5. data/.github/workflows/binary-gems.yml +117 -0
  6. data/.github/workflows/source-gem.yml +143 -0
  7. data/.gitignore +24 -0
  8. data/.hgsigs +34 -0
  9. data/.hgtags +41 -0
  10. data/.irbrc +23 -0
  11. data/.pryrc +23 -0
  12. data/.tm_properties +21 -0
  13. data/.travis.yml +49 -0
  14. data/BSDL +22 -0
  15. data/Contributors.rdoc +46 -0
  16. data/Gemfile +18 -0
  17. data/History.md +901 -0
  18. data/LICENSE +56 -0
  19. data/Manifest.txt +73 -0
  20. data/POSTGRES +23 -0
  21. data/README-OS_X.rdoc +68 -0
  22. data/README-Windows.rdoc +56 -0
  23. data/README.ja.md +302 -0
  24. data/README.md +373 -0
  25. data/Rakefile +118 -0
  26. data/Rakefile.cross +299 -0
  27. data/certs/ged.pem +24 -0
  28. data/certs/kanis@comcard.de.pem +20 -0
  29. data/certs/larskanis-2022.pem +26 -0
  30. data/certs/larskanis-2023.pem +24 -0
  31. data/certs/larskanis-2024.pem +24 -0
  32. data/ext/errorcodes.def +1044 -0
  33. data/ext/errorcodes.rb +45 -0
  34. data/ext/errorcodes.txt +497 -0
  35. data/ext/extconf.rb +174 -0
  36. data/ext/gvl_wrappers.c +21 -0
  37. data/ext/gvl_wrappers.h +264 -0
  38. data/ext/pg.c +692 -0
  39. data/ext/pg.h +392 -0
  40. data/ext/pg_binary_decoder.c +308 -0
  41. data/ext/pg_binary_encoder.c +387 -0
  42. data/ext/pg_coder.c +624 -0
  43. data/ext/pg_connection.c +4681 -0
  44. data/ext/pg_copy_coder.c +917 -0
  45. data/ext/pg_errors.c +95 -0
  46. data/ext/pg_record_coder.c +522 -0
  47. data/ext/pg_result.c +1766 -0
  48. data/ext/pg_text_decoder.c +1005 -0
  49. data/ext/pg_text_encoder.c +827 -0
  50. data/ext/pg_tuple.c +572 -0
  51. data/ext/pg_type_map.c +200 -0
  52. data/ext/pg_type_map_all_strings.c +130 -0
  53. data/ext/pg_type_map_by_class.c +271 -0
  54. data/ext/pg_type_map_by_column.c +355 -0
  55. data/ext/pg_type_map_by_mri_type.c +313 -0
  56. data/ext/pg_type_map_by_oid.c +388 -0
  57. data/ext/pg_type_map_in_ruby.c +333 -0
  58. data/ext/pg_util.c +149 -0
  59. data/ext/pg_util.h +65 -0
  60. data/ext/vc/pg.sln +26 -0
  61. data/ext/vc/pg_18/pg.vcproj +216 -0
  62. data/ext/vc/pg_19/pg_19.vcproj +209 -0
  63. data/lib/pg/basic_type_map_based_on_result.rb +67 -0
  64. data/lib/pg/basic_type_map_for_queries.rb +202 -0
  65. data/lib/pg/basic_type_map_for_results.rb +104 -0
  66. data/lib/pg/basic_type_registry.rb +303 -0
  67. data/lib/pg/binary_decoder/date.rb +9 -0
  68. data/lib/pg/binary_decoder/timestamp.rb +26 -0
  69. data/lib/pg/binary_encoder/timestamp.rb +20 -0
  70. data/lib/pg/coder.rb +106 -0
  71. data/lib/pg/connection.rb +990 -0
  72. data/lib/pg/exceptions.rb +25 -0
  73. data/lib/pg/load_balance_service.rb +406 -0
  74. data/lib/pg/result.rb +43 -0
  75. data/lib/pg/text_decoder/date.rb +18 -0
  76. data/lib/pg/text_decoder/inet.rb +9 -0
  77. data/lib/pg/text_decoder/json.rb +14 -0
  78. data/lib/pg/text_decoder/numeric.rb +9 -0
  79. data/lib/pg/text_decoder/timestamp.rb +30 -0
  80. data/lib/pg/text_encoder/date.rb +12 -0
  81. data/lib/pg/text_encoder/inet.rb +28 -0
  82. data/lib/pg/text_encoder/json.rb +14 -0
  83. data/lib/pg/text_encoder/numeric.rb +9 -0
  84. data/lib/pg/text_encoder/timestamp.rb +24 -0
  85. data/lib/pg/tuple.rb +30 -0
  86. data/lib/pg/type_map_by_column.rb +16 -0
  87. data/lib/pg/version.rb +5 -0
  88. data/lib/yugabyte_ysql.rb +130 -0
  89. data/misc/openssl-pg-segfault.rb +31 -0
  90. data/misc/postgres/History.txt +9 -0
  91. data/misc/postgres/Manifest.txt +5 -0
  92. data/misc/postgres/README.txt +21 -0
  93. data/misc/postgres/Rakefile +21 -0
  94. data/misc/postgres/lib/postgres.rb +16 -0
  95. data/misc/ruby-pg/History.txt +9 -0
  96. data/misc/ruby-pg/Manifest.txt +5 -0
  97. data/misc/ruby-pg/README.txt +21 -0
  98. data/misc/ruby-pg/Rakefile +21 -0
  99. data/misc/ruby-pg/lib/ruby/pg.rb +16 -0
  100. data/rakelib/task_extension.rb +46 -0
  101. data/sample/array_insert.rb +20 -0
  102. data/sample/async_api.rb +102 -0
  103. data/sample/async_copyto.rb +39 -0
  104. data/sample/async_mixed.rb +56 -0
  105. data/sample/check_conn.rb +21 -0
  106. data/sample/copydata.rb +71 -0
  107. data/sample/copyfrom.rb +81 -0
  108. data/sample/copyto.rb +19 -0
  109. data/sample/cursor.rb +21 -0
  110. data/sample/disk_usage_report.rb +177 -0
  111. data/sample/issue-119.rb +94 -0
  112. data/sample/losample.rb +69 -0
  113. data/sample/minimal-testcase.rb +17 -0
  114. data/sample/notify_wait.rb +72 -0
  115. data/sample/pg_statistics.rb +285 -0
  116. data/sample/replication_monitor.rb +222 -0
  117. data/sample/test_binary_values.rb +33 -0
  118. data/sample/wal_shipper.rb +434 -0
  119. data/sample/warehouse_partitions.rb +311 -0
  120. data/yugabyte_ysql.gemspec +33 -0
  121. metadata +232 -0
data/ext/pg_type_map.c ADDED
@@ -0,0 +1,200 @@
1
+ /*
2
+ * pg_column_map.c - PG::ColumnMap class extension
3
+ * $Id$
4
+ *
5
+ */
6
+
7
+ #include "pg.h"
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 | RUBY_TYPED_WB_PROTECTED | PG_RUBY_TYPED_FROZEN_SHAREABLE,
41
+ };
42
+
43
+ VALUE rb_cTypeMap;
44
+ VALUE rb_mDefaultTypeMappable;
45
+ static ID s_id_fit_to_query;
46
+ static ID s_id_fit_to_result;
47
+
48
+ NORETURN( VALUE
49
+ pg_typemap_fit_to_result( VALUE self, VALUE result ));
50
+ NORETURN( VALUE
51
+ pg_typemap_fit_to_query( VALUE self, VALUE params ));
52
+ NORETURN( int
53
+ pg_typemap_fit_to_copy_get( VALUE self ));
54
+ NORETURN( VALUE
55
+ pg_typemap_result_value( t_typemap *p_typemap, VALUE result, int tuple, int field ));
56
+ NORETURN( t_pg_coder *
57
+ pg_typemap_typecast_query_param( t_typemap *p_typemap, VALUE param_value, int field ));
58
+ NORETURN( VALUE
59
+ pg_typemap_typecast_copy_get( t_typemap *p_typemap, VALUE field_str, int fieldno, int format, int enc_idx ));
60
+
61
+ VALUE
62
+ pg_typemap_fit_to_result( VALUE self, VALUE result )
63
+ {
64
+ rb_raise( rb_eNotImpError, "type map %s is not suitable to map result values", rb_obj_classname(self) );
65
+ }
66
+
67
+ VALUE
68
+ pg_typemap_fit_to_query( VALUE self, VALUE params )
69
+ {
70
+ rb_raise( rb_eNotImpError, "type map %s is not suitable to map query params", rb_obj_classname(self) );
71
+ }
72
+
73
+ int
74
+ pg_typemap_fit_to_copy_get( VALUE self )
75
+ {
76
+ rb_raise( rb_eNotImpError, "type map %s is not suitable to map get_copy_data results", rb_obj_classname(self) );
77
+ }
78
+
79
+ VALUE
80
+ pg_typemap_result_value( t_typemap *p_typemap, VALUE result, int tuple, int field )
81
+ {
82
+ rb_raise( rb_eNotImpError, "type map is not suitable to map result values" );
83
+ }
84
+
85
+ t_pg_coder *
86
+ pg_typemap_typecast_query_param( t_typemap *p_typemap, VALUE param_value, int field )
87
+ {
88
+ rb_raise( rb_eNotImpError, "type map is not suitable to map query params" );
89
+ }
90
+
91
+ VALUE
92
+ pg_typemap_typecast_copy_get( t_typemap *p_typemap, VALUE field_str, int fieldno, int format, int enc_idx )
93
+ {
94
+ rb_raise( rb_eNotImpError, "type map is not suitable to map get_copy_data results" );
95
+ }
96
+
97
+ const struct pg_typemap_funcs pg_typemap_funcs = {
98
+ pg_typemap_fit_to_result,
99
+ pg_typemap_fit_to_query,
100
+ pg_typemap_fit_to_copy_get,
101
+ pg_typemap_result_value,
102
+ pg_typemap_typecast_query_param,
103
+ pg_typemap_typecast_copy_get
104
+ };
105
+
106
+ static VALUE
107
+ pg_typemap_s_allocate( VALUE klass )
108
+ {
109
+ VALUE self;
110
+ t_typemap *this;
111
+
112
+ self = TypedData_Make_Struct( klass, t_typemap, &pg_typemap_type, this );
113
+ this->funcs = pg_typemap_funcs;
114
+
115
+ return self;
116
+ }
117
+
118
+ /*
119
+ * call-seq:
120
+ * res.default_type_map = typemap
121
+ *
122
+ * Set the default TypeMap that is used for values that could not be
123
+ * casted by this type map.
124
+ *
125
+ * +typemap+ must be a kind of PG::TypeMap
126
+ *
127
+ */
128
+ static VALUE
129
+ pg_typemap_default_type_map_set(VALUE self, VALUE typemap)
130
+ {
131
+ t_typemap *this = RTYPEDDATA_DATA( self );
132
+ t_typemap *tm;
133
+ UNUSED(tm);
134
+
135
+ rb_check_frozen(self);
136
+ /* Check type of method param */
137
+ TypedData_Get_Struct(typemap, t_typemap, &pg_typemap_type, tm);
138
+ RB_OBJ_WRITE(self, &this->default_typemap, typemap);
139
+
140
+ return typemap;
141
+ }
142
+
143
+ /*
144
+ * call-seq:
145
+ * res.default_type_map -> TypeMap
146
+ *
147
+ * Returns the default TypeMap that is currently set for values that could not be
148
+ * casted by this type map.
149
+ *
150
+ * Returns a kind of PG::TypeMap.
151
+ *
152
+ */
153
+ static VALUE
154
+ pg_typemap_default_type_map_get(VALUE self)
155
+ {
156
+ t_typemap *this = RTYPEDDATA_DATA( self );
157
+
158
+ return this->default_typemap;
159
+ }
160
+
161
+ /*
162
+ * call-seq:
163
+ * res.with_default_type_map( typemap )
164
+ *
165
+ * Set the default TypeMap that is used for values that could not be
166
+ * casted by this type map.
167
+ *
168
+ * +typemap+ must be a kind of PG::TypeMap
169
+ *
170
+ * Returns self.
171
+ */
172
+ static VALUE
173
+ pg_typemap_with_default_type_map(VALUE self, VALUE typemap)
174
+ {
175
+ pg_typemap_default_type_map_set( self, typemap );
176
+ return self;
177
+ }
178
+
179
+ void
180
+ init_pg_type_map(void)
181
+ {
182
+ s_id_fit_to_query = rb_intern("fit_to_query");
183
+ s_id_fit_to_result = rb_intern("fit_to_result");
184
+
185
+ /*
186
+ * Document-class: PG::TypeMap < Object
187
+ *
188
+ * This is the base class for type maps.
189
+ * See derived classes for implementations of different type cast strategies
190
+ * ( PG::TypeMapByColumn, PG::TypeMapByOid ).
191
+ *
192
+ */
193
+ rb_cTypeMap = rb_define_class_under( rb_mPG, "TypeMap", rb_cObject );
194
+ rb_define_alloc_func( rb_cTypeMap, pg_typemap_s_allocate );
195
+
196
+ rb_mDefaultTypeMappable = rb_define_module_under( rb_cTypeMap, "DefaultTypeMappable");
197
+ rb_define_method( rb_mDefaultTypeMappable, "default_type_map=", pg_typemap_default_type_map_set, 1 );
198
+ rb_define_method( rb_mDefaultTypeMappable, "default_type_map", pg_typemap_default_type_map_get, 0 );
199
+ rb_define_method( rb_mDefaultTypeMappable, "with_default_type_map", pg_typemap_with_default_type_map, 1 );
200
+ }
@@ -0,0 +1,130 @@
1
+ /*
2
+ * pg_type_map_all_strings.c - PG::TypeMapAllStrings class extension
3
+ * $Id$
4
+ *
5
+ * This is the default typemap.
6
+ *
7
+ */
8
+
9
+ #include "pg.h"
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 | RUBY_TYPED_WB_PROTECTED | PG_RUBY_TYPED_FROZEN_SHAREABLE,
22
+ };
23
+
24
+ VALUE rb_cTypeMapAllStrings;
25
+ VALUE pg_typemap_all_strings;
26
+
27
+ static VALUE
28
+ pg_tmas_fit_to_result( VALUE self, VALUE result )
29
+ {
30
+ return self;
31
+ }
32
+
33
+ static VALUE
34
+ pg_tmas_result_value( t_typemap *p_typemap, VALUE result, int tuple, int field )
35
+ {
36
+ VALUE ret;
37
+ char * val;
38
+ int len;
39
+ t_pg_result *p_result = pgresult_get_this(result);
40
+
41
+ if (PQgetisnull(p_result->pgresult, tuple, field)) {
42
+ return Qnil;
43
+ }
44
+
45
+ val = PQgetvalue( p_result->pgresult, tuple, field );
46
+ len = PQgetlength( p_result->pgresult, tuple, field );
47
+
48
+ if ( 0 == PQfformat(p_result->pgresult, field) ) {
49
+ ret = pg_text_dec_string(NULL, val, len, tuple, field, p_result->enc_idx);
50
+ } else {
51
+ ret = pg_bin_dec_bytea(NULL, val, len, tuple, field, p_result->enc_idx);
52
+ }
53
+
54
+ return ret;
55
+ }
56
+
57
+ static VALUE
58
+ pg_tmas_fit_to_query( VALUE self, VALUE params )
59
+ {
60
+ return self;
61
+ }
62
+
63
+ static t_pg_coder *
64
+ pg_tmas_typecast_query_param( t_typemap *p_typemap, VALUE param_value, int field )
65
+ {
66
+ return NULL;
67
+ }
68
+
69
+ static int
70
+ pg_tmas_fit_to_copy_get( VALUE self )
71
+ {
72
+ /* We can not predict the number of columns for copy */
73
+ return 0;
74
+ }
75
+
76
+ static VALUE
77
+ pg_tmas_typecast_copy_get( t_typemap *p_typemap, VALUE field_str, int fieldno, int format, int enc_idx )
78
+ {
79
+ rb_str_modify(field_str);
80
+ if( format == 0 ){
81
+ PG_ENCODING_SET_NOCHECK( field_str, enc_idx );
82
+ } else {
83
+ PG_ENCODING_SET_NOCHECK( field_str, rb_ascii8bit_encindex() );
84
+ }
85
+ return field_str;
86
+ }
87
+
88
+ static VALUE
89
+ pg_tmas_s_allocate( VALUE klass )
90
+ {
91
+ t_typemap *this;
92
+ VALUE self;
93
+
94
+ self = TypedData_Make_Struct( klass, t_typemap, &pg_tmas_type, this );
95
+
96
+ this->funcs.fit_to_result = pg_tmas_fit_to_result;
97
+ this->funcs.fit_to_query = pg_tmas_fit_to_query;
98
+ this->funcs.fit_to_copy_get = pg_tmas_fit_to_copy_get;
99
+ this->funcs.typecast_result_value = pg_tmas_result_value;
100
+ this->funcs.typecast_query_param = pg_tmas_typecast_query_param;
101
+ this->funcs.typecast_copy_get = pg_tmas_typecast_copy_get;
102
+
103
+ return self;
104
+ }
105
+
106
+
107
+ void
108
+ init_pg_type_map_all_strings(void)
109
+ {
110
+ /*
111
+ * Document-class: PG::TypeMapAllStrings < PG::TypeMap
112
+ *
113
+ * This type map casts all values received from the database server to Strings
114
+ * and sends all values to the server after conversion to String by +#to_s+ .
115
+ * That means, it is hard coded to PG::TextEncoder::String for value encoding
116
+ * and to PG::TextDecoder::String for text format respectively PG::BinaryDecoder::Bytea
117
+ * for binary format received from the server.
118
+ *
119
+ * It is suitable for type casting query bind parameters, result values and
120
+ * COPY IN/OUT data.
121
+ *
122
+ * This is the default type map for each PG::Connection .
123
+ *
124
+ */
125
+ rb_cTypeMapAllStrings = rb_define_class_under( rb_mPG, "TypeMapAllStrings", rb_cTypeMap );
126
+ rb_define_alloc_func( rb_cTypeMapAllStrings, pg_tmas_s_allocate );
127
+
128
+ pg_typemap_all_strings = rb_obj_freeze( rb_funcall( rb_cTypeMapAllStrings, rb_intern("new"), 0 ));
129
+ rb_gc_register_address( &pg_typemap_all_strings );
130
+ }
@@ -0,0 +1,271 @@
1
+ /*
2
+ * pg_type_map_by_class.c - PG::TypeMapByClass class extension
3
+ * $Id$
4
+ *
5
+ * This type map can be used to select value encoders based on the class
6
+ * of the given value to be send.
7
+ *
8
+ */
9
+
10
+ #include "pg.h"
11
+
12
+ static VALUE rb_cTypeMapByClass;
13
+
14
+ typedef struct {
15
+ t_typemap typemap;
16
+
17
+ VALUE klass_to_coder;
18
+ VALUE self;
19
+
20
+ struct pg_tmbk_coder_cache_entry {
21
+ VALUE klass;
22
+ t_pg_coder *p_coder;
23
+ } cache_row[0x100];
24
+ } t_tmbk;
25
+
26
+ /*
27
+ * We use 8 Bits of the klass object id as index to a 256 entry cache.
28
+ * This avoids full lookups in most cases.
29
+ */
30
+ #define CACHE_LOOKUP(this, klass) ( &this->cache_row[(((unsigned long)klass) >> 8) & 0xff] )
31
+
32
+
33
+ static t_pg_coder *
34
+ pg_tmbk_lookup_klass(t_tmbk *this, VALUE klass, VALUE param_value)
35
+ {
36
+ t_pg_coder *p_coder;
37
+ struct pg_tmbk_coder_cache_entry *p_ce;
38
+
39
+ p_ce = CACHE_LOOKUP(this, klass);
40
+
41
+ /* Is the cache entry for the expected klass? */
42
+ if( p_ce->klass == klass ) {
43
+ p_coder = p_ce->p_coder;
44
+ } else {
45
+ /* No, then do a full lookup based on the ancestors. */
46
+ VALUE obj = rb_hash_lookup( this->klass_to_coder, klass );
47
+
48
+ if( NIL_P(obj) ){
49
+ int i;
50
+ VALUE ancestors = rb_mod_ancestors( klass );
51
+
52
+ Check_Type( ancestors, T_ARRAY );
53
+ /* Don't look at the first element, it's expected to equal klass. */
54
+ for( i=1; i<RARRAY_LEN(ancestors); i++ ){
55
+ obj = rb_hash_lookup( this->klass_to_coder, rb_ary_entry( ancestors, i) );
56
+
57
+ if( !NIL_P(obj) )
58
+ break;
59
+ }
60
+ }
61
+
62
+ if(NIL_P(obj)){
63
+ p_coder = NULL;
64
+ }else if(rb_obj_is_kind_of(obj, rb_cPG_Coder)){
65
+ TypedData_Get_Struct(obj, t_pg_coder, &pg_coder_type, p_coder);
66
+ }else{
67
+ if( RB_TYPE_P(obj, T_SYMBOL) ){
68
+ /* A Symbol: Call the method with this name. */
69
+ obj = rb_funcall(this->self, SYM2ID(obj), 1, param_value);
70
+ }else{
71
+ /* A Proc object (or something that responds to #call). */
72
+ obj = rb_funcall(obj, rb_intern("call"), 1, param_value);
73
+ }
74
+
75
+ if( NIL_P(obj) ){
76
+ p_coder = NULL;
77
+ }else{
78
+ /* Check retrieved coder type */
79
+ TypedData_Get_Struct(obj, t_pg_coder, &pg_coder_type, p_coder);
80
+ }
81
+
82
+ /* We can not cache coders retrieved by ruby code, because we can not anticipate
83
+ * the returned Coder object. */
84
+ return p_coder;
85
+ }
86
+
87
+ /* Write the retrieved coder to the cache */
88
+ p_ce->klass = klass;
89
+ p_ce->p_coder = p_coder;
90
+ }
91
+ return p_coder;
92
+ }
93
+
94
+
95
+ static t_pg_coder *
96
+ pg_tmbk_typecast_query_param( t_typemap *p_typemap, VALUE param_value, int field )
97
+ {
98
+ t_tmbk *this = (t_tmbk *)p_typemap;
99
+ t_pg_coder *p_coder;
100
+
101
+ p_coder = pg_tmbk_lookup_klass( this, rb_obj_class(param_value), param_value );
102
+
103
+ if( !p_coder ){
104
+ t_typemap *default_tm = RTYPEDDATA_DATA( this->typemap.default_typemap );
105
+ return default_tm->funcs.typecast_query_param( default_tm, param_value, field );
106
+ }
107
+
108
+ return p_coder;
109
+ }
110
+
111
+ static VALUE
112
+ pg_tmbk_fit_to_query( VALUE self, VALUE params )
113
+ {
114
+ t_tmbk *this = (t_tmbk *)RTYPEDDATA_DATA(self);
115
+ /* Nothing to check at this typemap, but ensure that the default type map fits. */
116
+ t_typemap *default_tm = RTYPEDDATA_DATA( this->typemap.default_typemap );
117
+ default_tm->funcs.fit_to_query( this->typemap.default_typemap, params );
118
+ return self;
119
+ }
120
+
121
+ static void
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)
139
+ {
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));
148
+ }
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 | RUBY_TYPED_WB_PROTECTED | PG_RUBY_TYPED_FROZEN_SHAREABLE,
161
+ };
162
+
163
+ static VALUE
164
+ pg_tmbk_s_allocate( VALUE klass )
165
+ {
166
+ t_tmbk *this;
167
+ VALUE self;
168
+
169
+ self = TypedData_Make_Struct( klass, t_tmbk, &pg_tmbk_type, this );
170
+ this->typemap.funcs.fit_to_result = pg_typemap_fit_to_result;
171
+ this->typemap.funcs.fit_to_query = pg_tmbk_fit_to_query;
172
+ this->typemap.funcs.fit_to_copy_get = pg_typemap_fit_to_copy_get;
173
+ this->typemap.funcs.typecast_result_value = pg_typemap_result_value;
174
+ this->typemap.funcs.typecast_query_param = pg_tmbk_typecast_query_param;
175
+ this->typemap.funcs.typecast_copy_get = pg_typemap_typecast_copy_get;
176
+ RB_OBJ_WRITE(self, &this->typemap.default_typemap, pg_typemap_all_strings);
177
+
178
+ /* We need to store self in the this-struct, because pg_tmbk_typecast_query_param(),
179
+ * is called with the this-pointer only. */
180
+ this->self = self;
181
+ RB_OBJ_WRITE(self, &this->klass_to_coder, rb_hash_new());
182
+
183
+ /* The cache is properly initialized by TypedData_Make_Struct(). */
184
+
185
+ return self;
186
+ }
187
+
188
+ /*
189
+ * call-seq:
190
+ * typemap.[class] = coder
191
+ *
192
+ * Assigns a new PG::Coder object to the type map. The encoder
193
+ * is chosen for all values that are a kind of the given +class+ .
194
+ *
195
+ * +coder+ can be one of the following:
196
+ * * +nil+ - Values are forwarded to the #default_type_map .
197
+ * * a PG::Coder - Values are encoded by the given encoder
198
+ * * a Symbol - The method of this type map (or a derivation) that is called for each value to sent.
199
+ * It must return a PG::Coder or +nil+ .
200
+ * * a Proc - The Proc object is called for each value. It must return a PG::Coder or +nil+ .
201
+ *
202
+ */
203
+ static VALUE
204
+ pg_tmbk_aset( VALUE self, VALUE klass, VALUE coder )
205
+ {
206
+ t_tmbk *this = RTYPEDDATA_DATA( self );
207
+
208
+ rb_check_frozen(self);
209
+
210
+ if(NIL_P(coder)){
211
+ rb_hash_delete( this->klass_to_coder, klass );
212
+ }else{
213
+ rb_hash_aset( this->klass_to_coder, klass, coder );
214
+ }
215
+
216
+ /* The cache lookup key can be a derivation of the klass.
217
+ * So we can not expire the cache selectively. */
218
+ memset( &this->cache_row, 0, sizeof(this->cache_row) );
219
+
220
+ return coder;
221
+ }
222
+
223
+ /*
224
+ * call-seq:
225
+ * typemap.[class] -> coder
226
+ *
227
+ * Returns the encoder object for the given +class+
228
+ */
229
+ static VALUE
230
+ pg_tmbk_aref( VALUE self, VALUE klass )
231
+ {
232
+ t_tmbk *this = RTYPEDDATA_DATA( self );
233
+
234
+ return rb_hash_lookup(this->klass_to_coder, klass);
235
+ }
236
+
237
+ /*
238
+ * call-seq:
239
+ * typemap.coders -> Hash
240
+ *
241
+ * Returns all classes and their assigned encoder object.
242
+ */
243
+ static VALUE
244
+ pg_tmbk_coders( VALUE self )
245
+ {
246
+ t_tmbk *this = RTYPEDDATA_DATA( self );
247
+
248
+ return rb_obj_freeze(rb_hash_dup(this->klass_to_coder));
249
+ }
250
+
251
+ void
252
+ init_pg_type_map_by_class(void)
253
+ {
254
+ /*
255
+ * Document-class: PG::TypeMapByClass < PG::TypeMap
256
+ *
257
+ * This type map casts values based on the class or the ancestors of the given value
258
+ * to be sent.
259
+ *
260
+ * This type map is usable for type casting query bind parameters and COPY data
261
+ * for PG::Connection#put_copy_data . Therefore only encoders might be assigned by
262
+ * the #[]= method.
263
+ */
264
+ rb_cTypeMapByClass = rb_define_class_under( rb_mPG, "TypeMapByClass", rb_cTypeMap );
265
+ rb_define_alloc_func( rb_cTypeMapByClass, pg_tmbk_s_allocate );
266
+ rb_define_method( rb_cTypeMapByClass, "[]=", pg_tmbk_aset, 2 );
267
+ rb_define_method( rb_cTypeMapByClass, "[]", pg_tmbk_aref, 1 );
268
+ rb_define_method( rb_cTypeMapByClass, "coders", pg_tmbk_coders, 0 );
269
+ /* rb_mDefaultTypeMappable = rb_define_module_under( rb_cTypeMap, "DefaultTypeMappable"); */
270
+ rb_include_module( rb_cTypeMapByClass, rb_mDefaultTypeMappable );
271
+ }