pg 0.18.0 → 1.0.0

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 (66) hide show
  1. checksums.yaml +5 -5
  2. checksums.yaml.gz.sig +0 -0
  3. data/BSDL +2 -2
  4. data/ChangeLog +1221 -4
  5. data/History.rdoc +130 -0
  6. data/Manifest.txt +0 -18
  7. data/README-Windows.rdoc +15 -26
  8. data/README.rdoc +16 -10
  9. data/Rakefile +32 -23
  10. data/Rakefile.cross +56 -38
  11. data/ext/errorcodes.def +33 -0
  12. data/ext/errorcodes.txt +15 -1
  13. data/ext/extconf.rb +27 -35
  14. data/ext/gvl_wrappers.c +4 -0
  15. data/ext/gvl_wrappers.h +27 -39
  16. data/ext/pg.c +19 -51
  17. data/ext/pg.h +22 -79
  18. data/ext/pg_binary_decoder.c +3 -1
  19. data/ext/pg_binary_encoder.c +14 -12
  20. data/ext/pg_coder.c +31 -10
  21. data/ext/pg_connection.c +350 -263
  22. data/ext/pg_copy_coder.c +34 -4
  23. data/ext/pg_result.c +27 -25
  24. data/ext/pg_text_decoder.c +9 -10
  25. data/ext/pg_text_encoder.c +93 -73
  26. data/ext/pg_type_map.c +20 -13
  27. data/ext/pg_type_map_by_column.c +7 -7
  28. data/ext/pg_type_map_by_mri_type.c +2 -2
  29. data/ext/pg_type_map_in_ruby.c +4 -7
  30. data/ext/util.c +3 -3
  31. data/ext/util.h +1 -1
  32. data/lib/pg/basic_type_mapping.rb +69 -42
  33. data/lib/pg/connection.rb +89 -38
  34. data/lib/pg/result.rb +10 -5
  35. data/lib/pg/text_decoder.rb +12 -3
  36. data/lib/pg/text_encoder.rb +8 -0
  37. data/lib/pg.rb +18 -10
  38. data/spec/helpers.rb +9 -16
  39. data/spec/pg/basic_type_mapping_spec.rb +58 -4
  40. data/spec/pg/connection_spec.rb +477 -217
  41. data/spec/pg/result_spec.rb +14 -7
  42. data/spec/pg/type_map_by_class_spec.rb +2 -2
  43. data/spec/pg/type_map_by_mri_type_spec.rb +1 -1
  44. data/spec/pg/type_spec.rb +145 -33
  45. data/spec/pg_spec.rb +1 -1
  46. data.tar.gz.sig +0 -0
  47. metadata +67 -66
  48. metadata.gz.sig +0 -0
  49. data/sample/array_insert.rb +0 -20
  50. data/sample/async_api.rb +0 -106
  51. data/sample/async_copyto.rb +0 -39
  52. data/sample/async_mixed.rb +0 -56
  53. data/sample/check_conn.rb +0 -21
  54. data/sample/copyfrom.rb +0 -81
  55. data/sample/copyto.rb +0 -19
  56. data/sample/cursor.rb +0 -21
  57. data/sample/disk_usage_report.rb +0 -186
  58. data/sample/issue-119.rb +0 -94
  59. data/sample/losample.rb +0 -69
  60. data/sample/minimal-testcase.rb +0 -17
  61. data/sample/notify_wait.rb +0 -72
  62. data/sample/pg_statistics.rb +0 -294
  63. data/sample/replication_monitor.rb +0 -231
  64. data/sample/test_binary_values.rb +0 -33
  65. data/sample/wal_shipper.rb +0 -434
  66. data/sample/warehouse_partitions.rb +0 -320
data/ext/pg_copy_coder.c CHANGED
@@ -167,9 +167,15 @@ pg_copycoder_type_map_get(VALUE self)
167
167
  * conn.put_copy_data ["string2", 42, true]
168
168
  * end
169
169
  * This creates +my_table+ and inserts two rows.
170
+ *
171
+ * It is possible to manually assign a type encoder for each column per PG::TypeMapByColumn,
172
+ * or to make use of PG::BasicTypeMapBasedOnResult to assign them based on the table OIDs.
173
+ *
174
+ * See also PG::TextDecoder::CopyRow for the decoding direction with
175
+ * PG::Connection#get_copy_data .
170
176
  */
171
177
  static int
