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.
- checksums.yaml +5 -5
- checksums.yaml.gz.sig +0 -0
- data/BSDL +2 -2
- data/ChangeLog +1221 -4
- data/History.rdoc +130 -0
- data/Manifest.txt +0 -18
- data/README-Windows.rdoc +15 -26
- data/README.rdoc +16 -10
- data/Rakefile +32 -23
- data/Rakefile.cross +56 -38
- data/ext/errorcodes.def +33 -0
- data/ext/errorcodes.txt +15 -1
- data/ext/extconf.rb +27 -35
- data/ext/gvl_wrappers.c +4 -0
- data/ext/gvl_wrappers.h +27 -39
- data/ext/pg.c +19 -51
- data/ext/pg.h +22 -79
- data/ext/pg_binary_decoder.c +3 -1
- data/ext/pg_binary_encoder.c +14 -12
- data/ext/pg_coder.c +31 -10
- data/ext/pg_connection.c +350 -263
- data/ext/pg_copy_coder.c +34 -4
- data/ext/pg_result.c +27 -25
- data/ext/pg_text_decoder.c +9 -10
- data/ext/pg_text_encoder.c +93 -73
- data/ext/pg_type_map.c +20 -13
- data/ext/pg_type_map_by_column.c +7 -7
- data/ext/pg_type_map_by_mri_type.c +2 -2
- data/ext/pg_type_map_in_ruby.c +4 -7
- data/ext/util.c +3 -3
- data/ext/util.h +1 -1
- data/lib/pg/basic_type_mapping.rb +69 -42
- data/lib/pg/connection.rb +89 -38
- data/lib/pg/result.rb +10 -5
- data/lib/pg/text_decoder.rb +12 -3
- data/lib/pg/text_encoder.rb +8 -0
- data/lib/pg.rb +18 -10
- data/spec/helpers.rb +9 -16
- data/spec/pg/basic_type_mapping_spec.rb +58 -4
- data/spec/pg/connection_spec.rb +477 -217
- data/spec/pg/result_spec.rb +14 -7
- data/spec/pg/type_map_by_class_spec.rb +2 -2
- data/spec/pg/type_map_by_mri_type_spec.rb +1 -1
- data/spec/pg/type_spec.rb +145 -33
- data/spec/pg_spec.rb +1 -1
- data.tar.gz.sig +0 -0
- metadata +67 -66
- metadata.gz.sig +0 -0
- data/sample/array_insert.rb +0 -20
- data/sample/async_api.rb +0 -106
- data/sample/async_copyto.rb +0 -39
- data/sample/async_mixed.rb +0 -56
- data/sample/check_conn.rb +0 -21
- data/sample/copyfrom.rb +0 -81
- data/sample/copyto.rb +0 -19
- data/sample/cursor.rb +0 -21
- data/sample/disk_usage_report.rb +0 -186
- data/sample/issue-119.rb +0 -94
- data/sample/losample.rb +0 -69
- data/sample/minimal-testcase.rb +0 -17
- data/sample/notify_wait.rb +0 -72
- data/sample/pg_statistics.rb +0 -294
- data/sample/replication_monitor.rb +0 -231
- data/sample/test_binary_values.rb +0 -33
- data/sample/wal_shipper.rb +0 -434
- 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+
|
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
|
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 =
|
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() ->
|
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() ->
|
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 ) ->
|
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 ) ->
|
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 ) ->
|
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 ) ->
|
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() ->
|
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
|
-
*
|
776
|
-
* *
|
777
|
-
* *
|
778
|
-
* *
|
779
|
-
* *
|
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
|
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
|
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
|
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
|
|
data/ext/pg_text_decoder.c
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
/*
|
2
2
|
* pg_text_decoder.c - PG::TextDecoder module
|
3
|
-
* $Id: pg_text_decoder.c,v
|
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::
|
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
|
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 =
|
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 =
|
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
|
}
|