pg 1.2.3-x64-mingw32 → 1.3.0.rc4-x64-mingw32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (111) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/.appveyor.yml +36 -0
  4. data/.gems +6 -0
  5. data/.github/workflows/binary-gems.yml +86 -0
  6. data/.github/workflows/source-gem.yml +130 -0
  7. data/.gitignore +13 -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/Gemfile +14 -0
  15. data/History.rdoc +77 -7
  16. data/Manifest.txt +0 -1
  17. data/README.rdoc +7 -6
  18. data/Rakefile +27 -138
  19. data/Rakefile.cross +6 -5
  20. data/certs/ged.pem +24 -0
  21. data/ext/errorcodes.def +8 -0
  22. data/ext/errorcodes.txt +3 -1
  23. data/ext/extconf.rb +91 -19
  24. data/ext/gvl_wrappers.c +4 -0
  25. data/ext/gvl_wrappers.h +23 -0
  26. data/ext/pg.c +59 -4
  27. data/ext/pg.h +18 -1
  28. data/ext/pg_coder.c +82 -28
  29. data/ext/pg_connection.c +676 -492
  30. data/ext/pg_copy_coder.c +45 -16
  31. data/ext/pg_record_coder.c +39 -11
  32. data/ext/pg_result.c +61 -31
  33. data/ext/pg_text_decoder.c +1 -1
  34. data/ext/pg_text_encoder.c +6 -6
  35. data/ext/pg_tuple.c +47 -21
  36. data/ext/pg_type_map.c +41 -8
  37. data/ext/pg_type_map_all_strings.c +14 -1
  38. data/ext/pg_type_map_by_class.c +49 -24
  39. data/ext/pg_type_map_by_column.c +64 -28
  40. data/ext/pg_type_map_by_mri_type.c +47 -18
  41. data/ext/pg_type_map_by_oid.c +52 -23
  42. data/ext/pg_type_map_in_ruby.c +50 -19
  43. data/ext/pg_util.c +2 -2
  44. data/lib/2.5/pg_ext.so +0 -0
  45. data/lib/2.6/pg_ext.so +0 -0
  46. data/lib/2.7/pg_ext.so +0 -0
  47. data/lib/3.0/pg_ext.so +0 -0
  48. data/lib/pg/basic_type_map_based_on_result.rb +47 -0
  49. data/lib/pg/basic_type_map_for_queries.rb +193 -0
  50. data/lib/pg/basic_type_map_for_results.rb +81 -0
  51. data/lib/pg/basic_type_registry.rb +296 -0
  52. data/lib/pg/coder.rb +1 -1
  53. data/lib/pg/connection.rb +587 -58
  54. data/lib/pg/version.rb +4 -0
  55. data/lib/pg.rb +40 -27
  56. data/lib/x64-mingw32/libpq.dll +0 -0
  57. data/misc/openssl-pg-segfault.rb +31 -0
  58. data/misc/postgres/History.txt +9 -0
  59. data/misc/postgres/Manifest.txt +5 -0
  60. data/misc/postgres/README.txt +21 -0
  61. data/misc/postgres/Rakefile +21 -0
  62. data/misc/postgres/lib/postgres.rb +16 -0
  63. data/misc/ruby-pg/History.txt +9 -0
  64. data/misc/ruby-pg/Manifest.txt +5 -0
  65. data/misc/ruby-pg/README.txt +21 -0
  66. data/misc/ruby-pg/Rakefile +21 -0
  67. data/misc/ruby-pg/lib/ruby/pg.rb +16 -0
  68. data/pg.gemspec +32 -0
  69. data/sample/array_insert.rb +20 -0
  70. data/sample/async_api.rb +106 -0
  71. data/sample/async_copyto.rb +39 -0
  72. data/sample/async_mixed.rb +56 -0
  73. data/sample/check_conn.rb +21 -0
  74. data/sample/copydata.rb +71 -0
  75. data/sample/copyfrom.rb +81 -0
  76. data/sample/copyto.rb +19 -0
  77. data/sample/cursor.rb +21 -0
  78. data/sample/disk_usage_report.rb +177 -0
  79. data/sample/issue-119.rb +94 -0
  80. data/sample/losample.rb +69 -0
  81. data/sample/minimal-testcase.rb +17 -0
  82. data/sample/notify_wait.rb +72 -0
  83. data/sample/pg_statistics.rb +285 -0
  84. data/sample/replication_monitor.rb +222 -0
  85. data/sample/test_binary_values.rb +33 -0
  86. data/sample/wal_shipper.rb +434 -0
  87. data/sample/warehouse_partitions.rb +311 -0
  88. data.tar.gz.sig +0 -0
  89. metadata +92 -233
  90. metadata.gz.sig +0 -0
  91. data/ChangeLog +0 -0
  92. data/lib/2.2/pg_ext.so +0 -0
  93. data/lib/2.3/pg_ext.so +0 -0
  94. data/lib/2.4/pg_ext.so +0 -0
  95. data/lib/pg/basic_type_mapping.rb +0 -522
  96. data/spec/data/expected_trace.out +0 -26
  97. data/spec/data/random_binary_data +0 -0
  98. data/spec/helpers.rb +0 -380
  99. data/spec/pg/basic_type_mapping_spec.rb +0 -630
  100. data/spec/pg/connection_spec.rb +0 -1949
  101. data/spec/pg/connection_sync_spec.rb +0 -41
  102. data/spec/pg/result_spec.rb +0 -681
  103. data/spec/pg/tuple_spec.rb +0 -333
  104. data/spec/pg/type_map_by_class_spec.rb +0 -138
  105. data/spec/pg/type_map_by_column_spec.rb +0 -226
  106. data/spec/pg/type_map_by_mri_type_spec.rb +0 -136
  107. data/spec/pg/type_map_by_oid_spec.rb +0 -149
  108. data/spec/pg/type_map_in_ruby_spec.rb +0 -164
  109. data/spec/pg/type_map_spec.rb +0 -22
  110. data/spec/pg/type_spec.rb +0 -1123
  111. data/spec/pg_spec.rb +0 -50
