pg 0.18.3 → 1.4.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (118) hide show
  1. checksums.yaml +5 -5
  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 +129 -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/BSDL +2 -2
  15. data/Gemfile +14 -0
  16. data/History.rdoc +448 -4
  17. data/Manifest.txt +8 -21
  18. data/README-Windows.rdoc +4 -4
  19. data/README.ja.rdoc +1 -2
  20. data/README.rdoc +69 -17
  21. data/Rakefile +33 -135
  22. data/Rakefile.cross +70 -69
  23. data/certs/ged.pem +24 -0
  24. data/certs/larskanis-2022.pem +26 -0
  25. data/ext/errorcodes.def +109 -0
  26. data/ext/errorcodes.rb +1 -1
  27. data/ext/errorcodes.txt +35 -2
  28. data/ext/extconf.rb +120 -54
  29. data/ext/gvl_wrappers.c +8 -0
  30. data/ext/gvl_wrappers.h +44 -33
  31. data/ext/pg.c +213 -171
  32. data/ext/pg.h +92 -98
  33. data/ext/pg_binary_decoder.c +84 -15
  34. data/ext/pg_binary_encoder.c +24 -21
  35. data/ext/pg_coder.c +175 -39
  36. data/ext/pg_connection.c +1730 -1135
  37. data/ext/pg_copy_coder.c +94 -27
  38. data/ext/pg_record_coder.c +521 -0
  39. data/ext/pg_result.c +640 -221
  40. data/ext/pg_text_decoder.c +608 -40
  41. data/ext/pg_text_encoder.c +253 -99
  42. data/ext/pg_tuple.c +569 -0
  43. data/ext/pg_type_map.c +61 -21
  44. data/ext/pg_type_map_all_strings.c +19 -5
  45. data/ext/pg_type_map_by_class.c +54 -24
  46. data/ext/pg_type_map_by_column.c +79 -40
  47. data/ext/pg_type_map_by_mri_type.c +48 -19
  48. data/ext/pg_type_map_by_oid.c +55 -25
  49. data/ext/pg_type_map_in_ruby.c +51 -20
  50. data/ext/{util.c → pg_util.c} +12 -12
  51. data/ext/{util.h → pg_util.h} +2 -2
  52. data/lib/pg/basic_type_map_based_on_result.rb +47 -0
  53. data/lib/pg/basic_type_map_for_queries.rb +193 -0
  54. data/lib/pg/basic_type_map_for_results.rb +81 -0
  55. data/lib/pg/basic_type_registry.rb +301 -0
  56. data/lib/pg/binary_decoder.rb +23 -0
  57. data/lib/pg/coder.rb +24 -3
  58. data/lib/pg/connection.rb +723 -65
  59. data/lib/pg/constants.rb +2 -1
  60. data/lib/pg/exceptions.rb +9 -2
  61. data/lib/pg/result.rb +24 -7
  62. data/lib/pg/text_decoder.rb +24 -22
  63. data/lib/pg/text_encoder.rb +40 -8
  64. data/lib/pg/tuple.rb +30 -0
  65. data/lib/pg/type_map_by_column.rb +3 -2
  66. data/lib/pg/version.rb +4 -0
  67. data/lib/pg.rb +61 -36
  68. data/misc/openssl-pg-segfault.rb +31 -0
  69. data/misc/postgres/History.txt +9 -0
  70. data/misc/postgres/Manifest.txt +5 -0
  71. data/misc/postgres/README.txt +21 -0
  72. data/misc/postgres/Rakefile +21 -0
  73. data/misc/postgres/lib/postgres.rb +16 -0
  74. data/misc/ruby-pg/History.txt +9 -0
  75. data/misc/ruby-pg/Manifest.txt +5 -0
  76. data/misc/ruby-pg/README.txt +21 -0
  77. data/misc/ruby-pg/Rakefile +21 -0
  78. data/misc/ruby-pg/lib/ruby/pg.rb +16 -0
  79. data/pg.gemspec +32 -0
  80. data/rakelib/task_extension.rb +46 -0
  81. data/sample/array_insert.rb +1 -1
  82. data/sample/async_api.rb +4 -8
  83. data/sample/async_copyto.rb +1 -1
  84. data/sample/async_mixed.rb +1 -1
  85. data/sample/check_conn.rb +1 -1
  86. data/sample/copydata.rb +71 -0
  87. data/sample/copyfrom.rb +1 -1
  88. data/sample/copyto.rb +1 -1
  89. data/sample/cursor.rb +1 -1
  90. data/sample/disk_usage_report.rb +6 -15
  91. data/sample/issue-119.rb +2 -2
  92. data/sample/losample.rb +1 -1
  93. data/sample/minimal-testcase.rb +2 -2
  94. data/sample/notify_wait.rb +1 -1
  95. data/sample/pg_statistics.rb +6 -15
  96. data/sample/replication_monitor.rb +9 -18
  97. data/sample/test_binary_values.rb +1 -1
  98. data/sample/wal_shipper.rb +2 -2
  99. data/sample/warehouse_partitions.rb +8 -17
  100. data.tar.gz.sig +0 -0
  101. metadata +80 -230
  102. metadata.gz.sig +0 -0
  103. data/ChangeLog +0 -5804
  104. data/lib/pg/basic_type_mapping.rb +0 -399
  105. data/spec/data/expected_trace.out +0 -26
  106. data/spec/data/random_binary_data +0 -0
  107. data/spec/helpers.rb +0 -355
  108. data/spec/pg/basic_type_mapping_spec.rb +0 -251
  109. data/spec/pg/connection_spec.rb +0 -1538
  110. data/spec/pg/result_spec.rb +0 -449
  111. data/spec/pg/type_map_by_class_spec.rb +0 -138
  112. data/spec/pg/type_map_by_column_spec.rb +0 -222
  113. data/spec/pg/type_map_by_mri_type_spec.rb +0 -136
  114. data/spec/pg/type_map_by_oid_spec.rb +0 -149
  115. data/spec/pg/type_map_in_ruby_spec.rb +0 -164
  116. data/spec/pg/type_map_spec.rb +0 -22
  117. data/spec/pg/type_spec.rb +0 -690
  118. data/spec/pg_spec.rb +0 -50
