pg 1.2.3 → 1.6.1
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/CHANGELOG.md +986 -0
- data/Gemfile +23 -0
- data/README-Windows.rdoc +1 -1
- data/README.ja.md +300 -0
- data/README.md +327 -0
- data/Rakefile +123 -144
- data/certs/ged.pem +24 -0
- data/certs/kanis@comcard.de.pem +20 -0
- data/certs/larskanis-2022.pem +26 -0
- data/certs/larskanis-2023.pem +24 -0
- data/certs/larskanis-2024.pem +24 -0
- data/ext/errorcodes.def +16 -5
- data/ext/errorcodes.rb +0 -0
- data/ext/errorcodes.txt +5 -5
- data/ext/extconf.rb +259 -33
- data/ext/gvl_wrappers.c +17 -2
- data/ext/gvl_wrappers.h +56 -0
- data/ext/pg.c +89 -63
- data/ext/pg.h +31 -8
- data/ext/pg_binary_decoder.c +232 -1
- data/ext/pg_binary_encoder.c +428 -1
- data/ext/pg_cancel_connection.c +360 -0
- data/ext/pg_coder.c +148 -36
- data/ext/pg_connection.c +1365 -817
- data/ext/pg_copy_coder.c +360 -38
- data/ext/pg_errors.c +1 -1
- data/ext/pg_record_coder.c +56 -25
- data/ext/pg_result.c +187 -76
- data/ext/pg_text_decoder.c +32 -11
- data/ext/pg_text_encoder.c +65 -33
- data/ext/pg_tuple.c +84 -61
- data/ext/pg_type_map.c +44 -10
- data/ext/pg_type_map_all_strings.c +17 -3
- data/ext/pg_type_map_by_class.c +54 -27
- data/ext/pg_type_map_by_column.c +74 -31
- data/ext/pg_type_map_by_mri_type.c +48 -19
- data/ext/pg_type_map_by_oid.c +61 -27
- data/ext/pg_type_map_in_ruby.c +55 -21
- data/ext/pg_util.c +2 -2
- data/lib/pg/basic_type_map_based_on_result.rb +67 -0
- data/lib/pg/basic_type_map_for_queries.rb +206 -0
- data/lib/pg/basic_type_map_for_results.rb +104 -0
- data/lib/pg/basic_type_registry.rb +311 -0
- data/lib/pg/binary_decoder/date.rb +9 -0
- data/lib/pg/binary_decoder/timestamp.rb +26 -0
- data/lib/pg/binary_encoder/timestamp.rb +20 -0
- data/lib/pg/cancel_connection.rb +53 -0
- data/lib/pg/coder.rb +18 -14
- data/lib/pg/connection.rb +894 -91
- data/lib/pg/exceptions.rb +20 -1
- data/lib/pg/text_decoder/date.rb +21 -0
- data/lib/pg/text_decoder/inet.rb +9 -0
- data/lib/pg/text_decoder/json.rb +17 -0
- data/lib/pg/text_decoder/numeric.rb +9 -0
- data/lib/pg/text_decoder/timestamp.rb +30 -0
- data/lib/pg/text_encoder/date.rb +13 -0
- data/lib/pg/text_encoder/inet.rb +31 -0
- data/lib/pg/text_encoder/json.rb +17 -0
- data/lib/pg/text_encoder/numeric.rb +9 -0
- data/lib/pg/text_encoder/timestamp.rb +24 -0
- data/lib/pg/version.rb +4 -0
- data/lib/pg.rb +109 -39
- 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/misc/yugabyte/Dockerfile +9 -0
- data/misc/yugabyte/docker-compose.yml +28 -0
- data/misc/yugabyte/pg-test.rb +45 -0
- data/pg.gemspec +38 -0
- data/ports/patches/krb5/1.21.3/0001-Allow-static-linking-krb5-library.patch +30 -0
- data/ports/patches/openssl/3.5.1/0001-aarch64-mingw.patch +21 -0
- data/ports/patches/postgresql/17.5/0001-Use-workaround-of-__builtin_setjmp-only-on-MINGW-on-.patch +42 -0
- data/ports/patches/postgresql/17.5/0001-libpq-Process-buffered-SSL-read-bytes-to-support-rec.patch +52 -0
- data/rakelib/pg_gem_helper.rb +64 -0
- data/rakelib/task_extension.rb +46 -0
- data/sample/array_insert.rb +20 -0
- data/sample/async_api.rb +102 -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 +139 -213
- metadata.gz.sig +0 -0
- data/.gemtest +0 -0
- data/ChangeLog +0 -0
- data/History.rdoc +0 -578
- data/Manifest.txt +0 -73
- data/README.ja.rdoc +0 -13
- data/README.rdoc +0 -213
- data/Rakefile.cross +0 -299
- data/lib/pg/basic_type_mapping.rb +0 -522
- data/lib/pg/binary_decoder.rb +0 -23
- data/lib/pg/constants.rb +0 -12
- data/lib/pg/text_decoder.rb +0 -46
- data/lib/pg/text_encoder.rb +0 -59
- 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,20 +12,38 @@
|
|
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
|
|
18
|
-
static PQnoticeReceiver default_notice_receiver = NULL;
|
19
|
-
static PQnoticeProcessor default_notice_processor = NULL;
|
20
|
-
|
21
19
|
static VALUE pgconn_finish( VALUE );
|
22
20
|
static VALUE pgconn_set_default_encoding( VALUE self );
|
21
|
+
static VALUE pgconn_wait_for_flush( VALUE self );
|
23
22
|
static void pgconn_set_internal_encoding_index( VALUE );
|
23
|
+
static const rb_data_type_t pg_connection_type;
|
24
|
+
static VALUE pgconn_async_flush(VALUE self);
|
24
25
|
|
25
26
|
/*
|
26
27
|
* Global functions
|
27
28
|
*/
|
28
29
|
|
30
|
+
/*
|
31
|
+
* Convenience function to raise connection errors
|
32
|
+
*/
|
33
|
+
void
|
34
|
+
pg_raise_conn_error( VALUE klass, VALUE self, const char *format, ...)
|
35
|
+
{
|
36
|
+
VALUE msg, error;
|
37
|
+
va_list ap;
|
38
|
+
|
39
|
+
va_start(ap, format);
|
40
|
+
msg = rb_vsprintf(format, ap);
|
41
|
+
va_end(ap);
|
42
|
+
error = rb_exc_new_str(klass, msg);
|
43
|
+
rb_iv_set(error, "@connection", self);
|
44
|
+
rb_exc_raise(error);
|
45
|
+
}
|
46
|
+
|
29
47
|
/*
|
30
48
|
* Fetch the PG::Connection object data pointer.
|
31
49
|
*/
|
@@ -33,7 +51,7 @@ t_pg_connection *
|
|
33
51
|
pg_get_connection( VALUE self )
|
34
52
|
{
|
35
53
|
t_pg_connection *this;
|
36
|
-
|
54
|
+
TypedData_Get_Struct( self, t_pg_connection, &pg_connection_type, this);
|
37
55
|
|
38
56
|
return this;
|
39
57
|
}
|
@@ -46,10 +64,10 @@ static t_pg_connection *
|
|
46
64
|
pg_get_connection_safe( VALUE self )
|
47
65
|
{
|
48
66
|
t_pg_connection *this;
|
49
|
-
|
67
|
+
TypedData_Get_Struct( self, t_pg_connection, &pg_connection_type, this);
|
50
68
|
|
51
69
|
if ( !this->pgconn )
|
52
|
-
|
70
|
+
pg_raise_conn_error( rb_eConnectionBad, self, "connection is closed");
|
53
71
|
|
54
72
|
return this;
|
55
73
|
}
|
@@ -65,15 +83,30 @@ PGconn *
|
|
65
83
|
pg_get_pgconn( VALUE self )
|
66
84
|
{
|
67
85
|
t_pg_connection *this;
|
68
|
-
|
86
|
+
TypedData_Get_Struct( self, t_pg_connection, &pg_connection_type, this);
|
69
87
|
|
70
|
-
if ( !this->pgconn )
|
71
|
-
|
88
|
+
if ( !this->pgconn ){
|
89
|
+
pg_raise_conn_error( rb_eConnectionBad, self, "connection is closed");
|
90
|
+
}
|
72
91
|
|
73
92
|
return this->pgconn;
|
74
93
|
}
|
75
94
|
|
76
95
|
|
96
|
+
void
|
97
|
+
pg_unwrap_socket_io( VALUE self, VALUE *p_socket_io, int ruby_sd )
|
98
|
+
{
|
99
|
+
if ( RTEST(*p_socket_io) ) {
|
100
|
+
#if defined(_WIN32)
|
101
|
+
if( rb_w32_unwrap_io_handle(ruby_sd) )
|
102
|
+
pg_raise_conn_error( rb_eConnectionBad, self, "Could not unwrap win32 socket handle");
|
103
|
+
#endif
|
104
|
+
rb_funcall( *p_socket_io, rb_intern("close"), 0 );
|
105
|
+
}
|
106
|
+
|
107
|
+
RB_OBJ_WRITE(self, p_socket_io, Qnil);
|
108
|
+
}
|
109
|
+
|
77
110
|
|
78
111
|
/*
|
79
112
|
* Close the associated socket IO object if there is one.
|
@@ -82,18 +115,7 @@ static void
|
|
82
115
|
pgconn_close_socket_io( VALUE self )
|
83
116
|
{
|
84
117
|
t_pg_connection *this = pg_get_connection( self );
|
85
|
-
|
86
|
-
|
87
|
-
if ( RTEST(socket_io) ) {
|
88
|
-
#if defined(_WIN32)
|
89
|
-
if( rb_w32_unwrap_io_handle(this->ruby_sd) ){
|
90
|
-
rb_raise(rb_eConnectionBad, "Could not unwrap win32 socket handle");
|
91
|
-
}
|
92
|
-
#endif
|
93
|
-
rb_funcall( socket_io, rb_intern("close"), 0 );
|
94
|
-
}
|
95
|
-
|
96
|
-
this->socket_io = Qnil;
|
118
|
+
pg_unwrap_socket_io( self, &this->socket_io, this->ruby_sd);
|
97
119
|
}
|
98
120
|
|
99
121
|
|
@@ -145,16 +167,31 @@ static const char *pg_cstr_enc(VALUE str, int enc_idx){
|
|
145
167
|
* GC Mark function
|
146
168
|
*/
|
147
169
|
static void
|
148
|
-
pgconn_gc_mark(
|
170
|
+
pgconn_gc_mark( void *_this )
|
171
|
+
{
|
172
|
+
t_pg_connection *this = (t_pg_connection *)_this;
|
173
|
+
rb_gc_mark_movable( this->socket_io );
|
174
|
+
rb_gc_mark_movable( this->notice_receiver );
|
175
|
+
rb_gc_mark_movable( this->notice_processor );
|
176
|
+
rb_gc_mark_movable( this->type_map_for_queries );
|
177
|
+
rb_gc_mark_movable( this->type_map_for_results );
|
178
|
+
rb_gc_mark_movable( this->trace_stream );
|
179
|
+
rb_gc_mark_movable( this->encoder_for_put_copy_data );
|
180
|
+
rb_gc_mark_movable( this->decoder_for_get_copy_data );
|
181
|
+
}
|
182
|
+
|
183
|
+
static void
|
184
|
+
pgconn_gc_compact( void *_this )
|
149
185
|
{
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
186
|
+
t_pg_connection *this = (t_pg_connection *)_this;
|
187
|
+
pg_gc_location( this->socket_io );
|
188
|
+
pg_gc_location( this->notice_receiver );
|
189
|
+
pg_gc_location( this->notice_processor );
|
190
|
+
pg_gc_location( this->type_map_for_queries );
|
191
|
+
pg_gc_location( this->type_map_for_results );
|
192
|
+
pg_gc_location( this->trace_stream );
|
193
|
+
pg_gc_location( this->encoder_for_put_copy_data );
|
194
|
+
pg_gc_location( this->decoder_for_get_copy_data );
|
158
195
|
}
|
159
196
|
|
160
197
|
|
@@ -162,11 +199,15 @@ pgconn_gc_mark( t_pg_connection *this )
|
|
162
199
|
* GC Free function
|
163
200
|
*/
|
164
201
|
static void
|
165
|
-
pgconn_gc_free(
|
202
|
+
pgconn_gc_free( void *_this )
|
166
203
|
{
|
204
|
+
t_pg_connection *this = (t_pg_connection *)_this;
|
167
205
|
#if defined(_WIN32)
|
168
|
-
if ( RTEST(this->socket_io) )
|
169
|
-
rb_w32_unwrap_io_handle(
|
206
|
+
if ( RTEST(this->socket_io) ) {
|
207
|
+
if( rb_w32_unwrap_io_handle(this->ruby_sd) ){
|
208
|
+
rb_warn("pg: Could not unwrap win32 socket handle by garbage collector");
|
209
|
+
}
|
210
|
+
}
|
170
211
|
#endif
|
171
212
|
if (this->pgconn != NULL)
|
172
213
|
PQfinish( this->pgconn );
|
@@ -174,6 +215,29 @@ pgconn_gc_free( t_pg_connection *this )
|
|
174
215
|
xfree(this);
|
175
216
|
}
|
176
217
|
|
218
|
+
/*
|
219
|
+
* Object Size function
|
220
|
+
*/
|
221
|
+
static size_t
|
222
|
+
pgconn_memsize( const void *_this )
|
223
|
+
{
|
224
|
+
const t_pg_connection *this = (const t_pg_connection *)_this;
|
225
|
+
return sizeof(*this);
|
226
|
+
}
|
227
|
+
|
228
|
+
static const rb_data_type_t pg_connection_type = {
|
229
|
+
"PG::Connection",
|
230
|
+
{
|
231
|
+
pgconn_gc_mark,
|
232
|
+
pgconn_gc_free,
|
233
|
+
pgconn_memsize,
|
234
|
+
pgconn_gc_compact,
|
235
|
+
},
|
236
|
+
0,
|
237
|
+
0,
|
238
|
+
RUBY_TYPED_WB_PROTECTED,
|
239
|
+
};
|
240
|
+
|
177
241
|
|
178
242
|
/**************************************************************************
|
179
243
|
* Class Methods
|
@@ -189,93 +253,39 @@ static VALUE
|
|
189
253
|
pgconn_s_allocate( VALUE klass )
|
190
254
|
{
|
191
255
|
t_pg_connection *this;
|
192
|
-
VALUE self =
|
256
|
+
VALUE self = TypedData_Make_Struct( klass, t_pg_connection, &pg_connection_type, this );
|
193
257
|
|
194
258
|
this->pgconn = NULL;
|
195
|
-
this->socket_io
|
196
|
-
this->notice_receiver
|
197
|
-
this->notice_processor
|
198
|
-
this->type_map_for_queries
|
199
|
-
this->type_map_for_results
|
200
|
-
this->encoder_for_put_copy_data
|
201
|
-
this->decoder_for_get_copy_data
|
202
|
-
this->trace_stream
|
259
|
+
RB_OBJ_WRITE(self, &this->socket_io, Qnil);
|
260
|
+
RB_OBJ_WRITE(self, &this->notice_receiver, Qnil);
|
261
|
+
RB_OBJ_WRITE(self, &this->notice_processor, Qnil);
|
262
|
+
RB_OBJ_WRITE(self, &this->type_map_for_queries, pg_typemap_all_strings);
|
263
|
+
RB_OBJ_WRITE(self, &this->type_map_for_results, pg_typemap_all_strings);
|
264
|
+
RB_OBJ_WRITE(self, &this->encoder_for_put_copy_data, Qnil);
|
265
|
+
RB_OBJ_WRITE(self, &this->decoder_for_get_copy_data, Qnil);
|
266
|
+
RB_OBJ_WRITE(self, &this->trace_stream, Qnil);
|
267
|
+
rb_ivar_set(self, rb_intern("@calls_to_put_copy_data"), INT2FIX(0));
|
268
|
+
rb_ivar_set(self, rb_intern("@iopts_for_reset"), Qnil);
|
203
269
|
|
204
270
|
return self;
|
205
271
|
}
|
206
272
|
|
207
|
-
|
208
|
-
/*
|
209
|
-
* Document-method: new
|
210
|
-
*
|
211
|
-
* call-seq:
|
212
|
-
* PG::Connection.new -> conn
|
213
|
-
* PG::Connection.new(connection_hash) -> conn
|
214
|
-
* PG::Connection.new(connection_string) -> conn
|
215
|
-
* PG::Connection.new(host, port, options, tty, dbname, user, password) -> conn
|
216
|
-
*
|
217
|
-
* Create a connection to the specified server.
|
218
|
-
*
|
219
|
-
* +connection_hash+ must be a ruby Hash with connection parameters.
|
220
|
-
* See the {list of valid parameters}[https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-PARAMKEYWORDS] in the PostgreSQL documentation.
|
221
|
-
*
|
222
|
-
* There are two accepted formats for +connection_string+: plain <code>keyword = value</code> strings and URIs.
|
223
|
-
* See the documentation of {connection strings}[https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNSTRING].
|
224
|
-
*
|
225
|
-
* The positional parameter form has the same functionality except that the missing parameters will always take on default values. The parameters are:
|
226
|
-
* [+host+]
|
227
|
-
* server hostname
|
228
|
-
* [+port+]
|
229
|
-
* server port number
|
230
|
-
* [+options+]
|
231
|
-
* backend options
|
232
|
-
* [+tty+]
|
233
|
-
* (ignored in newer versions of PostgreSQL)
|
234
|
-
* [+dbname+]
|
235
|
-
* connecting database name
|
236
|
-
* [+user+]
|
237
|
-
* login user name
|
238
|
-
* [+password+]
|
239
|
-
* login password
|
240
|
-
*
|
241
|
-
* Examples:
|
242
|
-
*
|
243
|
-
* # Connect using all defaults
|
244
|
-
* PG::Connection.new
|
245
|
-
*
|
246
|
-
* # As a Hash
|
247
|
-
* PG::Connection.new( :dbname => 'test', :port => 5432 )
|
248
|
-
*
|
249
|
-
* # As a String
|
250
|
-
* PG::Connection.new( "dbname=test port=5432" )
|
251
|
-
*
|
252
|
-
* # As an Array
|
253
|
-
* PG::Connection.new( nil, 5432, nil, nil, 'test', nil, nil )
|
254
|
-
*
|
255
|
-
* If the Ruby default internal encoding is set (i.e., <code>Encoding.default_internal != nil</code>), the
|
256
|
-
* connection will have its +client_encoding+ set accordingly.
|
257
|
-
*
|
258
|
-
* Raises a PG::Error if the connection fails.
|
259
|
-
*/
|
260
273
|
static VALUE
|
261
|
-
|
274
|
+
pgconn_s_sync_connect(int argc, VALUE *argv, VALUE klass)
|
262
275
|
{
|
263
276
|
t_pg_connection *this;
|
264
277
|
VALUE conninfo;
|
265
|
-
VALUE
|
278
|
+
VALUE self = pgconn_s_allocate( klass );
|
266
279
|
|
267
280
|
this = pg_get_connection( self );
|
268
281
|
conninfo = rb_funcall2( rb_cPGconn, rb_intern("parse_connect_args"), argc, argv );
|
269
282
|
this->pgconn = gvl_PQconnectdb(StringValueCStr(conninfo));
|
270
283
|
|
271
284
|
if(this->pgconn == NULL)
|
272
|
-
rb_raise(rb_ePGerror, "PQconnectdb() unable to allocate structure");
|
285
|
+
rb_raise(rb_ePGerror, "PQconnectdb() unable to allocate PGconn structure");
|
273
286
|
|
274
|
-
if (PQstatus(this->pgconn) == CONNECTION_BAD)
|
275
|
-
|
276
|
-
rb_iv_set(error, "@connection", self);
|
277
|
-
rb_exc_raise(error);
|
278
|
-
}
|
287
|
+
if (PQstatus(this->pgconn) == CONNECTION_BAD)
|
288
|
+
pg_raise_conn_error( rb_eConnectionBad, self, "%s", PQerrorMessage(this->pgconn));
|
279
289
|
|
280
290
|
pgconn_set_default_encoding( self );
|
281
291
|
|
@@ -308,7 +318,6 @@ pgconn_s_connect_start( int argc, VALUE *argv, VALUE klass )
|
|
308
318
|
{
|
309
319
|
VALUE rb_conn;
|
310
320
|
VALUE conninfo;
|
311
|
-
VALUE error;
|
312
321
|
t_pg_connection *this;
|
313
322
|
|
314
323
|
/*
|
@@ -321,13 +330,10 @@ pgconn_s_connect_start( int argc, VALUE *argv, VALUE klass )
|
|
321
330
|
this->pgconn = gvl_PQconnectStart( StringValueCStr(conninfo) );
|
322
331
|
|
323
332
|
if( this->pgconn == NULL )
|
324
|
-
rb_raise(rb_ePGerror, "PQconnectStart() unable to allocate structure");
|
333
|
+
rb_raise(rb_ePGerror, "PQconnectStart() unable to allocate PGconn structure");
|
325
334
|
|
326
|
-
if ( PQstatus(this->pgconn) == CONNECTION_BAD )
|
327
|
-
|
328
|
-
rb_iv_set(error, "@connection", rb_conn);
|
329
|
-
rb_exc_raise(error);
|
330
|
-
}
|
335
|
+
if ( PQstatus(this->pgconn) == CONNECTION_BAD )
|
336
|
+
pg_raise_conn_error( rb_eConnectionBad, rb_conn, "%s", PQerrorMessage(this->pgconn));
|
331
337
|
|
332
338
|
if ( rb_block_given_p() ) {
|
333
339
|
return rb_ensure( rb_yield, rb_conn, pgconn_finish, rb_conn );
|
@@ -335,34 +341,14 @@ pgconn_s_connect_start( int argc, VALUE *argv, VALUE klass )
|
|
335
341
|
return rb_conn;
|
336
342
|
}
|
337
343
|
|
338
|
-
/*
|
339
|
-
* call-seq:
|
340
|
-
* PG::Connection.ping(connection_hash) -> Integer
|
341
|
-
* PG::Connection.ping(connection_string) -> Integer
|
342
|
-
* PG::Connection.ping(host, port, options, tty, dbname, login, password) -> Integer
|
343
|
-
*
|
344
|
-
* Check server status.
|
345
|
-
*
|
346
|
-
* See PG::Connection.new for a description of the parameters.
|
347
|
-
*
|
348
|
-
* Returns one of:
|
349
|
-
* [+PQPING_OK+]
|
350
|
-
* server is accepting connections
|
351
|
-
* [+PQPING_REJECT+]
|
352
|
-
* server is alive but rejecting connections
|
353
|
-
* [+PQPING_NO_RESPONSE+]
|
354
|
-
* could not establish connection
|
355
|
-
* [+PQPING_NO_ATTEMPT+]
|
356
|
-
* connection not attempted (bad params)
|
357
|
-
*/
|
358
344
|
static VALUE
|
359
|
-
|
345
|
+
pgconn_s_sync_ping( int argc, VALUE *argv, VALUE klass )
|
360
346
|
{
|
361
347
|
PGPing ping;
|
362
348
|
VALUE conninfo;
|
363
349
|
|
364
350
|
conninfo = rb_funcall2( klass, rb_intern("parse_connect_args"), argc, argv );
|
365
|
-
ping =
|
351
|
+
ping = gvl_PQping( StringValueCStr(conninfo) );
|
366
352
|
|
367
353
|
return INT2FIX((int)ping);
|
368
354
|
}
|
@@ -403,32 +389,39 @@ pgconn_s_conndefaults(VALUE self)
|
|
403
389
|
return array;
|
404
390
|
}
|
405
391
|
|
406
|
-
|
407
|
-
#ifdef HAVE_PQENCRYPTPASSWORDCONN
|
408
392
|
/*
|
409
|
-
*
|
410
|
-
* conn.encrypt_password( password, username, algorithm=nil ) -> String
|
411
|
-
*
|
412
|
-
* This function is intended to be used by client applications that wish to send commands like <tt>ALTER USER joe PASSWORD 'pwd'</tt>.
|
413
|
-
* It is good practice not to send the original cleartext password in such a command, because it might be exposed in command logs, activity displays, and so on.
|
414
|
-
* Instead, use this function to convert the password to encrypted form before it is sent.
|
393
|
+
* Document-method: PG::Connection.conninfo_parse
|
415
394
|
*
|
416
|
-
*
|
417
|
-
*
|
418
|
-
* Currently supported algorithms are +md5+ and +scram-sha-256+ (+on+ and +off+ are also accepted as aliases for +md5+, for compatibility with older server versions).
|
419
|
-
* Note that support for +scram-sha-256+ was introduced in PostgreSQL version 10, and will not work correctly with older server versions.
|
420
|
-
* If algorithm is omitted or +nil+, this function will query the server for the current value of the +password_encryption+ setting.
|
421
|
-
* That can block, and will fail if the current transaction is aborted, or if the connection is busy executing another query.
|
422
|
-
* If you wish to use the default algorithm for the server but want to avoid blocking, query +password_encryption+ yourself before calling #encrypt_password, and pass that value as the algorithm.
|
423
|
-
*
|
424
|
-
* Return value is the encrypted password.
|
425
|
-
* The caller can assume the string doesn't contain any special characters that would require escaping.
|
395
|
+
* call-seq:
|
396
|
+
* PG::Connection.conninfo_parse(conninfo_string) -> Array
|
426
397
|
*
|
427
|
-
*
|
428
|
-
*
|
398
|
+
* Returns parsed connection options from the provided connection string as an array of hashes.
|
399
|
+
* Each hash has the same keys as PG::Connection.conndefaults() .
|
400
|
+
* The values from the +conninfo_string+ are stored in the +:val+ key.
|
429
401
|
*/
|
430
402
|
static VALUE
|
431
|
-
|
403
|
+
pgconn_s_conninfo_parse(VALUE self, VALUE conninfo)
|
404
|
+
{
|
405
|
+
VALUE array;
|
406
|
+
char *errmsg = NULL;
|
407
|
+
PQconninfoOption *options = PQconninfoParse(StringValueCStr(conninfo), &errmsg);
|
408
|
+
if(errmsg){
|
409
|
+
VALUE error = rb_str_new_cstr(errmsg);
|
410
|
+
PQfreemem(errmsg);
|
411
|
+
rb_raise(rb_ePGerror, "%"PRIsVALUE, error);
|
412
|
+
}
|
413
|
+
array = pgconn_make_conninfo_array( options );
|
414
|
+
|
415
|
+
PQconninfoFree(options);
|
416
|
+
|
417
|
+
UNUSED( self );
|
418
|
+
|
419
|
+
return array;
|
420
|
+
}
|
421
|
+
|
422
|
+
|
423
|
+
static VALUE
|
424
|
+
pgconn_sync_encrypt_password(int argc, VALUE *argv, VALUE self)
|
432
425
|
{
|
433
426
|
char *encrypted = NULL;
|
434
427
|
VALUE rval = Qnil;
|
@@ -445,12 +438,11 @@ pgconn_encrypt_password(int argc, VALUE *argv, VALUE self)
|
|
445
438
|
rval = rb_str_new2( encrypted );
|
446
439
|
PQfreemem( encrypted );
|
447
440
|
} else {
|
448
|
-
|
441
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
|
449
442
|
}
|
450
443
|
|
451
444
|
return rval;
|
452
445
|
}
|
453
|
-
#endif
|
454
446
|
|
455
447
|
|
456
448
|
/*
|
@@ -499,17 +491,18 @@ pgconn_s_encrypt_password(VALUE self, VALUE password, VALUE username)
|
|
499
491
|
* the asynchronous connection is ready
|
500
492
|
*
|
501
493
|
* Example:
|
502
|
-
*
|
503
|
-
*
|
494
|
+
* require "io/wait"
|
495
|
+
*
|
496
|
+
* conn = PG::Connection.connect_start(dbname: 'mydatabase')
|
504
497
|
* status = conn.connect_poll
|
505
498
|
* while(status != PG::PGRES_POLLING_OK) do
|
506
499
|
* # do some work while waiting for the connection to complete
|
507
500
|
* if(status == PG::PGRES_POLLING_READING)
|
508
|
-
*
|
501
|
+
* unless conn.socket_io.wait_readable(10.0)
|
509
502
|
* raise "Asynchronous connection timed out!"
|
510
503
|
* end
|
511
504
|
* elsif(status == PG::PGRES_POLLING_WRITING)
|
512
|
-
*
|
505
|
+
* unless conn.socket_io.wait_writable(10.0)
|
513
506
|
* raise "Asynchronous connection timed out!"
|
514
507
|
* end
|
515
508
|
* end
|
@@ -522,7 +515,10 @@ static VALUE
|
|
522
515
|
pgconn_connect_poll(VALUE self)
|
523
516
|
{
|
524
517
|
PostgresPollingStatusType status;
|
518
|
+
|
519
|
+
pgconn_close_socket_io(self);
|
525
520
|
status = gvl_PQconnectPoll(pg_get_pgconn(self));
|
521
|
+
|
526
522
|
return INT2FIX((int)status);
|
527
523
|
}
|
528
524
|
|
@@ -559,21 +555,35 @@ pgconn_finished_p( VALUE self )
|
|
559
555
|
}
|
560
556
|
|
561
557
|
|
562
|
-
/*
|
563
|
-
* call-seq:
|
564
|
-
* conn.reset()
|
565
|
-
*
|
566
|
-
* Resets the backend connection. This method closes the
|
567
|
-
* backend connection and tries to re-connect.
|
568
|
-
*/
|
569
558
|
static VALUE
|
570
|
-
|
559
|
+
pgconn_sync_reset( VALUE self )
|
571
560
|
{
|
572
561
|
pgconn_close_socket_io( self );
|
573
562
|
gvl_PQreset( pg_get_pgconn(self) );
|
574
563
|
return self;
|
575
564
|
}
|
576
565
|
|
566
|
+
static VALUE
|
567
|
+
pgconn_reset_start2( VALUE self, VALUE conninfo )
|
568
|
+
{
|
569
|
+
t_pg_connection *this = pg_get_connection( self );
|
570
|
+
|
571
|
+
/* Close old connection */
|
572
|
+
pgconn_close_socket_io( self );
|
573
|
+
PQfinish( this->pgconn );
|
574
|
+
|
575
|
+
/* Start new connection */
|
576
|
+
this->pgconn = gvl_PQconnectStart( StringValueCStr(conninfo) );
|
577
|
+
|
578
|
+
if( this->pgconn == NULL )
|
579
|
+
rb_raise(rb_ePGerror, "PQconnectStart() unable to allocate PGconn structure");
|
580
|
+
|
581
|
+
if ( PQstatus(this->pgconn) == CONNECTION_BAD )
|
582
|
+
pg_raise_conn_error( rb_eConnectionBad, self, "%s", PQerrorMessage(this->pgconn));
|
583
|
+
|
584
|
+
return Qnil;
|
585
|
+
}
|
586
|
+
|
577
587
|
/*
|
578
588
|
* call-seq:
|
579
589
|
* conn.reset_start() -> nil
|
@@ -589,7 +599,7 @@ pgconn_reset_start(VALUE self)
|
|
589
599
|
{
|
590
600
|
pgconn_close_socket_io( self );
|
591
601
|
if(gvl_PQresetStart(pg_get_pgconn(self)) == 0)
|
592
|
-
|
602
|
+
pg_raise_conn_error( rb_eUnableToSend, self, "reset has failed");
|
593
603
|
return Qnil;
|
594
604
|
}
|
595
605
|
|
@@ -598,14 +608,17 @@ pgconn_reset_start(VALUE self)
|
|
598
608
|
* conn.reset_poll -> Integer
|
599
609
|
*
|
600
610
|
* Checks the status of a connection reset operation.
|
601
|
-
* See
|
611
|
+
* See Connection.connect_start and #connect_poll for
|
602
612
|
* usage information and return values.
|
603
613
|
*/
|
604
614
|
static VALUE
|
605
615
|
pgconn_reset_poll(VALUE self)
|
606
616
|
{
|
607
617
|
PostgresPollingStatusType status;
|
618
|
+
|
619
|
+
pgconn_close_socket_io(self);
|
608
620
|
status = gvl_PQresetPoll(pg_get_pgconn(self));
|
621
|
+
|
609
622
|
return INT2FIX((int)status);
|
610
623
|
}
|
611
624
|
|
@@ -656,7 +669,18 @@ pgconn_pass(VALUE self)
|
|
656
669
|
* call-seq:
|
657
670
|
* conn.host()
|
658
671
|
*
|
659
|
-
* Returns the
|
672
|
+
* Returns the server host name of the active connection.
|
673
|
+
* This can be a host name, an IP address, or a directory path if the connection is via Unix socket.
|
674
|
+
* (The path case can be distinguished because it will always be an absolute path, beginning with +/+ .)
|
675
|
+
*
|
676
|
+
* If the connection parameters specified both host and hostaddr, then +host+ will return the host information.
|
677
|
+
* If only hostaddr was specified, then that is returned.
|
678
|
+
* If multiple hosts were specified in the connection parameters, +host+ returns the host actually connected to.
|
679
|
+
*
|
680
|
+
* If there is an error producing the host information (perhaps if the connection has not been fully established or there was an error), it returns an empty string.
|
681
|
+
*
|
682
|
+
* If multiple hosts were specified in the connection parameters, it is not possible to rely on the result of +host+ until the connection is established.
|
683
|
+
* The status of the connection can be checked using the function Connection#status .
|
660
684
|
*/
|
661
685
|
static VALUE
|
662
686
|
pgconn_host(VALUE self)
|
@@ -666,6 +690,26 @@ pgconn_host(VALUE self)
|
|
666
690
|
return rb_str_new2(host);
|
667
691
|
}
|
668
692
|
|
693
|
+
/* PQhostaddr() appeared in PostgreSQL-12 together with PQresultMemorySize() */
|
694
|
+
#if defined(HAVE_PQRESULTMEMORYSIZE)
|
695
|
+
/*
|
696
|
+
* call-seq:
|
697
|
+
* conn.hostaddr()
|
698
|
+
*
|
699
|
+
* Returns the server IP address of the active connection.
|
700
|
+
* This can be the address that a host name resolved to, or an IP address provided through the hostaddr parameter.
|
701
|
+
* If there is an error producing the host information (perhaps if the connection has not been fully established or there was an error), it returns an empty string.
|
702
|
+
*
|
703
|
+
*/
|
704
|
+
static VALUE
|
705
|
+
pgconn_hostaddr(VALUE self)
|
706
|
+
{
|
707
|
+
char *host = PQhostaddr(pg_get_pgconn(self));
|
708
|
+
if (!host) return Qnil;
|
709
|
+
return rb_str_new2(host);
|
710
|
+
}
|
711
|
+
#endif
|
712
|
+
|
669
713
|
/*
|
670
714
|
* call-seq:
|
671
715
|
* conn.port()
|
@@ -676,21 +720,22 @@ static VALUE
|
|
676
720
|
pgconn_port(VALUE self)
|
677
721
|
{
|
678
722
|
char* port = PQport(pg_get_pgconn(self));
|
679
|
-
|
723
|
+
if (!port || port[0] == '\0')
|
724
|
+
return INT2NUM(DEF_PGPORT);
|
725
|
+
else
|
726
|
+
return INT2NUM(atoi(port));
|
680
727
|
}
|
681
728
|
|
682
729
|
/*
|
683
730
|
* call-seq:
|
684
731
|
* conn.tty()
|
685
732
|
*
|
686
|
-
*
|
733
|
+
* Obsolete function.
|
687
734
|
*/
|
688
735
|
static VALUE
|
689
736
|
pgconn_tty(VALUE self)
|
690
737
|
{
|
691
|
-
|
692
|
-
if (!tty) return Qnil;
|
693
|
-
return rb_str_new2(tty);
|
738
|
+
return rb_str_new2("");
|
694
739
|
}
|
695
740
|
|
696
741
|
/*
|
@@ -708,14 +753,12 @@ pgconn_options(VALUE self)
|
|
708
753
|
}
|
709
754
|
|
710
755
|
|
711
|
-
#ifdef HAVE_PQCONNINFO
|
712
756
|
/*
|
713
757
|
* call-seq:
|
714
758
|
* conn.conninfo -> hash
|
715
759
|
*
|
716
760
|
* Returns the connection options used by a live connection.
|
717
761
|
*
|
718
|
-
* Available since PostgreSQL-9.3
|
719
762
|
*/
|
720
763
|
static VALUE
|
721
764
|
pgconn_conninfo( VALUE self )
|
@@ -728,14 +771,24 @@ pgconn_conninfo( VALUE self )
|
|
728
771
|
|
729
772
|
return array;
|
730
773
|
}
|
731
|
-
#endif
|
732
774
|
|
733
775
|
|
734
776
|
/*
|
735
777
|
* call-seq:
|
736
778
|
* conn.status()
|
737
779
|
*
|
738
|
-
* Returns status of connection
|
780
|
+
* Returns the status of the connection, which is one:
|
781
|
+
* PG::Constants::CONNECTION_OK
|
782
|
+
* PG::Constants::CONNECTION_BAD
|
783
|
+
*
|
784
|
+
* ... and other constants of kind PG::Constants::CONNECTION_*
|
785
|
+
*
|
786
|
+
* This method returns the status of the last command from memory.
|
787
|
+
* It doesn't do any socket access hence is not suitable to test the connectivity.
|
788
|
+
* See check_socket for a way to verify the socket state.
|
789
|
+
*
|
790
|
+
* Example:
|
791
|
+
* PG.constants.grep(/CONNECTION_/).find{|c| PG.const_get(c) == conn.status} # => :CONNECTION_OK
|
739
792
|
*/
|
740
793
|
static VALUE
|
741
794
|
pgconn_status(VALUE self)
|
@@ -792,38 +845,62 @@ pgconn_parameter_status(VALUE self, VALUE param_name)
|
|
792
845
|
* call-seq:
|
793
846
|
* conn.protocol_version -> Integer
|
794
847
|
*
|
795
|
-
*
|
796
|
-
*
|
797
|
-
*
|
848
|
+
* Interrogates the frontend/backend protocol being used.
|
849
|
+
*
|
850
|
+
* Applications might wish to use this function to determine whether certain features are supported.
|
851
|
+
* Currently, the only value is 3 (3.0 protocol).
|
852
|
+
* The protocol version will not change after connection startup is complete, but it could theoretically change during a connection reset.
|
853
|
+
* The 3.0 protocol is supported by PostgreSQL server versions 7.4 and above.
|
854
|
+
*
|
855
|
+
* PG::ConnectionBad is raised if the connection is bad.
|
798
856
|
*/
|
799
857
|
static VALUE
|
800
858
|
pgconn_protocol_version(VALUE self)
|
801
859
|
{
|
802
|
-
|
860
|
+
int protocol_version = PQprotocolVersion(pg_get_pgconn(self));
|
861
|
+
if (protocol_version == 0) {
|
862
|
+
pg_raise_conn_error( rb_eConnectionBad, self, "PQprotocolVersion() can't get protocol version");
|
863
|
+
}
|
864
|
+
return INT2NUM(protocol_version);
|
803
865
|
}
|
804
866
|
|
805
867
|
/*
|
806
868
|
* call-seq:
|
807
869
|
* conn.server_version -> Integer
|
808
870
|
*
|
809
|
-
*
|
810
|
-
*
|
811
|
-
*
|
812
|
-
*
|
813
|
-
*
|
871
|
+
* Returns an integer representing the server version.
|
872
|
+
*
|
873
|
+
* Applications might use this function to determine the version of the database server they are connected to.
|
874
|
+
* The result is formed by multiplying the server's major version number by 10000 and adding the minor version number.
|
875
|
+
* For example, version 10.1 will be returned as 100001, and version 11.0 will be returned as 110000.
|
876
|
+
*
|
877
|
+
* PG::ConnectionBad is raised if the connection is bad.
|
878
|
+
*
|
879
|
+
* Prior to major version 10, PostgreSQL used three-part version numbers in which the first two parts together represented the major version.
|
880
|
+
* For those versions, PQserverVersion uses two digits for each part; for example version 9.1.5 will be returned as 90105, and version 9.2.0 will be returned as 90200.
|
881
|
+
*
|
882
|
+
* Therefore, for purposes of determining feature compatibility, applications should divide the result of PQserverVersion by 100 not 10000 to determine a logical major version number.
|
883
|
+
* In all release series, only the last two digits differ between minor releases (bug-fix releases).
|
814
884
|
*
|
815
885
|
*/
|
816
886
|
static VALUE
|
817
887
|
pgconn_server_version(VALUE self)
|
818
888
|
{
|
819
|
-
|
889
|
+
int server_version = PQserverVersion(pg_get_pgconn(self));
|
890
|
+
if (server_version == 0) {
|
891
|
+
pg_raise_conn_error( rb_eConnectionBad, self, "PQserverVersion() can't get server version");
|
892
|
+
}
|
893
|
+
return INT2NUM(server_version);
|
820
894
|
}
|
821
895
|
|
822
896
|
/*
|
823
897
|
* call-seq:
|
824
898
|
* conn.error_message -> String
|
825
899
|
*
|
826
|
-
* Returns the error message
|
900
|
+
* Returns the error message most recently generated by an operation on the connection.
|
901
|
+
*
|
902
|
+
* Nearly all libpq functions will set a message for conn.error_message if they fail.
|
903
|
+
* Note that by libpq convention, a nonempty error_message result can consist of multiple lines, and will include a trailing newline.
|
827
904
|
*/
|
828
905
|
static VALUE
|
829
906
|
pgconn_error_message(VALUE self)
|
@@ -857,51 +934,68 @@ pgconn_socket(VALUE self)
|
|
857
934
|
pg_deprecated(4, ("conn.socket is deprecated and should be replaced by conn.socket_io"));
|
858
935
|
|
859
936
|
if( (sd = PQsocket(pg_get_pgconn(self))) < 0)
|
860
|
-
|
937
|
+
pg_raise_conn_error( rb_eConnectionBad, self, "PQsocket() can't get socket descriptor");
|
938
|
+
|
861
939
|
return INT2NUM(sd);
|
862
940
|
}
|
863
941
|
|
942
|
+
|
943
|
+
VALUE
|
944
|
+
pg_wrap_socket_io(int sd, VALUE self, VALUE *p_socket_io, int *p_ruby_sd)
|
945
|
+
{
|
946
|
+
int ruby_sd;
|
947
|
+
VALUE cSocket;
|
948
|
+
VALUE socket_io = *p_socket_io;
|
949
|
+
|
950
|
+
#ifdef _WIN32
|
951
|
+
ruby_sd = rb_w32_wrap_io_handle((HANDLE)(intptr_t)sd, O_RDWR|O_BINARY|O_NOINHERIT);
|
952
|
+
if( ruby_sd == -1 )
|
953
|
+
pg_raise_conn_error( rb_eConnectionBad, self, "Could not wrap win32 socket handle");
|
954
|
+
|
955
|
+
*p_ruby_sd = ruby_sd;
|
956
|
+
#else
|
957
|
+
*p_ruby_sd = ruby_sd = sd;
|
958
|
+
#endif
|
959
|
+
|
960
|
+
cSocket = rb_const_get(rb_cObject, rb_intern("BasicSocket"));
|
961
|
+
socket_io = rb_funcall( cSocket, rb_intern("for_fd"), 1, INT2NUM(ruby_sd));
|
962
|
+
|
963
|
+
/* Disable autoclose feature */
|
964
|
+
rb_funcall( socket_io, s_id_autoclose_set, 1, Qfalse );
|
965
|
+
|
966
|
+
RB_OBJ_WRITE(self, p_socket_io, socket_io);
|
967
|
+
|
968
|
+
return socket_io;
|
969
|
+
}
|
970
|
+
|
864
971
|
/*
|
865
972
|
* call-seq:
|
866
973
|
* conn.socket_io() -> IO
|
867
974
|
*
|
868
|
-
* Fetch
|
869
|
-
* This object can be used for IO.select to wait for events while running
|
870
|
-
*
|
975
|
+
* Fetch an IO object created from the Connection's underlying socket.
|
976
|
+
* This object can be used per <tt>socket_io.wait_readable</tt>, <tt>socket_io.wait_writable</tt> or for <tt>IO.select</tt> to wait for events while running asynchronous API calls.
|
977
|
+
* <tt>IO#wait_*able</tt> is <tt>Fiber.scheduler</tt> compatible in contrast to <tt>IO.select</tt>.
|
978
|
+
*
|
979
|
+
* The IO object can change while the connection is established, but is memorized afterwards.
|
980
|
+
* So be sure not to cache the IO object, but repeat calling <tt>conn.socket_io</tt> instead.
|
871
981
|
*
|
872
|
-
* Using this
|
873
|
-
* being closed by Ruby when an IO created using <tt>IO.for_fd(conn.socket)</tt>
|
874
|
-
* goes out of scope. In contrast to #socket, it also works on Windows.
|
982
|
+
* Using this method also works on Windows in contrast to using #socket .
|
983
|
+
* It also avoids the problem of the underlying connection being closed by Ruby when an IO created using <tt>IO.for_fd(conn.socket)</tt> goes out of scope.
|
875
984
|
*/
|
876
985
|
static VALUE
|
877
986
|
pgconn_socket_io(VALUE self)
|
878
987
|
{
|
879
|
-
int sd;
|
880
|
-
int ruby_sd;
|
881
|
-
ID id_autoclose = rb_intern("autoclose=");
|
882
988
|
t_pg_connection *this = pg_get_connection_safe( self );
|
883
|
-
VALUE socket_io = this->socket_io;
|
884
989
|
|
885
|
-
if ( !RTEST(socket_io) ) {
|
886
|
-
|
887
|
-
|
888
|
-
|
889
|
-
|
890
|
-
|
891
|
-
this->ruby_sd = ruby_sd;
|
892
|
-
#else
|
893
|
-
ruby_sd = sd;
|
894
|
-
#endif
|
895
|
-
|
896
|
-
socket_io = rb_funcall( rb_cIO, rb_intern("for_fd"), 1, INT2NUM(ruby_sd) );
|
897
|
-
|
898
|
-
/* Disable autoclose feature */
|
899
|
-
rb_funcall( socket_io, id_autoclose, 1, Qfalse );
|
900
|
-
|
901
|
-
this->socket_io = socket_io;
|
990
|
+
if ( !RTEST(this->socket_io) ) {
|
991
|
+
int sd;
|
992
|
+
if( (sd = PQsocket(this->pgconn)) < 0){
|
993
|
+
pg_raise_conn_error( rb_eConnectionBad, self, "PQsocket() can't get socket descriptor");
|
994
|
+
}
|
995
|
+
return pg_wrap_socket_io( sd, self, &this->socket_io, &this->ruby_sd);
|
902
996
|
}
|
903
997
|
|
904
|
-
return socket_io;
|
998
|
+
return this->socket_io;
|
905
999
|
}
|
906
1000
|
|
907
1001
|
/*
|
@@ -918,6 +1012,53 @@ pgconn_backend_pid(VALUE self)
|
|
918
1012
|
return INT2NUM(PQbackendPID(pg_get_pgconn(self)));
|
919
1013
|
}
|
920
1014
|
|
1015
|
+
#ifndef HAVE_PQSETCHUNKEDROWSMODE
|
1016
|
+
typedef struct
|
1017
|
+
{
|
1018
|
+
struct sockaddr_storage addr;
|
1019
|
+
socklen_t salen;
|
1020
|
+
} SockAddr;
|
1021
|
+
|
1022
|
+
/* Copy of struct pg_cancel from libpq-int.h
|
1023
|
+
*
|
1024
|
+
* See https://github.com/postgres/postgres/blame/master/src/interfaces/libpq/libpq-int.h#L577-L586
|
1025
|
+
*/
|
1026
|
+
struct pg_cancel
|
1027
|
+
{
|
1028
|
+
SockAddr raddr; /* Remote address */
|
1029
|
+
int be_pid; /* PID of backend --- needed for cancels */
|
1030
|
+
int be_key; /* key of backend --- needed for cancels */
|
1031
|
+
};
|
1032
|
+
|
1033
|
+
/*
|
1034
|
+
* call-seq:
|
1035
|
+
* conn.backend_key() -> Integer
|
1036
|
+
*
|
1037
|
+
* Returns the key of the backend server process for this connection.
|
1038
|
+
* This key can be used to cancel queries on the server.
|
1039
|
+
*/
|
1040
|
+
static VALUE
|
1041
|
+
pgconn_backend_key(VALUE self)
|
1042
|
+
{
|
1043
|
+
int be_key;
|
1044
|
+
struct pg_cancel *cancel;
|
1045
|
+
PGconn *conn = pg_get_pgconn(self);
|
1046
|
+
|
1047
|
+
cancel = (struct pg_cancel*)PQgetCancel(conn);
|
1048
|
+
if(cancel == NULL)
|
1049
|
+
pg_raise_conn_error( rb_ePGerror, self, "Invalid connection!");
|
1050
|
+
|
1051
|
+
if( cancel->be_pid != PQbackendPID(conn) )
|
1052
|
+
rb_raise(rb_ePGerror,"Unexpected binary struct layout - please file a bug report at ruby-pg!");
|
1053
|
+
|
1054
|
+
be_key = cancel->be_key;
|
1055
|
+
|
1056
|
+
PQfreeCancel(cancel);
|
1057
|
+
|
1058
|
+
return INT2NUM(be_key);
|
1059
|
+
}
|
1060
|
+
#endif
|
1061
|
+
|
921
1062
|
/*
|
922
1063
|
* call-seq:
|
923
1064
|
* conn.connection_needs_password() -> Boolean
|
@@ -948,7 +1089,7 @@ pgconn_connection_used_password(VALUE self)
|
|
948
1089
|
/* :TODO: get_ssl */
|
949
1090
|
|
950
1091
|
|
951
|
-
static VALUE
|
1092
|
+
static VALUE pgconn_sync_exec_params( int, VALUE *, VALUE );
|
952
1093
|
|
953
1094
|
/*
|
954
1095
|
* call-seq:
|
@@ -962,11 +1103,11 @@ static VALUE pgconn_exec_params( int, VALUE *, VALUE );
|
|
962
1103
|
* However #async_exec has two advantages:
|
963
1104
|
*
|
964
1105
|
* 1. #async_exec can be aborted by signals (like Ctrl-C), while #exec blocks signal processing until the query is answered.
|
965
|
-
* 2. Ruby VM gets notified about IO blocked operations.
|
966
|
-
*
|
1106
|
+
* 2. Ruby VM gets notified about IO blocked operations and can pass them through <tt>Fiber.scheduler</tt>.
|
1107
|
+
* So only <tt>async_*</tt> methods are compatible to event based schedulers like the async gem.
|
967
1108
|
*/
|
968
1109
|
static VALUE
|
969
|
-
|
1110
|
+
pgconn_sync_exec(int argc, VALUE *argv, VALUE self)
|
970
1111
|
{
|
971
1112
|
t_pg_connection *this = pg_get_connection_safe( self );
|
972
1113
|
PGresult *result = NULL;
|
@@ -987,7 +1128,7 @@ pgconn_exec(int argc, VALUE *argv, VALUE self)
|
|
987
1128
|
pg_deprecated(0, ("forwarding exec to exec_params is deprecated"));
|
988
1129
|
|
989
1130
|
/* Otherwise, just call #exec_params instead for backward-compatibility */
|
990
|
-
return
|
1131
|
+
return pgconn_sync_exec_params( argc, argv, self );
|
991
1132
|
|
992
1133
|
}
|
993
1134
|
|
@@ -1019,7 +1160,7 @@ struct query_params_data {
|
|
1019
1160
|
* Filled by alloc_query_params()
|
1020
1161
|
*/
|
1021
1162
|
|
1022
|
-
/* Wraps the pointer of allocated memory, if function parameters
|
1163
|
+
/* Wraps the pointer of allocated memory, if function parameters don't
|
1023
1164
|
* fit in the memory_pool below.
|
1024
1165
|
*/
|
1025
1166
|
VALUE heap_pool;
|
@@ -1037,7 +1178,7 @@ struct query_params_data {
|
|
1037
1178
|
Oid *types;
|
1038
1179
|
|
1039
1180
|
/* This array takes the string values for the timeframe of the query,
|
1040
|
-
* if param value
|
1181
|
+
* if param value conversion is required
|
1041
1182
|
*/
|
1042
1183
|
VALUE gc_array;
|
1043
1184
|
|
@@ -1051,8 +1192,9 @@ struct query_params_data {
|
|
1051
1192
|
};
|
1052
1193
|
|
1053
1194
|
static void
|
1054
|
-
free_typecast_heap_chain(
|
1195
|
+
free_typecast_heap_chain(void *_chain_entry)
|
1055
1196
|
{
|
1197
|
+
struct linked_typecast_data *chain_entry = (struct linked_typecast_data *)_chain_entry;
|
1056
1198
|
while(chain_entry){
|
1057
1199
|
struct linked_typecast_data *next = chain_entry->next;
|
1058
1200
|
xfree(chain_entry);
|
@@ -1060,6 +1202,18 @@ free_typecast_heap_chain(struct linked_typecast_data *chain_entry)
|
|
1060
1202
|
}
|
1061
1203
|
}
|
1062
1204
|
|
1205
|
+
static const rb_data_type_t pg_typecast_buffer_type = {
|
1206
|
+
"PG::Connection typecast buffer chain",
|
1207
|
+
{
|
1208
|
+
(RUBY_DATA_FUNC) NULL,
|
1209
|
+
free_typecast_heap_chain,
|
1210
|
+
(size_t (*)(const void *))NULL,
|
1211
|
+
},
|
1212
|
+
0,
|
1213
|
+
0,
|
1214
|
+
RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
|
1215
|
+
};
|
1216
|
+
|
1063
1217
|
static char *
|
1064
1218
|
alloc_typecast_buf( VALUE *typecast_heap_chain, int len )
|
1065
1219
|
{
|
@@ -1070,17 +1224,28 @@ alloc_typecast_buf( VALUE *typecast_heap_chain, int len )
|
|
1070
1224
|
/* Did we already wrap a memory chain per T_DATA object? */
|
1071
1225
|
if( NIL_P( *typecast_heap_chain ) ){
|
1072
1226
|
/* Leave free'ing of the buffer chain to the GC, when paramsData has left the stack */
|
1073
|
-
*typecast_heap_chain =
|
1227
|
+
*typecast_heap_chain = TypedData_Wrap_Struct( rb_cObject, &pg_typecast_buffer_type, allocated );
|
1074
1228
|
allocated->next = NULL;
|
1075
1229
|
} else {
|
1076
1230
|
/* Append to the chain */
|
1077
|
-
allocated->next =
|
1078
|
-
|
1231
|
+
allocated->next = RTYPEDDATA_DATA( *typecast_heap_chain );
|
1232
|
+
RTYPEDDATA_DATA( *typecast_heap_chain ) = allocated;
|
1079
1233
|
}
|
1080
1234
|
|
1081
1235
|
return &allocated->data[0];
|
1082
1236
|
}
|
1083
1237
|
|
1238
|
+
static const rb_data_type_t pg_query_heap_pool_type = {
|
1239
|
+
"PG::Connection query heap pool",
|
1240
|
+
{
|
1241
|
+
(RUBY_DATA_FUNC) NULL,
|
1242
|
+
RUBY_TYPED_DEFAULT_FREE,
|
1243
|
+
(size_t (*)(const void *))NULL,
|
1244
|
+
},
|
1245
|
+
0,
|
1246
|
+
0,
|
1247
|
+
RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
|
1248
|
+
};
|
1084
1249
|
|
1085
1250
|
static int
|
1086
1251
|
alloc_query_params(struct query_params_data *paramsData)
|
@@ -1095,7 +1260,7 @@ alloc_query_params(struct query_params_data *paramsData)
|
|
1095
1260
|
|
1096
1261
|
Check_Type(paramsData->params, T_ARRAY);
|
1097
1262
|
|
1098
|
-
p_typemap =
|
1263
|
+
p_typemap = RTYPEDDATA_DATA( paramsData->typemap );
|
1099
1264
|
p_typemap->funcs.fit_to_query( paramsData->typemap, paramsData->params );
|
1100
1265
|
|
1101
1266
|
paramsData->heap_pool = Qnil;
|
@@ -1114,7 +1279,7 @@ alloc_query_params(struct query_params_data *paramsData)
|
|
1114
1279
|
/* Allocate one combined memory pool for all possible function parameters */
|
1115
1280
|
memory_pool = (char*)xmalloc( required_pool_size );
|
1116
1281
|
/* Leave free'ing of the buffer to the GC, when paramsData has left the stack */
|
1117
|
-
paramsData->heap_pool =
|
1282
|
+
paramsData->heap_pool = TypedData_Wrap_Struct( rb_cObject, &pg_query_heap_pool_type, memory_pool );
|
1118
1283
|
required_pool_size = 0;
|
1119
1284
|
}else{
|
1120
1285
|
/* Use stack memory for function parameters */
|
@@ -1165,7 +1330,7 @@ alloc_query_params(struct query_params_data *paramsData)
|
|
1165
1330
|
paramsData->lengths[i] = 0;
|
1166
1331
|
} else {
|
1167
1332
|
t_pg_coder_enc_func enc_func = pg_coder_enc_func( conv );
|
1168
|
-
VALUE intermediate;
|
1333
|
+
VALUE intermediate = Qnil;
|
1169
1334
|
|
1170
1335
|
/* 1st pass for retiving the required memory space */
|
1171
1336
|
int len = enc_func(conv, param_value, NULL, &intermediate, paramsData->enc_idx);
|
@@ -1205,8 +1370,6 @@ alloc_query_params(struct query_params_data *paramsData)
|
|
1205
1370
|
required_pool_size += len;
|
1206
1371
|
}
|
1207
1372
|
}
|
1208
|
-
|
1209
|
-
RB_GC_GUARD(intermediate);
|
1210
1373
|
}
|
1211
1374
|
}
|
1212
1375
|
}
|
@@ -1227,12 +1390,11 @@ pgconn_query_assign_typemap( VALUE self, struct query_params_data *paramsData )
|
|
1227
1390
|
/* Use default typemap for queries. It's type is checked when assigned. */
|
1228
1391
|
paramsData->typemap = pg_get_connection(self)->type_map_for_queries;
|
1229
1392
|
}else{
|
1393
|
+
t_typemap *tm;
|
1394
|
+
UNUSED(tm);
|
1395
|
+
|
1230
1396
|
/* 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 );
|
1397
|
+
TypedData_Get_Struct(paramsData->typemap, t_typemap, &pg_typemap_type, tm);
|
1236
1398
|
}
|
1237
1399
|
}
|
1238
1400
|
|
@@ -1246,7 +1408,7 @@ pgconn_query_assign_typemap( VALUE self, struct query_params_data *paramsData )
|
|
1246
1408
|
* It's not recommended to use explicit sync or async variants but #exec_params instead, unless you have a good reason to do so.
|
1247
1409
|
*/
|
1248
1410
|
static VALUE
|
1249
|
-
|
1411
|
+
pgconn_sync_exec_params( int argc, VALUE *argv, VALUE self )
|
1250
1412
|
{
|
1251
1413
|
t_pg_connection *this = pg_get_connection_safe( self );
|
1252
1414
|
PGresult *result = NULL;
|
@@ -1266,7 +1428,7 @@ pgconn_exec_params( int argc, VALUE *argv, VALUE self )
|
|
1266
1428
|
*/
|
1267
1429
|
if ( NIL_P(paramsData.params) ) {
|
1268
1430
|
pg_deprecated(1, ("forwarding exec_params to exec is deprecated"));
|
1269
|
-
return
|
1431
|
+
return pgconn_sync_exec( 1, argv, self );
|
1270
1432
|
}
|
1271
1433
|
pgconn_query_assign_typemap( self, ¶msData );
|
1272
1434
|
|
@@ -1297,7 +1459,7 @@ pgconn_exec_params( int argc, VALUE *argv, VALUE self )
|
|
1297
1459
|
* It's not recommended to use explicit sync or async variants but #prepare instead, unless you have a good reason to do so.
|
1298
1460
|
*/
|
1299
1461
|
static VALUE
|
1300
|
-
|
1462
|
+
pgconn_sync_prepare(int argc, VALUE *argv, VALUE self)
|
1301
1463
|
{
|
1302
1464
|
t_pg_connection *this = pg_get_connection_safe( self );
|
1303
1465
|
PGresult *result = NULL;
|
@@ -1346,7 +1508,7 @@ pgconn_prepare(int argc, VALUE *argv, VALUE self)
|
|
1346
1508
|
* It's not recommended to use explicit sync or async variants but #exec_prepared instead, unless you have a good reason to do so.
|
1347
1509
|
*/
|
1348
1510
|
static VALUE
|
1349
|
-
|
1511
|
+
pgconn_sync_exec_prepared(int argc, VALUE *argv, VALUE self)
|
1350
1512
|
{
|
1351
1513
|
t_pg_connection *this = pg_get_connection_safe( self );
|
1352
1514
|
PGresult *result = NULL;
|
@@ -1382,6 +1544,19 @@ pgconn_exec_prepared(int argc, VALUE *argv, VALUE self)
|
|
1382
1544
|
return rb_pgresult;
|
1383
1545
|
}
|
1384
1546
|
|
1547
|
+
static VALUE
|
1548
|
+
pgconn_sync_describe_close_prepared_portal(VALUE self, VALUE name, PGresult *(*func)(PGconn *, const char *))
|
1549
|
+
{
|
1550
|
+
PGresult *result;
|
1551
|
+
VALUE rb_pgresult;
|
1552
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
1553
|
+
const char *stmt = NIL_P(name) ? NULL : pg_cstr_enc(name, this->enc_idx);
|
1554
|
+
result = func(this->pgconn, stmt);
|
1555
|
+
rb_pgresult = pg_new_result(result, self);
|
1556
|
+
pg_result_check(rb_pgresult);
|
1557
|
+
return rb_pgresult;
|
1558
|
+
}
|
1559
|
+
|
1385
1560
|
/*
|
1386
1561
|
* call-seq:
|
1387
1562
|
* conn.sync_describe_prepared( statement_name ) -> PG::Result
|
@@ -1391,22 +1566,9 @@ pgconn_exec_prepared(int argc, VALUE *argv, VALUE self)
|
|
1391
1566
|
* It's not recommended to use explicit sync or async variants but #describe_prepared instead, unless you have a good reason to do so.
|
1392
1567
|
*/
|
1393
1568
|
static VALUE
|
1394
|
-
|
1569
|
+
pgconn_sync_describe_prepared(VALUE self, VALUE stmt_name)
|
1395
1570
|
{
|
1396
|
-
|
1397
|
-
VALUE rb_pgresult;
|
1398
|
-
t_pg_connection *this = pg_get_connection_safe( self );
|
1399
|
-
const char *stmt;
|
1400
|
-
if(NIL_P(stmt_name)) {
|
1401
|
-
stmt = NULL;
|
1402
|
-
}
|
1403
|
-
else {
|
1404
|
-
stmt = pg_cstr_enc(stmt_name, this->enc_idx);
|
1405
|
-
}
|
1406
|
-
result = gvl_PQdescribePrepared(this->pgconn, stmt);
|
1407
|
-
rb_pgresult = pg_new_result(result, self);
|
1408
|
-
pg_result_check(rb_pgresult);
|
1409
|
-
return rb_pgresult;
|
1571
|
+
return pgconn_sync_describe_close_prepared_portal(self, stmt_name, gvl_PQdescribePrepared);
|
1410
1572
|
}
|
1411
1573
|
|
1412
1574
|
|
@@ -1419,25 +1581,45 @@ pgconn_describe_prepared(VALUE self, VALUE stmt_name)
|
|
1419
1581
|
* It's not recommended to use explicit sync or async variants but #describe_portal instead, unless you have a good reason to do so.
|
1420
1582
|
*/
|
1421
1583
|
static VALUE
|
1422
|
-
|
1423
|
-
VALUE self, stmt_name;
|
1584
|
+
pgconn_sync_describe_portal(VALUE self, VALUE stmt_name)
|
1424
1585
|
{
|
1425
|
-
|
1426
|
-
|
1427
|
-
|
1428
|
-
|
1429
|
-
|
1430
|
-
|
1431
|
-
|
1432
|
-
|
1433
|
-
|
1434
|
-
|
1435
|
-
|
1436
|
-
|
1437
|
-
|
1438
|
-
|
1586
|
+
return pgconn_sync_describe_close_prepared_portal(self, stmt_name, gvl_PQdescribePortal);
|
1587
|
+
}
|
1588
|
+
|
1589
|
+
|
1590
|
+
#ifdef HAVE_PQSETCHUNKEDROWSMODE
|
1591
|
+
/*
|
1592
|
+
* call-seq:
|
1593
|
+
* conn.sync_close_prepared( stmt_name ) -> PG::Result
|
1594
|
+
*
|
1595
|
+
* This function has the same behavior as #async_close_prepared, but is implemented using the synchronous command processing API of libpq.
|
1596
|
+
* See #async_exec for the differences between the two API variants.
|
1597
|
+
* It's not recommended to use explicit sync or async variants but #close_prepared instead, unless you have a good reason to do so.
|
1598
|
+
*
|
1599
|
+
* Available since PostgreSQL-17.
|
1600
|
+
*/
|
1601
|
+
static VALUE
|
1602
|
+
pgconn_sync_close_prepared(VALUE self, VALUE stmt_name)
|
1603
|
+
{
|
1604
|
+
return pgconn_sync_describe_close_prepared_portal(self, stmt_name, gvl_PQclosePrepared);
|
1439
1605
|
}
|
1440
1606
|
|
1607
|
+
/*
|
1608
|
+
* call-seq:
|
1609
|
+
* conn.sync_close_portal( portal_name ) -> PG::Result
|
1610
|
+
*
|
1611
|
+
* This function has the same behavior as #async_close_portal, but is implemented using the synchronous command processing API of libpq.
|
1612
|
+
* See #async_exec for the differences between the two API variants.
|
1613
|
+
* It's not recommended to use explicit sync or async variants but #close_portal instead, unless you have a good reason to do so.
|
1614
|
+
*
|
1615
|
+
* Available since PostgreSQL-17.
|
1616
|
+
*/
|
1617
|
+
static VALUE
|
1618
|
+
pgconn_sync_close_portal(VALUE self, VALUE stmt_name)
|
1619
|
+
{
|
1620
|
+
return pgconn_sync_describe_close_prepared_portal(self, stmt_name, gvl_PQclosePortal);
|
1621
|
+
}
|
1622
|
+
#endif
|
1441
1623
|
|
1442
1624
|
/*
|
1443
1625
|
* call-seq:
|
@@ -1454,6 +1636,10 @@ pgconn_describe_portal(self, stmt_name)
|
|
1454
1636
|
* * +PGRES_NONFATAL_ERROR+
|
1455
1637
|
* * +PGRES_FATAL_ERROR+
|
1456
1638
|
* * +PGRES_COPY_BOTH+
|
1639
|
+
* * +PGRES_SINGLE_TUPLE+
|
1640
|
+
* * +PGRES_TUPLES_CHUNK+
|
1641
|
+
* * +PGRES_PIPELINE_SYNC+
|
1642
|
+
* * +PGRES_PIPELINE_ABORTED+
|
1457
1643
|
*/
|
1458
1644
|
static VALUE
|
1459
1645
|
pgconn_make_empty_pgresult(VALUE self, VALUE status)
|
@@ -1509,9 +1695,9 @@ pgconn_s_escape(VALUE self, VALUE string)
|
|
1509
1695
|
if( !singleton ) {
|
1510
1696
|
size = PQescapeStringConn(pg_get_pgconn(self), RSTRING_PTR(result),
|
1511
1697
|
RSTRING_PTR(string), RSTRING_LEN(string), &error);
|
1512
|
-
if(error)
|
1513
|
-
|
1514
|
-
|
1698
|
+
if(error)
|
1699
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(pg_get_pgconn(self)));
|
1700
|
+
|
1515
1701
|
} else {
|
1516
1702
|
size = PQescapeString(RSTRING_PTR(result), RSTRING_PTR(string), RSTRING_LEN(string));
|
1517
1703
|
}
|
@@ -1607,7 +1793,6 @@ pgconn_escape_literal(VALUE self, VALUE string)
|
|
1607
1793
|
{
|
1608
1794
|
t_pg_connection *this = pg_get_connection_safe( self );
|
1609
1795
|
char *escaped = NULL;
|
1610
|
-
VALUE error;
|
1611
1796
|
VALUE result = Qnil;
|
1612
1797
|
int enc_idx = this->enc_idx;
|
1613
1798
|
|
@@ -1618,12 +1803,8 @@ pgconn_escape_literal(VALUE self, VALUE string)
|
|
1618
1803
|
|
1619
1804
|
escaped = PQescapeLiteral(this->pgconn, RSTRING_PTR(string), RSTRING_LEN(string));
|
1620
1805
|
if (escaped == NULL)
|
1621
|
-
|
1622
|
-
|
1623
|
-
rb_iv_set(error, "@connection", self);
|
1624
|
-
rb_exc_raise(error);
|
1625
|
-
return Qnil;
|
1626
|
-
}
|
1806
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(this->pgconn));
|
1807
|
+
|
1627
1808
|
result = rb_str_new2(escaped);
|
1628
1809
|
PQfreemem(escaped);
|
1629
1810
|
PG_ENCODING_SET_NOCHECK(result, enc_idx);
|
@@ -1646,7 +1827,6 @@ pgconn_escape_identifier(VALUE self, VALUE string)
|
|
1646
1827
|
{
|
1647
1828
|
t_pg_connection *this = pg_get_connection_safe( self );
|
1648
1829
|
char *escaped = NULL;
|
1649
|
-
VALUE error;
|
1650
1830
|
VALUE result = Qnil;
|
1651
1831
|
int enc_idx = this->enc_idx;
|
1652
1832
|
|
@@ -1657,12 +1837,8 @@ pgconn_escape_identifier(VALUE self, VALUE string)
|
|
1657
1837
|
|
1658
1838
|
escaped = PQescapeIdentifier(this->pgconn, RSTRING_PTR(string), RSTRING_LEN(string));
|
1659
1839
|
if (escaped == NULL)
|
1660
|
-
|
1661
|
-
|
1662
|
-
rb_iv_set(error, "@connection", self);
|
1663
|
-
rb_exc_raise(error);
|
1664
|
-
return Qnil;
|
1665
|
-
}
|
1840
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(this->pgconn));
|
1841
|
+
|
1666
1842
|
result = rb_str_new2(escaped);
|
1667
1843
|
PQfreemem(escaped);
|
1668
1844
|
PG_ENCODING_SET_NOCHECK(result, enc_idx);
|
@@ -1686,14 +1862,11 @@ pgconn_escape_identifier(VALUE self, VALUE string)
|
|
1686
1862
|
* (column names, types, etc) that an ordinary Result object for the query
|
1687
1863
|
* would have.
|
1688
1864
|
*
|
1689
|
-
* *Caution:* While processing a query, the server may return some rows and
|
1690
|
-
*
|
1691
|
-
*
|
1692
|
-
*
|
1693
|
-
* application
|
1694
|
-
* For proper transactional behavior, the application must be designed to discard
|
1695
|
-
* or undo whatever has been done with the previously-processed rows, if the query
|
1696
|
-
* ultimately fails.
|
1865
|
+
* *Caution:* While processing a query, the server may return some rows and then encounter an error, causing the query to be aborted.
|
1866
|
+
* Ordinarily, pg discards any such rows and reports only the error.
|
1867
|
+
* But in single-row or chunked mode, some rows may have already been returned to the application.
|
1868
|
+
* Hence, the application will see some PGRES_SINGLE_TUPLE or PGRES_TUPLES_CHUNK PG::Result objects followed by a PG::Error raised in get_result.
|
1869
|
+
* For proper transactional behavior, the application must be designed to discard or undo whatever has been done with the previously-processed rows, if the query ultimately fails.
|
1697
1870
|
*
|
1698
1871
|
* Example:
|
1699
1872
|
* conn.send_query( "your SQL command" )
|
@@ -1710,26 +1883,61 @@ static VALUE
|
|
1710
1883
|
pgconn_set_single_row_mode(VALUE self)
|
1711
1884
|
{
|
1712
1885
|
PGconn *conn = pg_get_pgconn(self);
|
1713
|
-
VALUE error;
|
1714
1886
|
|
1887
|
+
rb_check_frozen(self);
|
1715
1888
|
if( PQsetSingleRowMode(conn) == 0 )
|
1716
|
-
|
1717
|
-
error = rb_exc_new2(rb_ePGerror, PQerrorMessage(conn));
|
1718
|
-
rb_iv_set(error, "@connection", self);
|
1719
|
-
rb_exc_raise(error);
|
1720
|
-
}
|
1889
|
+
pg_raise_conn_error( rb_ePGerror, self, "PQsetSingleRowMode %s", PQerrorMessage(conn));
|
1721
1890
|
|
1722
1891
|
return self;
|
1723
1892
|
}
|
1724
1893
|
|
1725
|
-
|
1726
|
-
|
1894
|
+
#ifdef HAVE_PQSETCHUNKEDROWSMODE
|
1727
1895
|
/*
|
1728
1896
|
* call-seq:
|
1729
|
-
* conn.
|
1897
|
+
* conn.set_chunked_rows_mode -> self
|
1730
1898
|
*
|
1731
|
-
*
|
1732
|
-
*
|
1899
|
+
* Select chunked mode for the currently-executing query.
|
1900
|
+
*
|
1901
|
+
* This function is similar to set_single_row_mode, except that it specifies retrieval of up to +chunk_size+ rows per PGresult, not necessarily just one row.
|
1902
|
+
* This function can only be called immediately after send_query or one of its sibling functions, before any other operation on the connection such as consume_input or get_result.
|
1903
|
+
* If called at the correct time, the function activates chunked mode for the current query.
|
1904
|
+
* Otherwise the mode stays unchanged and the function raises an error.
|
1905
|
+
* In any case, the mode reverts to normal after completion of the current query.
|
1906
|
+
*
|
1907
|
+
* Example:
|
1908
|
+
* conn.send_query( "your SQL command" )
|
1909
|
+
* conn.set_chunked_rows_mode(10)
|
1910
|
+
* loop do
|
1911
|
+
* res = conn.get_result or break
|
1912
|
+
* res.check
|
1913
|
+
* res.each do |row|
|
1914
|
+
* # do something with the received max. 10 rows
|
1915
|
+
* end
|
1916
|
+
* end
|
1917
|
+
*
|
1918
|
+
* Available since PostgreSQL-17
|
1919
|
+
*/
|
1920
|
+
static VALUE
|
1921
|
+
pgconn_set_chunked_rows_mode(VALUE self, VALUE chunk_size)
|
1922
|
+
{
|
1923
|
+
PGconn *conn = pg_get_pgconn(self);
|
1924
|
+
|
1925
|
+
rb_check_frozen(self);
|
1926
|
+
if( PQsetChunkedRowsMode(conn, NUM2INT(chunk_size)) == 0 )
|
1927
|
+
pg_raise_conn_error( rb_ePGerror, self, "PQsetChunkedRowsMode %s", PQerrorMessage(conn));
|
1928
|
+
|
1929
|
+
return self;
|
1930
|
+
}
|
1931
|
+
#endif
|
1932
|
+
|
1933
|
+
static VALUE pgconn_send_query_params(int argc, VALUE *argv, VALUE self);
|
1934
|
+
|
1935
|
+
/*
|
1936
|
+
* call-seq:
|
1937
|
+
* conn.send_query(sql) -> nil
|
1938
|
+
*
|
1939
|
+
* Sends SQL query request specified by _sql_ to PostgreSQL for
|
1940
|
+
* asynchronous processing, and immediately returns.
|
1733
1941
|
* On failure, it raises a PG::Error.
|
1734
1942
|
*
|
1735
1943
|
* For backward compatibility, if you pass more than one parameter to this method,
|
@@ -1741,15 +1949,13 @@ static VALUE
|
|
1741
1949
|
pgconn_send_query(int argc, VALUE *argv, VALUE self)
|
1742
1950
|
{
|
1743
1951
|
t_pg_connection *this = pg_get_connection_safe( self );
|
1744
|
-
VALUE error;
|
1745
1952
|
|
1746
1953
|
/* If called with no or nil parameters, use PQexec for compatibility */
|
1747
1954
|
if ( argc == 1 || (argc >= 2 && argc <= 4 && NIL_P(argv[1]) )) {
|
1748
|
-
if(gvl_PQsendQuery(this->pgconn, pg_cstr_enc(argv[0], this->enc_idx)) == 0)
|
1749
|
-
|
1750
|
-
|
1751
|
-
|
1752
|
-
}
|
1955
|
+
if(gvl_PQsendQuery(this->pgconn, pg_cstr_enc(argv[0], this->enc_idx)) == 0)
|
1956
|
+
pg_raise_conn_error( rb_eUnableToSend, self, "PQsendQuery %s", PQerrorMessage(this->pgconn));
|
1957
|
+
|
1958
|
+
pgconn_wait_for_flush( self );
|
1753
1959
|
return Qnil;
|
1754
1960
|
}
|
1755
1961
|
|
@@ -1779,7 +1985,7 @@ pgconn_send_query(int argc, VALUE *argv, VALUE self)
|
|
1779
1985
|
* or, it may be a String. If it is a string, that is equivalent to the hash:
|
1780
1986
|
* { :value => <string value>, :type => 0, :format => 0 }
|
1781
1987
|
*
|
1782
|
-
* PostgreSQL bind parameters are represented as $1, $
|
1988
|
+
* PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
|
1783
1989
|
* inside the SQL query. The 0th element of the +params+ array is bound
|
1784
1990
|
* to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
|
1785
1991
|
*
|
@@ -1805,7 +2011,6 @@ pgconn_send_query_params(int argc, VALUE *argv, VALUE self)
|
|
1805
2011
|
t_pg_connection *this = pg_get_connection_safe( self );
|
1806
2012
|
int result;
|
1807
2013
|
VALUE command, in_res_fmt;
|
1808
|
-
VALUE error;
|
1809
2014
|
int nParams;
|
1810
2015
|
int resultFormat;
|
1811
2016
|
struct query_params_data paramsData = { this->enc_idx };
|
@@ -1822,11 +2027,10 @@ pgconn_send_query_params(int argc, VALUE *argv, VALUE self)
|
|
1822
2027
|
|
1823
2028
|
free_query_params( ¶msData );
|
1824
2029
|
|
1825
|
-
if(result == 0)
|
1826
|
-
|
1827
|
-
|
1828
|
-
|
1829
|
-
}
|
2030
|
+
if(result == 0)
|
2031
|
+
pg_raise_conn_error( rb_eUnableToSend, self, "PQsendQueryParams %s", PQerrorMessage(this->pgconn));
|
2032
|
+
|
2033
|
+
pgconn_wait_for_flush( self );
|
1830
2034
|
return Qnil;
|
1831
2035
|
}
|
1832
2036
|
|
@@ -1847,7 +2051,7 @@ pgconn_send_query_params(int argc, VALUE *argv, VALUE self)
|
|
1847
2051
|
*
|
1848
2052
|
* For example: "SELECT $1::int"
|
1849
2053
|
*
|
1850
|
-
* PostgreSQL bind parameters are represented as $1, $
|
2054
|
+
* PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
|
1851
2055
|
* inside the SQL query.
|
1852
2056
|
*/
|
1853
2057
|
static VALUE
|
@@ -1857,7 +2061,6 @@ pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
|
|
1857
2061
|
int result;
|
1858
2062
|
VALUE name, command, in_paramtypes;
|
1859
2063
|
VALUE param;
|
1860
|
-
VALUE error;
|
1861
2064
|
int i = 0;
|
1862
2065
|
int nParams = 0;
|
1863
2066
|
Oid *paramTypes = NULL;
|
@@ -1886,10 +2089,9 @@ pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
|
|
1886
2089
|
xfree(paramTypes);
|
1887
2090
|
|
1888
2091
|
if(result == 0) {
|
1889
|
-
|
1890
|
-
rb_iv_set(error, "@connection", self);
|
1891
|
-
rb_exc_raise(error);
|
2092
|
+
pg_raise_conn_error( rb_eUnableToSend, self, "PQsendPrepare %s", PQerrorMessage(this->pgconn));
|
1892
2093
|
}
|
2094
|
+
pgconn_wait_for_flush( self );
|
1893
2095
|
return Qnil;
|
1894
2096
|
}
|
1895
2097
|
|
@@ -1911,7 +2113,7 @@ pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
|
|
1911
2113
|
* or, it may be a String. If it is a string, that is equivalent to the hash:
|
1912
2114
|
* { :value => <string value>, :format => 0 }
|
1913
2115
|
*
|
1914
|
-
* PostgreSQL bind parameters are represented as $1, $
|
2116
|
+
* PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
|
1915
2117
|
* inside the SQL query. The 0th element of the +params+ array is bound
|
1916
2118
|
* to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
|
1917
2119
|
*
|
@@ -1931,7 +2133,6 @@ pgconn_send_query_prepared(int argc, VALUE *argv, VALUE self)
|
|
1931
2133
|
t_pg_connection *this = pg_get_connection_safe( self );
|
1932
2134
|
int result;
|
1933
2135
|
VALUE name, in_res_fmt;
|
1934
|
-
VALUE error;
|
1935
2136
|
int nParams;
|
1936
2137
|
int resultFormat;
|
1937
2138
|
struct query_params_data paramsData = { this->enc_idx };
|
@@ -1941,7 +2142,6 @@ pgconn_send_query_prepared(int argc, VALUE *argv, VALUE self)
|
|
1941
2142
|
|
1942
2143
|
if(NIL_P(paramsData.params)) {
|
1943
2144
|
paramsData.params = rb_ary_new2(0);
|
1944
|
-
resultFormat = 0;
|
1945
2145
|
}
|
1946
2146
|
pgconn_query_assign_typemap( self, ¶msData );
|
1947
2147
|
|
@@ -1954,11 +2154,24 @@ pgconn_send_query_prepared(int argc, VALUE *argv, VALUE self)
|
|
1954
2154
|
|
1955
2155
|
free_query_params( ¶msData );
|
1956
2156
|
|
1957
|
-
if(result == 0)
|
1958
|
-
|
1959
|
-
|
1960
|
-
|
1961
|
-
|
2157
|
+
if(result == 0)
|
2158
|
+
pg_raise_conn_error( rb_eUnableToSend, self, "PQsendQueryPrepared %s", PQerrorMessage(this->pgconn));
|
2159
|
+
|
2160
|
+
pgconn_wait_for_flush( self );
|
2161
|
+
return Qnil;
|
2162
|
+
}
|
2163
|
+
|
2164
|
+
|
2165
|
+
static VALUE
|
2166
|
+
pgconn_send_describe_close_prepared_portal(VALUE self, VALUE name, int (*func)(PGconn *, const char *), const char *funame)
|
2167
|
+
{
|
2168
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
2169
|
+
const char *stmt = NIL_P(name) ? NULL : pg_cstr_enc(name, this->enc_idx);
|
2170
|
+
/* returns 0 on failure */
|
2171
|
+
if(func(this->pgconn, stmt) == 0)
|
2172
|
+
pg_raise_conn_error( rb_eUnableToSend, self, "%s %s", funame, PQerrorMessage(this->pgconn));
|
2173
|
+
|
2174
|
+
pgconn_wait_for_flush( self );
|
1962
2175
|
return Qnil;
|
1963
2176
|
}
|
1964
2177
|
|
@@ -1972,15 +2185,9 @@ pgconn_send_query_prepared(int argc, VALUE *argv, VALUE self)
|
|
1972
2185
|
static VALUE
|
1973
2186
|
pgconn_send_describe_prepared(VALUE self, VALUE stmt_name)
|
1974
2187
|
{
|
1975
|
-
|
1976
|
-
|
1977
|
-
|
1978
|
-
if(gvl_PQsendDescribePrepared(this->pgconn, pg_cstr_enc(stmt_name, this->enc_idx)) == 0) {
|
1979
|
-
error = rb_exc_new2(rb_eUnableToSend, PQerrorMessage(this->pgconn));
|
1980
|
-
rb_iv_set(error, "@connection", self);
|
1981
|
-
rb_exc_raise(error);
|
1982
|
-
}
|
1983
|
-
return Qnil;
|
2188
|
+
return pgconn_send_describe_close_prepared_portal(
|
2189
|
+
self, stmt_name, gvl_PQsendDescribePrepared,
|
2190
|
+
"PQsendDescribePrepared");
|
1984
2191
|
}
|
1985
2192
|
|
1986
2193
|
|
@@ -1994,36 +2201,50 @@ pgconn_send_describe_prepared(VALUE self, VALUE stmt_name)
|
|
1994
2201
|
static VALUE
|
1995
2202
|
pgconn_send_describe_portal(VALUE self, VALUE portal)
|
1996
2203
|
{
|
1997
|
-
|
1998
|
-
|
1999
|
-
|
2000
|
-
if(gvl_PQsendDescribePortal(this->pgconn, pg_cstr_enc(portal, this->enc_idx)) == 0) {
|
2001
|
-
error = rb_exc_new2(rb_eUnableToSend, PQerrorMessage(this->pgconn));
|
2002
|
-
rb_iv_set(error, "@connection", self);
|
2003
|
-
rb_exc_raise(error);
|
2004
|
-
}
|
2005
|
-
return Qnil;
|
2204
|
+
return pgconn_send_describe_close_prepared_portal(
|
2205
|
+
self, portal, gvl_PQsendDescribePortal,
|
2206
|
+
"PQsendDescribePortal");
|
2006
2207
|
}
|
2007
2208
|
|
2008
|
-
|
2209
|
+
#ifdef HAVE_PQSETCHUNKEDROWSMODE
|
2009
2210
|
/*
|
2010
2211
|
* call-seq:
|
2011
|
-
* conn.
|
2012
|
-
*
|
2212
|
+
* conn.send_close_prepared( statement_name ) -> nil
|
2213
|
+
*
|
2214
|
+
* Asynchronously send _command_ to the server. Does not block.
|
2215
|
+
* Use in combination with +conn.get_result+.
|
2013
2216
|
*
|
2014
|
-
*
|
2015
|
-
|
2016
|
-
|
2217
|
+
* Available since PostgreSQL-17.
|
2218
|
+
*/
|
2219
|
+
static VALUE
|
2220
|
+
pgconn_send_close_prepared(VALUE self, VALUE stmt_name)
|
2221
|
+
{
|
2222
|
+
return pgconn_send_describe_close_prepared_portal(
|
2223
|
+
self, stmt_name, gvl_PQsendClosePrepared,
|
2224
|
+
"PQsendClosePrepared");
|
2225
|
+
}
|
2226
|
+
|
2227
|
+
|
2228
|
+
/*
|
2229
|
+
* call-seq:
|
2230
|
+
* conn.send_close_portal( portal_name ) -> nil
|
2017
2231
|
*
|
2018
|
-
*
|
2019
|
-
*
|
2232
|
+
* Asynchronously send _command_ to the server. Does not block.
|
2233
|
+
* Use in combination with +conn.get_result+.
|
2020
2234
|
*
|
2021
|
-
*
|
2022
|
-
* and the PG::Result object will automatically be cleared when the block terminates.
|
2023
|
-
* In this instance, <code>conn.exec</code> returns the value of the block.
|
2235
|
+
* Available since PostgreSQL-17.
|
2024
2236
|
*/
|
2025
2237
|
static VALUE
|
2026
|
-
|
2238
|
+
pgconn_send_close_portal(VALUE self, VALUE portal)
|
2239
|
+
{
|
2240
|
+
return pgconn_send_describe_close_prepared_portal(
|
2241
|
+
self, portal, gvl_PQsendClosePortal,
|
2242
|
+
"PQsendClosePortal");
|
2243
|
+
}
|
2244
|
+
#endif
|
2245
|
+
|
2246
|
+
static VALUE
|
2247
|
+
pgconn_sync_get_result(VALUE self)
|
2027
2248
|
{
|
2028
2249
|
PGconn *conn = pg_get_pgconn(self);
|
2029
2250
|
PGresult *result;
|
@@ -2049,17 +2270,15 @@ pgconn_get_result(VALUE self)
|
|
2049
2270
|
* or *notifies* to see if the state has changed.
|
2050
2271
|
*/
|
2051
2272
|
static VALUE
|
2052
|
-
pgconn_consume_input(self)
|
2053
|
-
VALUE self;
|
2273
|
+
pgconn_consume_input(VALUE self)
|
2054
2274
|
{
|
2055
|
-
VALUE error;
|
2056
2275
|
PGconn *conn = pg_get_pgconn(self);
|
2057
2276
|
/* returns 0 on error */
|
2058
2277
|
if(PQconsumeInput(conn) == 0) {
|
2059
|
-
|
2060
|
-
|
2061
|
-
rb_exc_raise(error);
|
2278
|
+
pgconn_close_socket_io(self);
|
2279
|
+
pg_raise_conn_error( rb_eConnectionBad, self, "%s", PQerrorMessage(conn));
|
2062
2280
|
}
|
2281
|
+
|
2063
2282
|
return Qnil;
|
2064
2283
|
}
|
2065
2284
|
|
@@ -2068,38 +2287,20 @@ pgconn_consume_input(self)
|
|
2068
2287
|
* conn.is_busy() -> Boolean
|
2069
2288
|
*
|
2070
2289
|
* Returns +true+ if a command is busy, that is, if
|
2071
|
-
*
|
2290
|
+
* #get_result would block. Otherwise returns +false+.
|
2072
2291
|
*/
|
2073
2292
|
static VALUE
|
2074
|
-
pgconn_is_busy(self)
|
2075
|
-
VALUE self;
|
2293
|
+
pgconn_is_busy(VALUE self)
|
2076
2294
|
{
|
2077
2295
|
return gvl_PQisBusy(pg_get_pgconn(self)) ? Qtrue : Qfalse;
|
2078
2296
|
}
|
2079
2297
|
|
2080
|
-
/*
|
2081
|
-
* call-seq:
|
2082
|
-
* conn.setnonblocking(Boolean) -> nil
|
2083
|
-
*
|
2084
|
-
* Sets the nonblocking status of the connection.
|
2085
|
-
* In the blocking state, calls to #send_query
|
2086
|
-
* will block until the message is sent to the server,
|
2087
|
-
* but will not wait for the query results.
|
2088
|
-
* In the nonblocking state, calls to #send_query
|
2089
|
-
* will return an error if the socket is not ready for
|
2090
|
-
* writing.
|
2091
|
-
* Note: This function does not affect #exec, because
|
2092
|
-
* that function doesn't return until the server has
|
2093
|
-
* processed the query and returned the results.
|
2094
|
-
* Returns +nil+.
|
2095
|
-
*/
|
2096
2298
|
static VALUE
|
2097
|
-
|
2098
|
-
VALUE self, state;
|
2299
|
+
pgconn_sync_setnonblocking(VALUE self, VALUE state)
|
2099
2300
|
{
|
2100
2301
|
int arg;
|
2101
|
-
VALUE error;
|
2102
2302
|
PGconn *conn = pg_get_pgconn(self);
|
2303
|
+
rb_check_frozen(self);
|
2103
2304
|
if(state == Qtrue)
|
2104
2305
|
arg = 1;
|
2105
2306
|
else if (state == Qfalse)
|
@@ -2107,67 +2308,33 @@ pgconn_setnonblocking(self, state)
|
|
2107
2308
|
else
|
2108
2309
|
rb_raise(rb_eArgError, "Boolean value expected");
|
2109
2310
|
|
2110
|
-
if(PQsetnonblocking(conn, arg) == -1)
|
2111
|
-
|
2112
|
-
|
2113
|
-
rb_exc_raise(error);
|
2114
|
-
}
|
2311
|
+
if(PQsetnonblocking(conn, arg) == -1)
|
2312
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
|
2313
|
+
|
2115
2314
|
return Qnil;
|
2116
2315
|
}
|
2117
2316
|
|
2118
2317
|
|
2119
|
-
/*
|
2120
|
-
* call-seq:
|
2121
|
-
* conn.isnonblocking() -> Boolean
|
2122
|
-
*
|
2123
|
-
* Returns +true+ if a command is busy, that is, if
|
2124
|
-
* PQgetResult would block. Otherwise returns +false+.
|
2125
|
-
*/
|
2126
2318
|
static VALUE
|
2127
|
-
|
2128
|
-
VALUE self;
|
2319
|
+
pgconn_sync_isnonblocking(VALUE self)
|
2129
2320
|
{
|
2130
2321
|
return PQisnonblocking(pg_get_pgconn(self)) ? Qtrue : Qfalse;
|
2131
2322
|
}
|
2132
2323
|
|
2133
|
-
/*
|
2134
|
-
* call-seq:
|
2135
|
-
* conn.flush() -> Boolean
|
2136
|
-
*
|
2137
|
-
* Attempts to flush any queued output data to the server.
|
2138
|
-
* Returns +true+ if data is successfully flushed, +false+
|
2139
|
-
* if not (can only return +false+ if connection is
|
2140
|
-
* nonblocking.
|
2141
|
-
* Raises PG::Error if some other failure occurred.
|
2142
|
-
*/
|
2143
2324
|
static VALUE
|
2144
|
-
|
2145
|
-
VALUE self;
|
2325
|
+
pgconn_sync_flush(VALUE self)
|
2146
2326
|
{
|
2147
2327
|
PGconn *conn = pg_get_pgconn(self);
|
2148
|
-
int ret;
|
2149
|
-
|
2150
|
-
|
2151
|
-
|
2152
|
-
error = rb_exc_new2(rb_ePGerror, PQerrorMessage(conn));
|
2153
|
-
rb_iv_set(error, "@connection", self);
|
2154
|
-
rb_exc_raise(error);
|
2155
|
-
}
|
2328
|
+
int ret = PQflush(conn);
|
2329
|
+
if(ret == -1)
|
2330
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
|
2331
|
+
|
2156
2332
|
return (ret) ? Qfalse : Qtrue;
|
2157
2333
|
}
|
2158
2334
|
|
2159
|
-
|
2160
|
-
* call-seq:
|
2161
|
-
* conn.cancel() -> String
|
2162
|
-
*
|
2163
|
-
* Requests cancellation of the command currently being
|
2164
|
-
* processed. (Only implemented in PostgreSQL >= 8.0)
|
2165
|
-
*
|
2166
|
-
* Returns +nil+ on success, or a string containing the
|
2167
|
-
* error message if a failure occurs.
|
2168
|
-
*/
|
2335
|
+
#ifndef HAVE_PQSETCHUNKEDROWSMODE
|
2169
2336
|
static VALUE
|
2170
|
-
|
2337
|
+
pgconn_sync_cancel(VALUE self)
|
2171
2338
|
{
|
2172
2339
|
char errbuf[256];
|
2173
2340
|
PGcancel *cancel;
|
@@ -2176,9 +2343,9 @@ pgconn_cancel(VALUE self)
|
|
2176
2343
|
|
2177
2344
|
cancel = PQgetCancel(pg_get_pgconn(self));
|
2178
2345
|
if(cancel == NULL)
|
2179
|
-
|
2346
|
+
pg_raise_conn_error( rb_ePGerror, self, "Invalid connection!");
|
2180
2347
|
|
2181
|
-
ret = gvl_PQcancel(cancel, errbuf,
|
2348
|
+
ret = gvl_PQcancel(cancel, errbuf, sizeof(errbuf));
|
2182
2349
|
if(ret == 1)
|
2183
2350
|
retval = Qnil;
|
2184
2351
|
else
|
@@ -2187,6 +2354,7 @@ pgconn_cancel(VALUE self)
|
|
2187
2354
|
PQfreeCancel(cancel);
|
2188
2355
|
return retval;
|
2189
2356
|
}
|
2357
|
+
#endif
|
2190
2358
|
|
2191
2359
|
|
2192
2360
|
/*
|
@@ -2229,55 +2397,73 @@ pgconn_notifies(VALUE self)
|
|
2229
2397
|
return hash;
|
2230
2398
|
}
|
2231
2399
|
|
2232
|
-
|
2233
|
-
|
2234
|
-
|
2235
|
-
|
2236
|
-
*
|
2400
|
+
#ifndef HAVE_RB_IO_DESCRIPTOR
|
2401
|
+
static int
|
2402
|
+
rb_io_descriptor(VALUE io)
|
2403
|
+
{
|
2404
|
+
rb_io_t *fptr;
|
2405
|
+
Check_Type(io, T_FILE);
|
2406
|
+
fptr = RFILE(io)->fptr;
|
2407
|
+
rb_io_check_closed(fptr);
|
2408
|
+
return fptr->fd;
|
2409
|
+
}
|
2410
|
+
#endif
|
2411
|
+
|
2412
|
+
#if defined(_WIN32)
|
2413
|
+
|
2414
|
+
/* We use a specialized implementation of rb_io_wait() on Windows.
|
2415
|
+
* This is because rb_io_wait() and rb_wait_for_single_fd() are very slow on Windows.
|
2237
2416
|
*/
|
2238
2417
|
|
2418
|
+
#if defined(HAVE_RUBY_FIBER_SCHEDULER_H)
|
2419
|
+
#include <ruby/fiber/scheduler.h>
|
2420
|
+
#endif
|
2421
|
+
|
2422
|
+
typedef enum {
|
2423
|
+
PG_RUBY_IO_READABLE = RB_WAITFD_IN,
|
2424
|
+
PG_RUBY_IO_WRITABLE = RB_WAITFD_OUT,
|
2425
|
+
PG_RUBY_IO_PRIORITY = RB_WAITFD_PRI,
|
2426
|
+
} pg_rb_io_event_t;
|
2427
|
+
|
2239
2428
|
int rb_w32_wait_events( HANDLE *events, int num, DWORD timeout );
|
2240
2429
|
|
2241
|
-
static
|
2242
|
-
|
2243
|
-
|
2244
|
-
|
2245
|
-
void *retval;
|
2430
|
+
static VALUE
|
2431
|
+
pg_rb_thread_io_wait(VALUE io, VALUE events, VALUE timeout) {
|
2432
|
+
struct timeval ptimeout;
|
2433
|
+
|
2246
2434
|
struct timeval aborttime={0,0}, currtime, waittime;
|
2247
2435
|
DWORD timeout_milisec = INFINITE;
|
2248
|
-
|
2249
|
-
WSAEVENT hEvent;
|
2436
|
+
HANDLE hEvent = WSACreateEvent();
|
2250
2437
|
|
2251
|
-
|
2252
|
-
|
2253
|
-
|
2254
|
-
hEvent = WSACreateEvent();
|
2438
|
+
long rb_events = NUM2UINT(events);
|
2439
|
+
long w32_events = 0;
|
2440
|
+
DWORD wait_ret;
|
2255
2441
|
|
2256
|
-
|
2257
|
-
|
2258
|
-
|
2259
|
-
rb_raise( rb_eConnectionBad, "PQconsumeInput() %s", PQerrorMessage(conn) );
|
2260
|
-
}
|
2442
|
+
if( !NIL_P(timeout) ){
|
2443
|
+
ptimeout.tv_sec = (time_t)(NUM2DBL(timeout));
|
2444
|
+
ptimeout.tv_usec = (time_t)((NUM2DBL(timeout) - (double)ptimeout.tv_sec) * 1e6);
|
2261
2445
|
|
2262
|
-
if ( ptimeout ) {
|
2263
2446
|
gettimeofday(&currtime, NULL);
|
2264
|
-
timeradd(&currtime, ptimeout, &aborttime);
|
2447
|
+
timeradd(&currtime, &ptimeout, &aborttime);
|
2265
2448
|
}
|
2266
2449
|
|
2267
|
-
|
2268
|
-
|
2450
|
+
if(rb_events & PG_RUBY_IO_READABLE) w32_events |= FD_READ | FD_ACCEPT | FD_CLOSE;
|
2451
|
+
if(rb_events & PG_RUBY_IO_WRITABLE) w32_events |= FD_WRITE | FD_CONNECT;
|
2452
|
+
if(rb_events & PG_RUBY_IO_PRIORITY) w32_events |= FD_OOB;
|
2453
|
+
|
2454
|
+
for(;;) {
|
2455
|
+
if ( WSAEventSelect(_get_osfhandle(rb_io_descriptor(io)), hEvent, w32_events) == SOCKET_ERROR ) {
|
2269
2456
|
WSACloseEvent( hEvent );
|
2270
2457
|
rb_raise( rb_eConnectionBad, "WSAEventSelect socket error: %d", WSAGetLastError() );
|
2271
2458
|
}
|
2272
2459
|
|
2273
|
-
if (
|
2460
|
+
if ( !NIL_P(timeout) ) {
|
2274
2461
|
gettimeofday(&currtime, NULL);
|
2275
2462
|
timersub(&aborttime, &currtime, &waittime);
|
2276
2463
|
timeout_milisec = (DWORD)( waittime.tv_sec * 1e3 + waittime.tv_usec / 1e3 );
|
2277
2464
|
}
|
2278
2465
|
|
2279
|
-
|
2280
|
-
if( !ptimeout || (waittime.tv_sec >= 0 && waittime.tv_usec >= 0) ){
|
2466
|
+
if( NIL_P(timeout) || (waittime.tv_sec >= 0 && waittime.tv_usec >= 0) ){
|
2281
2467
|
/* Wait for the socket to become readable before checking again */
|
2282
2468
|
wait_ret = rb_w32_wait_events( &hEvent, 1, timeout_milisec );
|
2283
2469
|
} else {
|
@@ -2286,9 +2472,11 @@ wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readabl
|
|
2286
2472
|
|
2287
2473
|
if ( wait_ret == WAIT_TIMEOUT ) {
|
2288
2474
|
WSACloseEvent( hEvent );
|
2289
|
-
return
|
2475
|
+
return UINT2NUM(0);
|
2290
2476
|
} else if ( wait_ret == WAIT_OBJECT_0 ) {
|
2477
|
+
WSACloseEvent( hEvent );
|
2291
2478
|
/* The event we were waiting for. */
|
2479
|
+
return UINT2NUM(rb_events);
|
2292
2480
|
} else if ( wait_ret == WAIT_OBJECT_0 + 1) {
|
2293
2481
|
/* This indicates interruption from timer thread, GC, exception
|
2294
2482
|
* from other threads etc... */
|
@@ -2300,36 +2488,64 @@ wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readabl
|
|
2300
2488
|
WSACloseEvent( hEvent );
|
2301
2489
|
rb_raise( rb_eConnectionBad, "Wait on socket abandoned (WaitForMultipleObjects)" );
|
2302
2490
|
}
|
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
|
-
}
|
2309
2491
|
}
|
2492
|
+
}
|
2310
2493
|
|
2311
|
-
|
2312
|
-
|
2494
|
+
static VALUE
|
2495
|
+
pg_rb_io_wait(VALUE io, VALUE events, VALUE timeout) {
|
2496
|
+
#if defined(HAVE_RUBY_FIBER_SCHEDULER_H)
|
2497
|
+
/* We don't support Fiber.scheduler on Windows ruby-3.0 because there is no fast way to check whether a scheduler is active.
|
2498
|
+
* Fortunately ruby-3.1 offers a C-API for it.
|
2499
|
+
*/
|
2500
|
+
VALUE scheduler = rb_fiber_scheduler_current();
|
2501
|
+
|
2502
|
+
if (!NIL_P(scheduler)) {
|
2503
|
+
return rb_io_wait(io, events, timeout);
|
2504
|
+
}
|
2505
|
+
#endif
|
2506
|
+
return pg_rb_thread_io_wait(io, events, timeout);
|
2313
2507
|
}
|
2314
2508
|
|
2509
|
+
#elif defined(HAVE_RB_IO_WAIT)
|
2510
|
+
|
2511
|
+
/* Use our own function and constants names, to avoid conflicts with truffleruby-head on its road to ruby-3.0 compatibility. */
|
2512
|
+
#define pg_rb_io_wait rb_io_wait
|
2513
|
+
#define PG_RUBY_IO_READABLE RUBY_IO_READABLE
|
2514
|
+
#define PG_RUBY_IO_WRITABLE RUBY_IO_WRITABLE
|
2515
|
+
#define PG_RUBY_IO_PRIORITY RUBY_IO_PRIORITY
|
2516
|
+
|
2315
2517
|
#else
|
2518
|
+
/* For compat with ruby < 3.0 */
|
2519
|
+
|
2520
|
+
typedef enum {
|
2521
|
+
PG_RUBY_IO_READABLE = RB_WAITFD_IN,
|
2522
|
+
PG_RUBY_IO_WRITABLE = RB_WAITFD_OUT,
|
2523
|
+
PG_RUBY_IO_PRIORITY = RB_WAITFD_PRI,
|
2524
|
+
} pg_rb_io_event_t;
|
2316
2525
|
|
2317
|
-
|
2526
|
+
static VALUE
|
2527
|
+
pg_rb_io_wait(VALUE io, VALUE events, VALUE timeout) {
|
2528
|
+
struct timeval waittime;
|
2529
|
+
int res;
|
2530
|
+
|
2531
|
+
if( !NIL_P(timeout) ){
|
2532
|
+
waittime.tv_sec = (time_t)(NUM2DBL(timeout));
|
2533
|
+
waittime.tv_usec = (time_t)((NUM2DBL(timeout) - (double)waittime.tv_sec) * 1e6);
|
2534
|
+
}
|
2535
|
+
res = rb_wait_for_single_fd(rb_io_descriptor(io), NUM2UINT(events), NIL_P(timeout) ? NULL : &waittime);
|
2536
|
+
|
2537
|
+
return UINT2NUM(res);
|
2538
|
+
}
|
2539
|
+
#endif
|
2318
2540
|
|
2319
2541
|
static void *
|
2320
|
-
wait_socket_readable(
|
2542
|
+
wait_socket_readable( VALUE self, struct timeval *ptimeout, void *(*is_readable)(PGconn *))
|
2321
2543
|
{
|
2322
|
-
|
2323
|
-
int ret;
|
2544
|
+
VALUE ret;
|
2324
2545
|
void *retval;
|
2325
2546
|
struct timeval aborttime={0,0}, currtime, waittime;
|
2326
|
-
|
2327
|
-
|
2328
|
-
rb_raise(rb_eConnectionBad, "PQsocket() can't get socket descriptor");
|
2329
|
-
|
2330
|
-
/* Check for connection errors (PQisBusy is true on connection errors) */
|
2331
|
-
if ( PQconsumeInput(conn) == 0 )
|
2332
|
-
rb_raise( rb_eConnectionBad, "PQconsumeInput() %s", PQerrorMessage(conn) );
|
2547
|
+
VALUE wait_timeout = Qnil;
|
2548
|
+
PGconn *conn = pg_get_pgconn(self);
|
2333
2549
|
|
2334
2550
|
if ( ptimeout ) {
|
2335
2551
|
gettimeofday(&currtime, NULL);
|
@@ -2340,36 +2556,81 @@ wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readabl
|
|
2340
2556
|
if ( ptimeout ) {
|
2341
2557
|
gettimeofday(&currtime, NULL);
|
2342
2558
|
timersub(&aborttime, &currtime, &waittime);
|
2559
|
+
wait_timeout = DBL2NUM((double)(waittime.tv_sec) + (double)(waittime.tv_usec) / 1000000.0);
|
2343
2560
|
}
|
2344
2561
|
|
2345
2562
|
/* Is the given timeout valid? */
|
2346
2563
|
if( !ptimeout || (waittime.tv_sec >= 0 && waittime.tv_usec >= 0) ){
|
2564
|
+
VALUE socket_io;
|
2565
|
+
|
2566
|
+
/* before we wait for data, make sure everything has been sent */
|
2567
|
+
pgconn_async_flush(self);
|
2568
|
+
if ((retval=is_readable(conn)))
|
2569
|
+
return retval;
|
2570
|
+
|
2571
|
+
socket_io = pgconn_socket_io(self);
|
2347
2572
|
/* Wait for the socket to become readable before checking again */
|
2348
|
-
ret =
|
2573
|
+
ret = pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE), wait_timeout);
|
2349
2574
|
} else {
|
2350
|
-
ret =
|
2351
|
-
}
|
2352
|
-
|
2353
|
-
if ( ret < 0 ){
|
2354
|
-
rb_sys_fail( "rb_wait_for_single_fd()" );
|
2575
|
+
ret = Qfalse;
|
2355
2576
|
}
|
2356
2577
|
|
2357
2578
|
/* Return false if the select() timed out */
|
2358
|
-
if ( ret ==
|
2579
|
+
if ( ret == Qfalse ){
|
2359
2580
|
return NULL;
|
2360
2581
|
}
|
2361
2582
|
|
2362
2583
|
/* Check for connection errors (PQisBusy is true on connection errors) */
|
2363
2584
|
if ( PQconsumeInput(conn) == 0 ){
|
2364
|
-
|
2585
|
+
pgconn_close_socket_io(self);
|
2586
|
+
pg_raise_conn_error(rb_eConnectionBad, self, "PQconsumeInput() %s", PQerrorMessage(conn));
|
2365
2587
|
}
|
2366
2588
|
}
|
2367
2589
|
|
2368
2590
|
return retval;
|
2369
2591
|
}
|
2370
2592
|
|
2593
|
+
/*
|
2594
|
+
* call-seq:
|
2595
|
+
* conn.flush() -> Boolean
|
2596
|
+
*
|
2597
|
+
* Attempts to flush any queued output data to the server.
|
2598
|
+
* Returns +true+ if data is successfully flushed, +false+
|
2599
|
+
* if not. It can only return +false+ if connection is
|
2600
|
+
* in nonblocking mode.
|
2601
|
+
* Raises PG::Error if some other failure occurred.
|
2602
|
+
*/
|
2603
|
+
static VALUE
|
2604
|
+
pgconn_async_flush(VALUE self)
|
2605
|
+
{
|
2606
|
+
while( pgconn_sync_flush(self) == Qfalse ){
|
2607
|
+
/* wait for the socket to become read- or write-ready */
|
2608
|
+
int events;
|
2609
|
+
VALUE socket_io = pgconn_socket_io(self);
|
2610
|
+
events = RB_NUM2INT(pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE | PG_RUBY_IO_WRITABLE), Qnil));
|
2611
|
+
|
2612
|
+
if (events & PG_RUBY_IO_READABLE){
|
2613
|
+
pgconn_consume_input(self);
|
2614
|
+
}
|
2615
|
+
}
|
2616
|
+
return Qtrue;
|
2617
|
+
}
|
2618
|
+
|
2619
|
+
static VALUE
|
2620
|
+
pgconn_wait_for_flush( VALUE self ){
|
2621
|
+
if( !pg_get_connection_safe(self)->flush_data )
|
2622
|
+
return Qnil;
|
2371
2623
|
|
2372
|
-
|
2624
|
+
return pgconn_async_flush(self);
|
2625
|
+
}
|
2626
|
+
|
2627
|
+
static VALUE
|
2628
|
+
pgconn_flush_data_set( VALUE self, VALUE enabled ){
|
2629
|
+
t_pg_connection *conn = pg_get_connection(self);
|
2630
|
+
rb_check_frozen(self);
|
2631
|
+
conn->flush_data = RTEST(enabled);
|
2632
|
+
return enabled;
|
2633
|
+
}
|
2373
2634
|
|
2374
2635
|
static void *
|
2375
2636
|
notify_readable(PGconn *conn)
|
@@ -2408,7 +2669,7 @@ pgconn_wait_for_notify(int argc, VALUE *argv, VALUE self)
|
|
2408
2669
|
ptimeout = &timeout;
|
2409
2670
|
}
|
2410
2671
|
|
2411
|
-
pnotification = (PGnotify*) wait_socket_readable(
|
2672
|
+
pnotification = (PGnotify*) wait_socket_readable( self, ptimeout, notify_readable);
|
2412
2673
|
|
2413
2674
|
/* Return nil if the select timed out */
|
2414
2675
|
if ( !pnotification ) return Qnil;
|
@@ -2429,28 +2690,8 @@ pgconn_wait_for_notify(int argc, VALUE *argv, VALUE self)
|
|
2429
2690
|
}
|
2430
2691
|
|
2431
2692
|
|
2432
|
-
/*
|
2433
|
-
* call-seq:
|
2434
|
-
* conn.put_copy_data( buffer [, encoder] ) -> Boolean
|
2435
|
-
*
|
2436
|
-
* Transmits _buffer_ as copy data to the server.
|
2437
|
-
* Returns true if the data was sent, false if it was
|
2438
|
-
* not sent (false is only possible if the connection
|
2439
|
-
* is in nonblocking mode, and this command would block).
|
2440
|
-
*
|
2441
|
-
* _encoder_ can be a PG::Coder derivation (typically PG::TextEncoder::CopyRow).
|
2442
|
-
* This encodes the data fields given as _buffer_ from an Array of Strings to
|
2443
|
-
* PostgreSQL's COPY text format inclusive proper escaping. Optionally
|
2444
|
-
* the encoder can type cast the fields from various Ruby types in one step,
|
2445
|
-
* if PG::TextEncoder::CopyRow#type_map is set accordingly.
|
2446
|
-
*
|
2447
|
-
* Raises an exception if an error occurs.
|
2448
|
-
*
|
2449
|
-
* See also #copy_data.
|
2450
|
-
*
|
2451
|
-
*/
|
2452
2693
|
static VALUE
|
2453
|
-
|
2694
|
+
pgconn_sync_put_copy_data(int argc, VALUE *argv, VALUE self)
|
2454
2695
|
{
|
2455
2696
|
int ret;
|
2456
2697
|
int len;
|
@@ -2458,7 +2699,7 @@ pgconn_put_copy_data(int argc, VALUE *argv, VALUE self)
|
|
2458
2699
|
VALUE value;
|
2459
2700
|
VALUE buffer = Qnil;
|
2460
2701
|
VALUE encoder;
|
2461
|
-
VALUE intermediate;
|
2702
|
+
VALUE intermediate = Qnil;
|
2462
2703
|
t_pg_coder *p_coder = NULL;
|
2463
2704
|
|
2464
2705
|
rb_scan_args( argc, argv, "11", &value, &encoder );
|
@@ -2467,13 +2708,11 @@ pgconn_put_copy_data(int argc, VALUE *argv, VALUE self)
|
|
2467
2708
|
if( NIL_P(this->encoder_for_put_copy_data) ){
|
2468
2709
|
buffer = value;
|
2469
2710
|
} else {
|
2470
|
-
p_coder =
|
2711
|
+
p_coder = RTYPEDDATA_DATA( this->encoder_for_put_copy_data );
|
2471
2712
|
}
|
2472
|
-
} else if( rb_obj_is_kind_of(encoder, rb_cPG_Coder) ) {
|
2473
|
-
Data_Get_Struct( encoder, t_pg_coder, p_coder );
|
2474
2713
|
} else {
|
2475
|
-
|
2476
|
-
|
2714
|
+
/* Check argument type and use argument encoder */
|
2715
|
+
TypedData_Get_Struct(encoder, t_pg_coder, &pg_coder_type, p_coder);
|
2477
2716
|
}
|
2478
2717
|
|
2479
2718
|
if( p_coder ){
|
@@ -2496,36 +2735,18 @@ pgconn_put_copy_data(int argc, VALUE *argv, VALUE self)
|
|
2496
2735
|
Check_Type(buffer, T_STRING);
|
2497
2736
|
|
2498
2737
|
ret = gvl_PQputCopyData(this->pgconn, RSTRING_PTR(buffer), RSTRING_LENINT(buffer));
|
2499
|
-
if(ret == -1)
|
2500
|
-
|
2501
|
-
|
2502
|
-
rb_exc_raise(error);
|
2503
|
-
}
|
2504
|
-
RB_GC_GUARD(intermediate);
|
2738
|
+
if(ret == -1)
|
2739
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(this->pgconn));
|
2740
|
+
|
2505
2741
|
RB_GC_GUARD(buffer);
|
2506
2742
|
|
2507
2743
|
return (ret) ? Qtrue : Qfalse;
|
2508
2744
|
}
|
2509
2745
|
|
2510
|
-
/*
|
2511
|
-
* call-seq:
|
2512
|
-
* conn.put_copy_end( [ error_message ] ) -> Boolean
|
2513
|
-
*
|
2514
|
-
* Sends end-of-data indication to the server.
|
2515
|
-
*
|
2516
|
-
* _error_message_ is an optional parameter, and if set,
|
2517
|
-
* forces the COPY command to fail with the string
|
2518
|
-
* _error_message_.
|
2519
|
-
*
|
2520
|
-
* Returns true if the end-of-data was sent, false if it was
|
2521
|
-
* not sent (false is only possible if the connection
|
2522
|
-
* is in nonblocking mode, and this command would block).
|
2523
|
-
*/
|
2524
2746
|
static VALUE
|
2525
|
-
|
2747
|
+
pgconn_sync_put_copy_end(int argc, VALUE *argv, VALUE self)
|
2526
2748
|
{
|
2527
2749
|
VALUE str;
|
2528
|
-
VALUE error;
|
2529
2750
|
int ret;
|
2530
2751
|
const char *error_message = NULL;
|
2531
2752
|
t_pg_connection *this = pg_get_connection_safe( self );
|
@@ -2536,38 +2757,16 @@ pgconn_put_copy_end(int argc, VALUE *argv, VALUE self)
|
|
2536
2757
|
error_message = pg_cstr_enc(str, this->enc_idx);
|
2537
2758
|
|
2538
2759
|
ret = gvl_PQputCopyEnd(this->pgconn, error_message);
|
2539
|
-
if(ret == -1)
|
2540
|
-
|
2541
|
-
|
2542
|
-
rb_exc_raise(error);
|
2543
|
-
}
|
2760
|
+
if(ret == -1)
|
2761
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(this->pgconn));
|
2762
|
+
|
2544
2763
|
return (ret) ? Qtrue : Qfalse;
|
2545
2764
|
}
|
2546
2765
|
|
2547
|
-
/*
|
2548
|
-
* call-seq:
|
2549
|
-
* conn.get_copy_data( [ async = false [, decoder = nil ]] ) -> Object
|
2550
|
-
*
|
2551
|
-
* Return one row of data, +nil+
|
2552
|
-
* if the copy is done, or +false+ if the call would
|
2553
|
-
* block (only possible if _async_ is true).
|
2554
|
-
*
|
2555
|
-
* If _decoder_ is not set or +nil+, data is returned as binary string.
|
2556
|
-
*
|
2557
|
-
* If _decoder_ is set to a PG::Coder derivation, the return type depends on this decoder.
|
2558
|
-
* PG::TextDecoder::CopyRow decodes the received data fields from one row of PostgreSQL's
|
2559
|
-
* COPY text format to an Array of Strings.
|
2560
|
-
* Optionally the decoder can type cast the single fields to various Ruby types in one step,
|
2561
|
-
* if PG::TextDecoder::CopyRow#type_map is set accordingly.
|
2562
|
-
*
|
2563
|
-
* See also #copy_data.
|
2564
|
-
*
|
2565
|
-
*/
|
2566
2766
|
static VALUE
|
2567
|
-
|
2767
|
+
pgconn_sync_get_copy_data(int argc, VALUE *argv, VALUE self )
|
2568
2768
|
{
|
2569
2769
|
VALUE async_in;
|
2570
|
-
VALUE error;
|
2571
2770
|
VALUE result;
|
2572
2771
|
int ret;
|
2573
2772
|
char *buffer;
|
@@ -2579,20 +2778,16 @@ pgconn_get_copy_data(int argc, VALUE *argv, VALUE self )
|
|
2579
2778
|
|
2580
2779
|
if( NIL_P(decoder) ){
|
2581
2780
|
if( !NIL_P(this->decoder_for_get_copy_data) ){
|
2582
|
-
p_coder =
|
2781
|
+
p_coder = RTYPEDDATA_DATA( this->decoder_for_get_copy_data );
|
2583
2782
|
}
|
2584
|
-
} else if( rb_obj_is_kind_of(decoder, rb_cPG_Coder) ) {
|
2585
|
-
Data_Get_Struct( decoder, t_pg_coder, p_coder );
|
2586
2783
|
} else {
|
2587
|
-
|
2588
|
-
|
2784
|
+
/* Check argument type and use argument decoder */
|
2785
|
+
TypedData_Get_Struct(decoder, t_pg_coder, &pg_coder_type, p_coder);
|
2589
2786
|
}
|
2590
2787
|
|
2591
2788
|
ret = gvl_PQgetCopyData(this->pgconn, &buffer, RTEST(async_in));
|
2592
|
-
if(ret == -2)
|
2593
|
-
|
2594
|
-
rb_iv_set(error, "@connection", self);
|
2595
|
-
rb_exc_raise(error);
|
2789
|
+
if(ret == -2){ /* error */
|
2790
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(this->pgconn));
|
2596
2791
|
}
|
2597
2792
|
if(ret == -1) { /* No data left */
|
2598
2793
|
return Qnil;
|
@@ -2637,7 +2832,6 @@ pgconn_set_error_verbosity(VALUE self, VALUE in_verbosity)
|
|
2637
2832
|
return INT2FIX(PQsetErrorVerbosity(conn, verbosity));
|
2638
2833
|
}
|
2639
2834
|
|
2640
|
-
#ifdef HAVE_PQRESULTVERBOSEERRORMESSAGE
|
2641
2835
|
/*
|
2642
2836
|
* call-seq:
|
2643
2837
|
* conn.set_error_context_visibility( context_visibility ) -> Integer
|
@@ -2657,7 +2851,6 @@ pgconn_set_error_verbosity(VALUE self, VALUE in_verbosity)
|
|
2657
2851
|
*
|
2658
2852
|
* See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-control.html#LIBPQ-PQSETERRORCONTEXTVISIBILITY].
|
2659
2853
|
*
|
2660
|
-
* Available since PostgreSQL-9.6
|
2661
2854
|
*/
|
2662
2855
|
static VALUE
|
2663
2856
|
pgconn_set_error_context_visibility(VALUE self, VALUE in_context_visibility)
|
@@ -2666,7 +2859,6 @@ pgconn_set_error_context_visibility(VALUE self, VALUE in_context_visibility)
|
|
2666
2859
|
PGContextVisibility context_visibility = NUM2INT(in_context_visibility);
|
2667
2860
|
return INT2FIX(PQsetErrorContextVisibility(conn, context_visibility));
|
2668
2861
|
}
|
2669
|
-
#endif
|
2670
2862
|
|
2671
2863
|
/*
|
2672
2864
|
* call-seq:
|
@@ -2686,6 +2878,7 @@ pgconn_trace(VALUE self, VALUE stream)
|
|
2686
2878
|
VALUE new_file;
|
2687
2879
|
t_pg_connection *this = pg_get_connection_safe( self );
|
2688
2880
|
|
2881
|
+
rb_check_frozen(self);
|
2689
2882
|
if(!rb_respond_to(stream,rb_intern("fileno")))
|
2690
2883
|
rb_raise(rb_eArgError, "stream does not respond to method: fileno");
|
2691
2884
|
|
@@ -2707,7 +2900,7 @@ pgconn_trace(VALUE self, VALUE stream)
|
|
2707
2900
|
rb_raise(rb_eArgError, "stream is not writable");
|
2708
2901
|
|
2709
2902
|
new_file = rb_funcall(rb_cIO, rb_intern("new"), 1, INT2NUM(new_fd));
|
2710
|
-
this->trace_stream
|
2903
|
+
RB_OBJ_WRITE(self, &this->trace_stream, new_file);
|
2711
2904
|
|
2712
2905
|
PQtrace(this->pgconn, new_fp);
|
2713
2906
|
return Qnil;
|
@@ -2726,7 +2919,7 @@ pgconn_untrace(VALUE self)
|
|
2726
2919
|
|
2727
2920
|
PQuntrace(this->pgconn);
|
2728
2921
|
rb_funcall(this->trace_stream, rb_intern("close"), 0);
|
2729
|
-
this->trace_stream
|
2922
|
+
RB_OBJ_WRITE(self, &this->trace_stream, Qnil);
|
2730
2923
|
return Qnil;
|
2731
2924
|
}
|
2732
2925
|
|
@@ -2785,13 +2978,14 @@ pgconn_set_notice_receiver(VALUE self)
|
|
2785
2978
|
VALUE proc, old_proc;
|
2786
2979
|
t_pg_connection *this = pg_get_connection_safe( self );
|
2787
2980
|
|
2981
|
+
rb_check_frozen(self);
|
2788
2982
|
/* If default_notice_receiver is unset, assume that the current
|
2789
2983
|
* notice receiver is the default, and save it to a global variable.
|
2790
2984
|
* This should not be a problem because the default receiver is
|
2791
2985
|
* always the same, so won't vary among connections.
|
2792
2986
|
*/
|
2793
|
-
if(default_notice_receiver == NULL)
|
2794
|
-
default_notice_receiver = PQsetNoticeReceiver(this->pgconn, NULL, NULL);
|
2987
|
+
if(this->default_notice_receiver == NULL)
|
2988
|
+
this->default_notice_receiver = PQsetNoticeReceiver(this->pgconn, NULL, NULL);
|
2795
2989
|
|
2796
2990
|
old_proc = this->notice_receiver;
|
2797
2991
|
if( rb_block_given_p() ) {
|
@@ -2800,10 +2994,10 @@ pgconn_set_notice_receiver(VALUE self)
|
|
2800
2994
|
} else {
|
2801
2995
|
/* if no block is given, set back to default */
|
2802
2996
|
proc = Qnil;
|
2803
|
-
PQsetNoticeReceiver(this->pgconn, default_notice_receiver, NULL);
|
2997
|
+
PQsetNoticeReceiver(this->pgconn, this->default_notice_receiver, NULL);
|
2804
2998
|
}
|
2805
2999
|
|
2806
|
-
this->notice_receiver
|
3000
|
+
RB_OBJ_WRITE(self, &this->notice_receiver, proc);
|
2807
3001
|
return old_proc;
|
2808
3002
|
}
|
2809
3003
|
|
@@ -2818,10 +3012,10 @@ notice_processor_proxy(void *arg, const char *message)
|
|
2818
3012
|
VALUE self = (VALUE)arg;
|
2819
3013
|
t_pg_connection *this = pg_get_connection( self );
|
2820
3014
|
|
2821
|
-
if (this->
|
3015
|
+
if (this->notice_processor != Qnil) {
|
2822
3016
|
VALUE message_str = rb_str_new2(message);
|
2823
3017
|
PG_ENCODING_SET_NOCHECK( message_str, this->enc_idx );
|
2824
|
-
rb_funcall(this->
|
3018
|
+
rb_funcall(this->notice_processor, rb_intern("call"), 1, message_str);
|
2825
3019
|
}
|
2826
3020
|
return;
|
2827
3021
|
}
|
@@ -2830,7 +3024,7 @@ notice_processor_proxy(void *arg, const char *message)
|
|
2830
3024
|
* call-seq:
|
2831
3025
|
* conn.set_notice_processor {|message| ... } -> Proc
|
2832
3026
|
*
|
2833
|
-
* See #set_notice_receiver for the
|
3027
|
+
* See #set_notice_receiver for the description of what this and the
|
2834
3028
|
* notice_processor methods do.
|
2835
3029
|
*
|
2836
3030
|
* This function takes a new block to act as the notice processor and returns
|
@@ -2845,25 +3039,26 @@ pgconn_set_notice_processor(VALUE self)
|
|
2845
3039
|
VALUE proc, old_proc;
|
2846
3040
|
t_pg_connection *this = pg_get_connection_safe( self );
|
2847
3041
|
|
3042
|
+
rb_check_frozen(self);
|
2848
3043
|
/* If default_notice_processor is unset, assume that the current
|
2849
3044
|
* notice processor is the default, and save it to a global variable.
|
2850
3045
|
* This should not be a problem because the default processor is
|
2851
3046
|
* always the same, so won't vary among connections.
|
2852
3047
|
*/
|
2853
|
-
if(default_notice_processor == NULL)
|
2854
|
-
default_notice_processor = PQsetNoticeProcessor(this->pgconn, NULL, NULL);
|
3048
|
+
if(this->default_notice_processor == NULL)
|
3049
|
+
this->default_notice_processor = PQsetNoticeProcessor(this->pgconn, NULL, NULL);
|
2855
3050
|
|
2856
|
-
old_proc = this->
|
3051
|
+
old_proc = this->notice_processor;
|
2857
3052
|
if( rb_block_given_p() ) {
|
2858
3053
|
proc = rb_block_proc();
|
2859
3054
|
PQsetNoticeProcessor(this->pgconn, gvl_notice_processor_proxy, (void *)self);
|
2860
3055
|
} else {
|
2861
3056
|
/* if no block is given, set back to default */
|
2862
3057
|
proc = Qnil;
|
2863
|
-
PQsetNoticeProcessor(this->pgconn, default_notice_processor, NULL);
|
3058
|
+
PQsetNoticeProcessor(this->pgconn, this->default_notice_processor, NULL);
|
2864
3059
|
}
|
2865
3060
|
|
2866
|
-
this->
|
3061
|
+
RB_OBJ_WRITE(self, &this->notice_processor, proc);
|
2867
3062
|
return old_proc;
|
2868
3063
|
}
|
2869
3064
|
|
@@ -2884,68 +3079,28 @@ pgconn_get_client_encoding(VALUE self)
|
|
2884
3079
|
|
2885
3080
|
/*
|
2886
3081
|
* call-seq:
|
2887
|
-
* conn.
|
3082
|
+
* conn.sync_set_client_encoding( encoding )
|
2888
3083
|
*
|
2889
|
-
*
|
3084
|
+
* This function has the same behavior as #async_set_client_encoding, but is implemented using the synchronous command processing API of libpq.
|
3085
|
+
* See #async_exec for the differences between the two API variants.
|
3086
|
+
* 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
3087
|
*/
|
2891
3088
|
static VALUE
|
2892
|
-
|
3089
|
+
pgconn_sync_set_client_encoding(VALUE self, VALUE str)
|
2893
3090
|
{
|
2894
3091
|
PGconn *conn = pg_get_pgconn( self );
|
2895
3092
|
|
3093
|
+
rb_check_frozen(self);
|
2896
3094
|
Check_Type(str, T_STRING);
|
2897
3095
|
|
2898
|
-
if ( (gvl_PQsetClientEncoding(conn, StringValueCStr(str))) == -1 )
|
2899
|
-
|
2900
|
-
|
3096
|
+
if ( (gvl_PQsetClientEncoding(conn, StringValueCStr(str))) == -1 )
|
3097
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
|
3098
|
+
|
2901
3099
|
pgconn_set_internal_encoding_index( self );
|
2902
3100
|
|
2903
3101
|
return Qnil;
|
2904
3102
|
}
|
2905
3103
|
|
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
3104
|
|
2950
3105
|
/*
|
2951
3106
|
* call-seq:
|
@@ -3020,10 +3175,8 @@ get_result_readable(PGconn *conn)
|
|
3020
3175
|
* If +true+ is returned, +conn.is_busy+ will return +false+
|
3021
3176
|
* and +conn.get_result+ will not block.
|
3022
3177
|
*/
|
3023
|
-
|
3178
|
+
VALUE
|
3024
3179
|
pgconn_block( int argc, VALUE *argv, VALUE self ) {
|
3025
|
-
PGconn *conn = pg_get_pgconn( self );
|
3026
|
-
|
3027
3180
|
struct timeval timeout;
|
3028
3181
|
struct timeval *ptimeout = NULL;
|
3029
3182
|
VALUE timeout_in;
|
@@ -3037,7 +3190,7 @@ pgconn_block( int argc, VALUE *argv, VALUE self ) {
|
|
3037
3190
|
ptimeout = &timeout;
|
3038
3191
|
}
|
3039
3192
|
|
3040
|
-
ret = wait_socket_readable(
|
3193
|
+
ret = wait_socket_readable( self, ptimeout, get_result_readable);
|
3041
3194
|
|
3042
3195
|
if( !ret )
|
3043
3196
|
return Qfalse;
|
@@ -3046,6 +3199,42 @@ pgconn_block( int argc, VALUE *argv, VALUE self ) {
|
|
3046
3199
|
}
|
3047
3200
|
|
3048
3201
|
|
3202
|
+
/*
|
3203
|
+
* call-seq:
|
3204
|
+
* conn.sync_get_last_result( ) -> PG::Result
|
3205
|
+
*
|
3206
|
+
* This function has the same behavior as #async_get_last_result, but is implemented using the synchronous command processing API of libpq.
|
3207
|
+
* See #async_exec for the differences between the two API variants.
|
3208
|
+
* 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.
|
3209
|
+
*/
|
3210
|
+
static VALUE
|
3211
|
+
pgconn_sync_get_last_result(VALUE self)
|
3212
|
+
{
|
3213
|
+
PGconn *conn = pg_get_pgconn(self);
|
3214
|
+
VALUE rb_pgresult = Qnil;
|
3215
|
+
PGresult *cur, *prev;
|
3216
|
+
|
3217
|
+
|
3218
|
+
cur = prev = NULL;
|
3219
|
+
while ((cur = gvl_PQgetResult(conn)) != NULL) {
|
3220
|
+
int status;
|
3221
|
+
|
3222
|
+
if (prev) PQclear(prev);
|
3223
|
+
prev = cur;
|
3224
|
+
|
3225
|
+
status = PQresultStatus(cur);
|
3226
|
+
if (status == PGRES_COPY_OUT || status == PGRES_COPY_IN || status == PGRES_COPY_BOTH)
|
3227
|
+
break;
|
3228
|
+
}
|
3229
|
+
|
3230
|
+
if (prev) {
|
3231
|
+
rb_pgresult = pg_new_result( prev, self );
|
3232
|
+
pg_result_check(rb_pgresult);
|
3233
|
+
}
|
3234
|
+
|
3235
|
+
return rb_pgresult;
|
3236
|
+
}
|
3237
|
+
|
3049
3238
|
/*
|
3050
3239
|
* call-seq:
|
3051
3240
|
* conn.get_last_result( ) -> PG::Result
|
@@ -3056,27 +3245,38 @@ pgconn_block( int argc, VALUE *argv, VALUE self ) {
|
|
3056
3245
|
* returns the last non-NULL result, or +nil+ if no
|
3057
3246
|
* results are available.
|
3058
3247
|
*
|
3248
|
+
* If the last result contains a bad result_status, an
|
3249
|
+
* appropriate exception is raised.
|
3250
|
+
*
|
3059
3251
|
* This function is similar to #get_result
|
3060
3252
|
* except that it is designed to get one and only
|
3061
|
-
* one result.
|
3253
|
+
* one result and that it checks the result state.
|
3062
3254
|
*/
|
3063
3255
|
static VALUE
|
3064
|
-
|
3256
|
+
pgconn_async_get_last_result(VALUE self)
|
3065
3257
|
{
|
3066
3258
|
PGconn *conn = pg_get_pgconn(self);
|
3067
3259
|
VALUE rb_pgresult = Qnil;
|
3068
3260
|
PGresult *cur, *prev;
|
3069
3261
|
|
3070
|
-
|
3071
3262
|
cur = prev = NULL;
|
3072
|
-
|
3263
|
+
for(;;) {
|
3073
3264
|
int status;
|
3074
3265
|
|
3266
|
+
/* Wait for input before reading each result.
|
3267
|
+
* That way we support the ruby-3.x IO scheduler and don't block other ruby threads.
|
3268
|
+
*/
|
3269
|
+
wait_socket_readable(self, NULL, get_result_readable);
|
3270
|
+
|
3271
|
+
cur = gvl_PQgetResult(conn);
|
3272
|
+
if (cur == NULL)
|
3273
|
+
break;
|
3274
|
+
|
3075
3275
|
if (prev) PQclear(prev);
|
3076
3276
|
prev = cur;
|
3077
3277
|
|
3078
3278
|
status = PQresultStatus(cur);
|
3079
|
-
if (status == PGRES_COPY_OUT || status == PGRES_COPY_IN)
|
3279
|
+
if (status == PGRES_COPY_OUT || status == PGRES_COPY_IN || status == PGRES_COPY_BOTH)
|
3080
3280
|
break;
|
3081
3281
|
}
|
3082
3282
|
|
@@ -3093,29 +3293,91 @@ pgconn_get_last_result(VALUE self)
|
|
3093
3293
|
* conn.discard_results()
|
3094
3294
|
*
|
3095
3295
|
* Silently discard any prior query result that application didn't eat.
|
3096
|
-
* This is
|
3097
|
-
*
|
3296
|
+
* This is internally used prior to Connection#exec and sibling methods.
|
3297
|
+
* It doesn't raise an exception on connection errors, but returns +false+ instead.
|
3298
|
+
*
|
3299
|
+
* Returns:
|
3300
|
+
* * +nil+ when the connection is already idle
|
3301
|
+
* * +true+ when some results have been discarded
|
3302
|
+
* * +false+ when a failure occurred and the connection was closed
|
3303
|
+
*
|
3098
3304
|
*/
|
3099
3305
|
static VALUE
|
3100
3306
|
pgconn_discard_results(VALUE self)
|
3101
3307
|
{
|
3102
3308
|
PGconn *conn = pg_get_pgconn(self);
|
3309
|
+
VALUE socket_io;
|
3310
|
+
|
3311
|
+
switch( PQtransactionStatus(conn) ) {
|
3312
|
+
case PQTRANS_IDLE:
|
3313
|
+
case PQTRANS_INTRANS:
|
3314
|
+
case PQTRANS_INERROR:
|
3315
|
+
return Qnil;
|
3316
|
+
default:;
|
3317
|
+
}
|
3103
3318
|
|
3104
|
-
|
3105
|
-
|
3106
|
-
|
3319
|
+
socket_io = pgconn_socket_io(self);
|
3320
|
+
|
3321
|
+
for(;;) {
|
3322
|
+
PGresult *cur;
|
3323
|
+
int status;
|
3324
|
+
|
3325
|
+
/* pgconn_block() raises an exception in case of errors.
|
3326
|
+
* To avoid this call pg_rb_io_wait() and PQconsumeInput() without rb_raise().
|
3327
|
+
*/
|
3328
|
+
while( gvl_PQisBusy(conn) ){
|
3329
|
+
int events;
|
3330
|
+
|
3331
|
+
switch( PQflush(conn) ) {
|
3332
|
+
case 1:
|
3333
|
+
events = RB_NUM2INT(pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE | PG_RUBY_IO_WRITABLE), Qnil));
|
3334
|
+
if (events & PG_RUBY_IO_READABLE){
|
3335
|
+
if ( PQconsumeInput(conn) == 0 ) goto error;
|
3336
|
+
}
|
3337
|
+
break;
|
3338
|
+
case 0:
|
3339
|
+
pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE), Qnil);
|
3340
|
+
if ( PQconsumeInput(conn) == 0 ) goto error;
|
3341
|
+
break;
|
3342
|
+
default:
|
3343
|
+
goto error;
|
3344
|
+
}
|
3345
|
+
}
|
3346
|
+
|
3347
|
+
cur = gvl_PQgetResult(conn);
|
3348
|
+
if( cur == NULL) break;
|
3349
|
+
|
3350
|
+
status = PQresultStatus(cur);
|
3107
3351
|
PQclear(cur);
|
3108
3352
|
if (status == PGRES_COPY_IN){
|
3109
|
-
gvl_PQputCopyEnd(conn, "COPY terminated by new
|
3353
|
+
while( gvl_PQputCopyEnd(conn, "COPY terminated by new query or discard_results") == 0 ){
|
3354
|
+
pgconn_async_flush(self);
|
3355
|
+
}
|
3110
3356
|
}
|
3111
3357
|
if (status == PGRES_COPY_OUT){
|
3112
|
-
|
3113
|
-
|
3114
|
-
|
3358
|
+
for(;;) {
|
3359
|
+
char *buffer = NULL;
|
3360
|
+
int st = gvl_PQgetCopyData(conn, &buffer, 1);
|
3361
|
+
if( st == 0 ) {
|
3362
|
+
/* would block -> wait for readable data */
|
3363
|
+
pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE), Qnil);
|
3364
|
+
if ( PQconsumeInput(conn) == 0 ) goto error;
|
3365
|
+
} else if( st > 0 ) {
|
3366
|
+
/* some data retrieved -> discard it */
|
3367
|
+
PQfreemem(buffer);
|
3368
|
+
} else {
|
3369
|
+
/* no more data */
|
3370
|
+
break;
|
3371
|
+
}
|
3372
|
+
}
|
3115
3373
|
}
|
3116
3374
|
}
|
3117
3375
|
|
3118
|
-
return
|
3376
|
+
return Qtrue;
|
3377
|
+
|
3378
|
+
error:
|
3379
|
+
pgconn_close_socket_io(self);
|
3380
|
+
return Qfalse;
|
3119
3381
|
}
|
3120
3382
|
|
3121
3383
|
/*
|
@@ -3138,6 +3400,7 @@ pgconn_discard_results(VALUE self)
|
|
3138
3400
|
* #exec is an alias for #async_exec which is almost identical to #sync_exec .
|
3139
3401
|
* #sync_exec is implemented on the simpler synchronous command processing API of libpq, whereas
|
3140
3402
|
* #async_exec is implemented on the asynchronous API and on ruby's IO mechanisms.
|
3403
|
+
* Only #async_exec is compatible to <tt>Fiber.scheduler</tt> based asynchronous IO processing introduced in ruby-3.0.
|
3141
3404
|
* Both methods ensure that other threads can process while waiting for the server to
|
3142
3405
|
* complete the request, but #sync_exec blocks all signals to be processed until the query is finished.
|
3143
3406
|
* This is most notably visible by a delayed reaction to Control+C.
|
@@ -3152,8 +3415,7 @@ pgconn_async_exec(int argc, VALUE *argv, VALUE self)
|
|
3152
3415
|
|
3153
3416
|
pgconn_discard_results( self );
|
3154
3417
|
pgconn_send_query( argc, argv, self );
|
3155
|
-
|
3156
|
-
rb_pgresult = pgconn_get_last_result( self );
|
3418
|
+
rb_pgresult = pgconn_async_get_last_result( self );
|
3157
3419
|
|
3158
3420
|
if ( rb_block_given_p() ) {
|
3159
3421
|
return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
|
@@ -3182,7 +3444,7 @@ pgconn_async_exec(int argc, VALUE *argv, VALUE self)
|
|
3182
3444
|
* or, it may be a String. If it is a string, that is equivalent to the hash:
|
3183
3445
|
* { :value => <string value>, :type => 0, :format => 0 }
|
3184
3446
|
*
|
3185
|
-
* PostgreSQL bind parameters are represented as $1, $
|
3447
|
+
* PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
|
3186
3448
|
* inside the SQL query. The 0th element of the +params+ array is bound
|
3187
3449
|
* to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
|
3188
3450
|
*
|
@@ -3225,8 +3487,7 @@ pgconn_async_exec_params(int argc, VALUE *argv, VALUE self)
|
|
3225
3487
|
} else {
|
3226
3488
|
pgconn_send_query_params( argc, argv, self );
|
3227
3489
|
}
|
3228
|
-
|
3229
|
-
rb_pgresult = pgconn_get_last_result( self );
|
3490
|
+
rb_pgresult = pgconn_async_get_last_result( self );
|
3230
3491
|
|
3231
3492
|
if ( rb_block_given_p() ) {
|
3232
3493
|
return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
|
@@ -3252,7 +3513,7 @@ pgconn_async_exec_params(int argc, VALUE *argv, VALUE self)
|
|
3252
3513
|
*
|
3253
3514
|
* For example: "SELECT $1::int"
|
3254
3515
|
*
|
3255
|
-
* PostgreSQL bind parameters are represented as $1, $
|
3516
|
+
* PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
|
3256
3517
|
* inside the SQL query.
|
3257
3518
|
*
|
3258
3519
|
* See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQPREPARE].
|
@@ -3264,8 +3525,7 @@ pgconn_async_prepare(int argc, VALUE *argv, VALUE self)
|
|
3264
3525
|
|
3265
3526
|
pgconn_discard_results( self );
|
3266
3527
|
pgconn_send_prepare( argc, argv, self );
|
3267
|
-
|
3268
|
-
rb_pgresult = pgconn_get_last_result( self );
|
3528
|
+
rb_pgresult = pgconn_async_get_last_result( self );
|
3269
3529
|
|
3270
3530
|
if ( rb_block_given_p() ) {
|
3271
3531
|
return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
|
@@ -3292,7 +3552,7 @@ pgconn_async_prepare(int argc, VALUE *argv, VALUE self)
|
|
3292
3552
|
* or, it may be a String. If it is a string, that is equivalent to the hash:
|
3293
3553
|
* { :value => <string value>, :format => 0 }
|
3294
3554
|
*
|
3295
|
-
* PostgreSQL bind parameters are represented as $1, $
|
3555
|
+
* PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
|
3296
3556
|
* inside the SQL query. The 0th element of the +params+ array is bound
|
3297
3557
|
* to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
|
3298
3558
|
*
|
@@ -3318,8 +3578,7 @@ pgconn_async_exec_prepared(int argc, VALUE *argv, VALUE self)
|
|
3318
3578
|
|
3319
3579
|
pgconn_discard_results( self );
|
3320
3580
|
pgconn_send_query_prepared( argc, argv, self );
|
3321
|
-
|
3322
|
-
rb_pgresult = pgconn_get_last_result( self );
|
3581
|
+
rb_pgresult = pgconn_async_get_last_result( self );
|
3323
3582
|
|
3324
3583
|
if ( rb_block_given_p() ) {
|
3325
3584
|
return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
|
@@ -3327,6 +3586,21 @@ pgconn_async_exec_prepared(int argc, VALUE *argv, VALUE self)
|
|
3327
3586
|
return rb_pgresult;
|
3328
3587
|
}
|
3329
3588
|
|
3589
|
+
static VALUE
|
3590
|
+
pgconn_async_describe_close_prepared_potral(VALUE self, VALUE name, VALUE
|
3591
|
+
(*func)(VALUE, VALUE))
|
3592
|
+
{
|
3593
|
+
VALUE rb_pgresult = Qnil;
|
3594
|
+
|
3595
|
+
pgconn_discard_results( self );
|
3596
|
+
func( self, name );
|
3597
|
+
rb_pgresult = pgconn_async_get_last_result( self );
|
3598
|
+
|
3599
|
+
if ( rb_block_given_p() ) {
|
3600
|
+
return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
|
3601
|
+
}
|
3602
|
+
return rb_pgresult;
|
3603
|
+
}
|
3330
3604
|
|
3331
3605
|
/*
|
3332
3606
|
* call-seq:
|
@@ -3339,17 +3613,7 @@ pgconn_async_exec_prepared(int argc, VALUE *argv, VALUE self)
|
|
3339
3613
|
static VALUE
|
3340
3614
|
pgconn_async_describe_portal(VALUE self, VALUE portal)
|
3341
3615
|
{
|
3342
|
-
|
3343
|
-
|
3344
|
-
pgconn_discard_results( self );
|
3345
|
-
pgconn_send_describe_portal( self, portal );
|
3346
|
-
pgconn_block( 0, NULL, self ); /* wait for input (without blocking) before reading the last result */
|
3347
|
-
rb_pgresult = pgconn_get_last_result( self );
|
3348
|
-
|
3349
|
-
if ( rb_block_given_p() ) {
|
3350
|
-
return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
|
3351
|
-
}
|
3352
|
-
return rb_pgresult;
|
3616
|
+
return pgconn_async_describe_close_prepared_potral(self, portal, pgconn_send_describe_portal);
|
3353
3617
|
}
|
3354
3618
|
|
3355
3619
|
|
@@ -3364,28 +3628,64 @@ pgconn_async_describe_portal(VALUE self, VALUE portal)
|
|
3364
3628
|
static VALUE
|
3365
3629
|
pgconn_async_describe_prepared(VALUE self, VALUE stmt_name)
|
3366
3630
|
{
|
3367
|
-
|
3368
|
-
|
3369
|
-
pgconn_discard_results( self );
|
3370
|
-
pgconn_send_describe_prepared( self, stmt_name );
|
3371
|
-
pgconn_block( 0, NULL, self ); /* wait for input (without blocking) before reading the last result */
|
3372
|
-
rb_pgresult = pgconn_get_last_result( self );
|
3631
|
+
return pgconn_async_describe_close_prepared_potral(self, stmt_name, pgconn_send_describe_prepared);
|
3632
|
+
}
|
3373
3633
|
|
3374
|
-
|
3375
|
-
|
3376
|
-
|
3377
|
-
|
3634
|
+
#ifdef HAVE_PQSETCHUNKEDROWSMODE
|
3635
|
+
/*
|
3636
|
+
* call-seq:
|
3637
|
+
* conn.close_prepared( statement_name ) -> PG::Result
|
3638
|
+
*
|
3639
|
+
* Submits a request to close the specified prepared statement, and waits for completion.
|
3640
|
+
* close_prepared allows an application to close a previously prepared statement.
|
3641
|
+
* Closing a statement releases all of its associated resources on the server and allows its name to be reused.
|
3642
|
+
* It's the same as using the +DEALLOCATE+ SQL statement, but on a lower protocol level.
|
3643
|
+
*
|
3644
|
+
* +statement_name+ can be "" or +nil+ to reference the unnamed statement.
|
3645
|
+
* It is fine if no statement exists with this name, in that case the operation is a no-op.
|
3646
|
+
* On success, a PG::Result with status PGRES_COMMAND_OK is returned.
|
3647
|
+
*
|
3648
|
+
* See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQCLOSEPREPARED].
|
3649
|
+
*
|
3650
|
+
* Available since PostgreSQL-17.
|
3651
|
+
*/
|
3652
|
+
static VALUE
|
3653
|
+
pgconn_async_close_prepared(VALUE self, VALUE stmt_name)
|
3654
|
+
{
|
3655
|
+
return pgconn_async_describe_close_prepared_potral(self, stmt_name, pgconn_send_close_prepared);
|
3378
3656
|
}
|
3379
3657
|
|
3658
|
+
/*
|
3659
|
+
* call-seq:
|
3660
|
+
* conn.close_portal( portal_name ) -> PG::Result
|
3661
|
+
*
|
3662
|
+
* Submits a request to close the specified portal, and waits for completion.
|
3663
|
+
*
|
3664
|
+
* close_portal allows an application to trigger a close of a previously created portal.
|
3665
|
+
* Closing a portal releases all of its associated resources on the server and allows its name to be reused.
|
3666
|
+
* (pg does not provide any direct access to portals, but you can use this function to close a cursor created with a DECLARE CURSOR SQL command.)
|
3667
|
+
*
|
3668
|
+
* +portal_name+ can be "" or +nil+ to reference the unnamed portal.
|
3669
|
+
* It is fine if no portal exists with this name, in that case the operation is a no-op.
|
3670
|
+
* On success, a PG::Result with status PGRES_COMMAND_OK is returned.
|
3671
|
+
*
|
3672
|
+
* See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQCLOSEPORTAL].
|
3673
|
+
*
|
3674
|
+
* Available since PostgreSQL-17.
|
3675
|
+
*/
|
3676
|
+
static VALUE
|
3677
|
+
pgconn_async_close_portal(VALUE self, VALUE portal)
|
3678
|
+
{
|
3679
|
+
return pgconn_async_describe_close_prepared_potral(self, portal, pgconn_send_close_portal);
|
3680
|
+
}
|
3681
|
+
#endif
|
3380
3682
|
|
3381
|
-
#ifdef HAVE_PQSSLATTRIBUTE
|
3382
3683
|
/*
|
3383
3684
|
* call-seq:
|
3384
3685
|
* conn.ssl_in_use? -> Boolean
|
3385
3686
|
*
|
3386
3687
|
* Returns +true+ if the connection uses SSL/TLS, +false+ if not.
|
3387
3688
|
*
|
3388
|
-
* Available since PostgreSQL-9.5
|
3389
3689
|
*/
|
3390
3690
|
static VALUE
|
3391
3691
|
pgconn_ssl_in_use(VALUE self)
|
@@ -3419,7 +3719,6 @@ pgconn_ssl_in_use(VALUE self)
|
|
3419
3719
|
*
|
3420
3720
|
* See also #ssl_attribute_names and the {corresponding libpq function}[https://www.postgresql.org/docs/current/libpq-status.html#LIBPQ-PQSSLATTRIBUTE].
|
3421
3721
|
*
|
3422
|
-
* Available since PostgreSQL-9.5
|
3423
3722
|
*/
|
3424
3723
|
static VALUE
|
3425
3724
|
pgconn_ssl_attribute(VALUE self, VALUE attribute_name)
|
@@ -3438,7 +3737,6 @@ pgconn_ssl_attribute(VALUE self, VALUE attribute_name)
|
|
3438
3737
|
*
|
3439
3738
|
* See also #ssl_attribute
|
3440
3739
|
*
|
3441
|
-
* Available since PostgreSQL-9.5
|
3442
3740
|
*/
|
3443
3741
|
static VALUE
|
3444
3742
|
pgconn_ssl_attribute_names(VALUE self)
|
@@ -3454,13 +3752,163 @@ pgconn_ssl_attribute_names(VALUE self)
|
|
3454
3752
|
}
|
3455
3753
|
|
3456
3754
|
|
3755
|
+
|
3756
|
+
#ifdef HAVE_PQENTERPIPELINEMODE
|
3757
|
+
/*
|
3758
|
+
* call-seq:
|
3759
|
+
* conn.pipeline_status -> Integer
|
3760
|
+
*
|
3761
|
+
* Returns the current pipeline mode status of the libpq connection.
|
3762
|
+
*
|
3763
|
+
* PQpipelineStatus can return one of the following values:
|
3764
|
+
*
|
3765
|
+
* * PQ_PIPELINE_ON - The libpq connection is in pipeline mode.
|
3766
|
+
* * PQ_PIPELINE_OFF - The libpq connection is not in pipeline mode.
|
3767
|
+
* * PQ_PIPELINE_ABORTED - The libpq connection is in pipeline mode and an error occurred while processing the current pipeline.
|
3768
|
+
* The aborted flag is cleared when PQgetResult returns a result of type PGRES_PIPELINE_SYNC.
|
3769
|
+
*
|
3770
|
+
* Available since PostgreSQL-14
|
3771
|
+
*/
|
3772
|
+
static VALUE
|
3773
|
+
pgconn_pipeline_status(VALUE self)
|
3774
|
+
{
|
3775
|
+
int res = PQpipelineStatus(pg_get_pgconn(self));
|
3776
|
+
return INT2FIX(res);
|
3777
|
+
}
|
3778
|
+
|
3779
|
+
|
3780
|
+
/*
|
3781
|
+
* call-seq:
|
3782
|
+
* conn.enter_pipeline_mode -> nil
|
3783
|
+
*
|
3784
|
+
* Causes a connection to enter pipeline mode if it is currently idle or already in pipeline mode.
|
3785
|
+
*
|
3786
|
+
* 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.
|
3787
|
+
* This function does not actually send anything to the server, it just changes the libpq connection state.
|
3788
|
+
*
|
3789
|
+
* See the {PostgreSQL documentation}[https://www.postgresql.org/docs/17/libpq-pipeline-mode.html#LIBPQ-PIPELINE-MODE].
|
3790
|
+
*
|
3791
|
+
* Available since PostgreSQL-14
|
3792
|
+
*/
|
3793
|
+
static VALUE
|
3794
|
+
pgconn_enter_pipeline_mode(VALUE self)
|
3795
|
+
{
|
3796
|
+
PGconn *conn = pg_get_pgconn(self);
|
3797
|
+
int res = PQenterPipelineMode(conn);
|
3798
|
+
if( res != 1 )
|
3799
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
|
3800
|
+
|
3801
|
+
return Qnil;
|
3802
|
+
}
|
3803
|
+
|
3804
|
+
/*
|
3805
|
+
* call-seq:
|
3806
|
+
* conn.exit_pipeline_mode -> nil
|
3807
|
+
*
|
3808
|
+
* Causes a connection to exit pipeline mode if it is currently in pipeline mode with an empty queue and no pending results.
|
3809
|
+
*
|
3810
|
+
* Takes no action if not in pipeline mode.
|
3811
|
+
* 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.
|
3812
|
+
*
|
3813
|
+
* Available since PostgreSQL-14
|
3814
|
+
*/
|
3815
|
+
static VALUE
|
3816
|
+
pgconn_exit_pipeline_mode(VALUE self)
|
3817
|
+
{
|
3818
|
+
PGconn *conn = pg_get_pgconn(self);
|
3819
|
+
int res = PQexitPipelineMode(conn);
|
3820
|
+
if( res != 1 )
|
3821
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
|
3822
|
+
|
3823
|
+
return Qnil;
|
3824
|
+
}
|
3825
|
+
|
3826
|
+
|
3827
|
+
/*
|
3828
|
+
* call-seq:
|
3829
|
+
* conn.sync_pipeline_sync -> nil
|
3830
|
+
*
|
3831
|
+
* This function has the same behavior as #async_pipeline_sync, but is implemented using the synchronous command processing API of libpq.
|
3832
|
+
* See #async_exec for the differences between the two API variants.
|
3833
|
+
* It's not recommended to use explicit sync or async variants but #pipeline_sync instead, unless you have a good reason to do so.
|
3834
|
+
*
|
3835
|
+
* Available since PostgreSQL-14
|
3836
|
+
*/
|
3837
|
+
static VALUE
|
3838
|
+
pgconn_sync_pipeline_sync(VALUE self)
|
3839
|
+
{
|
3840
|
+
PGconn *conn = pg_get_pgconn(self);
|
3841
|
+
int res = gvl_PQpipelineSync(conn);
|
3842
|
+
if( res != 1 )
|
3843
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
|
3844
|
+
|
3845
|
+
return Qnil;
|
3846
|
+
}
|
3847
|
+
|
3848
|
+
|
3849
|
+
#ifdef HAVE_PQSETCHUNKEDROWSMODE
|
3850
|
+
/*
|
3851
|
+
* call-seq:
|
3852
|
+
* conn.send_pipeline_sync -> nil
|
3853
|
+
*
|
3854
|
+
* Marks a synchronization point in a pipeline by sending a sync message without flushing the send buffer.
|
3855
|
+
*
|
3856
|
+
* This serves as the delimiter of an implicit transaction and an error recovery point.
|
3857
|
+
* Raises PG::Error if the connection is not in pipeline mode or sending a sync message failed.
|
3858
|
+
* Note that the message is not itself flushed to the server automatically; use flush if necessary.
|
3859
|
+
*
|
3860
|
+
* Available since PostgreSQL-17
|
3861
|
+
*/
|
3862
|
+
static VALUE
|
3863
|
+
pgconn_send_pipeline_sync(VALUE self)
|
3864
|
+
{
|
3865
|
+
PGconn *conn = pg_get_pgconn(self);
|
3866
|
+
int res = gvl_PQsendPipelineSync(conn);
|
3867
|
+
if( res != 1 )
|
3868
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
|
3869
|
+
|
3870
|
+
return Qnil;
|
3871
|
+
}
|
3457
3872
|
#endif
|
3458
3873
|
|
3459
3874
|
|
3875
|
+
/*
|
3876
|
+
* call-seq:
|
3877
|
+
* conn.send_flush_request -> nil
|
3878
|
+
*
|
3879
|
+
* Sends a request for the server to flush its output buffer.
|
3880
|
+
*
|
3881
|
+
* 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.
|
3882
|
+
* This function is useful to cause the server to flush its output buffer in pipeline mode without establishing a synchronization point.
|
3883
|
+
* Note that the request is not itself flushed to the server automatically; use Connection#flush if necessary.
|
3884
|
+
*
|
3885
|
+
* Available since PostgreSQL-14
|
3886
|
+
*/
|
3887
|
+
static VALUE
|
3888
|
+
pgconn_send_flush_request(VALUE self)
|
3889
|
+
{
|
3890
|
+
PGconn *conn = pg_get_pgconn(self);
|
3891
|
+
int res = PQsendFlushRequest(conn);
|
3892
|
+
if( res != 1 )
|
3893
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
|
3894
|
+
|
3895
|
+
return Qnil;
|
3896
|
+
}
|
3897
|
+
|
3898
|
+
#endif
|
3899
|
+
|
3460
3900
|
/**************************************************************************
|
3461
3901
|
* LARGE OBJECT SUPPORT
|
3462
3902
|
**************************************************************************/
|
3463
3903
|
|
3904
|
+
#define BLOCKING_BEGIN(conn) do { \
|
3905
|
+
int old_nonblocking = PQisnonblocking(conn); \
|
3906
|
+
PQsetnonblocking(conn, 0);
|
3907
|
+
|
3908
|
+
#define BLOCKING_END(th) \
|
3909
|
+
PQsetnonblocking(conn, old_nonblocking); \
|
3910
|
+
} while(0);
|
3911
|
+
|
3464
3912
|
/*
|
3465
3913
|
* call-seq:
|
3466
3914
|
* conn.lo_creat( [mode] ) -> Integer
|
@@ -3481,9 +3929,12 @@ pgconn_locreat(int argc, VALUE *argv, VALUE self)
|
|
3481
3929
|
else
|
3482
3930
|
mode = NUM2INT(nmode);
|
3483
3931
|
|
3484
|
-
|
3932
|
+
BLOCKING_BEGIN(conn)
|
3933
|
+
lo_oid = lo_creat(conn, mode);
|
3934
|
+
BLOCKING_END(conn)
|
3935
|
+
|
3485
3936
|
if (lo_oid == 0)
|
3486
|
-
|
3937
|
+
pg_raise_conn_error( rb_ePGerror, self, "lo_creat failed");
|
3487
3938
|
|
3488
3939
|
return UINT2NUM(lo_oid);
|
3489
3940
|
}
|
@@ -3504,7 +3955,7 @@ pgconn_locreate(VALUE self, VALUE in_lo_oid)
|
|
3504
3955
|
|
3505
3956
|
ret = lo_create(conn, lo_oid);
|
3506
3957
|
if (ret == InvalidOid)
|
3507
|
-
|
3958
|
+
pg_raise_conn_error( rb_ePGerror, self, "lo_create failed");
|
3508
3959
|
|
3509
3960
|
return UINT2NUM(ret);
|
3510
3961
|
}
|
@@ -3526,9 +3977,12 @@ pgconn_loimport(VALUE self, VALUE filename)
|
|
3526
3977
|
|
3527
3978
|
Check_Type(filename, T_STRING);
|
3528
3979
|
|
3529
|
-
|
3980
|
+
BLOCKING_BEGIN(conn)
|
3981
|
+
lo_oid = lo_import(conn, StringValueCStr(filename));
|
3982
|
+
BLOCKING_END(conn)
|
3983
|
+
|
3530
3984
|
if (lo_oid == 0) {
|
3531
|
-
|
3985
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
|
3532
3986
|
}
|
3533
3987
|
return UINT2NUM(lo_oid);
|
3534
3988
|
}
|
@@ -3544,12 +3998,17 @@ pgconn_loexport(VALUE self, VALUE lo_oid, VALUE filename)
|
|
3544
3998
|
{
|
3545
3999
|
PGconn *conn = pg_get_pgconn(self);
|
3546
4000
|
Oid oid;
|
4001
|
+
int ret;
|
3547
4002
|
Check_Type(filename, T_STRING);
|
3548
4003
|
|
3549
4004
|
oid = NUM2UINT(lo_oid);
|
3550
4005
|
|
3551
|
-
|
3552
|
-
|
4006
|
+
BLOCKING_BEGIN(conn)
|
4007
|
+
ret = lo_export(conn, oid, StringValueCStr(filename));
|
4008
|
+
BLOCKING_END(conn)
|
4009
|
+
|
4010
|
+
if (ret < 0) {
|
4011
|
+
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
|
3553
4012
|
}
|
3554
4013
|
return Qnil;
|
3555
4014
|
}
|
@@ -3579,8 +4038,12 @@ pgconn_loopen(int argc, VALUE *argv, VALUE self)
|
|
3579
4038
|
else
|
3580
4039
|
mode = NUM2INT(nmode);
|
3581
4040
|
|
3582
|
-
|
3583
|
-
|
4041
|
+
BLOCKING_BEGIN(conn)
|
4042
|
+
fd = lo_open(conn, lo_oid, mode);
|
4043
|
+
BLOCKING_END(conn)
|
4044
|
+
|
4045
|
+
if(fd < 0) {
|
4046
|
+
pg_raise_conn_error( rb_ePGerror, self, "can't open large object: %s", PQerrorMessage(conn));
|
3584
4047
|
}
|
3585
4048
|
return INT2FIX(fd);
|
3586
4049
|
}
|
@@ -3602,11 +4065,15 @@ pgconn_lowrite(VALUE self, VALUE in_lo_desc, VALUE buffer)
|
|
3602
4065
|
Check_Type(buffer, T_STRING);
|
3603
4066
|
|
3604
4067
|
if( RSTRING_LEN(buffer) < 0) {
|
3605
|
-
|
4068
|
+
pg_raise_conn_error( rb_ePGerror, self, "write buffer zero string");
|
3606
4069
|
}
|
3607
|
-
|
3608
|
-
|
3609
|
-
|
4070
|
+
BLOCKING_BEGIN(conn)
|
4071
|
+
n = lo_write(conn, fd, StringValuePtr(buffer),
|
4072
|
+
RSTRING_LEN(buffer));
|
4073
|
+
BLOCKING_END(conn)
|
4074
|
+
|
4075
|
+
if(n < 0) {
|
4076
|
+
pg_raise_conn_error( rb_ePGerror, self, "lo_write failed: %s", PQerrorMessage(conn));
|
3610
4077
|
}
|
3611
4078
|
|
3612
4079
|
return INT2FIX(n);
|
@@ -3629,16 +4096,17 @@ pgconn_loread(VALUE self, VALUE in_lo_desc, VALUE in_len)
|
|
3629
4096
|
VALUE str;
|
3630
4097
|
char *buffer;
|
3631
4098
|
|
3632
|
-
|
3633
|
-
|
3634
|
-
rb_raise(rb_eNoMemError, "ALLOC failed!");
|
4099
|
+
if (len < 0)
|
4100
|
+
pg_raise_conn_error( rb_ePGerror, self, "negative length %d given", len);
|
3635
4101
|
|
3636
|
-
|
3637
|
-
rb_raise(rb_ePGerror,"nagative length %d given", len);
|
3638
|
-
}
|
4102
|
+
buffer = ALLOC_N(char, len);
|
3639
4103
|
|
3640
|
-
|
3641
|
-
|
4104
|
+
BLOCKING_BEGIN(conn)
|
4105
|
+
ret = lo_read(conn, lo_desc, buffer, len);
|
4106
|
+
BLOCKING_END(conn)
|
4107
|
+
|
4108
|
+
if(ret < 0)
|
4109
|
+
pg_raise_conn_error( rb_ePGerror, self, "lo_read failed");
|
3642
4110
|
|
3643
4111
|
if(ret == 0) {
|
3644
4112
|
xfree(buffer);
|
@@ -3667,8 +4135,12 @@ pgconn_lolseek(VALUE self, VALUE in_lo_desc, VALUE offset, VALUE whence)
|
|
3667
4135
|
int lo_desc = NUM2INT(in_lo_desc);
|
3668
4136
|
int ret;
|
3669
4137
|
|
3670
|
-
|
3671
|
-
|
4138
|
+
BLOCKING_BEGIN(conn)
|
4139
|
+
ret = lo_lseek(conn, lo_desc, NUM2INT(offset), NUM2INT(whence));
|
4140
|
+
BLOCKING_END(conn)
|
4141
|
+
|
4142
|
+
if(ret < 0) {
|
4143
|
+
pg_raise_conn_error( rb_ePGerror, self, "lo_lseek failed");
|
3672
4144
|
}
|
3673
4145
|
|
3674
4146
|
return INT2FIX(ret);
|
@@ -3687,8 +4159,12 @@ pgconn_lotell(VALUE self, VALUE in_lo_desc)
|
|
3687
4159
|
PGconn *conn = pg_get_pgconn(self);
|
3688
4160
|
int lo_desc = NUM2INT(in_lo_desc);
|
3689
4161
|
|
3690
|
-
|
3691
|
-
|
4162
|
+
BLOCKING_BEGIN(conn)
|
4163
|
+
position = lo_tell(conn, lo_desc);
|
4164
|
+
BLOCKING_END(conn)
|
4165
|
+
|
4166
|
+
if(position < 0)
|
4167
|
+
pg_raise_conn_error( rb_ePGerror, self, "lo_tell failed");
|
3692
4168
|
|
3693
4169
|
return INT2FIX(position);
|
3694
4170
|
}
|
@@ -3705,9 +4181,14 @@ pgconn_lotruncate(VALUE self, VALUE in_lo_desc, VALUE in_len)
|
|
3705
4181
|
PGconn *conn = pg_get_pgconn(self);
|
3706
4182
|
int lo_desc = NUM2INT(in_lo_desc);
|
3707
4183
|
size_t len = NUM2INT(in_len);
|
4184
|
+
int ret;
|
3708
4185
|
|
3709
|
-
|
3710
|
-
|
4186
|
+
BLOCKING_BEGIN(conn)
|
4187
|
+
ret = lo_truncate(conn,lo_desc,len);
|
4188
|
+
BLOCKING_END(conn)
|
4189
|
+
|
4190
|
+
if(ret < 0)
|
4191
|
+
pg_raise_conn_error( rb_ePGerror, self, "lo_truncate failed");
|
3711
4192
|
|
3712
4193
|
return Qnil;
|
3713
4194
|
}
|
@@ -3723,9 +4204,14 @@ pgconn_loclose(VALUE self, VALUE in_lo_desc)
|
|
3723
4204
|
{
|
3724
4205
|
PGconn *conn = pg_get_pgconn(self);
|
3725
4206
|
int lo_desc = NUM2INT(in_lo_desc);
|
4207
|
+
int ret;
|
3726
4208
|
|
3727
|
-
|
3728
|
-
|
4209
|
+
BLOCKING_BEGIN(conn)
|
4210
|
+
ret = lo_close(conn,lo_desc);
|
4211
|
+
BLOCKING_END(conn)
|
4212
|
+
|
4213
|
+
if(ret < 0)
|
4214
|
+
pg_raise_conn_error( rb_ePGerror, self, "lo_close failed");
|
3729
4215
|
|
3730
4216
|
return Qnil;
|
3731
4217
|
}
|
@@ -3741,9 +4227,14 @@ pgconn_lounlink(VALUE self, VALUE in_oid)
|
|
3741
4227
|
{
|
3742
4228
|
PGconn *conn = pg_get_pgconn(self);
|
3743
4229
|
Oid oid = NUM2UINT(in_oid);
|
4230
|
+
int ret;
|
3744
4231
|
|
3745
|
-
|
3746
|
-
|
4232
|
+
BLOCKING_BEGIN(conn)
|
4233
|
+
ret = lo_unlink(conn,oid);
|
4234
|
+
BLOCKING_END(conn)
|
4235
|
+
|
4236
|
+
if(ret < 0)
|
4237
|
+
pg_raise_conn_error( rb_ePGerror, self, "lo_unlink failed");
|
3747
4238
|
|
3748
4239
|
return Qnil;
|
3749
4240
|
}
|
@@ -3800,12 +4291,13 @@ static VALUE pgconn_external_encoding(VALUE self);
|
|
3800
4291
|
static VALUE
|
3801
4292
|
pgconn_internal_encoding_set(VALUE self, VALUE enc)
|
3802
4293
|
{
|
4294
|
+
rb_check_frozen(self);
|
3803
4295
|
if (NIL_P(enc)) {
|
3804
|
-
|
4296
|
+
pgconn_sync_set_client_encoding( self, rb_usascii_str_new_cstr("SQL_ASCII") );
|
3805
4297
|
return enc;
|
3806
4298
|
}
|
3807
4299
|
else if ( TYPE(enc) == T_STRING && strcasecmp("JOHAB", StringValueCStr(enc)) == 0 ) {
|
3808
|
-
|
4300
|
+
pgconn_sync_set_client_encoding(self, rb_usascii_str_new_cstr("JOHAB"));
|
3809
4301
|
return enc;
|
3810
4302
|
}
|
3811
4303
|
else {
|
@@ -3843,16 +4335,34 @@ pgconn_external_encoding(VALUE self)
|
|
3843
4335
|
return rb_enc_from_encoding( enc );
|
3844
4336
|
}
|
3845
4337
|
|
4338
|
+
/*
|
4339
|
+
* call-seq:
|
4340
|
+
* conn.set_client_encoding( encoding )
|
4341
|
+
*
|
4342
|
+
* Sets the client encoding to the _encoding_ String.
|
4343
|
+
*/
|
4344
|
+
static VALUE
|
4345
|
+
pgconn_async_set_client_encoding(VALUE self, VALUE encname)
|
4346
|
+
{
|
4347
|
+
VALUE query_format, query;
|
4348
|
+
|
4349
|
+
rb_check_frozen(self);
|
4350
|
+
Check_Type(encname, T_STRING);
|
4351
|
+
query_format = rb_str_new_cstr("set client_encoding to '%s'");
|
4352
|
+
query = rb_funcall(query_format, rb_intern("%"), 1, encname);
|
4353
|
+
|
4354
|
+
pgconn_async_exec(1, &query, self);
|
4355
|
+
pgconn_set_internal_encoding_index( self );
|
4356
|
+
|
4357
|
+
return Qnil;
|
4358
|
+
}
|
3846
4359
|
|
3847
4360
|
static VALUE
|
3848
4361
|
pgconn_set_client_encoding_async1( VALUE args )
|
3849
4362
|
{
|
3850
4363
|
VALUE self = ((VALUE*)args)[0];
|
3851
4364
|
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);
|
4365
|
+
pgconn_async_set_client_encoding(self, encname);
|
3856
4366
|
return 0;
|
3857
4367
|
}
|
3858
4368
|
|
@@ -3867,9 +4377,9 @@ pgconn_set_client_encoding_async2( VALUE arg, VALUE ex )
|
|
3867
4377
|
|
3868
4378
|
|
3869
4379
|
static VALUE
|
3870
|
-
pgconn_set_client_encoding_async( VALUE self,
|
4380
|
+
pgconn_set_client_encoding_async( VALUE self, VALUE encname )
|
3871
4381
|
{
|
3872
|
-
VALUE args[] = { self,
|
4382
|
+
VALUE args[] = { self, encname };
|
3873
4383
|
return rb_rescue(pgconn_set_client_encoding_async1, (VALUE)&args, pgconn_set_client_encoding_async2, Qnil);
|
3874
4384
|
}
|
3875
4385
|
|
@@ -3886,16 +4396,23 @@ static VALUE
|
|
3886
4396
|
pgconn_set_default_encoding( VALUE self )
|
3887
4397
|
{
|
3888
4398
|
PGconn *conn = pg_get_pgconn( self );
|
3889
|
-
rb_encoding *
|
3890
|
-
|
3891
|
-
|
3892
|
-
if ((
|
3893
|
-
|
3894
|
-
|
3895
|
-
|
3896
|
-
|
4399
|
+
rb_encoding *rb_enc;
|
4400
|
+
|
4401
|
+
rb_check_frozen(self);
|
4402
|
+
if (( rb_enc = rb_default_internal_encoding() )) {
|
4403
|
+
rb_encoding * conn_encoding = pg_conn_enc_get( conn );
|
4404
|
+
|
4405
|
+
/* Don't set the server encoding, if it's unnecessary.
|
4406
|
+
* This is important for connection proxies, who disallow configuration settings.
|
4407
|
+
*/
|
4408
|
+
if ( conn_encoding != rb_enc ) {
|
4409
|
+
const char *encname = pg_get_rb_encoding_as_pg_encoding( rb_enc );
|
4410
|
+
if ( pgconn_set_client_encoding_async(self, rb_str_new_cstr(encname)) != 0 )
|
4411
|
+
rb_warning( "Failed to set the default_internal encoding to %s: '%s'",
|
4412
|
+
encname, PQerrorMessage(conn) );
|
4413
|
+
}
|
3897
4414
|
pgconn_set_internal_encoding_index( self );
|
3898
|
-
return rb_enc_from_encoding(
|
4415
|
+
return rb_enc_from_encoding( rb_enc );
|
3899
4416
|
} else {
|
3900
4417
|
pgconn_set_internal_encoding_index( self );
|
3901
4418
|
return Qnil;
|
@@ -3916,13 +4433,14 @@ static VALUE
|
|
3916
4433
|
pgconn_type_map_for_queries_set(VALUE self, VALUE typemap)
|
3917
4434
|
{
|
3918
4435
|
t_pg_connection *this = pg_get_connection( self );
|
4436
|
+
t_typemap *tm;
|
4437
|
+
UNUSED(tm);
|
3919
4438
|
|
3920
|
-
|
3921
|
-
|
3922
|
-
|
3923
|
-
|
3924
|
-
|
3925
|
-
this->type_map_for_queries = typemap;
|
4439
|
+
rb_check_frozen(self);
|
4440
|
+
/* Check type of method param */
|
4441
|
+
TypedData_Get_Struct(typemap, t_typemap, &pg_typemap_type, tm);
|
4442
|
+
|
4443
|
+
RB_OBJ_WRITE(self, &this->type_map_for_queries, typemap);
|
3926
4444
|
|
3927
4445
|
return typemap;
|
3928
4446
|
}
|
@@ -3956,13 +4474,12 @@ static VALUE
|
|
3956
4474
|
pgconn_type_map_for_results_set(VALUE self, VALUE typemap)
|
3957
4475
|
{
|
3958
4476
|
t_pg_connection *this = pg_get_connection( self );
|
4477
|
+
t_typemap *tm;
|
4478
|
+
UNUSED(tm);
|
3959
4479
|
|
3960
|
-
|
3961
|
-
|
3962
|
-
|
3963
|
-
}
|
3964
|
-
Check_Type(typemap, T_DATA);
|
3965
|
-
this->type_map_for_results = typemap;
|
4480
|
+
rb_check_frozen(self);
|
4481
|
+
TypedData_Get_Struct(typemap, t_typemap, &pg_typemap_type, tm);
|
4482
|
+
RB_OBJ_WRITE(self, &this->type_map_for_results, typemap);
|
3966
4483
|
|
3967
4484
|
return typemap;
|
3968
4485
|
}
|
@@ -3996,20 +4513,20 @@ pgconn_type_map_for_results_get(VALUE self)
|
|
3996
4513
|
*
|
3997
4514
|
*/
|
3998
4515
|
static VALUE
|
3999
|
-
pgconn_encoder_for_put_copy_data_set(VALUE self, VALUE
|
4516
|
+
pgconn_encoder_for_put_copy_data_set(VALUE self, VALUE encoder)
|
4000
4517
|
{
|
4001
4518
|
t_pg_connection *this = pg_get_connection( self );
|
4002
4519
|
|
4003
|
-
|
4004
|
-
|
4005
|
-
|
4006
|
-
|
4007
|
-
|
4008
|
-
|
4520
|
+
rb_check_frozen(self);
|
4521
|
+
if( encoder != Qnil ){
|
4522
|
+
t_pg_coder *co;
|
4523
|
+
UNUSED(co);
|
4524
|
+
/* Check argument type */
|
4525
|
+
TypedData_Get_Struct(encoder, t_pg_coder, &pg_coder_type, co);
|
4009
4526
|
}
|
4010
|
-
this->encoder_for_put_copy_data
|
4527
|
+
RB_OBJ_WRITE(self, &this->encoder_for_put_copy_data, encoder);
|
4011
4528
|
|
4012
|
-
return
|
4529
|
+
return encoder;
|
4013
4530
|
}
|
4014
4531
|
|
4015
4532
|
/*
|
@@ -4045,20 +4562,20 @@ pgconn_encoder_for_put_copy_data_get(VALUE self)
|
|
4045
4562
|
*
|
4046
4563
|
*/
|
4047
4564
|
static VALUE
|
4048
|
-
pgconn_decoder_for_get_copy_data_set(VALUE self, VALUE
|
4565
|
+
pgconn_decoder_for_get_copy_data_set(VALUE self, VALUE decoder)
|
4049
4566
|
{
|
4050
4567
|
t_pg_connection *this = pg_get_connection( self );
|
4051
4568
|
|
4052
|
-
|
4053
|
-
|
4054
|
-
|
4055
|
-
|
4056
|
-
|
4057
|
-
|
4569
|
+
rb_check_frozen(self);
|
4570
|
+
if( decoder != Qnil ){
|
4571
|
+
t_pg_coder *co;
|
4572
|
+
UNUSED(co);
|
4573
|
+
/* Check argument type */
|
4574
|
+
TypedData_Get_Struct(decoder, t_pg_coder, &pg_coder_type, co);
|
4058
4575
|
}
|
4059
|
-
this->decoder_for_get_copy_data
|
4576
|
+
RB_OBJ_WRITE(self, &this->decoder_for_get_copy_data, decoder);
|
4060
4577
|
|
4061
|
-
return
|
4578
|
+
return decoder;
|
4062
4579
|
}
|
4063
4580
|
|
4064
4581
|
/*
|
@@ -4102,6 +4619,7 @@ pgconn_field_name_type_set(VALUE self, VALUE sym)
|
|
4102
4619
|
{
|
4103
4620
|
t_pg_connection *this = pg_get_connection( self );
|
4104
4621
|
|
4622
|
+
rb_check_frozen(self);
|
4105
4623
|
this->flags &= ~PG_RESULT_FIELD_NAMES_MASK;
|
4106
4624
|
if( sym == sym_symbol ) this->flags |= PG_RESULT_FIELD_NAMES_SYMBOL;
|
4107
4625
|
else if ( sym == sym_static_symbol ) this->flags |= PG_RESULT_FIELD_NAMES_STATIC_SYMBOL;
|
@@ -4138,9 +4656,10 @@ pgconn_field_name_type_get(VALUE self)
|
|
4138
4656
|
* Document-class: PG::Connection
|
4139
4657
|
*/
|
4140
4658
|
void
|
4141
|
-
init_pg_connection()
|
4659
|
+
init_pg_connection(void)
|
4142
4660
|
{
|
4143
4661
|
s_id_encode = rb_intern("encode");
|
4662
|
+
s_id_autoclose_set = rb_intern("autoclose=");
|
4144
4663
|
sym_type = ID2SYM(rb_intern("type"));
|
4145
4664
|
sym_format = ID2SYM(rb_intern("format"));
|
4146
4665
|
sym_value = ID2SYM(rb_intern("value"));
|
@@ -4156,10 +4675,6 @@ init_pg_connection()
|
|
4156
4675
|
/****** PG::Connection CLASS METHODS ******/
|
4157
4676
|
rb_define_alloc_func( rb_cPGconn, pgconn_s_allocate );
|
4158
4677
|
|
4159
|
-
SINGLETON_ALIAS(rb_cPGconn, "connect", "new");
|
4160
|
-
SINGLETON_ALIAS(rb_cPGconn, "open", "new");
|
4161
|
-
SINGLETON_ALIAS(rb_cPGconn, "setdb", "new");
|
4162
|
-
SINGLETON_ALIAS(rb_cPGconn, "setdblogin", "new");
|
4163
4678
|
rb_define_singleton_method(rb_cPGconn, "escape_string", pgconn_s_escape, 1);
|
4164
4679
|
SINGLETON_ALIAS(rb_cPGconn, "escape", "escape_string");
|
4165
4680
|
rb_define_singleton_method(rb_cPGconn, "escape_bytea", pgconn_s_escape_bytea, 1);
|
@@ -4168,15 +4683,17 @@ init_pg_connection()
|
|
4168
4683
|
rb_define_singleton_method(rb_cPGconn, "quote_ident", pgconn_s_quote_ident, 1);
|
4169
4684
|
rb_define_singleton_method(rb_cPGconn, "connect_start", pgconn_s_connect_start, -1);
|
4170
4685
|
rb_define_singleton_method(rb_cPGconn, "conndefaults", pgconn_s_conndefaults, 0);
|
4171
|
-
rb_define_singleton_method(rb_cPGconn, "
|
4686
|
+
rb_define_singleton_method(rb_cPGconn, "conninfo_parse", pgconn_s_conninfo_parse, 1);
|
4687
|
+
rb_define_singleton_method(rb_cPGconn, "sync_ping", pgconn_s_sync_ping, -1);
|
4688
|
+
rb_define_singleton_method(rb_cPGconn, "sync_connect", pgconn_s_sync_connect, -1);
|
4172
4689
|
|
4173
4690
|
/****** PG::Connection INSTANCE METHODS: Connection Control ******/
|
4174
|
-
rb_define_method(rb_cPGconn, "initialize", pgconn_init, -1);
|
4175
4691
|
rb_define_method(rb_cPGconn, "connect_poll", pgconn_connect_poll, 0);
|
4176
4692
|
rb_define_method(rb_cPGconn, "finish", pgconn_finish, 0);
|
4177
4693
|
rb_define_method(rb_cPGconn, "finished?", pgconn_finished_p, 0);
|
4178
|
-
rb_define_method(rb_cPGconn, "
|
4694
|
+
rb_define_method(rb_cPGconn, "sync_reset", pgconn_sync_reset, 0);
|
4179
4695
|
rb_define_method(rb_cPGconn, "reset_start", pgconn_reset_start, 0);
|
4696
|
+
rb_define_private_method(rb_cPGconn, "reset_start2", pgconn_reset_start2, 1);
|
4180
4697
|
rb_define_method(rb_cPGconn, "reset_poll", pgconn_reset_poll, 0);
|
4181
4698
|
rb_define_alias(rb_cPGconn, "close", "finish");
|
4182
4699
|
|
@@ -4185,11 +4702,12 @@ init_pg_connection()
|
|
4185
4702
|
rb_define_method(rb_cPGconn, "user", pgconn_user, 0);
|
4186
4703
|
rb_define_method(rb_cPGconn, "pass", pgconn_pass, 0);
|
4187
4704
|
rb_define_method(rb_cPGconn, "host", pgconn_host, 0);
|
4705
|
+
#if defined(HAVE_PQRESULTMEMORYSIZE)
|
4706
|
+
rb_define_method(rb_cPGconn, "hostaddr", pgconn_hostaddr, 0);
|
4707
|
+
#endif
|
4188
4708
|
rb_define_method(rb_cPGconn, "port", pgconn_port, 0);
|
4189
4709
|
rb_define_method(rb_cPGconn, "tty", pgconn_tty, 0);
|
4190
|
-
#ifdef HAVE_PQCONNINFO
|
4191
4710
|
rb_define_method(rb_cPGconn, "conninfo", pgconn_conninfo, 0);
|
4192
|
-
#endif
|
4193
4711
|
rb_define_method(rb_cPGconn, "options", pgconn_options, 0);
|
4194
4712
|
rb_define_method(rb_cPGconn, "status", pgconn_status, 0);
|
4195
4713
|
rb_define_method(rb_cPGconn, "transaction_status", pgconn_transaction_status, 0);
|
@@ -4200,17 +4718,24 @@ init_pg_connection()
|
|
4200
4718
|
rb_define_method(rb_cPGconn, "socket", pgconn_socket, 0);
|
4201
4719
|
rb_define_method(rb_cPGconn, "socket_io", pgconn_socket_io, 0);
|
4202
4720
|
rb_define_method(rb_cPGconn, "backend_pid", pgconn_backend_pid, 0);
|
4721
|
+
#ifndef HAVE_PQSETCHUNKEDROWSMODE
|
4722
|
+
rb_define_method(rb_cPGconn, "backend_key", pgconn_backend_key, 0);
|
4723
|
+
#endif
|
4203
4724
|
rb_define_method(rb_cPGconn, "connection_needs_password", pgconn_connection_needs_password, 0);
|
4204
4725
|
rb_define_method(rb_cPGconn, "connection_used_password", pgconn_connection_used_password, 0);
|
4205
4726
|
/* rb_define_method(rb_cPGconn, "getssl", pgconn_getssl, 0); */
|
4206
4727
|
|
4207
4728
|
/****** PG::Connection INSTANCE METHODS: Command Execution ******/
|
4208
|
-
rb_define_method(rb_cPGconn, "sync_exec",
|
4209
|
-
rb_define_method(rb_cPGconn, "sync_exec_params",
|
4210
|
-
rb_define_method(rb_cPGconn, "sync_prepare",
|
4211
|
-
rb_define_method(rb_cPGconn, "sync_exec_prepared",
|
4212
|
-
rb_define_method(rb_cPGconn, "sync_describe_prepared",
|
4213
|
-
rb_define_method(rb_cPGconn, "sync_describe_portal",
|
4729
|
+
rb_define_method(rb_cPGconn, "sync_exec", pgconn_sync_exec, -1);
|
4730
|
+
rb_define_method(rb_cPGconn, "sync_exec_params", pgconn_sync_exec_params, -1);
|
4731
|
+
rb_define_method(rb_cPGconn, "sync_prepare", pgconn_sync_prepare, -1);
|
4732
|
+
rb_define_method(rb_cPGconn, "sync_exec_prepared", pgconn_sync_exec_prepared, -1);
|
4733
|
+
rb_define_method(rb_cPGconn, "sync_describe_prepared", pgconn_sync_describe_prepared, 1);
|
4734
|
+
rb_define_method(rb_cPGconn, "sync_describe_portal", pgconn_sync_describe_portal, 1);
|
4735
|
+
#ifdef HAVE_PQSETCHUNKEDROWSMODE
|
4736
|
+
rb_define_method(rb_cPGconn, "sync_close_prepared", pgconn_sync_close_prepared, 1);
|
4737
|
+
rb_define_method(rb_cPGconn, "sync_close_portal", pgconn_sync_close_portal, 1);
|
4738
|
+
#endif
|
4214
4739
|
|
4215
4740
|
rb_define_method(rb_cPGconn, "exec", pgconn_async_exec, -1);
|
4216
4741
|
rb_define_method(rb_cPGconn, "exec_params", pgconn_async_exec_params, -1);
|
@@ -4218,6 +4743,10 @@ init_pg_connection()
|
|
4218
4743
|
rb_define_method(rb_cPGconn, "exec_prepared", pgconn_async_exec_prepared, -1);
|
4219
4744
|
rb_define_method(rb_cPGconn, "describe_prepared", pgconn_async_describe_prepared, 1);
|
4220
4745
|
rb_define_method(rb_cPGconn, "describe_portal", pgconn_async_describe_portal, 1);
|
4746
|
+
#ifdef HAVE_PQSETCHUNKEDROWSMODE
|
4747
|
+
rb_define_method(rb_cPGconn, "close_prepared", pgconn_async_close_prepared, 1);
|
4748
|
+
rb_define_method(rb_cPGconn, "close_portal", pgconn_async_close_portal, 1);
|
4749
|
+
#endif
|
4221
4750
|
|
4222
4751
|
rb_define_alias(rb_cPGconn, "async_exec", "exec");
|
4223
4752
|
rb_define_alias(rb_cPGconn, "async_query", "async_exec");
|
@@ -4226,6 +4755,10 @@ init_pg_connection()
|
|
4226
4755
|
rb_define_alias(rb_cPGconn, "async_exec_prepared", "exec_prepared");
|
4227
4756
|
rb_define_alias(rb_cPGconn, "async_describe_prepared", "describe_prepared");
|
4228
4757
|
rb_define_alias(rb_cPGconn, "async_describe_portal", "describe_portal");
|
4758
|
+
#ifdef HAVE_PQSETCHUNKEDROWSMODE
|
4759
|
+
rb_define_alias(rb_cPGconn, "async_close_prepared", "close_prepared");
|
4760
|
+
rb_define_alias(rb_cPGconn, "async_close_portal", "close_portal");
|
4761
|
+
#endif
|
4229
4762
|
|
4230
4763
|
rb_define_method(rb_cPGconn, "make_empty_pgresult", pgconn_make_empty_pgresult, 1);
|
4231
4764
|
rb_define_method(rb_cPGconn, "escape_string", pgconn_s_escape, 1);
|
@@ -4235,6 +4768,9 @@ init_pg_connection()
|
|
4235
4768
|
rb_define_method(rb_cPGconn, "escape_bytea", pgconn_s_escape_bytea, 1);
|
4236
4769
|
rb_define_method(rb_cPGconn, "unescape_bytea", pgconn_s_unescape_bytea, 1);
|
4237
4770
|
rb_define_method(rb_cPGconn, "set_single_row_mode", pgconn_set_single_row_mode, 0);
|
4771
|
+
#ifdef HAVE_PQSETCHUNKEDROWSMODE
|
4772
|
+
rb_define_method(rb_cPGconn, "set_chunked_rows_mode", pgconn_set_chunked_rows_mode, 1);
|
4773
|
+
#endif
|
4238
4774
|
|
4239
4775
|
/****** PG::Connection INSTANCE METHODS: Asynchronous Command Processing ******/
|
4240
4776
|
rb_define_method(rb_cPGconn, "send_query", pgconn_send_query, -1);
|
@@ -4243,31 +4779,32 @@ init_pg_connection()
|
|
4243
4779
|
rb_define_method(rb_cPGconn, "send_query_prepared", pgconn_send_query_prepared, -1);
|
4244
4780
|
rb_define_method(rb_cPGconn, "send_describe_prepared", pgconn_send_describe_prepared, 1);
|
4245
4781
|
rb_define_method(rb_cPGconn, "send_describe_portal", pgconn_send_describe_portal, 1);
|
4246
|
-
rb_define_method(rb_cPGconn, "
|
4782
|
+
rb_define_method(rb_cPGconn, "sync_get_result", pgconn_sync_get_result, 0);
|
4247
4783
|
rb_define_method(rb_cPGconn, "consume_input", pgconn_consume_input, 0);
|
4248
4784
|
rb_define_method(rb_cPGconn, "is_busy", pgconn_is_busy, 0);
|
4249
|
-
rb_define_method(rb_cPGconn, "
|
4250
|
-
rb_define_method(rb_cPGconn, "
|
4251
|
-
|
4252
|
-
rb_define_method(rb_cPGconn, "flush",
|
4785
|
+
rb_define_method(rb_cPGconn, "sync_setnonblocking", pgconn_sync_setnonblocking, 1);
|
4786
|
+
rb_define_method(rb_cPGconn, "sync_isnonblocking", pgconn_sync_isnonblocking, 0);
|
4787
|
+
rb_define_method(rb_cPGconn, "sync_flush", pgconn_sync_flush, 0);
|
4788
|
+
rb_define_method(rb_cPGconn, "flush", pgconn_async_flush, 0);
|
4789
|
+
rb_define_alias(rb_cPGconn, "async_flush", "flush");
|
4253
4790
|
rb_define_method(rb_cPGconn, "discard_results", pgconn_discard_results, 0);
|
4254
4791
|
|
4255
4792
|
/****** PG::Connection INSTANCE METHODS: Cancelling Queries in Progress ******/
|
4256
|
-
|
4793
|
+
#ifndef HAVE_PQSETCHUNKEDROWSMODE
|
4794
|
+
rb_define_method(rb_cPGconn, "sync_cancel", pgconn_sync_cancel, 0);
|
4795
|
+
#endif
|
4257
4796
|
|
4258
4797
|
/****** PG::Connection INSTANCE METHODS: NOTIFY ******/
|
4259
4798
|
rb_define_method(rb_cPGconn, "notifies", pgconn_notifies, 0);
|
4260
4799
|
|
4261
4800
|
/****** PG::Connection INSTANCE METHODS: COPY ******/
|
4262
|
-
rb_define_method(rb_cPGconn, "
|
4263
|
-
rb_define_method(rb_cPGconn, "
|
4264
|
-
rb_define_method(rb_cPGconn, "
|
4801
|
+
rb_define_method(rb_cPGconn, "sync_put_copy_data", pgconn_sync_put_copy_data, -1);
|
4802
|
+
rb_define_method(rb_cPGconn, "sync_put_copy_end", pgconn_sync_put_copy_end, -1);
|
4803
|
+
rb_define_method(rb_cPGconn, "sync_get_copy_data", pgconn_sync_get_copy_data, -1);
|
4265
4804
|
|
4266
4805
|
/****** PG::Connection INSTANCE METHODS: Control Functions ******/
|
4267
4806
|
rb_define_method(rb_cPGconn, "set_error_verbosity", pgconn_set_error_verbosity, 1);
|
4268
|
-
#ifdef HAVE_PQRESULTVERBOSEERRORMESSAGE
|
4269
4807
|
rb_define_method(rb_cPGconn, "set_error_context_visibility", pgconn_set_error_context_visibility, 1 );
|
4270
|
-
#endif
|
4271
4808
|
rb_define_method(rb_cPGconn, "trace", pgconn_trace, 1);
|
4272
4809
|
rb_define_method(rb_cPGconn, "untrace", pgconn_untrace, 0);
|
4273
4810
|
|
@@ -4277,22 +4814,33 @@ init_pg_connection()
|
|
4277
4814
|
|
4278
4815
|
/****** PG::Connection INSTANCE METHODS: Other ******/
|
4279
4816
|
rb_define_method(rb_cPGconn, "get_client_encoding", pgconn_get_client_encoding, 0);
|
4280
|
-
rb_define_method(rb_cPGconn, "
|
4817
|
+
rb_define_method(rb_cPGconn, "sync_set_client_encoding", pgconn_sync_set_client_encoding, 1);
|
4818
|
+
rb_define_method(rb_cPGconn, "set_client_encoding", pgconn_async_set_client_encoding, 1);
|
4819
|
+
rb_define_alias(rb_cPGconn, "async_set_client_encoding", "set_client_encoding");
|
4281
4820
|
rb_define_alias(rb_cPGconn, "client_encoding=", "set_client_encoding");
|
4282
|
-
rb_define_method(rb_cPGconn, "transaction", pgconn_transaction, 0);
|
4283
4821
|
rb_define_method(rb_cPGconn, "block", pgconn_block, -1);
|
4822
|
+
rb_define_private_method(rb_cPGconn, "flush_data=", pgconn_flush_data_set, 1);
|
4284
4823
|
rb_define_method(rb_cPGconn, "wait_for_notify", pgconn_wait_for_notify, -1);
|
4285
4824
|
rb_define_alias(rb_cPGconn, "notifies_wait", "wait_for_notify");
|
4286
4825
|
rb_define_method(rb_cPGconn, "quote_ident", pgconn_s_quote_ident, 1);
|
4287
|
-
rb_define_method(rb_cPGconn, "
|
4288
|
-
|
4289
|
-
|
4290
|
-
|
4826
|
+
rb_define_method(rb_cPGconn, "sync_get_last_result", pgconn_sync_get_last_result, 0);
|
4827
|
+
rb_define_method(rb_cPGconn, "get_last_result", pgconn_async_get_last_result, 0);
|
4828
|
+
rb_define_alias(rb_cPGconn, "async_get_last_result", "get_last_result");
|
4829
|
+
rb_define_method(rb_cPGconn, "sync_encrypt_password", pgconn_sync_encrypt_password, -1);
|
4291
4830
|
|
4292
|
-
#ifdef HAVE_PQSSLATTRIBUTE
|
4293
4831
|
rb_define_method(rb_cPGconn, "ssl_in_use?", pgconn_ssl_in_use, 0);
|
4294
4832
|
rb_define_method(rb_cPGconn, "ssl_attribute", pgconn_ssl_attribute, 1);
|
4295
4833
|
rb_define_method(rb_cPGconn, "ssl_attribute_names", pgconn_ssl_attribute_names, 0);
|
4834
|
+
|
4835
|
+
#ifdef HAVE_PQENTERPIPELINEMODE
|
4836
|
+
rb_define_method(rb_cPGconn, "pipeline_status", pgconn_pipeline_status, 0);
|
4837
|
+
rb_define_method(rb_cPGconn, "enter_pipeline_mode", pgconn_enter_pipeline_mode, 0);
|
4838
|
+
rb_define_method(rb_cPGconn, "exit_pipeline_mode", pgconn_exit_pipeline_mode, 0);
|
4839
|
+
rb_define_method(rb_cPGconn, "sync_pipeline_sync", pgconn_sync_pipeline_sync, 0);
|
4840
|
+
rb_define_method(rb_cPGconn, "send_flush_request", pgconn_send_flush_request, 0);
|
4841
|
+
#ifdef HAVE_PQSETCHUNKEDROWSMODE
|
4842
|
+
rb_define_method(rb_cPGconn, "send_pipeline_sync", pgconn_send_pipeline_sync, 0);
|
4843
|
+
#endif
|
4296
4844
|
#endif
|
4297
4845
|
|
4298
4846
|
/****** PG::Connection INSTANCE METHODS: Large Object Support ******/
|