@@ -46,7 +46,7 @@ pg_tmbo_lookup_oid(t_tmbo *this, int format, Oid oid)
46
46
  } else {
47
47
  VALUE obj = rb_hash_lookup( this->format[format].oid_to_coder, UINT2NUM( oid ));
48
48
  /* obj must be nil or some kind of PG::Coder, this is checked at insertion */
49
- conv = NIL_P(obj) ? NULL : DATA_PTR(obj);
49
+ conv = NIL_P(obj) ? NULL : RTYPEDDATA_DATA(obj);
50
50
  /* Write the retrieved coder to the cache */
51
51
  p_ce->oid = oid;
52
52
  p_ce->p_coder = conv;
@@ -70,7 +70,7 @@ pg_tmbo_build_type_map_for_result2( t_tmbo *this, PGresult *pgresult )
70
70
  p_colmap->typemap.default_typemap = pg_typemap_all_strings;
71
71
 
72
72
  colmap = pg_tmbc_allocate();
73
- DATA_PTR(colmap) = p_colmap;
73
+ RTYPEDDATA_DATA(colmap) = p_colmap;
74
74
 
75
75
  for(i=0; i<nfields; i++)
76
76
  {
@@ -113,18 +113,18 @@ pg_tmbo_result_value(t_typemap *p_typemap, VALUE result, int tuple, int field)
113
113
  return dec_func( p_coder, val, len, tuple, field, p_result->enc_idx );
114
114
  }
115
115
 
116
- default_tm = DATA_PTR( this->typemap.default_typemap );
116
+ default_tm = RTYPEDDATA_DATA( this->typemap.default_typemap );
117
117
  return default_tm->funcs.typecast_result_value( default_tm, result, tuple, field );
118
118
  }
119
119
 
120
120
  static VALUE
121
121
  pg_tmbo_fit_to_result( VALUE self, VALUE result )
122
122
  {
123
- t_tmbo *this = DATA_PTR( self );
123
+ t_tmbo *this = RTYPEDDATA_DATA( self );
124
124
  PGresult *pgresult = pgresult_get( result );
125
125
 
126
- /* Ensure that the default type map fits equaly. */
127
- t_typemap *default_tm = DATA_PTR( this->typemap.default_typemap );
126
+ /* Ensure that the default type map fits equally. */
127
+ t_typemap *default_tm = RTYPEDDATA_DATA( this->typemap.default_typemap );
128
128
  VALUE sub_typemap = default_tm->funcs.fit_to_result( this->typemap.default_typemap, result );
129
129
 
130
130
  if( PQntuples( pgresult ) <= this->max_rows_for_online_lookup ){
@@ -137,7 +137,7 @@ pg_tmbo_fit_to_result( VALUE self, VALUE result )
137
137
  /* The default type map built a new object, so we need to propagate it
138
138
  * and build a copy of this type map. */
139
139
  VALUE new_typemap = pg_tmbo_s_allocate( rb_cTypeMapByOid );
140
- t_tmbo *p_new_typemap = DATA_PTR(new_typemap);
140
+ t_tmbo *p_new_typemap = RTYPEDDATA_DATA(new_typemap);
141
141
  *p_new_typemap = *this;
142
142
  p_new_typemap->typemap.default_typemap = sub_typemap;
143
143
  return new_typemap;
@@ -147,23 +147,56 @@ pg_tmbo_fit_to_result( VALUE self, VALUE result )
147
147
  * uses a fast array lookup.
148
148
  */
149
149
  VALUE new_typemap = pg_tmbo_build_type_map_for_result2( this, pgresult );
150
- t_tmbo *p_new_typemap = DATA_PTR(new_typemap);
150
+ t_tmbo *p_new_typemap = RTYPEDDATA_DATA(new_typemap);
151
151
  p_new_typemap->typemap.default_typemap = sub_typemap;
152
152
  return new_typemap;
153
153
  }
154
154
  }
155
155
 
156
156
  static void
157
- pg_tmbo_mark( t_tmbo *this )
157
+ pg_tmbo_mark( void *_this )
158
158
  {
159
+ t_tmbo *this = (t_tmbo *)_this;
159
160
  int i;
160
161
 
161
- rb_gc_mark(this->typemap.default_typemap);
162
+ pg_typemap_mark(&this->typemap);
162
163
  for( i=0; i<2; i++){
163
- rb_gc_mark(this->format[i].oid_to_coder);
164
+ rb_gc_mark_movable(this->format[i].oid_to_coder);
164
165
  }
165
166
  }