data/ext/pg_copy_coder.c CHANGED
@@ -21,17 +21,47 @@ typedef struct {
21
21
 
22
22
 
23
23
  static void
24
- pg_copycoder_mark( t_pg_copycoder *this )
24
+ pg_copycoder_mark( void *_this )
25
25
  {
26
- rb_gc_mark(this->typemap);
27
- rb_gc_mark(this->null_string);
26
+ t_pg_copycoder *this = (t_pg_copycoder *)_this;
27
+ rb_gc_mark_movable(this->typemap);
28
+ rb_gc_mark_movable(this->null_string);
28
29
  }
29
30
 
31
+ static size_t
32
+ pg_copycoder_memsize( const void *_this )
33
+ {
34
+ const t_pg_copycoder *this = (const t_pg_copycoder *)_this;
35
+ return sizeof(*this);
36
+ }
37
+
38
+ static void
39
+ pg_copycoder_compact( void *_this )
40
+ {
41
+ t_pg_copycoder *this = (t_pg_copycoder *)_this;
42
+ pg_coder_compact(&this->comp);
43
+ pg_gc_location(this->typemap);
44
+ pg_gc_location(this->null_string);
45
+ }
46
+
47
+ static const rb_data_type_t pg_copycoder_type = {
48
+ "PG::CopyCoder",
49
+ {
50
+ pg_copycoder_mark,
51
+ RUBY_TYPED_DEFAULT_FREE,
52
+ pg_copycoder_memsize,
53
+ pg_compact_callback(pg_copycoder_compact),
54
+ },
55
+ &pg_coder_type,
56
+ 0,
57
+ RUBY_TYPED_FREE_IMMEDIATELY,
58
+ };
59
+
30
60
  static VALUE
31
61
  pg_copycoder_encoder_allocate( VALUE klass )
32
62
  {
33
63
  t_pg_copycoder *this;
34
- VALUE self = Data_Make_Struct( klass, t_pg_copycoder, pg_copycoder_mark, -1, this );
64
+ VALUE self = TypedData_Make_Struct( klass, t_pg_copycoder, &pg_copycoder_type, this );
35
65
  pg_coder_init_encoder( self );
36
66
  this->typemap = pg_typemap_all_strings;
37
67
  this->delimiter = '\t';
@@ -43,7 +73,7 @@ static VALUE
43
73
  pg_copycoder_decoder_allocate( VALUE klass )
44
74
  {
45
75
  t_pg_copycoder *this;
46
- VALUE self = Data_Make_Struct( klass, t_pg_copycoder, pg_copycoder_mark, -1, this );
76
+ VALUE self = TypedData_Make_Struct( klass, t_pg_copycoder, &pg_copycoder_type, this );
47
77
  pg_coder_init_decoder( self );
48
78
  this->typemap = pg_typemap_all_strings;
49
79
  this->delimiter = '\t';
@@ -62,7 +92,7 @@ pg_copycoder_decoder_allocate( VALUE klass )
62
92
  static VALUE
63
93
  pg_copycoder_delimiter_set(VALUE self, VALUE delimiter)
64
94
  {
65
- t_pg_copycoder *this = DATA_PTR(self);
95
+ t_pg_copycoder *this = RTYPEDDATA_DATA(self);
66
96
  StringValue(delimiter);
67
97
  if(RSTRING_LEN(delimiter) != 1)
68
98
  rb_raise( rb_eArgError, "delimiter size must be one byte");
@@ -79,7 +109,7 @@ pg_copycoder_delimiter_set(VALUE self, VALUE delimiter)
79
109
  static VALUE
80
110
  pg_copycoder_delimiter_get(VALUE self)
81
111
  {
82
- t_pg_copycoder *this = DATA_PTR(self);
112
+ t_pg_copycoder *this = RTYPEDDATA_DATA(self);
83
113
  return rb_str_new(&this->delimiter, 1);
84
114
  }
85
115
 
@@ -92,7 +122,7 @@ pg_copycoder_delimiter_get(VALUE self)
92
122
  static VALUE
93
123
  pg_copycoder_null_string_set(VALUE self, VALUE null_string)
94
124
  {
95
- t_pg_copycoder *this = DATA_PTR(self);
125
+ t_pg_copycoder *this = RTYPEDDATA_DATA(self);
96
126
  StringValue(null_string);
97
127
  this->null_string = null_string;
98
128
  return null_string;
@@ -104,7 +134,7 @@ pg_copycoder_null_string_set(VALUE self, VALUE null_string)
104
134
  static VALUE
105
135
  pg_copycoder_null_string_get(VALUE self)
106
136
  {
107
- t_pg_copycoder *this = DATA_PTR(self);
137
+ t_pg_copycoder *this = RTYPEDDATA_DATA(self);
108
138
  return this->null_string;
109
139
  }
110
140
 
@@ -112,16 +142,17 @@ pg_copycoder_null_string_get(VALUE self)
112
142
  * call-seq:
113
143
  * coder.type_map = map
114
144
  *
145
+ * Defines how single columns are encoded or decoded.
115
146
  * +map+ must be a kind of PG::TypeMap .
116
147
  *
117
148
  * Defaults to a PG::TypeMapAllStrings , so that PG::TextEncoder::String respectively
118
- * PG::TextDecoder::String is used for encoding/decoding of all columns.
149
+ * PG::TextDecoder::String is used for encoding/decoding of each column.
119
150
  *
120
151
  */
121
152
  static VALUE
122
153
  pg_copycoder_type_map_set(VALUE self, VALUE type_map)
123
154
  {
124
- t_pg_copycoder *this = DATA_PTR( self );
155
+ t_pg_copycoder *this = RTYPEDDATA_DATA( self );
125
156
 
126
157
  if ( !rb_obj_is_kind_of(type_map, rb_cTypeMap) ){
127
158
  rb_raise( rb_eTypeError, "wrong elements type %s (expected some kind of PG::TypeMap)",
@@ -136,11 +167,12 @@ pg_copycoder_type_map_set(VALUE self, VALUE type_map)
136
167
  * call-seq:
137
168
  * coder.type_map -> PG::TypeMap
138
169
  *
170
+ * The PG::TypeMap that will be used for encoding and decoding of columns.
139
171
  */
140
172
  static VALUE
141
173
  pg_copycoder_type_map_get(VALUE self)
142
174
  {
143
- t_pg_copycoder *this = DATA_PTR( self );
175
+ t_pg_copycoder *this = RTYPEDDATA_DATA( self );
144
176
 
145
177
  return this->typemap;
146
178
  }
@@ -167,9 +199,15 @@ pg_copycoder_type_map_get(VALUE self)
167
199
  * conn.put_copy_data ["string2", 42, true]
168
200
  * end
169
201
  * This creates +my_table+ and inserts two rows.
202
+ *
203
+ * It is possible to manually assign a type encoder for each column per PG::TypeMapByColumn,
204
+ * or to make use of PG::BasicTypeMapBasedOnResult to assign them based on the table OIDs.
205
+ *
206
+ * See also PG::TextDecoder::CopyRow for the decoding direction with
207
+ * PG::Connection#get_copy_data .
170
208
  */
171
209
  static int
172
- pg_text_enc_copy_row(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate)
210
+ pg_text_enc_copy_row(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate, int enc_idx)
173
211
  {
174
212
  t_pg_copycoder *this = (t_pg_copycoder *)conv;
175
213
  t_pg_coder_enc_func enc_func;
@@ -179,11 +217,12 @@ pg_text_enc_copy_row(t_pg_coder *conv, VALUE value, char *out, VALUE *intermedia
179
217
  char *current_out;
180
218
  char *end_capa_ptr;
181
219
 
182
- p_typemap = DATA_PTR( this->typemap );
220
+ p_typemap = RTYPEDDATA_DATA( this->typemap );
183
221
  p_typemap->funcs.fit_to_query( this->typemap, value );
184
222
 
185
223
  /* Allocate a new string with embedded capacity and realloc exponential when needed. */
186
224
  PG_RB_STR_NEW( *intermediate, current_out, end_capa_ptr );
225
+ PG_ENCODING_SET_NOCHECK(*intermediate, enc_idx);
187
226
 
188
227
  for( i=0; i<RARRAY_LEN(value); i++){
189
228
  char *ptr1;
@@ -211,11 +250,11 @@ pg_text_enc_copy_row(t_pg_coder *conv, VALUE value, char *out, VALUE *intermedia
211
250
  enc_func = pg_coder_enc_func(p_elem_coder);
212
251
 
213
252
  /* 1st pass for retiving the required memory space */
214
- strlen = enc_func(p_elem_coder, entry, NULL, &subint);
253
+ strlen = enc_func(p_elem_coder, entry, NULL, &subint, enc_idx);
215
254
 
216
255
  if( strlen == -1 ){
217
256
  /* we can directly use String value in subint */
218
- strlen = RSTRING_LEN(subint);
257
+ strlen = RSTRING_LENINT(subint);
219
258
 
220
259
  /* size of string assuming the worst case, that every character must be escaped. */
221
260
  PG_RB_STR_ENSURE_CAPA( *intermediate, strlen * 2, current_out, end_capa_ptr );
@@ -234,7 +273,7 @@ pg_text_enc_copy_row(t_pg_coder *conv, VALUE value, char *out, VALUE *intermedia
234
273
  PG_RB_STR_ENSURE_CAPA( *intermediate, strlen * 2, current_out, end_capa_ptr );
235
274
 
236
275
  /* Place the unescaped string at current output position. */
237
- strlen = enc_func(p_elem_coder, entry, current_out, &subint);
276
+ strlen = enc_func(p_elem_coder, entry, current_out, &subint, enc_idx);
238
277
 
239
278
  ptr1 = current_out;
240
279
  ptr2 = current_out + strlen;
@@ -301,15 +340,38 @@ GetDecimalFromHex(char hex)
301
340
  * strings by PG::TextDecoder::String.
302
341
  *
303
342
  * Example with default type map ( TypeMapAllStrings ):
343
+ * conn.exec("CREATE TABLE my_table AS VALUES('astring', 7, FALSE), ('string2', 42, TRUE) ")
344
+ *
304
345
  * deco = PG::TextDecoder::CopyRow.new
305
346
  * conn.copy_data "COPY my_table TO STDOUT", deco do
306
347
  * while row=conn.get_copy_data
307
348
  * p row
308
349
  * end
309
350
  * end
310
- * This prints all rows of +my_table+ to stdout:
351
+ * This prints all rows of +my_table+ :
311
352
  * ["astring", "7", "f"]
312
353
  * ["string2", "42", "t"]
354
+ *
355
+ * Example with column based type map:
356
+ * tm = PG::TypeMapByColumn.new( [
357
+ * PG::TextDecoder::String.new,
358
+ * PG::TextDecoder::Integer.new,
359
+ * PG::TextDecoder::Boolean.new] )
360
+ * deco = PG::TextDecoder::CopyRow.new( type_map: tm )
361
+ * conn.copy_data "COPY my_table TO STDOUT", deco do
362
+ * while row=conn.get_copy_data
363
+ * p row
364
+ * end
365
+ * end
366
+ * This prints the rows with type casted columns:
367
+ * ["astring", 7, false]
368
+ * ["string2", 42, true]
369
+ *
370
+ * Instead of manually assigning a type decoder for each column, PG::BasicTypeMapForResults
371
+ * can be used to assign them based on the table OIDs.
372
+ *
373
+ * See also PG::TextEncoder::CopyRow for the encoding direction with
374
+ * PG::Connection#put_copy_data .
313
375
  */
314
376
  /*
315
377
  * Parse the current line into separate attributes (fields),
@@ -324,7 +386,7 @@ GetDecimalFromHex(char hex)
324
386
  * src/backend/commands/copy.c
325
387
  */
326
388
  static VALUE
327
- pg_text_dec_copy_row(t_pg_coder *conv, char *input_line, int len, int _tuple, int _field, int enc_idx)
389
+ pg_text_dec_copy_row(t_pg_coder *conv, const char *input_line, int len, int _tuple, int _field, int enc_idx)
328
390
  {
329
391
  t_pg_copycoder *this = (t_pg_copycoder *)conv;
330
392
 
@@ -338,12 +400,12 @@ pg_text_dec_copy_row(t_pg_coder *conv, char *input_line, int len, int _tuple, in
338
400
  int fieldno;
339
401
  int expected_fields;
340
402
  char *output_ptr;
341
- char *cur_ptr;
342
- char *line_end_ptr;
403
+ const char *cur_ptr;
404
+ const char *line_end_ptr;
343
405
  char *end_capa_ptr;
344
406
  t_typemap *p_typemap;
345
407
 
346
- p_typemap = DATA_PTR( this->typemap );
408
+ p_typemap = RTYPEDDATA_DATA( this->typemap );
347
409
  expected_fields = p_typemap->funcs.fit_to_copy_get( this->typemap );
348
410
 
349
411
  /* The received input string will probably have this->nfields fields. */
@@ -351,7 +413,7 @@ pg_text_dec_copy_row(t_pg_coder *conv, char *input_line, int len, int _tuple, in
351
413
 
352
414
  /* Allocate a new string with embedded capacity and realloc later with
353
415
  * exponential growing size when needed. */
354
- PG_RB_TAINTED_STR_NEW( field_str, output_ptr, end_capa_ptr );
416
+ PG_RB_STR_NEW( field_str, output_ptr, end_capa_ptr );
355
417
 
356
418
  /* set pointer variables for loop */
357
419
  cur_ptr = input_line;
@@ -362,9 +424,9 @@ pg_text_dec_copy_row(t_pg_coder *conv, char *input_line, int len, int _tuple, in
362
424
  for (;;)
363
425
  {
364
426
  int found_delim = 0;
365
- char *start_ptr;
366
- char *end_ptr;
367
- int input_len;
427
+ const char *start_ptr;
428
+ const char *end_ptr;
429
+ long input_len;
368
430
 
369
431
  /* Remember start of field on input side */
370
432
  start_ptr = cur_ptr;
@@ -513,7 +575,7 @@ pg_text_dec_copy_row(t_pg_coder *conv, char *input_line, int len, int _tuple, in
513
575
  if( field_value == field_str ){
514
576
  /* Our output string will be send to the user, so we can not reuse
515
577
  * it for the next field. */
516
- PG_RB_TAINTED_STR_NEW( field_str, output_ptr, end_capa_ptr );
578
+ PG_RB_STR_NEW( field_str, output_ptr, end_capa_ptr );
517
579
  }
518
580
  }
519
581
  /* Reset the pointer to the start of the output/buffer string. */
@@ -555,7 +617,12 @@ init_pg_copycoder()
555
617
  /* rb_mPG_TextEncoder = rb_define_module_under( rb_mPG, "TextEncoder" ); */
556
618
  /* dummy = rb_define_class_under( rb_mPG_TextEncoder, "CopyRow", rb_cPG_CopyEncoder ); */
557
619
  pg_define_coder( "CopyRow", pg_text_enc_copy_row, rb_cPG_CopyEncoder, rb_mPG_TextEncoder );
620
+ rb_include_module( rb_cPG_CopyEncoder, rb_mPG_BinaryFormatting );
621
+
558
622
  /* rb_mPG_TextDecoder = rb_define_module_under( rb_mPG, "TextDecoder" ); */
559
623
  /* dummy = rb_define_class_under( rb_mPG_TextDecoder, "CopyRow", rb_cPG_CopyDecoder ); */
560
624
  pg_define_coder( "CopyRow", pg_text_dec_copy_row, rb_cPG_CopyDecoder, rb_mPG_TextDecoder );
625
+ /* Although CopyRow is a text decoder, data can contain zero bytes and are not zero terminated.
626
+ * They are handled like binaries. So format is set to 1 (binary). */
627
+ rb_include_module( rb_cPG_CopyDecoder, rb_mPG_BinaryFormatting );
561
628
  }