172
- pg_text_enc_copy_row(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate)
178
+ pg_text_enc_copy_row(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate, int enc_idx)
173
179
  {
174
180
  t_pg_copycoder *this = (t_pg_copycoder *)conv;
175
181
  t_pg_coder_enc_func enc_func;
@@ -184,6 +190,7 @@ pg_text_enc_copy_row(t_pg_coder *conv, VALUE value, char *out, VALUE *intermedia
184
190
 
185
191
  /* Allocate a new string with embedded capacity and realloc exponential when needed. */
186
192
  PG_RB_STR_NEW( *intermediate, current_out, end_capa_ptr );
193
+ PG_ENCODING_SET_NOCHECK(*intermediate, enc_idx);
187
194
 
188
195
  for( i=0; i<RARRAY_LEN(value); i++){
189
196
  char *ptr1;
@@ -211,7 +218,7 @@ pg_text_enc_copy_row(t_pg_coder *conv, VALUE value, char *out, VALUE *intermedia
211
218
  enc_func = pg_coder_enc_func(p_elem_coder);
212
219
 
213
220
  /* 1st pass for retiving the required memory space */
214
- strlen = enc_func(p_elem_coder, entry, NULL, &subint);
221
+ strlen = enc_func(p_elem_coder, entry, NULL, &subint, enc_idx);
215
222
 
216
223
  if( strlen == -1 ){
217
224
  /* we can directly use String value in subint */
@@ -234,7 +241,7 @@ pg_text_enc_copy_row(t_pg_coder *conv, VALUE value, char *out, VALUE *intermedia
234
241
  PG_RB_STR_ENSURE_CAPA( *intermediate, strlen * 2, current_out, end_capa_ptr );
235
242
 
236
243
  /* Place the unescaped string at current output position. */
237
- strlen = enc_func(p_elem_coder, entry, current_out, &subint);
244
+ strlen = enc_func(p_elem_coder, entry, current_out, &subint, enc_idx);
238
245
 
239
246
  ptr1 = current_out;
240
247
  ptr2 = current_out + strlen;
@@ -301,15 +308,38 @@ GetDecimalFromHex(char hex)
301
308
  * strings by PG::TextDecoder::String.
302
309
  *
303
310
  * Example with default type map ( TypeMapAllStrings ):
311
+ * conn.exec("CREATE TABLE my_table AS VALUES('astring', 7, FALSE), ('string2', 42, TRUE) ")
312
+ *
304
313
  * deco = PG::TextDecoder::CopyRow.new
305
314
  * conn.copy_data "COPY my_table TO STDOUT", deco do
306
315
  * while row=conn.get_copy_data
307
316
  * p row
308
317
  * end
309
318
  * end
310
- * This prints all rows of +my_table+ to stdout:
319
+ * This prints all rows of +my_table+ :
311
320
  * ["astring", "7", "f"]
312
321
  * ["string2", "42", "t"]
322
+ *
323
+ * Example with column based type map:
324
+ * tm = PG::TypeMapByColumn.new( [
325
+ * PG::TextDecoder::String.new,
326
+ * PG::TextDecoder::Integer.new,
327
+ * PG::TextDecoder::Boolean.new] )
328
+ * deco = PG::TextDecoder::CopyRow.new( type_map: tm )
329
+ * conn.copy_data "COPY my_table TO STDOUT", deco do
330
+ * while row=conn.get_copy_data
331
+ * p row
332
+ * end
333
+ * end
334
+ * This prints the rows with type casted columns:
335
+ * ["astring", 7, false]
336
+ * ["string2", 42, true]
337
+ *
338
+ * Instead of manually assigning a type decoder for each column, PG::BasicTypeMapForResults
339
+ * can be used to assign them based on the table OIDs.
340
+ *
341
+ * See also PG::TextEncoder::CopyRow for the encoding direction with
342
+ * PG::Connection#put_copy_data .
313
343
  */
314
344
  /*
315
345
  * Parse the current line into separate attributes (fields),
data/ext/pg_result.c CHANGED
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  * pg_result.c - PG::Result class extension
3
- * $Id: pg_result.c,v f23dd01bcb52 2014/11/17 10:47:53 kanis $
3
+ * $Id: pg_result.c,v 7c5d9608349f 2018/01/03 16:11:52 lars $
4
4
  *
5
5
  */
6
6
 
@@ -92,12 +92,8 @@ pg_result_check( VALUE self )
92
92
  case PGRES_TUPLES_OK:
93
93
  case PGRES_COPY_OUT:
94
94
  case PGRES_COPY_IN:
95
- #ifdef HAVE_CONST_PGRES_COPY_BOTH
96
95
  case PGRES_COPY_BOTH:
97
- #endif
98
- #ifdef HAVE_CONST_PGRES_SINGLE_TUPLE
99
96
  case PGRES_SINGLE_TUPLE:
100
- #endif
101
97
  case PGRES_EMPTY_QUERY:
102
98
  case PGRES_COMMAND_OK:
103
99
  return self;
@@ -288,7 +284,7 @@ static void pgresult_init_fnames(VALUE self)
288
284
  *
289
285
  * Example:
290
286
  * require 'pg'
291
- * conn = PGconn.open(:dbname => 'test')
287
+ * conn = PG.connect(:dbname => 'test')
292
288
  * res = conn.exec('SELECT 1 AS a, 2 AS b, NULL AS c')
293
289
  * res.getvalue(0,0) # '1'
294
290
  * res[0]['b'] # '2'
@@ -302,7 +298,7 @@ static void pgresult_init_fnames(VALUE self)
302
298
 
303
299
  /*
304
300
  * call-seq:
305
- * res.result_status() -> Fixnum
301
+ * res.result_status() -> Integer
306
302
  *
307
303
  * Returns the status of the query. The status value is one of:
308
304
  * * +PGRES_EMPTY_QUERY+
@@ -414,7 +410,7 @@ pgresult_error_field(VALUE self, VALUE field)
414
410
 
415
411
  /*
416
412
  * call-seq:
417
- * res.ntuples() -> Fixnum
413
+ * res.ntuples() -> Integer
418
414
  *
419
415
  * Returns the number of tuples in the query result.
420
416
  */
@@ -466,7 +462,7 @@ pgresult_fname(VALUE self, VALUE index)
466
462
 
467
463
  /*
468
464
  * call-seq:
469
- * res.fnumber( name ) -> Fixnum
465
+ * res.fnumber( name ) -> Integer
470
466
  *
471
467
  * Returns the index of the field specified by the string +name+.
472
468
  * The given +name+ is treated like an identifier in an SQL command, that is,
@@ -527,7 +523,7 @@ pgresult_ftable(VALUE self, VALUE column_number)
527
523
 
528
524
  /*
529
525
  * call-seq:
530
- * res.ftablecol( column_number ) -> Fixnum
526
+ * res.ftablecol( column_number ) -> Integer
531
527
  *
532
528
  * Returns the column number (within its table) of the table from
533
529
  * which the column _column_number_ is made up.
@@ -552,7 +548,7 @@ pgresult_ftablecol(VALUE self, VALUE column_number)
552
548
 
553
549
  /*
554
550
  * call-seq:
555
- * res.fformat( column_number ) -> Fixnum
551
+ * res.fformat( column_number ) -> Integer
556
552
  *
557
553
  * Returns the format (0 for text, 1 for binary) of column
558
554
  * _column_number_.
@@ -696,7 +692,7 @@ pgresult_getisnull(VALUE self, VALUE tup_num, VALUE field_num)
696
692
 
697
693
  /*
698
694
  * call-seq:
699
- * res.getlength( tup_num, field_num ) -> Fixnum
695
+ * res.getlength( tup_num, field_num ) -> Integer
700
696
  *
701
697
  * Returns the (String) length of the field in bytes.
702
698
  *
@@ -721,7 +717,7 @@ pgresult_getlength(VALUE self, VALUE tup_num, VALUE field_num)
721
717
 
722
718
  /*
723
719
  * call-seq:
724
- * res.nparams() -> Fixnum
720
+ * res.nparams() -> Integer
725
721
  *
726
722
  * Returns the number of parameters of a prepared statement.
727
723
  * Only useful for the result returned by conn.describePrepared
@@ -772,11 +768,17 @@ pgresult_cmd_status(VALUE self)
772
768
  * Returns the number of tuples (rows) affected by the SQL command.
773
769
  *
774
770
  * If the SQL command that generated the PG::Result was not one of:
775
- * * +INSERT+
776
- * * +UPDATE+
777
- * * +DELETE+
778
- * * +MOVE+
779
- * * +FETCH+
771
+ *
772
+ * * <tt>SELECT</tt>
773
+ * * <tt>CREATE TABLE AS</tt>
774
+ * * <tt>INSERT</tt>
775
+ * * <tt>UPDATE</tt>
776
+ * * <tt>DELETE</tt>
777
+ * * <tt>MOVE</tt>
778
+ * * <tt>FETCH</tt>
779
+ * * <tt>COPY</tt>
780
+ * * an +EXECUTE+ of a prepared query that contains an +INSERT+, +UPDATE+, or +DELETE+ statement
781
+ *
780
782
  * or if no tuples were affected, <tt>0</tt> is returned.
781
783
  */
782
784
  static VALUE
@@ -863,7 +865,7 @@ pgresult_each_row(VALUE self)
863
865
  num_fields = PQnfields(this->pgresult);
864
866
 
865
867
  for ( row = 0; row < num_rows; row++ ) {
866
- VALUE row_values[num_fields];
868
+ PG_VARIABLE_LENGTH_ARRAY(VALUE, row_values, num_fields, PG_MAX_COLUMNS)
867
869
 
868
870
  /* populate the row */
869
871
  for ( field = 0; field < num_fields; field++ ) {
@@ -892,7 +894,7 @@ pgresult_values(VALUE self)
892
894
  VALUE results = rb_ary_new2( num_rows );
893
895
 
894
896
  for ( row = 0; row < num_rows; row++ ) {
895
- VALUE row_values[num_fields];
897
+ PG_VARIABLE_LENGTH_ARRAY(VALUE, row_values, num_fields, PG_MAX_COLUMNS)
896
898
 
897
899
  /* populate the row */
898
900
  for ( field = 0; field < num_fields; field++ ) {
@@ -1050,7 +1052,6 @@ pgresult_type_map_get(VALUE self)
1050
1052
  return this->typemap;
1051
1053
  }
1052
1054
 
1053
- #ifdef HAVE_PQSETSINGLEROWMODE
1054
1055
  /*
1055
1056
  * call-seq:
1056
1057
  * res.stream_each{ |tuple| ... }
@@ -1081,6 +1082,8 @@ pgresult_type_map_get(VALUE self)
1081
1082
  * # do something with the received row of the second query
1082
1083
  * end
1083
1084
  * conn.get_result # => nil (no more results)
1085
+ *
1086
+ * Available since PostgreSQL-9.2
1084
1087
  */
1085
1088
  static VALUE
1086
1089
  pgresult_stream_each(VALUE self)
@@ -1144,6 +1147,8 @@ pgresult_stream_each(VALUE self)
1144
1147
  *
1145
1148
  * This method works equally to #stream_each , but yields an Array of
1146
1149
  * values.
1150
+ *
1151
+ * Available since PostgreSQL-9.2
1147
1152
  */
1148
1153
  static VALUE
1149
1154
  pgresult_stream_each_row(VALUE self)
@@ -1176,7 +1181,7 @@ pgresult_stream_each_row(VALUE self)
1176
1181
  }
1177
1182
 
1178
1183
  for ( row = 0; row < ntuples; row++ ) {
1179
- VALUE row_values[nfields];
1184
+ PG_VARIABLE_LENGTH_ARRAY(VALUE, row_values, nfields, PG_MAX_COLUMNS)
1180
1185
  int field;
1181
1186
 
1182
1187
  /* populate the row */
@@ -1204,7 +1209,6 @@ pgresult_stream_each_row(VALUE self)
1204
1209
  /* never reached */
1205
1210
  return self;
1206
1211
  }
1207
- #endif
1208
1212
 
1209
1213
 
1210
1214
  void
@@ -1261,11 +1265,9 @@ init_pg_result()
1261
1265
  rb_define_method(rb_cPGresult, "type_map=", pgresult_type_map_set, 1);
1262
1266
  rb_define_method(rb_cPGresult, "type_map", pgresult_type_map_get, 0);
1263
1267
 
1264
- #ifdef HAVE_PQSETSINGLEROWMODE
1265
1268
  /****** PG::Result INSTANCE METHODS: streaming ******/
1266
1269
  rb_define_method(rb_cPGresult, "stream_each", pgresult_stream_each, 0);
1267
1270
  rb_define_method(rb_cPGresult, "stream_each_row", pgresult_stream_each_row, 0);
1268
- #endif
1269
1271
  }
1270
1272
 
1271
1273
 
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  * pg_text_decoder.c - PG::TextDecoder module
3
- * $Id: pg_text_decoder.c,v b7f9daeeba29 2014/11/21 19:53:47 lars $
3
+ * $Id: pg_text_decoder.c,v fcf731d3dff7 2015/09/08 12:25:06 jfali $
4
4
  *
5
5
  */
6
6
 
@@ -30,7 +30,9 @@
30
30
 
31
31
  #include "pg.h"
32
32
  #include "util.h"
33
+ #ifdef HAVE_INTTYPES_H
33
34
  #include <inttypes.h>
35
+ #endif
34
36
 
35
37
  VALUE rb_mPG_TextDecoder;
36
38
  static ID s_id_decode;
@@ -293,7 +295,7 @@ pg_text_dec_array(t_pg_coder *conv, char *val, int len, int tuple, int field, in
293
295
  }
294
296
 
295
297
  /*
296
- * Document-class: PG::TextDecoder::Identifier < PG::CompositeDecoder
298
+ * Document-class: PG::TextDecoder::Identifier < PG::SimpleDecoder
297
299
  *
298
300
  * This is the decoder class for PostgreSQL identifiers.
299
301
  *
@@ -305,16 +307,13 @@ pg_text_dec_array(t_pg_coder *conv, char *val, int len, int tuple, int field, in
305
307
  static VALUE
306
308
  pg_text_dec_identifier(t_pg_coder *conv, char *val, int len, int tuple, int field, int enc_idx)
307
309
  {
308
- t_pg_composite_coder *this = (t_pg_composite_coder *)conv;
309
- t_pg_coder_dec_func dec_func = pg_coder_dec_func(this->elem, 0);
310
-
311
310
  /* Return value: array */
312
311
  VALUE array;
313
312
  VALUE elem;
314
313
  int word_index = 0;
315
314
  int index;
316
315
  /* Use a buffer of the same length, as that will be the worst case */
317
- char word[len + 1];
316
+ PG_VARIABLE_LENGTH_ARRAY(char, word, len + 1, NAMEDATALEN)
318
317
 
319
318
  /* The current character in the input string. */
320
319
  char c;
@@ -331,7 +330,7 @@ pg_text_dec_identifier(t_pg_coder *conv, char *val, int len, int tuple, int fiel
331
330
  if(c == '.' && openQuote < 2 ) {
332
331
  word[word_index] = 0;
333
332
 
334
- elem = dec_func(conv, word, word_index, tuple, field, enc_idx);
333
+ elem = pg_text_dec_string(conv, word, word_index, tuple, field, enc_idx);
335
334
  rb_ary_push(array, elem);
336
335
 
337
336
  openQuote = 0;
@@ -353,7 +352,7 @@ pg_text_dec_identifier(t_pg_coder *conv, char *val, int len, int tuple, int fiel
353
352
  }
354
353
 
355
354
  word[word_index] = 0;
356
- elem = dec_func(conv, word, word_index, tuple, field, enc_idx);
355
+ elem = pg_text_dec_string(conv, word, word_index, tuple, field, enc_idx);
357
356
  rb_ary_push(array, elem);
358
357
 
359
358
  return array;
@@ -412,11 +411,11 @@ init_pg_text_decoder()
412
411
  pg_define_coder( "String", pg_text_dec_string, rb_cPG_SimpleDecoder, rb_mPG_TextDecoder );
413
412
  /* dummy = rb_define_class_under( rb_mPG_TextDecoder, "Bytea", rb_cPG_SimpleDecoder ); */
414
413
  pg_define_coder( "Bytea", pg_text_dec_bytea, rb_cPG_SimpleDecoder, rb_mPG_TextDecoder );
414
+ /* dummy = rb_define_class_under( rb_mPG_TextDecoder, "Identifier", rb_cPG_SimpleDecoder ); */
415
+ pg_define_coder( "Identifier", pg_text_dec_identifier, rb_cPG_SimpleDecoder, rb_mPG_TextDecoder );
415
416
 
416
417
  /* dummy = rb_define_class_under( rb_mPG_TextDecoder, "Array", rb_cPG_CompositeDecoder ); */
417
418
  pg_define_coder( "Array", pg_text_dec_array, rb_cPG_CompositeDecoder, rb_mPG_TextDecoder );
418
- /* dummy = rb_define_class_under( rb_mPG_TextDecoder, "Identifier", rb_cPG_CompositeDecoder ); */
419
- pg_define_coder( "Identifier", pg_text_dec_identifier, rb_cPG_CompositeDecoder, rb_mPG_TextDecoder );
420
419
  /* dummy = rb_define_class_under( rb_mPG_TextDecoder, "FromBase64", rb_cPG_CompositeDecoder ); */
421
420
  pg_define_coder( "FromBase64", pg_text_dec_from_base64, rb_cPG_CompositeDecoder, rb_mPG_TextDecoder );
422
421
  }