166
167
 
168
+ static size_t
169
+ pg_tmbo_memsize( const void *_this )
170
+ {
171
+ const t_tmbo *this = (const t_tmbo *)_this;
172
+ return sizeof(*this);
173
+ }
174
+
175
+ static void
176
+ pg_tmbo_compact( void *_this )
177
+ {
178
+ t_tmbo *this = (t_tmbo *)_this;
179
+ int i;
180
+
181
+ pg_typemap_compact(&this->typemap);
182
+ for( i=0; i<2; i++){
183
+ pg_gc_location(this->format[i].oid_to_coder);
184
+ }
185
+ }
186
+
187
+ static const rb_data_type_t pg_tmbo_type = {
188
+ "PG::TypeMapByOid",
189
+ {
190
+ pg_tmbo_mark,
191
+ RUBY_TYPED_DEFAULT_FREE,
192
+ pg_tmbo_memsize,
193
+ pg_compact_callback(pg_tmbo_compact),
194
+ },
195
+ &pg_typemap_type,
196
+ 0,
197
+ RUBY_TYPED_FREE_IMMEDIATELY,
198
+ };
199
+
167
200
  static VALUE
168
201
  pg_tmbo_s_allocate( VALUE klass )
169
202
  {
@@ -171,7 +204,7 @@ pg_tmbo_s_allocate( VALUE klass )
171
204
  VALUE self;
172
205
  int i;
173
206
 
174
- self = Data_Make_Struct( klass, t_tmbo, pg_tmbo_mark, -1, this );
207
+ self = TypedData_Make_Struct( klass, t_tmbo, &pg_tmbo_type, this );
175
208
 
176
209
  this->typemap.funcs.fit_to_result = pg_tmbo_fit_to_result;
177
210
  this->typemap.funcs.fit_to_query = pg_typemap_fit_to_query;
@@ -205,15 +238,11 @@ static VALUE
205
238
  pg_tmbo_add_coder( VALUE self, VALUE coder )
206
239
  {
207
240
  VALUE hash;
208
- t_tmbo *this = DATA_PTR( self );
241
+ t_tmbo *this = RTYPEDDATA_DATA( self );
209
242
  t_pg_coder *p_coder;
210
243
  struct pg_tmbo_oid_cache_entry *p_ce;
211
244
 
212
- if( !rb_obj_is_kind_of(coder, rb_cPG_Coder) )
213
- rb_raise(rb_eArgError, "invalid type %s (should be some kind of PG::Coder)",
214
- rb_obj_classname( coder ));
215
-
216
- Data_Get_Struct(coder, t_pg_coder, p_coder);
245
+ TypedData_Get_Struct(coder, t_pg_coder, &pg_coder_type, p_coder);
217
246
 
218
247
  if( p_coder->format < 0 || p_coder->format > 1 )
219
248
  rb_raise(rb_eArgError, "invalid format code %d", p_coder->format);
@@ -243,7 +272,7 @@ pg_tmbo_rm_coder( VALUE self, VALUE format, VALUE oid )
243
272
  {
244
273
  VALUE hash;
245
274
  VALUE coder;
246
- t_tmbo *this = DATA_PTR( self );
275
+ t_tmbo *this = RTYPEDDATA_DATA( self );
247
276
  int i_format = NUM2INT(format);
248
277
  struct pg_tmbo_oid_cache_entry *p_ce;
249
278
 
@@ -269,7 +298,7 @@ pg_tmbo_rm_coder( VALUE self, VALUE format, VALUE oid )
269
298
  static VALUE
270
299
  pg_tmbo_coders( VALUE self )
271
300
  {
272
- t_tmbo *this = DATA_PTR( self );
301
+ t_tmbo *this = RTYPEDDATA_DATA( self );
273
302
 
274
303
  return rb_ary_concat(
275
304
  rb_funcall(this->format[0].oid_to_coder, rb_intern("values"), 0),
@@ -288,7 +317,7 @@ pg_tmbo_coders( VALUE self )
288
317
  static VALUE
289
318
  pg_tmbo_max_rows_for_online_lookup_set( VALUE self, VALUE value )
290
319
  {
291
- t_tmbo *this = DATA_PTR( self );
320
+ t_tmbo *this = RTYPEDDATA_DATA( self );
292
321
  this->max_rows_for_online_lookup = NUM2INT(value);
293
322
  return value;
294
323
  }
@@ -300,7 +329,7 @@ pg_tmbo_max_rows_for_online_lookup_set( VALUE self, VALUE value )
300
329
  static VALUE
301
330
  pg_tmbo_max_rows_for_online_lookup_get( VALUE self )
302
331
  {
303
- t_tmbo *this = DATA_PTR( self );
332
+ t_tmbo *this = RTYPEDDATA_DATA( self );
304
333
  return INT2NUM(this->max_rows_for_online_lookup);
305
334
  }
306
335
 
@@ -315,7 +344,7 @@ pg_tmbo_max_rows_for_online_lookup_get( VALUE self )
315
344
  static VALUE
316
345
  pg_tmbo_build_column_map( VALUE self, VALUE result )
317
346
  {
318
- t_tmbo *this = DATA_PTR( self );
347
+ t_tmbo *this = RTYPEDDATA_DATA( self );
319
348
 
320
349
  if ( !rb_obj_is_kind_of(result, rb_cPGresult) ) {
321
350
  rb_raise( rb_eTypeError, "wrong argument type %s (expected kind of PG::Result)",
@@ -19,6 +19,33 @@ typedef struct {
19
19
  VALUE self;
20
20
  } t_tmir;
21
21
 
22
+ static size_t
23
+ pg_tmir_memsize( const void *_this )
24
+ {
25
+ const t_tmir *this = (const t_tmir *)_this;
26
+ return sizeof(*this);
27
+ }
28
+
29
+ static void
30
+ pg_tmir_compact( void *_this )
31
+ {
32
+ t_tmir *this = (t_tmir *)_this;
33
+ pg_typemap_compact(&this->typemap);
34
+ pg_gc_location(this->self);
35
+ }
36
+
37
+ static const rb_data_type_t pg_tmir_type = {
38
+ "PG::TypeMapInRuby",
39
+ {
40
+ pg_typemap_mark,
41
+ RUBY_TYPED_DEFAULT_FREE,
42
+ pg_tmir_memsize,
43
+ pg_compact_callback(pg_tmir_compact),
44
+ },
45
+ &pg_typemap_type,
46
+ 0,
47
+ RUBY_TYPED_FREE_IMMEDIATELY,
48
+ };
22
49
 
23
50
  /*
24
51
  * call-seq:
@@ -34,33 +61,37 @@ typedef struct {
34
61
  static VALUE
35
62
  pg_tmir_fit_to_result( VALUE self, VALUE result )
36
63
  {
37
- t_tmir *this = DATA_PTR( self );
64
+ t_tmir *this = RTYPEDDATA_DATA( self );
38
65
  t_typemap *default_tm;
39
66
  t_typemap *p_new_typemap;
40
67
  VALUE sub_typemap;
41
68
  VALUE new_typemap;
42
69
 
43
70
  if( rb_respond_to(self, s_id_fit_to_result) ){
71
+ t_typemap *tm;
72
+ UNUSED(tm);
44
73
  new_typemap = rb_funcall( self, s_id_fit_to_result, 1, result );
45
74
 
46
75
  if ( !rb_obj_is_kind_of(new_typemap, rb_cTypeMap) ) {
76
+ /* TypedData_Get_Struct() raises "wrong argument type", which is misleading,
77
+ * so we better raise our own message */
47
78
  rb_raise( rb_eTypeError, "wrong return type from fit_to_result: %s expected kind of PG::TypeMap",
48
79
  rb_obj_classname( new_typemap ) );
49
80
  }
50
- Check_Type( new_typemap, T_DATA );
81
+ TypedData_Get_Struct(new_typemap, t_typemap, &pg_typemap_type, tm);
51
82
  } else {
52
83
  new_typemap = self;
53
84
  }
54
85
 
55
- /* Ensure that the default type map fits equaly. */
56
- default_tm = DATA_PTR( this->typemap.default_typemap );
86
+ /* Ensure that the default type map fits equally. */
87
+ default_tm = RTYPEDDATA_DATA( this->typemap.default_typemap );
57
88
  sub_typemap = default_tm->funcs.fit_to_result( this->typemap.default_typemap, result );
58
89
 
59
90
  if( sub_typemap != this->typemap.default_typemap ){
60
91
  new_typemap = rb_obj_dup( new_typemap );
61
92
  }
62
93
 
63
- p_new_typemap = DATA_PTR(new_typemap);
94
+ p_new_typemap = RTYPEDDATA_DATA(new_typemap);
64
95
  p_new_typemap->default_typemap = sub_typemap;
65
96
  return new_typemap;
66
97
  }
@@ -95,8 +126,8 @@ pg_tmir_result_value( t_typemap *p_typemap, VALUE result, int tuple, int field )
95
126
  static VALUE
96
127
  pg_tmir_typecast_result_value( VALUE self, VALUE result, VALUE tuple, VALUE field )
97
128
  {
98
- t_tmir *this = DATA_PTR( self );
99
- t_typemap *default_tm = DATA_PTR( this->typemap.default_typemap );
129
+ t_tmir *this = RTYPEDDATA_DATA( self );
130
+ t_typemap *default_tm = RTYPEDDATA_DATA( this->typemap.default_typemap );
100
131
  return default_tm->funcs.typecast_result_value( default_tm, result, NUM2INT(tuple), NUM2INT(field) );
101
132
  }
102
133
 
@@ -113,15 +144,15 @@ pg_tmir_typecast_result_value( VALUE self, VALUE result, VALUE tuple, VALUE fiel
113
144
  static VALUE
114
145
  pg_tmir_fit_to_query( VALUE self, VALUE params )
115
146
  {
116
- t_tmir *this = DATA_PTR( self );
147
+ t_tmir *this = RTYPEDDATA_DATA( self );
117
148
  t_typemap *default_tm;
118
149
 
119
150
  if( rb_respond_to(self, s_id_fit_to_query) ){
120
151
  rb_funcall( self, s_id_fit_to_query, 1, params );
121
152
  }
122
153
 
123
- /* Ensure that the default type map fits equaly. */
124
- default_tm = DATA_PTR( this->typemap.default_typemap );
154
+ /* Ensure that the default type map fits equally. */
155
+ default_tm = RTYPEDDATA_DATA( this->typemap.default_typemap );
125
156
  default_tm->funcs.fit_to_query( this->typemap.default_typemap, params );
126
157
 
127
158
  return self;
@@ -137,7 +168,7 @@ pg_tmir_query_param( t_typemap *p_typemap, VALUE param_value, int field )
137
168
  if ( NIL_P(coder) ){
138
169
  return NULL;
139
170
  } else if( rb_obj_is_kind_of(coder, rb_cPG_Coder) ) {
140
- return DATA_PTR(coder);
171
+ return RTYPEDDATA_DATA(coder);
141
172
  } else {
142
173
  rb_raise( rb_eTypeError, "wrong return type from typecast_query_param: %s expected nil or kind of PG::Coder",
143
174
  rb_obj_classname( coder ) );
@@ -161,8 +192,8 @@ pg_tmir_query_param( t_typemap *p_typemap, VALUE param_value, int field )
161
192
  static VALUE
162
193
  pg_tmir_typecast_query_param( VALUE self, VALUE param_value, VALUE field )
163
194
  {
164
- t_tmir *this = DATA_PTR( self );
165
- t_typemap *default_tm = DATA_PTR( this->typemap.default_typemap );
195
+ t_tmir *this = RTYPEDDATA_DATA( self );
196
+ t_typemap *default_tm = RTYPEDDATA_DATA( this->typemap.default_typemap );
166
197
  t_pg_coder *p_coder = default_tm->funcs.typecast_query_param( default_tm, param_value, NUM2INT(field) );
167
198
 
168
199
  return p_coder ? p_coder->coder_obj : Qnil;
@@ -186,7 +217,7 @@ static VALUE pg_tmir_fit_to_copy_get_dummy( VALUE self ){}
186
217
  static int
187
218
  pg_tmir_fit_to_copy_get( VALUE self )
188
219
  {
189
- t_tmir *this = DATA_PTR( self );
220
+ t_tmir *this = RTYPEDDATA_DATA( self );
190
221
  t_typemap *default_tm;
191
222
  VALUE num_columns = INT2NUM(0);
192
223
 
@@ -198,8 +229,8 @@ pg_tmir_fit_to_copy_get( VALUE self )
198
229
  rb_raise( rb_eTypeError, "wrong return type from fit_to_copy_get: %s expected kind of Integer",
199
230
  rb_obj_classname( num_columns ) );
200
231
  }
201
- /* Ensure that the default type map fits equaly. */
202
- default_tm = DATA_PTR( this->typemap.default_typemap );
232
+ /* Ensure that the default type map fits equally. */
233
+ default_tm = RTYPEDDATA_DATA( this->typemap.default_typemap );
203
234
  default_tm->funcs.fit_to_copy_get( this->typemap.default_typemap );
204
235
 
205
236
  return NUM2INT(num_columns);;
@@ -239,8 +270,8 @@ pg_tmir_copy_get( t_typemap *p_typemap, VALUE field_str, int fieldno, int format
239
270
  static VALUE
240
271
  pg_tmir_typecast_copy_get( VALUE self, VALUE field_str, VALUE fieldno, VALUE format, VALUE enc )
241
272
  {
242
- t_tmir *this = DATA_PTR( self );
243
- t_typemap *default_tm = DATA_PTR( this->typemap.default_typemap );
273
+ t_tmir *this = RTYPEDDATA_DATA( self );
274
+ t_typemap *default_tm = RTYPEDDATA_DATA( this->typemap.default_typemap );
244
275
  int enc_idx = rb_to_encoding_index( enc );
245
276
 
246
277
  return default_tm->funcs.typecast_copy_get( default_tm, field_str, NUM2INT(fieldno), NUM2INT(format), enc_idx );
@@ -252,7 +283,7 @@ pg_tmir_s_allocate( VALUE klass )
252
283
  t_tmir *this;
253
284
  VALUE self;
254
285
 
255
- self = Data_Make_Struct( klass, t_tmir, NULL, -1, this );
286
+ self = TypedData_Make_Struct( klass, t_tmir, &pg_tmir_type, this );
256
287
 
257
288
  this->typemap.funcs.fit_to_result = pg_tmir_fit_to_result;
258
289
  this->typemap.funcs.fit_to_query = pg_tmir_fit_to_query;
data/ext/pg_util.c CHANGED
@@ -91,7 +91,7 @@ base64_decode( char *out, const char *in, unsigned int len)
91
91
  *out_ptr++ = (b << 4) | (c >> 2);
92
92
  *out_ptr++ = (c << 6) | d;
93
93
  } else if (in_ptr < iend_ptr){
94
- a = b = c = d = 0xff;
94
+ b = c = d = 0xff;
95
95
  while ((a = base64_decode_table[*in_ptr++]) == 0xff && in_ptr < iend_ptr) {}
96
96
  if (in_ptr < iend_ptr){
97
97
  while ((b = base64_decode_table[*in_ptr++]) == 0xff && in_ptr < iend_ptr) {}
@@ -116,7 +116,7 @@ base64_decode( char *out, const char *in, unsigned int len)
116
116
  }
117
117
 
118
118
 
119
- return (char*)out_ptr - out;
119
+ return (int)((char*)out_ptr - out);
120
120
  }
121
121
 
122
122
  /*
data/lib/2.5/pg_ext.so CHANGED
Binary file
data/lib/2.6/pg_ext.so CHANGED
Binary file
data/lib/2.7/pg_ext.so CHANGED
Binary file
data/lib/3.0/pg_ext.so ADDED
Binary file
@@ -0,0 +1,47 @@
1
+ # -*- ruby -*-
2
+ # frozen_string_literal: true
3
+
4
+ require 'pg' unless defined?( PG )
5
+
6
+ # Simple set of rules for type casting common PostgreSQL types from Ruby
7
+ # to PostgreSQL.
8
+ #
9
+ # OIDs of supported type casts are not hard-coded in the sources, but are retrieved from the
10
+ # PostgreSQL's +pg_type+ table in PG::BasicTypeMapBasedOnResult.new .
11
+ #
12
+ # This class works equal to PG::BasicTypeMapForResults, but does not define decoders for
13
+ # the given result OIDs, but encoders. So it can be used to type cast field values based on
14
+ # the type OID retrieved by a separate SQL query.
15
+ #
16
+ # PG::TypeMapByOid#build_column_map(result) can be used to generate a result independent
17
+ # PG::TypeMapByColumn type map, which can subsequently be used to cast query bind parameters
18
+ # or #put_copy_data fields.
19
+ #
20
+ # Example:
21
+ # conn.exec( "CREATE TEMP TABLE copytable (t TEXT, i INT, ai INT[])" )
22
+ #
23
+ # # Retrieve table OIDs per empty result set.
24
+ # res = conn.exec( "SELECT * FROM copytable LIMIT 0" )
25
+ # # Build a type map for common ruby to database type encoders.
26
+ # btm = PG::BasicTypeMapBasedOnResult.new(conn)
27
+ # # Build a PG::TypeMapByColumn with encoders suitable for copytable.
28
+ # tm = btm.build_column_map( res )
29
+ # row_encoder = PG::TextEncoder::CopyRow.new type_map: tm
30
+ #
31
+ # conn.copy_data( "COPY copytable FROM STDIN", row_encoder ) do |res|
32
+ # conn.put_copy_data ['a', 123, [5,4,3]]
33
+ # end
34
+ # This inserts a single row into copytable with type casts from ruby to
35
+ # database types.
36
+ class PG::BasicTypeMapBasedOnResult < PG::TypeMapByOid
37
+ include PG::BasicTypeRegistry::Checker
38
+
39
+ def initialize(connection_or_coder_maps, registry: nil)
40
+ @coder_maps = build_coder_maps(connection_or_coder_maps, registry: registry)
41
+
42
+ # Populate TypeMapByOid hash with encoders
43
+ @coder_maps.each_format(:encoder).flat_map{|f| f.coders }.each do |coder|
44
+ add_coder(coder)
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,193 @@
1
+ # -*- ruby -*-
2
+ # frozen_string_literal: true
3
+
4
+ require 'pg' unless defined?( PG )
5
+
6
+ # Simple set of rules for type casting common Ruby types to PostgreSQL.
7
+ #
8
+ # OIDs of supported type casts are not hard-coded in the sources, but are retrieved from the
9
+ # PostgreSQL's pg_type table in PG::BasicTypeMapForQueries.new .
10
+ #
11
+ # Query params are type casted based on the class of the given value.
12
+ #
13
+ # Higher level libraries will most likely not make use of this class, but use their
14
+ # own derivation of PG::TypeMapByClass or another set of rules to choose suitable
15
+ # encoders and decoders for the values to be sent.
16
+ #
17
+ # Example:
18
+ # conn = PG::Connection.new
19
+ # # Assign a default ruleset for type casts of input and output values.
20
+ # conn.type_map_for_queries = PG::BasicTypeMapForQueries.new(conn)
21
+ # # Execute a query. The Integer param value is typecasted internally by PG::BinaryEncoder::Int8.
22
+ # # The format of the parameter is set to 0 (text) and the OID of this parameter is set to 20 (int8).
23
+ # res = conn.exec_params( "SELECT $1", [5] )
24
+ class PG::BasicTypeMapForQueries < PG::TypeMapByClass
25
+ # Helper class for submission of binary strings into bytea columns.
26
+ #
27
+ # Since PG::BasicTypeMapForQueries chooses the encoder to be used by the class of the submitted value,
28
+ # it's necessary to send binary strings as BinaryData.
29
+ # That way they're distinct from text strings.
30
+ # Please note however that PG::BasicTypeMapForResults delivers bytea columns as plain String
31
+ # with binary encoding.
32
+ #
33
+ # conn.type_map_for_queries = PG::BasicTypeMapForQueries.new(conn)
34
+ # conn.exec("CREATE TEMP TABLE test (data bytea)")
35
+ # bd = PG::BasicTypeMapForQueries::BinaryData.new("ab\xff\0cd")
36
+ # conn.exec_params("INSERT INTO test (data) VALUES ($1)", [bd])
37
+ class BinaryData < String
38
+ end
39
+
40
+ class UndefinedEncoder < RuntimeError
41
+ end
42
+
43
+ include PG::BasicTypeRegistry::Checker
44
+
45
+ # Create a new type map for query submission
46
+ #
47
+ # Options:
48
+ # * +registry+: Custom type registry, nil for default global registry
49
+ # * +if_undefined+: Optional +Proc+ object which is called, if no type for an parameter class is not defined in the registry.
50
+ def initialize(connection_or_coder_maps, registry: nil, if_undefined: nil)
51
+ @coder_maps = build_coder_maps(connection_or_coder_maps, registry: registry)
52
+ @array_encoders_by_klass = array_encoders_by_klass
53
+ @encode_array_as = :array
54
+ @if_undefined = if_undefined || proc { |oid_name, format|
55
+ raise UndefinedEncoder, "no encoder defined for type #{oid_name.inspect} format #{format}"
56
+ }
57
+ init_encoders
58
+ end
59
+
60
+ # Change the mechanism that is used to encode ruby array values
61
+ #
62
+ # Possible values:
63
+ # * +:array+ : Encode the ruby array as a PostgreSQL array.
64
+ # The array element type is inferred from the class of the first array element. This is the default.
65
+ # * +:json+ : Encode the ruby array as a JSON document.
66
+ # * +:record+ : Encode the ruby array as a composite type row.
67
+ # * <code>"_type"</code> : Encode the ruby array as a particular PostgreSQL type.
68
+ # All PostgreSQL array types are supported.
69
+ # If there's an encoder registered for the elements +type+, it will be used.
70
+ # Otherwise a string conversion (by +value.to_s+) is done.
71
+ def encode_array_as=(pg_type)
72
+ case pg_type
73
+ when :array
74
+ when :json
75
+ when :record
76
+ when /\A_/
77
+ else
78
+ raise ArgumentError, "invalid pg_type #{pg_type.inspect}"
79
+ end
80
+
81
+ @encode_array_as = pg_type
82
+
83
+ init_encoders
84
+ end
85
+
86
+ attr_reader :encode_array_as
87
+
88
+ private
89
+
90
+ def init_encoders
91
+ coders.each { |kl, c| self[kl] = nil } # Clear type map
92
+ populate_encoder_list
93
+ @textarray_encoder = coder_by_name(0, :encoder, '_text')
94
+ end
95
+
96
+ def coder_by_name(format, direction, name)
97
+ check_format_and_direction(format, direction)
98
+ @coder_maps.map_for(format, direction).coder_by_name(name)
99
+ end
100
+
101
+ def undefined(name, format)
102
+ @if_undefined.call(name, format)
103
+ end
104
+
105
+ def populate_encoder_list
106
+ DEFAULT_TYPE_MAP.each do |klass, selector|
107
+ if Array === selector
108
+ format, name, oid_name = selector
109
+ coder = coder_by_name(format, :encoder, name).dup
110
+ if coder
111
+ if oid_name
112
+ oid_coder = coder_by_name(format, :encoder, oid_name)
113
+ if oid_coder
114
+ coder.oid = oid_coder.oid
115
+ else
116
+ undefined(oid_name, format)
117
+ end
118
+ else
119
+ coder.oid = 0
120
+ end
121
+ self[klass] = coder
122
+ else
123
+ undefined(name, format)
124
+ end
125
+ else
126
+
127
+ case @encode_array_as
128
+ when :array
129
+ self[klass] = selector
130
+ when :json
131
+ self[klass] = PG::TextEncoder::JSON.new
132
+ when :record
133
+ self[klass] = PG::TextEncoder::Record.new type_map: self
134
+ when /\A_/
135
+ coder = coder_by_name(0, :encoder, @encode_array_as)
136
+ if coder
137
+ self[klass] = coder
138
+ else
139
+ undefined(@encode_array_as, format)
140
+ end
141
+ else
142
+ raise ArgumentError, "invalid pg_type #{@encode_array_as.inspect}"
143
+ end
144
+ end
145
+ end
146
+ end
147
+
148
+ def array_encoders_by_klass
149
+ DEFAULT_ARRAY_TYPE_MAP.inject({}) do |h, (klass, (format, name))|
150
+ h[klass] = coder_by_name(format, :encoder, name)
151
+ h
152
+ end
153
+ end
154
+
155
+ def get_array_type(value)
156
+ elem = value
157
+ while elem.kind_of?(Array)
158
+ elem = elem.first
159
+ end
160
+ @array_encoders_by_klass[elem.class] ||
161
+ elem.class.ancestors.lazy.map{|ancestor| @array_encoders_by_klass[ancestor] }.find{|a| a } ||
162
+ @textarray_encoder
163
+ end
164
+
165
+ DEFAULT_TYPE_MAP = {
166
+ TrueClass => [1, 'bool', 'bool'],
167
+ FalseClass => [1, 'bool', 'bool'],
168
+ # We use text format and no type OID for numbers, because setting the OID can lead
169
+ # to unnecessary type conversions on server side.
170
+ Integer => [0, 'int8'],
171
+ Float => [0, 'float8'],
172
+ BigDecimal => [0, 'numeric'],
173
+ Time => [0, 'timestamptz'],
174
+ # We use text format and no type OID for IPAddr, because setting the OID can lead
175
+ # to unnecessary inet/cidr conversions on the server side.
176
+ IPAddr => [0, 'inet'],
177
+ Hash => [0, 'json'],
178
+ Array => :get_array_type,
179
+ BinaryData => [1, 'bytea'],
180
+ }
181
+
182
+ DEFAULT_ARRAY_TYPE_MAP = {
183
+ TrueClass => [0, '_bool'],
184
+ FalseClass => [0, '_bool'],
185
+ Integer => [0, '_int8'],
186
+ String => [0, '_text'],
187
+ Float => [0, '_float8'],
188
+ BigDecimal => [0, '_numeric'],
189
+ Time => [0, '_timestamptz'],
190
+ IPAddr => [0, '_inet'],
191
+ }
192
+
193
+ end
@@ -0,0 +1,81 @@
1
+ # -*- ruby -*-
2
+ # frozen_string_literal: true
3
+
4
+ require 'pg' unless defined?( PG )
5
+
6
+ # Simple set of rules for type casting common PostgreSQL types to Ruby.
7
+ #
8
+ # OIDs of supported type casts are not hard-coded in the sources, but are retrieved from the
9
+ # PostgreSQL's +pg_type+ table in PG::BasicTypeMapForResults.new .
10
+ #
11
+ # Result values are type casted based on the type OID of the given result column.
12
+ #
13
+ # Higher level libraries will most likely not make use of this class, but use their
14
+ # own set of rules to choose suitable encoders and decoders.
15
+ #
16
+ # Example:
17
+ # conn = PG::Connection.new
18
+ # # Assign a default ruleset for type casts of output values.
19
+ # conn.type_map_for_results = PG::BasicTypeMapForResults.new(conn)
20
+ # # Execute a query.
21
+ # res = conn.exec_params( "SELECT $1::INT", ['5'] )
22
+ # # Retrieve and cast the result value. Value format is 0 (text) and OID is 20. Therefore typecasting
23
+ # # is done by PG::TextDecoder::Integer internally for all value retrieval methods.
24
+ # res.values # => [[5]]
25
+ #
26
+ # PG::TypeMapByOid#build_column_map(result) can be used to generate
27
+ # a result independent PG::TypeMapByColumn type map, which can subsequently be used
28
+ # to cast #get_copy_data fields:
29
+ #
30
+ # For the following table:
31
+ # conn.exec( "CREATE TABLE copytable AS VALUES('a', 123, '{5,4,3}'::INT[])" )
32
+ #
33
+ # # Retrieve table OIDs per empty result set.
34
+ # res = conn.exec( "SELECT * FROM copytable LIMIT 0" )
35
+ # # Build a type map for common database to ruby type decoders.
36
+ # btm = PG::BasicTypeMapForResults.new(conn)
37
+ # # Build a PG::TypeMapByColumn with decoders suitable for copytable.
38
+ # tm = btm.build_column_map( res )
39
+ # row_decoder = PG::TextDecoder::CopyRow.new type_map: tm
40
+ #
41
+ # conn.copy_data( "COPY copytable TO STDOUT", row_decoder ) do |res|
42
+ # while row=conn.get_copy_data
43
+ # p row
44
+ # end
45
+ # end
46
+ # This prints the rows with type casted columns:
47
+ # ["a", 123, [5, 4, 3]]
48
+ #
49
+ # See also PG::BasicTypeMapBasedOnResult for the encoder direction and PG::BasicTypeRegistry for the definition of additional types.
50
+ class PG::BasicTypeMapForResults < PG::TypeMapByOid
51
+ include PG::BasicTypeRegistry::Checker
52
+
53
+ class WarningTypeMap < PG::TypeMapInRuby
54
+ def initialize(typenames)
55
+ @already_warned = Hash.new{|h, k| h[k] = {} }
56
+ @typenames_by_oid = typenames
57
+ end
58
+
59
+ def typecast_result_value(result, _tuple, field)
60
+ format = result.fformat(field)
61
+ oid = result.ftype(field)
62
+ unless @already_warned[format][oid]
63
+ warn "Warning: no type cast defined for type #{@typenames_by_oid[oid].inspect} format #{format} with oid #{oid}. Please cast this type explicitly to TEXT to be safe for future changes."
64
+ @already_warned[format][oid] = true
65
+ end
66
+ super
67
+ end
68
+ end
69
+
70
+ def initialize(connection_or_coder_maps, registry: nil)
71
+ @coder_maps = build_coder_maps(connection_or_coder_maps, registry: registry)
72
+
73
+ # Populate TypeMapByOid hash with decoders
74
+ @coder_maps.each_format(:decoder).flat_map{|f| f.coders }.each do |coder|
75
+ add_coder(coder)
76
+ end
77
+
78
+ typenames = @coder_maps.typenames_by_oid
79
+ self.default_type_map = WarningTypeMap.new(typenames)
80
+ end
81
+ end