pg 1.2.3-x86-mingw32 → 1.3.0.rc1-x86-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.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/.appveyor.yml +36 -0
- data/.gems +6 -0
- data/.github/workflows/binary-gems.yml +80 -0
- data/.github/workflows/source-gem.yml +129 -0
- data/.gitignore +13 -0
- data/.hgsigs +34 -0
- data/.hgtags +41 -0
- data/.irbrc +23 -0
- data/.pryrc +23 -0
- data/.tm_properties +21 -0
- data/.travis.yml +49 -0
- data/Gemfile +14 -0
- data/History.rdoc +75 -7
- data/Manifest.txt +0 -1
- data/README.rdoc +7 -6
- data/Rakefile +27 -138
- data/Rakefile.cross +5 -5
- data/certs/ged.pem +24 -0
- data/ext/errorcodes.def +8 -0
- data/ext/errorcodes.txt +3 -1
- data/ext/extconf.rb +90 -19
- data/ext/gvl_wrappers.c +4 -0
- data/ext/gvl_wrappers.h +23 -0
- data/ext/pg.c +35 -1
- data/ext/pg.h +18 -1
- data/ext/pg_coder.c +82 -28
- data/ext/pg_connection.c +538 -279
- data/ext/pg_copy_coder.c +45 -16
- data/ext/pg_record_coder.c +38 -10
- data/ext/pg_result.c +61 -31
- data/ext/pg_text_decoder.c +1 -1
- data/ext/pg_text_encoder.c +6 -6
- data/ext/pg_tuple.c +47 -21
- data/ext/pg_type_map.c +41 -8
- data/ext/pg_type_map_all_strings.c +14 -1
- data/ext/pg_type_map_by_class.c +49 -24
- data/ext/pg_type_map_by_column.c +64 -28
- data/ext/pg_type_map_by_mri_type.c +47 -18
- data/ext/pg_type_map_by_oid.c +52 -23
- data/ext/pg_type_map_in_ruby.c +50 -19
- data/ext/pg_util.c +2 -2
- data/lib/2.5/pg_ext.so +0 -0
- data/lib/2.6/pg_ext.so +0 -0
- data/lib/2.7/pg_ext.so +0 -0
- data/lib/3.0/pg_ext.so +0 -0
- data/lib/pg/basic_type_map_based_on_result.rb +47 -0
- data/lib/pg/basic_type_map_for_queries.rb +193 -0
- data/lib/pg/basic_type_map_for_results.rb +81 -0
- data/lib/pg/basic_type_registry.rb +296 -0
- data/lib/pg/coder.rb +1 -1
- data/lib/pg/connection.rb +369 -56
- data/lib/pg/version.rb +4 -0
- data/lib/pg.rb +38 -25
- data/lib/x86-mingw32/libpq.dll +0 -0
- data/misc/openssl-pg-segfault.rb +31 -0
- data/misc/postgres/History.txt +9 -0
- data/misc/postgres/Manifest.txt +5 -0
- data/misc/postgres/README.txt +21 -0
- data/misc/postgres/Rakefile +21 -0
- data/misc/postgres/lib/postgres.rb +16 -0
- data/misc/ruby-pg/History.txt +9 -0
- data/misc/ruby-pg/Manifest.txt +5 -0
- data/misc/ruby-pg/README.txt +21 -0
- data/misc/ruby-pg/Rakefile +21 -0
- data/misc/ruby-pg/lib/ruby/pg.rb +16 -0
- data/pg.gemspec +32 -0
- data/sample/array_insert.rb +20 -0
- data/sample/async_api.rb +106 -0
- data/sample/async_copyto.rb +39 -0
- data/sample/async_mixed.rb +56 -0
- data/sample/check_conn.rb +21 -0
- data/sample/copydata.rb +71 -0
- data/sample/copyfrom.rb +81 -0
- data/sample/copyto.rb +19 -0
- data/sample/cursor.rb +21 -0
- data/sample/disk_usage_report.rb +177 -0
- data/sample/issue-119.rb +94 -0
- data/sample/losample.rb +69 -0
- data/sample/minimal-testcase.rb +17 -0
- data/sample/notify_wait.rb +72 -0
- data/sample/pg_statistics.rb +285 -0
- data/sample/replication_monitor.rb +222 -0
- data/sample/test_binary_values.rb +33 -0
- data/sample/wal_shipper.rb +434 -0
- data/sample/warehouse_partitions.rb +311 -0
- data.tar.gz.sig +0 -0
- metadata +81 -230
- metadata.gz.sig +0 -0
- data/ChangeLog +0 -0
- data/lib/2.2/pg_ext.so +0 -0
- data/lib/2.3/pg_ext.so +0 -0
- data/lib/2.4/pg_ext.so +0 -0
- data/lib/pg/basic_type_mapping.rb +0 -522
- data/spec/data/expected_trace.out +0 -26
- data/spec/data/random_binary_data +0 -0
- data/spec/helpers.rb +0 -380
- data/spec/pg/basic_type_mapping_spec.rb +0 -630
- data/spec/pg/connection_spec.rb +0 -1949
- data/spec/pg/connection_sync_spec.rb +0 -41
- data/spec/pg/result_spec.rb +0 -681
- data/spec/pg/tuple_spec.rb +0 -333
- data/spec/pg/type_map_by_class_spec.rb +0 -138
- data/spec/pg/type_map_by_column_spec.rb +0 -226
- data/spec/pg/type_map_by_mri_type_spec.rb +0 -136
- data/spec/pg/type_map_by_oid_spec.rb +0 -149
- data/spec/pg/type_map_in_ruby_spec.rb +0 -164
- data/spec/pg/type_map_spec.rb +0 -22
- data/spec/pg/type_spec.rb +0 -1123
- data/spec/pg_spec.rb +0 -50
data/ext/pg_connection.c
CHANGED
@@ -12,6 +12,7 @@
|
|
12
12
|
|
13
13
|
VALUE rb_cPGconn;
|
14
14
|
static ID s_id_encode;
|
15
|
+
static ID s_id_autoclose_set;
|
15
16
|
static VALUE sym_type, sym_format, sym_value;
|
16
17
|
static VALUE sym_symbol, sym_string, sym_static_symbol;
|
17
18
|
|
@@ -20,7 +21,9 @@ static PQnoticeProcessor default_notice_processor = NULL;
|
|
20
21
|
|
21
22
|
static VALUE pgconn_finish( VALUE );
|
22
23
|
static VALUE pgconn_set_default_encoding( VALUE self );
|
24
|
+
static VALUE pgconn_wait_for_flush( VALUE self );
|
23
25
|
static void pgconn_set_internal_encoding_index( VALUE );
|
26
|
+
static const rb_data_type_t pg_connection_type;
|
24
27
|
|
25
28
|
/*
|
26
29
|
* Global functions
|
@@ -33,7 +36,7 @@ t_pg_connection *
|
|
33
36
|
pg_get_connection( VALUE self )
|
34
37
|
{
|
35
38
|
t_pg_connection *this;
|
36
|
-
|
39
|
+
TypedData_Get_Struct( self, t_pg_connection, &pg_connection_type, this);
|
37
40
|
|
38
41
|
return this;
|
39
42
|
}
|
@@ -46,7 +49,7 @@ static t_pg_connection *
|
|
46
49
|
pg_get_connection_safe( VALUE self )
|
47
50
|
{
|
48
51
|
t_pg_connection *this;
|
49
|
-
|
52
|
+
TypedData_Get_Struct( self, t_pg_connection, &pg_connection_type, this);
|
50
53
|
|
51
54
|
if ( !this->pgconn )
|
52
55
|
rb_raise( rb_eConnectionBad, "connection is closed" );
|
@@ -65,7 +68,7 @@ PGconn *
|
|
65
68
|
pg_get_pgconn( VALUE self )
|
66
69
|
{
|
67
70
|
t_pg_connection *this;
|
68
|
-
|
71
|
+
TypedData_Get_Struct( self, t_pg_connection, &pg_connection_type, this);
|
69
72
|
|
70
73
|
if ( !this->pgconn )
|
71
74
|
rb_raise( rb_eConnectionBad, "connection is closed" );
|
@@ -145,16 +148,31 @@ static const char *pg_cstr_enc(VALUE str, int enc_idx){
|
|
145
148
|
* GC Mark function
|
146
149
|
*/
|
147
150
|
static void
|
148
|
-
pgconn_gc_mark(
|
151
|
+
pgconn_gc_mark( void *_this )
|
149
152
|
{
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
153
|
+
t_pg_connection *this = (t_pg_connection *)_this;
|
154
|
+
rb_gc_mark_movable( this->socket_io );
|
155
|
+
rb_gc_mark_movable( this->notice_receiver );
|
156
|
+
rb_gc_mark_movable( this->notice_processor );
|
157
|
+
rb_gc_mark_movable( this->type_map_for_queries );
|
158
|
+
rb_gc_mark_movable( this->type_map_for_results );
|
159
|
+
rb_gc_mark_movable( this->trace_stream );
|
160
|
+
rb_gc_mark_movable( this->encoder_for_put_copy_data );
|
161
|
+
rb_gc_mark_movable( this->decoder_for_get_copy_data );
|
162
|
+
}
|
163
|
+
|
164
|
+
static void
|
165
|
+
pgconn_gc_compact( void *_this )
|
166
|
+
{
|
167
|
+
t_pg_connection *this = (t_pg_connection *)_this;
|
168
|
+
pg_gc_location( this->socket_io );
|
169
|
+
pg_gc_location( this->notice_receiver );
|
170
|
+
pg_gc_location( this->notice_processor );
|
171
|
+
pg_gc_location( this->type_map_for_queries );
|
172
|
+
pg_gc_location( this->type_map_for_results );
|
173
|
+
pg_gc_location( this->trace_stream );
|
174
|
+
pg_gc_location( this->encoder_for_put_copy_data );
|
175
|
+
pg_gc_location( this->decoder_for_get_copy_data );
|
158
176
|
}
|
159
177
|
|
160
178
|
|
@@ -162,11 +180,15 @@ pgconn_gc_mark( t_pg_connection *this )
|
|
162
180
|
* GC Free function
|
163
181
|
*/
|
164
182
|
static void
|
165
|
-
pgconn_gc_free(
|
183
|
+
pgconn_gc_free( void *_this )
|
166
184
|
{
|
185
|
+
t_pg_connection *this = (t_pg_connection *)_this;
|
167
186
|
#if defined(_WIN32)
|
168
|
-
if ( RTEST(this->socket_io) )
|
169
|
-
rb_w32_unwrap_io_handle(
|
187
|
+
if ( RTEST(this->socket_io) ) {
|
188
|
+
if( rb_w32_unwrap_io_handle(this->ruby_sd) ){
|
189
|
+
rb_warn("pg: Could not unwrap win32 socket handle by garbage collector");
|
190
|
+
}
|
191
|
+
}
|
170
192
|
#endif
|
171
193
|
if (this->pgconn != NULL)
|
172
194
|
PQfinish( this->pgconn );
|
@@ -174,6 +196,29 @@ pgconn_gc_free( t_pg_connection *this )
|
|
174
196
|
xfree(this);
|
175
197
|
}
|
176
198
|
|
199
|
+
/*
|
200
|
+
* Object Size function
|
201
|
+
*/
|
202
|
+
static size_t
|
203
|
+
pgconn_memsize( const void *_this )
|
204
|
+
{
|
205
|
+
const t_pg_connection *this = (const t_pg_connection *)_this;
|
206
|
+
return sizeof(*this);
|
207
|
+
}
|
208
|
+
|
209
|
+
static const rb_data_type_t pg_connection_type = {
|
210
|
+
"PG::Connection",
|
211
|
+
{
|
212
|
+
pgconn_gc_mark,
|
213
|
+
pgconn_gc_free,
|
214
|
+
pgconn_memsize,
|
215
|
+
pg_compact_callback(pgconn_gc_compact),
|
216
|
+
},
|
217
|
+
0,
|
218
|
+
0,
|
219
|
+
0,
|
220
|
+
};
|
221
|
+
|
177
222
|
|
178
223
|
/**************************************************************************
|
179
224
|
* Class Methods
|
@@ -189,7 +234,7 @@ static VALUE
|
|
189
234
|
pgconn_s_allocate( VALUE klass )
|
190
235
|
{
|
191
236
|
t_pg_connection *this;
|
192
|
-
VALUE self =
|
237
|
+
VALUE self = TypedData_Make_Struct( klass, t_pg_connection, &pg_connection_type, this );
|
193
238
|
|
194
239
|
this->pgconn = NULL;
|
195
240
|
this->socket_io = Qnil;
|
@@ -230,7 +275,7 @@ pgconn_s_allocate( VALUE klass )
|
|
230
275
|
* [+options+]
|
231
276
|
* backend options
|
232
277
|
* [+tty+]
|
233
|
-
* (ignored in
|
278
|
+
* (ignored in all versions of PostgreSQL)
|
234
279
|
* [+dbname+]
|
235
280
|
* connecting database name
|
236
281
|
* [+user+]
|
@@ -244,7 +289,7 @@ pgconn_s_allocate( VALUE klass )
|
|
244
289
|
* PG::Connection.new
|
245
290
|
*
|
246
291
|
* # As a Hash
|
247
|
-
* PG::Connection.new( :
|
292
|
+
* PG::Connection.new( dbname: 'test', port: 5432 )
|
248
293
|
*
|
249
294
|
* # As a String
|
250
295
|
* PG::Connection.new( "dbname=test port=5432" )
|
@@ -252,6 +297,9 @@ pgconn_s_allocate( VALUE klass )
|
|
252
297
|
* # As an Array
|
253
298
|
* PG::Connection.new( nil, 5432, nil, nil, 'test', nil, nil )
|
254
299
|
*
|
300
|
+
* # As an URI
|
301
|
+
* PG::Connection.new( "postgresql://user:pass@pgsql.example.com:5432/testdb?sslmode=require" )
|
302
|
+
*
|
255
303
|
* If the Ruby default internal encoding is set (i.e., <code>Encoding.default_internal != nil</code>), the
|
256
304
|
* connection will have its +client_encoding+ set accordingly.
|
257
305
|
*
|
@@ -362,7 +410,7 @@ pgconn_s_ping( int argc, VALUE *argv, VALUE klass )
|
|
362
410
|
VALUE conninfo;
|
363
411
|
|
364
412
|
conninfo = rb_funcall2( klass, rb_intern("parse_connect_args"), argc, argv );
|
365
|
-
ping =
|
413
|
+
ping = gvl_PQping( StringValueCStr(conninfo) );
|
366
414
|
|
367
415
|
return INT2FIX((int)ping);
|
368
416
|
}
|
@@ -676,21 +724,19 @@ static VALUE
|
|
676
724
|
pgconn_port(VALUE self)
|
677
725
|
{
|
678
726
|
char* port = PQport(pg_get_pgconn(self));
|
679
|
-
return INT2NUM(
|
727
|
+
return INT2NUM(atoi(port));
|
680
728
|
}
|
681
729
|
|
682
730
|
/*
|
683
731
|
* call-seq:
|
684
732
|
* conn.tty()
|
685
733
|
*
|
686
|
-
*
|
734
|
+
* Obsolete function.
|
687
735
|
*/
|
688
736
|
static VALUE
|
689
737
|
pgconn_tty(VALUE self)
|
690
738
|
{
|
691
|
-
|
692
|
-
if (!tty) return Qnil;
|
693
|
-
return rb_str_new2(tty);
|
739
|
+
return rb_str_new2("");
|
694
740
|
}
|
695
741
|
|
696
742
|
/*
|
@@ -708,7 +754,6 @@ pgconn_options(VALUE self)
|
|
708
754
|
}
|
709
755
|
|
710
756
|
|
711
|
-
#ifdef HAVE_PQCONNINFO
|
712
757
|
/*
|
713
758
|
* call-seq:
|
714
759
|
* conn.conninfo -> hash
|
@@ -728,7 +773,6 @@ pgconn_conninfo( VALUE self )
|
|
728
773
|
|
729
774
|
return array;
|
730
775
|
}
|
731
|
-
#endif
|
732
776
|
|
733
777
|
|
734
778
|
/*
|
@@ -823,7 +867,10 @@ pgconn_server_version(VALUE self)
|
|
823
867
|
* call-seq:
|
824
868
|
* conn.error_message -> String
|
825
869
|
*
|
826
|
-
* Returns the error message
|
870
|
+
* Returns the error message most recently generated by an operation on the connection.
|
871
|
+
*
|
872
|
+
* Nearly all libpq functions will set a message for conn.error_message if they fail.
|
873
|
+
* Note that by libpq convention, a nonempty error_message result can consist of multiple lines, and will include a trailing newline.
|
827
874
|
*/
|
828
875
|
static VALUE
|
829
876
|
pgconn_error_message(VALUE self)
|
@@ -878,8 +925,8 @@ pgconn_socket_io(VALUE self)
|
|
878
925
|
{
|
879
926
|
int sd;
|
880
927
|
int ruby_sd;
|
881
|
-
ID id_autoclose = rb_intern("autoclose=");
|
882
928
|
t_pg_connection *this = pg_get_connection_safe( self );
|
929
|
+
VALUE cSocket;
|
883
930
|
VALUE socket_io = this->socket_io;
|
884
931
|
|
885
932
|
if ( !RTEST(socket_io) ) {
|
@@ -888,15 +935,19 @@ pgconn_socket_io(VALUE self)
|
|
888
935
|
|
889
936
|
#ifdef _WIN32
|
890
937
|
ruby_sd = rb_w32_wrap_io_handle((HANDLE)(intptr_t)sd, O_RDWR|O_BINARY|O_NOINHERIT);
|
938
|
+
if( ruby_sd == -1 ){
|
939
|
+
rb_raise(rb_eConnectionBad, "Could not wrap win32 socket handle");
|
940
|
+
}
|
891
941
|
this->ruby_sd = ruby_sd;
|
892
942
|
#else
|
893
943
|
ruby_sd = sd;
|
894
944
|
#endif
|
895
945
|
|
896
|
-
|
946
|
+
cSocket = rb_const_get(rb_cObject, rb_intern("BasicSocket"));
|
947
|
+
socket_io = rb_funcall( cSocket, rb_intern("for_fd"), 1, INT2NUM(ruby_sd));
|
897
948
|
|
898
949
|
/* Disable autoclose feature */
|
899
|
-
rb_funcall( socket_io,
|
950
|
+
rb_funcall( socket_io, s_id_autoclose_set, 1, Qfalse );
|
900
951
|
|
901
952
|
this->socket_io = socket_io;
|
902
953
|
}
|
@@ -918,6 +969,51 @@ pgconn_backend_pid(VALUE self)
|
|
918
969
|
return INT2NUM(PQbackendPID(pg_get_pgconn(self)));
|
919
970
|
}
|
920
971
|
|
972
|
+
typedef struct
|
973
|
+
{
|
974
|
+
struct sockaddr_storage addr;
|
975
|
+
socklen_t salen;
|
976
|
+
} SockAddr;
|
977
|
+
|
978
|
+
/* Copy of struct pg_cancel from libpq-int.h
|
979
|
+
*
|
980
|
+
* See https://github.com/postgres/postgres/blame/master/src/interfaces/libpq/libpq-int.h#L577-L586
|
981
|
+
*/
|
982
|
+
struct pg_cancel
|
983
|
+
{
|
984
|
+
SockAddr raddr; /* Remote address */
|
985
|
+
int be_pid; /* PID of backend --- needed for cancels */
|
986
|
+
int be_key; /* key of backend --- needed for cancels */
|
987
|
+
};
|
988
|
+
|
989
|
+
/*
|
990
|
+
* call-seq:
|
991
|
+
* conn.backend_key() -> Integer
|
992
|
+
*
|
993
|
+
* Returns the key of the backend server process for this connection.
|
994
|
+
* This key can be used to cancel queries on the server.
|
995
|
+
*/
|
996
|
+
static VALUE
|
997
|
+
pgconn_backend_key(VALUE self)
|
998
|
+
{
|
999
|
+
int be_key;
|
1000
|
+
struct pg_cancel *cancel;
|
1001
|
+
PGconn *conn = pg_get_pgconn(self);
|
1002
|
+
|
1003
|
+
cancel = (struct pg_cancel*)PQgetCancel(conn);
|
1004
|
+
if(cancel == NULL)
|
1005
|
+
rb_raise(rb_ePGerror,"Invalid connection!");
|
1006
|
+
|
1007
|
+
if( cancel->be_pid != PQbackendPID(conn) )
|
1008
|
+
rb_raise(rb_ePGerror,"Unexpected binary struct layout - please file a bug report at ruby-pg!");
|
1009
|
+
|
1010
|
+
be_key = cancel->be_key;
|
1011
|
+
|
1012
|
+
PQfreeCancel(cancel);
|
1013
|
+
|
1014
|
+
return INT2NUM(be_key);
|
1015
|
+
}
|
1016
|
+
|
921
1017
|
/*
|
922
1018
|
* call-seq:
|
923
1019
|
* conn.connection_needs_password() -> Boolean
|
@@ -1019,7 +1115,7 @@ struct query_params_data {
|
|
1019
1115
|
* Filled by alloc_query_params()
|
1020
1116
|
*/
|
1021
1117
|
|
1022
|
-
/* Wraps the pointer of allocated memory, if function parameters
|
1118
|
+
/* Wraps the pointer of allocated memory, if function parameters don't
|
1023
1119
|
* fit in the memory_pool below.
|
1024
1120
|
*/
|
1025
1121
|
VALUE heap_pool;
|
@@ -1037,7 +1133,7 @@ struct query_params_data {
|
|
1037
1133
|
Oid *types;
|
1038
1134
|
|
1039
1135
|
/* This array takes the string values for the timeframe of the query,
|
1040
|
-
* if param value
|
1136
|
+
* if param value conversion is required
|
1041
1137
|
*/
|
1042
1138
|
VALUE gc_array;
|
1043
1139
|
|
@@ -1051,8 +1147,9 @@ struct query_params_data {
|
|
1051
1147
|
};
|
1052
1148
|
|
1053
1149
|
static void
|
1054
|
-
free_typecast_heap_chain(
|
1150
|
+
free_typecast_heap_chain(void *_chain_entry)
|
1055
1151
|
{
|
1152
|
+
struct linked_typecast_data *chain_entry = (struct linked_typecast_data *)_chain_entry;
|
1056
1153
|
while(chain_entry){
|
1057
1154
|
struct linked_typecast_data *next = chain_entry->next;
|
1058
1155
|
xfree(chain_entry);
|
@@ -1060,6 +1157,18 @@ free_typecast_heap_chain(struct linked_typecast_data *chain_entry)
|
|
1060
1157
|
}
|
1061
1158
|
}
|
1062
1159
|
|
1160
|
+
static const rb_data_type_t pg_typecast_buffer_type = {
|
1161
|
+
"PG::Connection typecast buffer chain",
|
1162
|
+
{
|
1163
|
+
(RUBY_DATA_FUNC) NULL,
|
1164
|
+
free_typecast_heap_chain,
|
1165
|
+
(size_t (*)(const void *))NULL,
|
1166
|
+
},
|
1167
|
+
0,
|
1168
|
+
0,
|
1169
|
+
RUBY_TYPED_FREE_IMMEDIATELY,
|
1170
|
+
};
|
1171
|
+
|
1063
1172
|
static char *
|
1064
1173
|
alloc_typecast_buf( VALUE *typecast_heap_chain, int len )
|
1065
1174
|
{
|
@@ -1070,17 +1179,28 @@ alloc_typecast_buf( VALUE *typecast_heap_chain, int len )
|
|
1070
1179
|
/* Did we already wrap a memory chain per T_DATA object? */
|
1071
1180
|
if( NIL_P( *typecast_heap_chain ) ){
|
1072
1181
|
/* Leave free'ing of the buffer chain to the GC, when paramsData has left the stack */
|
1073
|
-
*typecast_heap_chain =
|
1182
|
+
*typecast_heap_chain = TypedData_Wrap_Struct( rb_cObject, &pg_typecast_buffer_type, allocated );
|
1074
1183
|
allocated->next = NULL;
|
1075
1184
|
} else {
|
1076
1185
|
/* Append to the chain */
|
1077
|
-
allocated->next =
|
1078
|
-
|
1186
|
+
allocated->next = RTYPEDDATA_DATA( *typecast_heap_chain );
|
1187
|
+
RTYPEDDATA_DATA( *typecast_heap_chain ) = allocated;
|
1079
1188
|
}
|
1080
1189
|
|
1081
1190
|
return &allocated->data[0];
|
1082
1191
|
}
|
1083
1192
|
|
1193
|
+
static const rb_data_type_t pg_query_heap_pool_type = {
|
1194
|
+
"PG::Connection query heap pool",
|
1195
|
+
{
|
1196
|
+
(RUBY_DATA_FUNC) NULL,
|
1197
|
+
RUBY_TYPED_DEFAULT_FREE,
|
1198
|
+
(size_t (*)(const void *))NULL,
|
1199
|
+
},
|
1200
|
+
0,
|
1201
|
+
0,
|
1202
|
+
RUBY_TYPED_FREE_IMMEDIATELY,
|
1203
|
+
};
|
1084
1204
|
|
1085
1205
|
static int
|
1086
1206
|
alloc_query_params(struct query_params_data *paramsData)
|
@@ -1095,7 +1215,7 @@ alloc_query_params(struct query_params_data *paramsData)
|
|
1095
1215
|
|
1096
1216
|
Check_Type(paramsData->params, T_ARRAY);
|
1097
1217
|
|
1098
|
-
p_typemap =
|
1218
|
+
p_typemap = RTYPEDDATA_DATA( paramsData->typemap );
|
1099
1219
|
p_typemap->funcs.fit_to_query( paramsData->typemap, paramsData->params );
|
1100
1220
|
|
1101
1221
|
paramsData->heap_pool = Qnil;
|
@@ -1114,7 +1234,7 @@ alloc_query_params(struct query_params_data *paramsData)
|
|
1114
1234
|
/* Allocate one combined memory pool for all possible function parameters */
|
1115
1235
|
memory_pool = (char*)xmalloc( required_pool_size );
|
1116
1236
|
/* Leave free'ing of the buffer to the GC, when paramsData has left the stack */
|
1117
|
-
paramsData->heap_pool =
|
1237
|
+
paramsData->heap_pool = TypedData_Wrap_Struct( rb_cObject, &pg_query_heap_pool_type, memory_pool );
|
1118
1238
|
required_pool_size = 0;
|
1119
1239
|
}else{
|
1120
1240
|
/* Use stack memory for function parameters */
|
@@ -1227,12 +1347,11 @@ pgconn_query_assign_typemap( VALUE self, struct query_params_data *paramsData )
|
|
1227
1347
|
/* Use default typemap for queries. It's type is checked when assigned. */
|
1228
1348
|
paramsData->typemap = pg_get_connection(self)->type_map_for_queries;
|
1229
1349
|
}else{
|
1350
|
+
t_typemap *tm;
|
1351
|
+
UNUSED(tm);
|
1352
|
+
|
1230
1353
|
/* Check type of method param */
|
1231
|
-
|
1232
|
-
rb_raise( rb_eTypeError, "wrong argument type %s (expected kind of PG::TypeMap)",
|
1233
|
-
rb_obj_classname( paramsData->typemap ) );
|
1234
|
-
}
|
1235
|
-
Check_Type( paramsData->typemap, T_DATA );
|
1354
|
+
TypedData_Get_Struct(paramsData->typemap, t_typemap, &pg_typemap_type, tm);
|
1236
1355
|
}
|
1237
1356
|
}
|
1238
1357
|
|
@@ -1454,6 +1573,9 @@ pgconn_describe_portal(self, stmt_name)
|
|
1454
1573
|
* * +PGRES_NONFATAL_ERROR+
|
1455
1574
|
* * +PGRES_FATAL_ERROR+
|
1456
1575
|
* * +PGRES_COPY_BOTH+
|
1576
|
+
* * +PGRES_SINGLE_TUPLE+
|
1577
|
+
* * +PGRES_PIPELINE_SYNC+
|
1578
|
+
* * +PGRES_PIPELINE_ABORTED+
|
1457
1579
|
*/
|
1458
1580
|
static VALUE
|
1459
1581
|
pgconn_make_empty_pgresult(VALUE self, VALUE status)
|
@@ -1750,6 +1872,7 @@ pgconn_send_query(int argc, VALUE *argv, VALUE self)
|
|
1750
1872
|
rb_iv_set(error, "@connection", self);
|
1751
1873
|
rb_exc_raise(error);
|
1752
1874
|
}
|
1875
|
+
pgconn_wait_for_flush( self );
|
1753
1876
|
return Qnil;
|
1754
1877
|
}
|
1755
1878
|
|
@@ -1779,7 +1902,7 @@ pgconn_send_query(int argc, VALUE *argv, VALUE self)
|
|
1779
1902
|
* or, it may be a String. If it is a string, that is equivalent to the hash:
|
1780
1903
|
* { :value => <string value>, :type => 0, :format => 0 }
|
1781
1904
|
*
|
1782
|
-
* PostgreSQL bind parameters are represented as $1, $
|
1905
|
+
* PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
|
1783
1906
|
* inside the SQL query. The 0th element of the +params+ array is bound
|
1784
1907
|
* to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
|
1785
1908
|
*
|
@@ -1827,6 +1950,7 @@ pgconn_send_query_params(int argc, VALUE *argv, VALUE self)
|
|
1827
1950
|
rb_iv_set(error, "@connection", self);
|
1828
1951
|
rb_exc_raise(error);
|
1829
1952
|
}
|
1953
|
+
pgconn_wait_for_flush( self );
|
1830
1954
|
return Qnil;
|
1831
1955
|
}
|
1832
1956
|
|
@@ -1847,7 +1971,7 @@ pgconn_send_query_params(int argc, VALUE *argv, VALUE self)
|
|
1847
1971
|
*
|
1848
1972
|
* For example: "SELECT $1::int"
|
1849
1973
|
*
|
1850
|
-
* PostgreSQL bind parameters are represented as $1, $
|
1974
|
+
* PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
|
1851
1975
|
* inside the SQL query.
|
1852
1976
|
*/
|
1853
1977
|
static VALUE
|
@@ -1890,6 +2014,7 @@ pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
|
|
1890
2014
|
rb_iv_set(error, "@connection", self);
|
1891
2015
|
rb_exc_raise(error);
|
1892
2016
|
}
|
2017
|
+
pgconn_wait_for_flush( self );
|
1893
2018
|
return Qnil;
|
1894
2019
|
}
|
1895
2020
|
|
@@ -1911,7 +2036,7 @@ pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
|
|
1911
2036
|
* or, it may be a String. If it is a string, that is equivalent to the hash:
|
1912
2037
|
* { :value => <string value>, :format => 0 }
|
1913
2038
|
*
|
1914
|
-
* PostgreSQL bind parameters are represented as $1, $
|
2039
|
+
* PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
|
1915
2040
|
* inside the SQL query. The 0th element of the +params+ array is bound
|
1916
2041
|
* to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
|
1917
2042
|
*
|
@@ -1941,7 +2066,6 @@ pgconn_send_query_prepared(int argc, VALUE *argv, VALUE self)
|
|
1941
2066
|
|
1942
2067
|
if(NIL_P(paramsData.params)) {
|
1943
2068
|
paramsData.params = rb_ary_new2(0);
|
1944
|
-
resultFormat = 0;
|
1945
2069
|
}
|
1946
2070
|
pgconn_query_assign_typemap( self, ¶msData );
|
1947
2071
|
|
@@ -1959,6 +2083,7 @@ pgconn_send_query_prepared(int argc, VALUE *argv, VALUE self)
|
|
1959
2083
|
rb_iv_set(error, "@connection", self);
|
1960
2084
|
rb_exc_raise(error);
|
1961
2085
|
}
|
2086
|
+
pgconn_wait_for_flush( self );
|
1962
2087
|
return Qnil;
|
1963
2088
|
}
|
1964
2089
|
|
@@ -1980,6 +2105,7 @@ pgconn_send_describe_prepared(VALUE self, VALUE stmt_name)
|
|
1980
2105
|
rb_iv_set(error, "@connection", self);
|
1981
2106
|
rb_exc_raise(error);
|
1982
2107
|
}
|
2108
|
+
pgconn_wait_for_flush( self );
|
1983
2109
|
return Qnil;
|
1984
2110
|
}
|
1985
2111
|
|
@@ -2002,6 +2128,7 @@ pgconn_send_describe_portal(VALUE self, VALUE portal)
|
|
2002
2128
|
rb_iv_set(error, "@connection", self);
|
2003
2129
|
rb_exc_raise(error);
|
2004
2130
|
}
|
2131
|
+
pgconn_wait_for_flush( self );
|
2005
2132
|
return Qnil;
|
2006
2133
|
}
|
2007
2134
|
|
@@ -2141,8 +2268,7 @@ pgconn_isnonblocking(self)
|
|
2141
2268
|
* Raises PG::Error if some other failure occurred.
|
2142
2269
|
*/
|
2143
2270
|
static VALUE
|
2144
|
-
|
2145
|
-
VALUE self;
|
2271
|
+
pgconn_sync_flush(VALUE self)
|
2146
2272
|
{
|
2147
2273
|
PGconn *conn = pg_get_pgconn(self);
|
2148
2274
|
int ret;
|
@@ -2161,7 +2287,7 @@ pgconn_flush(self)
|
|
2161
2287
|
* conn.cancel() -> String
|
2162
2288
|
*
|
2163
2289
|
* Requests cancellation of the command currently being
|
2164
|
-
* processed.
|
2290
|
+
* processed.
|
2165
2291
|
*
|
2166
2292
|
* Returns +nil+ on success, or a string containing the
|
2167
2293
|
* error message if a failure occurs.
|
@@ -2178,7 +2304,7 @@ pgconn_cancel(VALUE self)
|
|
2178
2304
|
if(cancel == NULL)
|
2179
2305
|
rb_raise(rb_ePGerror,"Invalid connection!");
|
2180
2306
|
|
2181
|
-
ret = gvl_PQcancel(cancel, errbuf,
|
2307
|
+
ret = gvl_PQcancel(cancel, errbuf, sizeof(errbuf));
|
2182
2308
|
if(ret == 1)
|
2183
2309
|
retval = Qnil;
|
2184
2310
|
else
|
@@ -2229,103 +2355,44 @@ pgconn_notifies(VALUE self)
|
|
2229
2355
|
return hash;
|
2230
2356
|
}
|
2231
2357
|
|
2232
|
-
/* Win32 + Ruby 1.9+ */
|
2233
|
-
#if defined( _WIN32 )
|
2234
|
-
/*
|
2235
|
-
* On Windows, use platform-specific strategies to wait for the socket
|
2236
|
-
* instead of rb_wait_for_single_fd().
|
2237
|
-
*/
|
2238
|
-
|
2239
|
-
int rb_w32_wait_events( HANDLE *events, int num, DWORD timeout );
|
2240
|
-
|
2241
|
-
static void *
|
2242
|
-
wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readable)(PGconn *) )
|
2243
|
-
{
|
2244
|
-
int sd = PQsocket( conn );
|
2245
|
-
void *retval;
|
2246
|
-
struct timeval aborttime={0,0}, currtime, waittime;
|
2247
|
-
DWORD timeout_milisec = INFINITE;
|
2248
|
-
DWORD wait_ret;
|
2249
|
-
WSAEVENT hEvent;
|
2250
|
-
|
2251
|
-
if ( sd < 0 )
|
2252
|
-
rb_raise(rb_eConnectionBad, "PQsocket() can't get socket descriptor");
|
2253
2358
|
|
2254
|
-
|
2359
|
+
#if !defined(HAVE_RB_IO_WAIT)
|
2360
|
+
/* For compat with ruby < 3.0 */
|
2255
2361
|
|
2256
|
-
|
2257
|
-
|
2258
|
-
|
2259
|
-
|
2260
|
-
|
2362
|
+
typedef enum {
|
2363
|
+
RUBY_IO_READABLE = RB_WAITFD_IN,
|
2364
|
+
RUBY_IO_WRITABLE = RB_WAITFD_OUT,
|
2365
|
+
RUBY_IO_PRIORITY = RB_WAITFD_PRI,
|
2366
|
+
} rb_io_event_t;
|
2261
2367
|
|
2262
|
-
|
2263
|
-
|
2264
|
-
|
2265
|
-
|
2266
|
-
|
2267
|
-
|
2268
|
-
|
2269
|
-
|
2270
|
-
|
2271
|
-
|
2272
|
-
|
2273
|
-
if ( ptimeout ) {
|
2274
|
-
gettimeofday(&currtime, NULL);
|
2275
|
-
timersub(&aborttime, &currtime, &waittime);
|
2276
|
-
timeout_milisec = (DWORD)( waittime.tv_sec * 1e3 + waittime.tv_usec / 1e3 );
|
2277
|
-
}
|
2278
|
-
|
2279
|
-
/* Is the given timeout valid? */
|
2280
|
-
if( !ptimeout || (waittime.tv_sec >= 0 && waittime.tv_usec >= 0) ){
|
2281
|
-
/* Wait for the socket to become readable before checking again */
|
2282
|
-
wait_ret = rb_w32_wait_events( &hEvent, 1, timeout_milisec );
|
2283
|
-
} else {
|
2284
|
-
wait_ret = WAIT_TIMEOUT;
|
2285
|
-
}
|
2286
|
-
|
2287
|
-
if ( wait_ret == WAIT_TIMEOUT ) {
|
2288
|
-
WSACloseEvent( hEvent );
|
2289
|
-
return NULL;
|
2290
|
-
} else if ( wait_ret == WAIT_OBJECT_0 ) {
|
2291
|
-
/* The event we were waiting for. */
|
2292
|
-
} else if ( wait_ret == WAIT_OBJECT_0 + 1) {
|
2293
|
-
/* This indicates interruption from timer thread, GC, exception
|
2294
|
-
* from other threads etc... */
|
2295
|
-
rb_thread_check_ints();
|
2296
|
-
} else if ( wait_ret == WAIT_FAILED ) {
|
2297
|
-
WSACloseEvent( hEvent );
|
2298
|
-
rb_raise( rb_eConnectionBad, "Wait on socket error (WaitForMultipleObjects): %lu", GetLastError() );
|
2299
|
-
} else {
|
2300
|
-
WSACloseEvent( hEvent );
|
2301
|
-
rb_raise( rb_eConnectionBad, "Wait on socket abandoned (WaitForMultipleObjects)" );
|
2302
|
-
}
|
2303
|
-
|
2304
|
-
/* Check for connection errors (PQisBusy is true on connection errors) */
|
2305
|
-
if ( PQconsumeInput(conn) == 0 ) {
|
2306
|
-
WSACloseEvent( hEvent );
|
2307
|
-
rb_raise( rb_eConnectionBad, "PQconsumeInput() %s", PQerrorMessage(conn) );
|
2308
|
-
}
|
2368
|
+
static VALUE
|
2369
|
+
rb_io_wait(VALUE io, VALUE events, VALUE timeout) {
|
2370
|
+
rb_io_t *fptr;
|
2371
|
+
struct timeval waittime;
|
2372
|
+
int res;
|
2373
|
+
|
2374
|
+
GetOpenFile((io), fptr);
|
2375
|
+
if( !NIL_P(timeout) ){
|
2376
|
+
waittime.tv_sec = (time_t)(NUM2DBL(timeout));
|
2377
|
+
waittime.tv_usec = (time_t)(NUM2DBL(timeout) - (double)waittime.tv_sec);
|
2309
2378
|
}
|
2379
|
+
res = rb_wait_for_single_fd(fptr->fd, NUM2UINT(events), NIL_P(timeout) ? NULL : &waittime);
|
2310
2380
|
|
2311
|
-
|
2312
|
-
return retval;
|
2381
|
+
return UINT2NUM(res);
|
2313
2382
|
}
|
2314
|
-
|
2315
|
-
#else
|
2316
|
-
|
2317
|
-
/* non Win32 */
|
2383
|
+
#endif
|
2318
2384
|
|
2319
2385
|
static void *
|
2320
|
-
wait_socket_readable(
|
2386
|
+
wait_socket_readable( VALUE self, struct timeval *ptimeout, void *(*is_readable)(PGconn *))
|
2321
2387
|
{
|
2322
|
-
|
2323
|
-
|
2388
|
+
VALUE socket_io;
|
2389
|
+
VALUE ret;
|
2324
2390
|
void *retval;
|
2325
2391
|
struct timeval aborttime={0,0}, currtime, waittime;
|
2392
|
+
VALUE wait_timeout = Qnil;
|
2393
|
+
PGconn *conn = pg_get_pgconn(self);
|
2326
2394
|
|
2327
|
-
|
2328
|
-
rb_raise(rb_eConnectionBad, "PQsocket() can't get socket descriptor");
|
2395
|
+
socket_io = pgconn_socket_io(self);
|
2329
2396
|
|
2330
2397
|
/* Check for connection errors (PQisBusy is true on connection errors) */
|
2331
2398
|
if ( PQconsumeInput(conn) == 0 )
|
@@ -2340,22 +2407,19 @@ wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readabl
|
|
2340
2407
|
if ( ptimeout ) {
|
2341
2408
|
gettimeofday(&currtime, NULL);
|
2342
2409
|
timersub(&aborttime, &currtime, &waittime);
|
2410
|
+
wait_timeout = DBL2NUM((double)(waittime.tv_sec) + (double)(waittime.tv_usec) / 1000000.0);
|
2343
2411
|
}
|
2344
2412
|
|
2345
2413
|
/* Is the given timeout valid? */
|
2346
2414
|
if( !ptimeout || (waittime.tv_sec >= 0 && waittime.tv_usec >= 0) ){
|
2347
2415
|
/* Wait for the socket to become readable before checking again */
|
2348
|
-
ret =
|
2416
|
+
ret = rb_io_wait(socket_io, RB_INT2NUM(RUBY_IO_READABLE), wait_timeout);
|
2349
2417
|
} else {
|
2350
|
-
ret =
|
2351
|
-
}
|
2352
|
-
|
2353
|
-
if ( ret < 0 ){
|
2354
|
-
rb_sys_fail( "rb_wait_for_single_fd()" );
|
2418
|
+
ret = Qfalse;
|
2355
2419
|
}
|
2356
2420
|
|
2357
2421
|
/* Return false if the select() timed out */
|
2358
|
-
if ( ret ==
|
2422
|
+
if ( ret == Qfalse ){
|
2359
2423
|
return NULL;
|
2360
2424
|
}
|
2361
2425
|
|
@@ -2368,8 +2432,35 @@ wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readabl
|
|
2368
2432
|
return retval;
|
2369
2433
|
}
|
2370
2434
|
|
2435
|
+
static VALUE
|
2436
|
+
pgconn_async_flush(VALUE self)
|
2437
|
+
{
|
2438
|
+
while( pgconn_sync_flush(self) == Qfalse ){
|
2439
|
+
/* wait for the socket to become read- or write-ready */
|
2440
|
+
int events;
|
2441
|
+
VALUE socket_io = pgconn_socket_io(self);
|
2442
|
+
events = RB_NUM2INT(rb_io_wait(socket_io, RB_INT2NUM(RUBY_IO_READABLE | RUBY_IO_WRITABLE), Qnil));
|
2371
2443
|
|
2372
|
-
|
2444
|
+
if (events & RUBY_IO_READABLE)
|
2445
|
+
pgconn_consume_input(self);
|
2446
|
+
}
|
2447
|
+
return Qtrue;
|
2448
|
+
}
|
2449
|
+
|
2450
|
+
static VALUE
|
2451
|
+
pgconn_wait_for_flush( VALUE self ){
|
2452
|
+
if( !pg_get_connection_safe(self)->flush_data )
|
2453
|
+
return Qnil;
|
2454
|
+
|
2455
|
+
return pgconn_async_flush(self);
|
2456
|
+
}
|
2457
|
+
|
2458
|
+
static VALUE
|
2459
|
+
pgconn_flush_data_set( VALUE self, VALUE enabled ){
|
2460
|
+
t_pg_connection *conn = pg_get_connection(self);
|
2461
|
+
conn->flush_data = RTEST(enabled);
|
2462
|
+
return enabled;
|
2463
|
+
}
|
2373
2464
|
|
2374
2465
|
static void *
|
2375
2466
|
notify_readable(PGconn *conn)
|
@@ -2408,7 +2499,7 @@ pgconn_wait_for_notify(int argc, VALUE *argv, VALUE self)
|
|
2408
2499
|
ptimeout = &timeout;
|
2409
2500
|
}
|
2410
2501
|
|
2411
|
-
pnotification = (PGnotify*) wait_socket_readable(
|
2502
|
+
pnotification = (PGnotify*) wait_socket_readable( self, ptimeout, notify_readable);
|
2412
2503
|
|
2413
2504
|
/* Return nil if the select timed out */
|
2414
2505
|
if ( !pnotification ) return Qnil;
|
@@ -2467,13 +2558,11 @@ pgconn_put_copy_data(int argc, VALUE *argv, VALUE self)
|
|
2467
2558
|
if( NIL_P(this->encoder_for_put_copy_data) ){
|
2468
2559
|
buffer = value;
|
2469
2560
|
} else {
|
2470
|
-
p_coder =
|
2561
|
+
p_coder = RTYPEDDATA_DATA( this->encoder_for_put_copy_data );
|
2471
2562
|
}
|
2472
|
-
} else if( rb_obj_is_kind_of(encoder, rb_cPG_Coder) ) {
|
2473
|
-
Data_Get_Struct( encoder, t_pg_coder, p_coder );
|
2474
2563
|
} else {
|
2475
|
-
|
2476
|
-
|
2564
|
+
/* Check argument type and use argument encoder */
|
2565
|
+
TypedData_Get_Struct(encoder, t_pg_coder, &pg_coder_type, p_coder);
|
2477
2566
|
}
|
2478
2567
|
|
2479
2568
|
if( p_coder ){
|
@@ -2517,8 +2606,8 @@ pgconn_put_copy_data(int argc, VALUE *argv, VALUE self)
|
|
2517
2606
|
* forces the COPY command to fail with the string
|
2518
2607
|
* _error_message_.
|
2519
2608
|
*
|
2520
|
-
* Returns true if the end-of-data was sent, false if it was
|
2521
|
-
* not sent (false is only possible if the connection
|
2609
|
+
* Returns true if the end-of-data was sent, *false* if it was
|
2610
|
+
* not sent (*false* is only possible if the connection
|
2522
2611
|
* is in nonblocking mode, and this command would block).
|
2523
2612
|
*/
|
2524
2613
|
static VALUE
|
@@ -2546,11 +2635,11 @@ pgconn_put_copy_end(int argc, VALUE *argv, VALUE self)
|
|
2546
2635
|
|
2547
2636
|
/*
|
2548
2637
|
* call-seq:
|
2549
|
-
* conn.get_copy_data( [
|
2638
|
+
* conn.get_copy_data( [ nonblock = false [, decoder = nil ]] ) -> Object
|
2550
2639
|
*
|
2551
2640
|
* Return one row of data, +nil+
|
2552
2641
|
* if the copy is done, or +false+ if the call would
|
2553
|
-
* block (only possible if
|
2642
|
+
* block (only possible if _nonblock_ is true).
|
2554
2643
|
*
|
2555
2644
|
* If _decoder_ is not set or +nil+, data is returned as binary string.
|
2556
2645
|
*
|
@@ -2579,13 +2668,11 @@ pgconn_get_copy_data(int argc, VALUE *argv, VALUE self )
|
|
2579
2668
|
|
2580
2669
|
if( NIL_P(decoder) ){
|
2581
2670
|
if( !NIL_P(this->decoder_for_get_copy_data) ){
|
2582
|
-
p_coder =
|
2671
|
+
p_coder = RTYPEDDATA_DATA( this->decoder_for_get_copy_data );
|
2583
2672
|
}
|
2584
|
-
} else if( rb_obj_is_kind_of(decoder, rb_cPG_Coder) ) {
|
2585
|
-
Data_Get_Struct( decoder, t_pg_coder, p_coder );
|
2586
2673
|
} else {
|
2587
|
-
|
2588
|
-
|
2674
|
+
/* Check argument type and use argument decoder */
|
2675
|
+
TypedData_Get_Struct(decoder, t_pg_coder, &pg_coder_type, p_coder);
|
2589
2676
|
}
|
2590
2677
|
|
2591
2678
|
ret = gvl_PQgetCopyData(this->pgconn, &buffer, RTEST(async_in));
|
@@ -2830,7 +2917,7 @@ notice_processor_proxy(void *arg, const char *message)
|
|
2830
2917
|
* call-seq:
|
2831
2918
|
* conn.set_notice_processor {|message| ... } -> Proc
|
2832
2919
|
*
|
2833
|
-
* See #set_notice_receiver for the
|
2920
|
+
* See #set_notice_receiver for the description of what this and the
|
2834
2921
|
* notice_processor methods do.
|
2835
2922
|
*
|
2836
2923
|
* This function takes a new block to act as the notice processor and returns
|
@@ -2884,9 +2971,11 @@ pgconn_get_client_encoding(VALUE self)
|
|
2884
2971
|
|
2885
2972
|
/*
|
2886
2973
|
* call-seq:
|
2887
|
-
* conn.
|
2974
|
+
* conn.sync_set_client_encoding( encoding )
|
2888
2975
|
*
|
2889
|
-
*
|
2976
|
+
* This function has the same behavior as #async_set_client_encoding, but is implemented using the synchronous command processing API of libpq.
|
2977
|
+
* See #async_exec for the differences between the two API variants.
|
2978
|
+
* It's not recommended to use explicit sync or async variants but #set_client_encoding instead, unless you have a good reason to do so.
|
2890
2979
|
*/
|
2891
2980
|
static VALUE
|
2892
2981
|
pgconn_set_client_encoding(VALUE self, VALUE str)
|
@@ -2903,49 +2992,6 @@ pgconn_set_client_encoding(VALUE self, VALUE str)
|
|
2903
2992
|
return Qnil;
|
2904
2993
|
}
|
2905
2994
|
|
2906
|
-
/*
|
2907
|
-
* call-seq:
|
2908
|
-
* conn.transaction { |conn| ... } -> result of the block
|
2909
|
-
*
|
2910
|
-
* Executes a +BEGIN+ at the start of the block,
|
2911
|
-
* and a +COMMIT+ at the end of the block, or
|
2912
|
-
* +ROLLBACK+ if any exception occurs.
|
2913
|
-
*/
|
2914
|
-
static VALUE
|
2915
|
-
pgconn_transaction(VALUE self)
|
2916
|
-
{
|
2917
|
-
PGconn *conn = pg_get_pgconn(self);
|
2918
|
-
PGresult *result;
|
2919
|
-
VALUE rb_pgresult;
|
2920
|
-
VALUE block_result = Qnil;
|
2921
|
-
int status;
|
2922
|
-
|
2923
|
-
if (rb_block_given_p()) {
|
2924
|
-
result = gvl_PQexec(conn, "BEGIN");
|
2925
|
-
rb_pgresult = pg_new_result(result, self);
|
2926
|
-
pg_result_check(rb_pgresult);
|
2927
|
-
block_result = rb_protect(rb_yield, self, &status);
|
2928
|
-
if(status == 0) {
|
2929
|
-
result = gvl_PQexec(conn, "COMMIT");
|
2930
|
-
rb_pgresult = pg_new_result(result, self);
|
2931
|
-
pg_result_check(rb_pgresult);
|
2932
|
-
}
|
2933
|
-
else {
|
2934
|
-
/* exception occurred, ROLLBACK and re-raise */
|
2935
|
-
result = gvl_PQexec(conn, "ROLLBACK");
|
2936
|
-
rb_pgresult = pg_new_result(result, self);
|
2937
|
-
pg_result_check(rb_pgresult);
|
2938
|
-
rb_jump_tag(status);
|
2939
|
-
}
|
2940
|
-
|
2941
|
-
}
|
2942
|
-
else {
|
2943
|
-
/* no block supplied? */
|
2944
|
-
rb_raise(rb_eArgError, "Must supply block for PG::Connection#transaction");
|
2945
|
-
}
|
2946
|
-
return block_result;
|
2947
|
-
}
|
2948
|
-
|
2949
2995
|
|
2950
2996
|
/*
|
2951
2997
|
* call-seq:
|
@@ -3022,8 +3068,6 @@ get_result_readable(PGconn *conn)
|
|
3022
3068
|
*/
|
3023
3069
|
static VALUE
|
3024
3070
|
pgconn_block( int argc, VALUE *argv, VALUE self ) {
|
3025
|
-
PGconn *conn = pg_get_pgconn( self );
|
3026
|
-
|
3027
3071
|
struct timeval timeout;
|
3028
3072
|
struct timeval *ptimeout = NULL;
|
3029
3073
|
VALUE timeout_in;
|
@@ -3037,7 +3081,7 @@ pgconn_block( int argc, VALUE *argv, VALUE self ) {
|
|
3037
3081
|
ptimeout = &timeout;
|
3038
3082
|
}
|
3039
3083
|
|
3040
|
-
ret = wait_socket_readable(
|
3084
|
+
ret = wait_socket_readable( self, ptimeout, get_result_readable);
|
3041
3085
|
|
3042
3086
|
if( !ret )
|
3043
3087
|
return Qfalse;
|
@@ -3046,6 +3090,42 @@ pgconn_block( int argc, VALUE *argv, VALUE self ) {
|
|
3046
3090
|
}
|
3047
3091
|
|
3048
3092
|
|
3093
|
+
/*
|
3094
|
+
* call-seq:
|
3095
|
+
* conn.sync_get_last_result( ) -> PG::Result
|
3096
|
+
*
|
3097
|
+
* This function has the same behavior as #async_get_last_result, but is implemented using the synchronous command processing API of libpq.
|
3098
|
+
* See #async_exec for the differences between the two API variants.
|
3099
|
+
* It's not recommended to use explicit sync or async variants but #get_last_result instead, unless you have a good reason to do so.
|
3100
|
+
*/
|
3101
|
+
static VALUE
|
3102
|
+
pgconn_get_last_result(VALUE self)
|
3103
|
+
{
|
3104
|
+
PGconn *conn = pg_get_pgconn(self);
|
3105
|
+
VALUE rb_pgresult = Qnil;
|
3106
|
+
PGresult *cur, *prev;
|
3107
|
+
|
3108
|
+
|
3109
|
+
cur = prev = NULL;
|
3110
|
+
while ((cur = gvl_PQgetResult(conn)) != NULL) {
|
3111
|
+
int status;
|
3112
|
+
|
3113
|
+
if (prev) PQclear(prev);
|
3114
|
+
prev = cur;
|
3115
|
+
|
3116
|
+
status = PQresultStatus(cur);
|
3117
|
+
if (status == PGRES_COPY_OUT || status == PGRES_COPY_IN || status == PGRES_COPY_BOTH)
|
3118
|
+
break;
|
3119
|
+
}
|
3120
|
+
|
3121
|
+
if (prev) {
|
3122
|
+
rb_pgresult = pg_new_result( prev, self );
|
3123
|
+
pg_result_check(rb_pgresult);
|
3124
|
+
}
|
3125
|
+
|
3126
|
+
return rb_pgresult;
|
3127
|
+
}
|
3128
|
+
|
3049
3129
|
/*
|
3050
3130
|
* call-seq:
|
3051
3131
|
* conn.get_last_result( ) -> PG::Result
|
@@ -3056,27 +3136,35 @@ pgconn_block( int argc, VALUE *argv, VALUE self ) {
|
|
3056
3136
|
* returns the last non-NULL result, or +nil+ if no
|
3057
3137
|
* results are available.
|
3058
3138
|
*
|
3139
|
+
* If the last result contains a bad result_status, an
|
3140
|
+
* appropriate exception is raised.
|
3141
|
+
*
|
3059
3142
|
* This function is similar to #get_result
|
3060
3143
|
* except that it is designed to get one and only
|
3061
|
-
* one result.
|
3144
|
+
* one result and that it checks the result state.
|
3062
3145
|
*/
|
3063
3146
|
static VALUE
|
3064
|
-
|
3147
|
+
pgconn_async_get_last_result(VALUE self)
|
3065
3148
|
{
|
3066
3149
|
PGconn *conn = pg_get_pgconn(self);
|
3067
3150
|
VALUE rb_pgresult = Qnil;
|
3068
3151
|
PGresult *cur, *prev;
|
3069
3152
|
|
3070
|
-
|
3071
|
-
|
3072
|
-
while ((cur = gvl_PQgetResult(conn)) != NULL) {
|
3153
|
+
cur = prev = NULL;
|
3154
|
+
for(;;) {
|
3073
3155
|
int status;
|
3074
3156
|
|
3157
|
+
pgconn_block( 0, NULL, self ); /* wait for input (without blocking) before reading the last result */
|
3158
|
+
|
3159
|
+
cur = gvl_PQgetResult(conn);
|
3160
|
+
if (cur == NULL)
|
3161
|
+
break;
|
3162
|
+
|
3075
3163
|
if (prev) PQclear(prev);
|
3076
3164
|
prev = cur;
|
3077
3165
|
|
3078
3166
|
status = PQresultStatus(cur);
|
3079
|
-
if (status == PGRES_COPY_OUT || status == PGRES_COPY_IN)
|
3167
|
+
if (status == PGRES_COPY_OUT || status == PGRES_COPY_IN || status == PGRES_COPY_BOTH)
|
3080
3168
|
break;
|
3081
3169
|
}
|
3082
3170
|
|
@@ -3100,22 +3188,56 @@ static VALUE
|
|
3100
3188
|
pgconn_discard_results(VALUE self)
|
3101
3189
|
{
|
3102
3190
|
PGconn *conn = pg_get_pgconn(self);
|
3191
|
+
VALUE socket_io;
|
3103
3192
|
|
3104
|
-
|
3105
|
-
|
3106
|
-
|
3193
|
+
if( PQtransactionStatus(conn) == PQTRANS_IDLE ) {
|
3194
|
+
return Qnil;
|
3195
|
+
}
|
3196
|
+
|
3197
|
+
socket_io = pgconn_socket_io(self);
|
3198
|
+
|
3199
|
+
for(;;) {
|
3200
|
+
PGresult *cur;
|
3201
|
+
int status;
|
3202
|
+
|
3203
|
+
/* pgconn_block() raises an exception in case of errors.
|
3204
|
+
* To avoid this call rb_io_wait() and PQconsumeInput() without rb_raise().
|
3205
|
+
*/
|
3206
|
+
while( gvl_PQisBusy(conn) ){
|
3207
|
+
rb_io_wait(socket_io, RB_INT2NUM(RUBY_IO_READABLE), Qnil);
|
3208
|
+
if ( PQconsumeInput(conn) == 0 )
|
3209
|
+
return Qfalse;
|
3210
|
+
}
|
3211
|
+
|
3212
|
+
cur = gvl_PQgetResult(conn);
|
3213
|
+
if( cur == NULL) break;
|
3214
|
+
|
3215
|
+
status = PQresultStatus(cur);
|
3107
3216
|
PQclear(cur);
|
3108
3217
|
if (status == PGRES_COPY_IN){
|
3109
3218
|
gvl_PQputCopyEnd(conn, "COPY terminated by new PQexec");
|
3110
3219
|
}
|
3111
3220
|
if (status == PGRES_COPY_OUT){
|
3112
|
-
|
3113
|
-
|
3114
|
-
|
3221
|
+
for(;;) {
|
3222
|
+
char *buffer = NULL;
|
3223
|
+
int st = gvl_PQgetCopyData(conn, &buffer, 1);
|
3224
|
+
if( st == 0 ) {
|
3225
|
+
/* would block -> wait for readable data */
|
3226
|
+
rb_io_wait(socket_io, RB_INT2NUM(RUBY_IO_READABLE), Qnil);
|
3227
|
+
if ( PQconsumeInput(conn) == 0 )
|
3228
|
+
return Qfalse;
|
3229
|
+
} else if( st > 0 ) {
|
3230
|
+
/* some data retrieved -> discard it */
|
3231
|
+
PQfreemem(buffer);
|
3232
|
+
} else {
|
3233
|
+
/* no more data */
|
3234
|
+
break;
|
3235
|
+
}
|
3236
|
+
}
|
3115
3237
|
}
|
3116
3238
|
}
|
3117
3239
|
|
3118
|
-
return
|
3240
|
+
return Qtrue;
|
3119
3241
|
}
|
3120
3242
|
|
3121
3243
|
/*
|
@@ -3152,8 +3274,7 @@ pgconn_async_exec(int argc, VALUE *argv, VALUE self)
|
|
3152
3274
|
|
3153
3275
|
pgconn_discard_results( self );
|
3154
3276
|
pgconn_send_query( argc, argv, self );
|
3155
|
-
|
3156
|
-
rb_pgresult = pgconn_get_last_result( self );
|
3277
|
+
rb_pgresult = pgconn_async_get_last_result( self );
|
3157
3278
|
|
3158
3279
|
if ( rb_block_given_p() ) {
|
3159
3280
|
return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
|
@@ -3182,7 +3303,7 @@ pgconn_async_exec(int argc, VALUE *argv, VALUE self)
|
|
3182
3303
|
* or, it may be a String. If it is a string, that is equivalent to the hash:
|
3183
3304
|
* { :value => <string value>, :type => 0, :format => 0 }
|
3184
3305
|
*
|
3185
|
-
* PostgreSQL bind parameters are represented as $1, $
|
3306
|
+
* PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
|
3186
3307
|
* inside the SQL query. The 0th element of the +params+ array is bound
|
3187
3308
|
* to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
|
3188
3309
|
*
|
@@ -3225,8 +3346,7 @@ pgconn_async_exec_params(int argc, VALUE *argv, VALUE self)
|
|
3225
3346
|
} else {
|
3226
3347
|
pgconn_send_query_params( argc, argv, self );
|
3227
3348
|
}
|
3228
|
-
|
3229
|
-
rb_pgresult = pgconn_get_last_result( self );
|
3349
|
+
rb_pgresult = pgconn_async_get_last_result( self );
|
3230
3350
|
|
3231
3351
|
if ( rb_block_given_p() ) {
|
3232
3352
|
return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
|
@@ -3252,7 +3372,7 @@ pgconn_async_exec_params(int argc, VALUE *argv, VALUE self)
|
|
3252
3372
|
*
|
3253
3373
|
* For example: "SELECT $1::int"
|
3254
3374
|
*
|
3255
|
-
* PostgreSQL bind parameters are represented as $1, $
|
3375
|
+
* PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
|
3256
3376
|
* inside the SQL query.
|
3257
3377
|
*
|
3258
3378
|
* See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQPREPARE].
|
@@ -3264,8 +3384,7 @@ pgconn_async_prepare(int argc, VALUE *argv, VALUE self)
|
|
3264
3384
|
|
3265
3385
|
pgconn_discard_results( self );
|
3266
3386
|
pgconn_send_prepare( argc, argv, self );
|
3267
|
-
|
3268
|
-
rb_pgresult = pgconn_get_last_result( self );
|
3387
|
+
rb_pgresult = pgconn_async_get_last_result( self );
|
3269
3388
|
|
3270
3389
|
if ( rb_block_given_p() ) {
|
3271
3390
|
return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
|
@@ -3292,7 +3411,7 @@ pgconn_async_prepare(int argc, VALUE *argv, VALUE self)
|
|
3292
3411
|
* or, it may be a String. If it is a string, that is equivalent to the hash:
|
3293
3412
|
* { :value => <string value>, :format => 0 }
|
3294
3413
|
*
|
3295
|
-
* PostgreSQL bind parameters are represented as $1, $
|
3414
|
+
* PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
|
3296
3415
|
* inside the SQL query. The 0th element of the +params+ array is bound
|
3297
3416
|
* to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
|
3298
3417
|
*
|
@@ -3318,8 +3437,7 @@ pgconn_async_exec_prepared(int argc, VALUE *argv, VALUE self)
|
|
3318
3437
|
|
3319
3438
|
pgconn_discard_results( self );
|
3320
3439
|
pgconn_send_query_prepared( argc, argv, self );
|
3321
|
-
|
3322
|
-
rb_pgresult = pgconn_get_last_result( self );
|
3440
|
+
rb_pgresult = pgconn_async_get_last_result( self );
|
3323
3441
|
|
3324
3442
|
if ( rb_block_given_p() ) {
|
3325
3443
|
return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
|
@@ -3343,8 +3461,7 @@ pgconn_async_describe_portal(VALUE self, VALUE portal)
|
|
3343
3461
|
|
3344
3462
|
pgconn_discard_results( self );
|
3345
3463
|
pgconn_send_describe_portal( self, portal );
|
3346
|
-
|
3347
|
-
rb_pgresult = pgconn_get_last_result( self );
|
3464
|
+
rb_pgresult = pgconn_async_get_last_result( self );
|
3348
3465
|
|
3349
3466
|
if ( rb_block_given_p() ) {
|
3350
3467
|
return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
|
@@ -3368,8 +3485,7 @@ pgconn_async_describe_prepared(VALUE self, VALUE stmt_name)
|
|
3368
3485
|
|
3369
3486
|
pgconn_discard_results( self );
|
3370
3487
|
pgconn_send_describe_prepared( self, stmt_name );
|
3371
|
-
|
3372
|
-
rb_pgresult = pgconn_get_last_result( self );
|
3488
|
+
rb_pgresult = pgconn_async_get_last_result( self );
|
3373
3489
|
|
3374
3490
|
if ( rb_block_given_p() ) {
|
3375
3491
|
return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
|
@@ -3457,6 +3573,126 @@ pgconn_ssl_attribute_names(VALUE self)
|
|
3457
3573
|
#endif
|
3458
3574
|
|
3459
3575
|
|
3576
|
+
#ifdef HAVE_PQENTERPIPELINEMODE
|
3577
|
+
/*
|
3578
|
+
* call-seq:
|
3579
|
+
* conn.pipeline_status -> Integer
|
3580
|
+
*
|
3581
|
+
* Returns the current pipeline mode status of the libpq connection.
|
3582
|
+
*
|
3583
|
+
* PQpipelineStatus can return one of the following values:
|
3584
|
+
*
|
3585
|
+
* * PQ_PIPELINE_ON - The libpq connection is in pipeline mode.
|
3586
|
+
* * PQ_PIPELINE_OFF - The libpq connection is not in pipeline mode.
|
3587
|
+
* * PQ_PIPELINE_ABORTED - The libpq connection is in pipeline mode and an error occurred while processing the current pipeline.
|
3588
|
+
* The aborted flag is cleared when PQgetResult returns a result of type PGRES_PIPELINE_SYNC.
|
3589
|
+
*
|
3590
|
+
* Available since PostgreSQL-14
|
3591
|
+
*/
|
3592
|
+
static VALUE
|
3593
|
+
pgconn_pipeline_status(VALUE self)
|
3594
|
+
{
|
3595
|
+
int res = PQpipelineStatus(pg_get_pgconn(self));
|
3596
|
+
return INT2FIX(res);
|
3597
|
+
}
|
3598
|
+
|
3599
|
+
|
3600
|
+
/*
|
3601
|
+
* call-seq:
|
3602
|
+
* conn.enter_pipeline_mode -> nil
|
3603
|
+
*
|
3604
|
+
* Causes a connection to enter pipeline mode if it is currently idle or already in pipeline mode.
|
3605
|
+
*
|
3606
|
+
* Raises PG::Error and has no effect if the connection is not currently idle, i.e., it has a result ready, or it is waiting for more input from the server, etc.
|
3607
|
+
* This function does not actually send anything to the server, it just changes the libpq connection state.
|
3608
|
+
*
|
3609
|
+
* Available since PostgreSQL-14
|
3610
|
+
*/
|
3611
|
+
static VALUE
|
3612
|
+
pgconn_enter_pipeline_mode(VALUE self)
|
3613
|
+
{
|
3614
|
+
PGconn *conn = pg_get_pgconn(self);
|
3615
|
+
int res = PQenterPipelineMode(conn);
|
3616
|
+
if( res == 1 ) {
|
3617
|
+
return Qnil;
|
3618
|
+
} else {
|
3619
|
+
rb_raise(rb_ePGerror, "%s", PQerrorMessage(conn));
|
3620
|
+
}
|
3621
|
+
}
|
3622
|
+
|
3623
|
+
/*
|
3624
|
+
* call-seq:
|
3625
|
+
* conn.exit_pipeline_mode -> nil
|
3626
|
+
*
|
3627
|
+
* Causes a connection to exit pipeline mode if it is currently in pipeline mode with an empty queue and no pending results.
|
3628
|
+
*
|
3629
|
+
* Takes no action if not in pipeline mode.
|
3630
|
+
* Raises PG::Error if the current statement isn't finished processing, or PQgetResult has not been called to collect results from all previously sent query.
|
3631
|
+
*
|
3632
|
+
* Available since PostgreSQL-14
|
3633
|
+
*/
|
3634
|
+
static VALUE
|
3635
|
+
pgconn_exit_pipeline_mode(VALUE self)
|
3636
|
+
{
|
3637
|
+
PGconn *conn = pg_get_pgconn(self);
|
3638
|
+
int res = PQexitPipelineMode(conn);
|
3639
|
+
if( res == 1 ) {
|
3640
|
+
return Qnil;
|
3641
|
+
} else {
|
3642
|
+
rb_raise(rb_ePGerror, "%s", PQerrorMessage(conn));
|
3643
|
+
}
|
3644
|
+
}
|
3645
|
+
|
3646
|
+
|
3647
|
+
/*
|
3648
|
+
* call-seq:
|
3649
|
+
* conn.pipeline_sync -> nil
|
3650
|
+
*
|
3651
|
+
* Marks a synchronization point in a pipeline by sending a sync message and flushing the send buffer.
|
3652
|
+
* This serves as the delimiter of an implicit transaction and an error recovery point; see Section 34.5.1.3 of the PostgreSQL documentation.
|
3653
|
+
*
|
3654
|
+
* Raises PG::Error if the connection is not in pipeline mode or sending a sync message failed.
|
3655
|
+
*
|
3656
|
+
* Available since PostgreSQL-14
|
3657
|
+
*/
|
3658
|
+
static VALUE
|
3659
|
+
pgconn_pipeline_sync(VALUE self)
|
3660
|
+
{
|
3661
|
+
PGconn *conn = pg_get_pgconn(self);
|
3662
|
+
int res = PQpipelineSync(conn);
|
3663
|
+
if( res == 1 ) {
|
3664
|
+
return Qnil;
|
3665
|
+
} else {
|
3666
|
+
rb_raise(rb_ePGerror, "%s", PQerrorMessage(conn));
|
3667
|
+
}
|
3668
|
+
}
|
3669
|
+
|
3670
|
+
/*
|
3671
|
+
* call-seq:
|
3672
|
+
* conn.pipeline_sync -> nil
|
3673
|
+
*
|
3674
|
+
* Sends a request for the server to flush its output buffer.
|
3675
|
+
*
|
3676
|
+
* The server flushes its output buffer automatically as a result of Connection#pipeline_sync being called, or on any request when not in pipeline mode.
|
3677
|
+
* This function is useful to cause the server to flush its output buffer in pipeline mode without establishing a synchronization point.
|
3678
|
+
* Note that the request is not itself flushed to the server automatically; use Connection#flush if necessary.
|
3679
|
+
*
|
3680
|
+
* Available since PostgreSQL-14
|
3681
|
+
*/
|
3682
|
+
static VALUE
|
3683
|
+
pgconn_send_flush_request(VALUE self)
|
3684
|
+
{
|
3685
|
+
PGconn *conn = pg_get_pgconn(self);
|
3686
|
+
int res = PQsendFlushRequest(conn);
|
3687
|
+
if( res == 1 ) {
|
3688
|
+
return Qnil;
|
3689
|
+
} else {
|
3690
|
+
rb_raise(rb_ePGerror, "%s", PQerrorMessage(conn));
|
3691
|
+
}
|
3692
|
+
}
|
3693
|
+
|
3694
|
+
#endif
|
3695
|
+
|
3460
3696
|
/**************************************************************************
|
3461
3697
|
* LARGE OBJECT SUPPORT
|
3462
3698
|
**************************************************************************/
|
@@ -3843,16 +4079,33 @@ pgconn_external_encoding(VALUE self)
|
|
3843
4079
|
return rb_enc_from_encoding( enc );
|
3844
4080
|
}
|
3845
4081
|
|
4082
|
+
/*
|
4083
|
+
* call-seq:
|
4084
|
+
* conn.set_client_encoding( encoding )
|
4085
|
+
*
|
4086
|
+
* Sets the client encoding to the _encoding_ String.
|
4087
|
+
*/
|
4088
|
+
static VALUE
|
4089
|
+
pgconn_async_set_client_encoding(VALUE self, VALUE encname)
|
4090
|
+
{
|
4091
|
+
VALUE query_format, query;
|
4092
|
+
|
4093
|
+
Check_Type(encname, T_STRING);
|
4094
|
+
query_format = rb_str_new_cstr("set client_encoding to '%s'");
|
4095
|
+
query = rb_funcall(query_format, rb_intern("%"), 1, encname);
|
4096
|
+
|
4097
|
+
pgconn_async_exec(1, &query, self);
|
4098
|
+
pgconn_set_internal_encoding_index( self );
|
4099
|
+
|
4100
|
+
return Qnil;
|
4101
|
+
}
|
3846
4102
|
|
3847
4103
|
static VALUE
|
3848
4104
|
pgconn_set_client_encoding_async1( VALUE args )
|
3849
4105
|
{
|
3850
4106
|
VALUE self = ((VALUE*)args)[0];
|
3851
4107
|
VALUE encname = ((VALUE*)args)[1];
|
3852
|
-
|
3853
|
-
VALUE query = rb_funcall(query_format, rb_intern("%"), 1, encname);
|
3854
|
-
|
3855
|
-
pgconn_async_exec(1, &query, self);
|
4108
|
+
pgconn_async_set_client_encoding(self, encname);
|
3856
4109
|
return 0;
|
3857
4110
|
}
|
3858
4111
|
|
@@ -3867,9 +4120,9 @@ pgconn_set_client_encoding_async2( VALUE arg, VALUE ex )
|
|
3867
4120
|
|
3868
4121
|
|
3869
4122
|
static VALUE
|
3870
|
-
pgconn_set_client_encoding_async( VALUE self,
|
4123
|
+
pgconn_set_client_encoding_async( VALUE self, VALUE encname )
|
3871
4124
|
{
|
3872
|
-
VALUE args[] = { self,
|
4125
|
+
VALUE args[] = { self, encname };
|
3873
4126
|
return rb_rescue(pgconn_set_client_encoding_async1, (VALUE)&args, pgconn_set_client_encoding_async2, Qnil);
|
3874
4127
|
}
|
3875
4128
|
|
@@ -3891,10 +4144,9 @@ pgconn_set_default_encoding( VALUE self )
|
|
3891
4144
|
|
3892
4145
|
if (( enc = rb_default_internal_encoding() )) {
|
3893
4146
|
encname = pg_get_rb_encoding_as_pg_encoding( enc );
|
3894
|
-
if ( pgconn_set_client_encoding_async(self, encname) != 0 )
|
4147
|
+
if ( pgconn_set_client_encoding_async(self, rb_str_new_cstr(encname)) != 0 )
|
3895
4148
|
rb_warning( "Failed to set the default_internal encoding to %s: '%s'",
|
3896
4149
|
encname, PQerrorMessage(conn) );
|
3897
|
-
pgconn_set_internal_encoding_index( self );
|
3898
4150
|
return rb_enc_from_encoding( enc );
|
3899
4151
|
} else {
|
3900
4152
|
pgconn_set_internal_encoding_index( self );
|
@@ -3916,12 +4168,12 @@ static VALUE
|
|
3916
4168
|
pgconn_type_map_for_queries_set(VALUE self, VALUE typemap)
|
3917
4169
|
{
|
3918
4170
|
t_pg_connection *this = pg_get_connection( self );
|
4171
|
+
t_typemap *tm;
|
4172
|
+
UNUSED(tm);
|
4173
|
+
|
4174
|
+
/* Check type of method param */
|
4175
|
+
TypedData_Get_Struct(typemap, t_typemap, &pg_typemap_type, tm);
|
3919
4176
|
|
3920
|
-
if ( !rb_obj_is_kind_of(typemap, rb_cTypeMap) ) {
|
3921
|
-
rb_raise( rb_eTypeError, "wrong argument type %s (expected kind of PG::TypeMap)",
|
3922
|
-
rb_obj_classname( typemap ) );
|
3923
|
-
}
|
3924
|
-
Check_Type(typemap, T_DATA);
|
3925
4177
|
this->type_map_for_queries = typemap;
|
3926
4178
|
|
3927
4179
|
return typemap;
|
@@ -3956,12 +4208,10 @@ static VALUE
|
|
3956
4208
|
pgconn_type_map_for_results_set(VALUE self, VALUE typemap)
|
3957
4209
|
{
|
3958
4210
|
t_pg_connection *this = pg_get_connection( self );
|
4211
|
+
t_typemap *tm;
|
4212
|
+
UNUSED(tm);
|
3959
4213
|
|
3960
|
-
|
3961
|
-
rb_raise( rb_eTypeError, "wrong argument type %s (expected kind of PG::TypeMap)",
|
3962
|
-
rb_obj_classname( typemap ) );
|
3963
|
-
}
|
3964
|
-
Check_Type(typemap, T_DATA);
|
4214
|
+
TypedData_Get_Struct(typemap, t_typemap, &pg_typemap_type, tm);
|
3965
4215
|
this->type_map_for_results = typemap;
|
3966
4216
|
|
3967
4217
|
return typemap;
|
@@ -3996,20 +4246,19 @@ pgconn_type_map_for_results_get(VALUE self)
|
|
3996
4246
|
*
|
3997
4247
|
*/
|
3998
4248
|
static VALUE
|
3999
|
-
pgconn_encoder_for_put_copy_data_set(VALUE self, VALUE
|
4249
|
+
pgconn_encoder_for_put_copy_data_set(VALUE self, VALUE encoder)
|
4000
4250
|
{
|
4001
4251
|
t_pg_connection *this = pg_get_connection( self );
|
4002
4252
|
|
4003
|
-
if(
|
4004
|
-
|
4005
|
-
|
4006
|
-
|
4007
|
-
|
4008
|
-
Check_Type(typemap, T_DATA);
|
4253
|
+
if( encoder != Qnil ){
|
4254
|
+
t_pg_coder *co;
|
4255
|
+
UNUSED(co);
|
4256
|
+
/* Check argument type */
|
4257
|
+
TypedData_Get_Struct(encoder, t_pg_coder, &pg_coder_type, co);
|
4009
4258
|
}
|
4010
|
-
this->encoder_for_put_copy_data =
|
4259
|
+
this->encoder_for_put_copy_data = encoder;
|
4011
4260
|
|
4012
|
-
return
|
4261
|
+
return encoder;
|
4013
4262
|
}
|
4014
4263
|
|
4015
4264
|
/*
|
@@ -4045,20 +4294,19 @@ pgconn_encoder_for_put_copy_data_get(VALUE self)
|
|
4045
4294
|
*
|
4046
4295
|
*/
|
4047
4296
|
static VALUE
|
4048
|
-
pgconn_decoder_for_get_copy_data_set(VALUE self, VALUE
|
4297
|
+
pgconn_decoder_for_get_copy_data_set(VALUE self, VALUE decoder)
|
4049
4298
|
{
|
4050
4299
|
t_pg_connection *this = pg_get_connection( self );
|
4051
4300
|
|
4052
|
-
if(
|
4053
|
-
|
4054
|
-
|
4055
|
-
|
4056
|
-
|
4057
|
-
Check_Type(typemap, T_DATA);
|
4301
|
+
if( decoder != Qnil ){
|
4302
|
+
t_pg_coder *co;
|
4303
|
+
UNUSED(co);
|
4304
|
+
/* Check argument type */
|
4305
|
+
TypedData_Get_Struct(decoder, t_pg_coder, &pg_coder_type, co);
|
4058
4306
|
}
|
4059
|
-
this->decoder_for_get_copy_data =
|
4307
|
+
this->decoder_for_get_copy_data = decoder;
|
4060
4308
|
|
4061
|
-
return
|
4309
|
+
return decoder;
|
4062
4310
|
}
|
4063
4311
|
|
4064
4312
|
/*
|
@@ -4141,6 +4389,7 @@ void
|
|
4141
4389
|
init_pg_connection()
|
4142
4390
|
{
|
4143
4391
|
s_id_encode = rb_intern("encode");
|
4392
|
+
s_id_autoclose_set = rb_intern("autoclose=");
|
4144
4393
|
sym_type = ID2SYM(rb_intern("type"));
|
4145
4394
|
sym_format = ID2SYM(rb_intern("format"));
|
4146
4395
|
sym_value = ID2SYM(rb_intern("value"));
|
@@ -4187,9 +4436,7 @@ init_pg_connection()
|
|
4187
4436
|
rb_define_method(rb_cPGconn, "host", pgconn_host, 0);
|
4188
4437
|
rb_define_method(rb_cPGconn, "port", pgconn_port, 0);
|
4189
4438
|
rb_define_method(rb_cPGconn, "tty", pgconn_tty, 0);
|
4190
|
-
#ifdef HAVE_PQCONNINFO
|
4191
4439
|
rb_define_method(rb_cPGconn, "conninfo", pgconn_conninfo, 0);
|
4192
|
-
#endif
|
4193
4440
|
rb_define_method(rb_cPGconn, "options", pgconn_options, 0);
|
4194
4441
|
rb_define_method(rb_cPGconn, "status", pgconn_status, 0);
|
4195
4442
|
rb_define_method(rb_cPGconn, "transaction_status", pgconn_transaction_status, 0);
|
@@ -4200,6 +4447,7 @@ init_pg_connection()
|
|
4200
4447
|
rb_define_method(rb_cPGconn, "socket", pgconn_socket, 0);
|
4201
4448
|
rb_define_method(rb_cPGconn, "socket_io", pgconn_socket_io, 0);
|
4202
4449
|
rb_define_method(rb_cPGconn, "backend_pid", pgconn_backend_pid, 0);
|
4450
|
+
rb_define_method(rb_cPGconn, "backend_key", pgconn_backend_key, 0);
|
4203
4451
|
rb_define_method(rb_cPGconn, "connection_needs_password", pgconn_connection_needs_password, 0);
|
4204
4452
|
rb_define_method(rb_cPGconn, "connection_used_password", pgconn_connection_used_password, 0);
|
4205
4453
|
/* rb_define_method(rb_cPGconn, "getssl", pgconn_getssl, 0); */
|
@@ -4249,7 +4497,8 @@ init_pg_connection()
|
|
4249
4497
|
rb_define_method(rb_cPGconn, "setnonblocking", pgconn_setnonblocking, 1);
|
4250
4498
|
rb_define_method(rb_cPGconn, "isnonblocking", pgconn_isnonblocking, 0);
|
4251
4499
|
rb_define_alias(rb_cPGconn, "nonblocking?", "isnonblocking");
|
4252
|
-
rb_define_method(rb_cPGconn, "
|
4500
|
+
rb_define_method(rb_cPGconn, "sync_flush", pgconn_sync_flush, 0);
|
4501
|
+
rb_define_method(rb_cPGconn, "async_flush", pgconn_async_flush, 0);
|
4253
4502
|
rb_define_method(rb_cPGconn, "discard_results", pgconn_discard_results, 0);
|
4254
4503
|
|
4255
4504
|
/****** PG::Connection INSTANCE METHODS: Cancelling Queries in Progress ******/
|
@@ -4277,14 +4526,16 @@ init_pg_connection()
|
|
4277
4526
|
|
4278
4527
|
/****** PG::Connection INSTANCE METHODS: Other ******/
|
4279
4528
|
rb_define_method(rb_cPGconn, "get_client_encoding", pgconn_get_client_encoding, 0);
|
4280
|
-
rb_define_method(rb_cPGconn, "
|
4281
|
-
|
4282
|
-
|
4529
|
+
rb_define_method(rb_cPGconn, "sync_set_client_encoding", pgconn_set_client_encoding, 1);
|
4530
|
+
rb_define_method(rb_cPGconn, "async_set_client_encoding", pgconn_async_set_client_encoding, 1);
|
4531
|
+
rb_define_alias(rb_cPGconn, "async_client_encoding=", "async_set_client_encoding");
|
4283
4532
|
rb_define_method(rb_cPGconn, "block", pgconn_block, -1);
|
4533
|
+
rb_define_private_method(rb_cPGconn, "flush_data=", pgconn_flush_data_set, 1);
|
4284
4534
|
rb_define_method(rb_cPGconn, "wait_for_notify", pgconn_wait_for_notify, -1);
|
4285
4535
|
rb_define_alias(rb_cPGconn, "notifies_wait", "wait_for_notify");
|
4286
4536
|
rb_define_method(rb_cPGconn, "quote_ident", pgconn_s_quote_ident, 1);
|
4287
|
-
rb_define_method(rb_cPGconn, "
|
4537
|
+
rb_define_method(rb_cPGconn, "sync_get_last_result", pgconn_get_last_result, 0);
|
4538
|
+
rb_define_method(rb_cPGconn, "async_get_last_result", pgconn_async_get_last_result, 0);
|
4288
4539
|
#ifdef HAVE_PQENCRYPTPASSWORDCONN
|
4289
4540
|
rb_define_method(rb_cPGconn, "encrypt_password", pgconn_encrypt_password, -1);
|
4290
4541
|
#endif
|
@@ -4295,6 +4546,14 @@ init_pg_connection()
|
|
4295
4546
|
rb_define_method(rb_cPGconn, "ssl_attribute_names", pgconn_ssl_attribute_names, 0);
|
4296
4547
|
#endif
|
4297
4548
|
|
4549
|
+
#ifdef HAVE_PQENTERPIPELINEMODE
|
4550
|
+
rb_define_method(rb_cPGconn, "pipeline_status", pgconn_pipeline_status, 0);
|
4551
|
+
rb_define_method(rb_cPGconn, "enter_pipeline_mode", pgconn_enter_pipeline_mode, 0);
|
4552
|
+
rb_define_method(rb_cPGconn, "exit_pipeline_mode", pgconn_exit_pipeline_mode, 0);
|
4553
|
+
rb_define_method(rb_cPGconn, "pipeline_sync", pgconn_pipeline_sync, 0);
|
4554
|
+
rb_define_method(rb_cPGconn, "send_flush_request", pgconn_send_flush_request, 0);
|
4555
|
+
#endif
|
4556
|
+
|
4298
4557
|
/****** PG::Connection INSTANCE METHODS: Large Object Support ******/
|
4299
4558
|
rb_define_method(rb_cPGconn, "lo_creat", pgconn_locreat, -1);
|
4300
4559
|
rb_define_alias(rb_cPGconn, "locreat", "lo_creat");
|