pg 1.0.0 → 1.1.0.pre20180730144600
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.tar.gz.sig +0 -0
- data/ChangeLog +0 -6595
- data/History.rdoc +52 -0
- data/README.rdoc +11 -0
- data/Rakefile +1 -1
- data/Rakefile.cross +1 -1
- data/ext/errorcodes.rb +1 -1
- data/ext/extconf.rb +2 -0
- data/ext/pg.c +3 -2
- data/ext/pg.h +33 -5
- data/ext/pg_binary_decoder.c +69 -6
- data/ext/pg_binary_encoder.c +1 -1
- data/ext/pg_coder.c +52 -3
- data/ext/pg_connection.c +290 -103
- data/ext/pg_copy_coder.c +10 -5
- data/ext/pg_result.c +339 -113
- data/ext/pg_text_decoder.c +597 -37
- data/ext/pg_text_encoder.c +1 -1
- data/ext/pg_tuple.c +540 -0
- data/ext/pg_type_map.c +1 -1
- data/ext/pg_type_map_all_strings.c +1 -1
- data/ext/pg_type_map_by_class.c +1 -1
- data/ext/pg_type_map_by_column.c +1 -1
- data/ext/pg_type_map_by_mri_type.c +1 -1
- data/ext/pg_type_map_by_oid.c +1 -1
- data/ext/pg_type_map_in_ruby.c +1 -1
- data/ext/util.c +6 -6
- data/ext/util.h +2 -2
- data/lib/pg.rb +5 -3
- data/lib/pg/basic_type_mapping.rb +40 -7
- data/lib/pg/coder.rb +1 -1
- data/lib/pg/connection.rb +20 -1
- data/lib/pg/constants.rb +1 -1
- data/lib/pg/exceptions.rb +1 -1
- data/lib/pg/result.rb +1 -1
- data/lib/pg/text_decoder.rb +19 -23
- data/lib/pg/text_encoder.rb +35 -1
- data/lib/pg/type_map_by_column.rb +1 -1
- data/spec/helpers.rb +39 -7
- data/spec/pg/basic_type_mapping_spec.rb +230 -27
- data/spec/pg/connection_spec.rb +116 -77
- data/spec/pg/result_spec.rb +46 -11
- data/spec/pg/type_map_by_class_spec.rb +1 -1
- data/spec/pg/type_map_by_column_spec.rb +1 -1
- data/spec/pg/type_map_by_mri_type_spec.rb +1 -1
- data/spec/pg/type_map_by_oid_spec.rb +1 -1
- data/spec/pg/type_map_in_ruby_spec.rb +1 -1
- data/spec/pg/type_map_spec.rb +1 -1
- data/spec/pg/type_spec.rb +177 -11
- data/spec/pg_spec.rb +1 -1
- metadata +24 -28
- metadata.gz.sig +0 -0
data/ext/pg_connection.c
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
/*
|
2
2
|
* pg_connection.c - PG::Connection class extension
|
3
|
-
* $Id
|
3
|
+
* $Id$
|
4
4
|
*
|
5
5
|
*/
|
6
6
|
|
@@ -198,6 +198,8 @@ pgconn_s_allocate( VALUE klass )
|
|
198
198
|
this->decoder_for_get_copy_data = Qnil;
|
199
199
|
this->trace_stream = Qnil;
|
200
200
|
this->external_encoding = Qnil;
|
201
|
+
this->socket = -1;
|
202
|
+
this->guess_result_memsize = 1;
|
201
203
|
|
202
204
|
return self;
|
203
205
|
}
|
@@ -270,7 +272,6 @@ pgconn_init(int argc, VALUE *argv, VALUE self)
|
|
270
272
|
this = pg_get_connection( self );
|
271
273
|
conninfo = rb_funcall2( rb_cPGconn, rb_intern("parse_connect_args"), argc, argv );
|
272
274
|
this->pgconn = gvl_PQconnectdb(StringValueCStr(conninfo));
|
273
|
-
|
274
275
|
if(this->pgconn == NULL)
|
275
276
|
rb_raise(rb_ePGerror, "PQconnectdb() unable to allocate structure");
|
276
277
|
|
@@ -280,6 +281,10 @@ pgconn_init(int argc, VALUE *argv, VALUE self)
|
|
280
281
|
rb_exc_raise(error);
|
281
282
|
}
|
282
283
|
|
284
|
+
this->socket = PQsocket( this->pgconn );
|
285
|
+
if ( this->socket < 0 )
|
286
|
+
rb_raise(rb_eConnectionBad, "PQsocket() can't get socket descriptor");
|
287
|
+
|
283
288
|
pgconn_set_default_encoding( self );
|
284
289
|
|
285
290
|
if (rb_block_given_p()) {
|
@@ -330,6 +335,10 @@ pgconn_s_connect_start( int argc, VALUE *argv, VALUE klass )
|
|
330
335
|
rb_exc_raise(error);
|
331
336
|
}
|
332
337
|
|
338
|
+
this->socket = PQsocket( this->pgconn );
|
339
|
+
if ( this->socket < 0 )
|
340
|
+
rb_raise(rb_eConnectionBad, "PQsocket() can't get socket descriptor");
|
341
|
+
|
333
342
|
if ( rb_block_given_p() ) {
|
334
343
|
return rb_ensure( rb_yield, rb_conn, pgconn_finish, rb_conn );
|
335
344
|
}
|
@@ -899,10 +908,8 @@ pgconn_socket_io(VALUE self)
|
|
899
908
|
|
900
909
|
socket_io = rb_funcall( rb_cIO, rb_intern("for_fd"), 1, INT2NUM(ruby_sd) );
|
901
910
|
|
902
|
-
/* Disable autoclose feature
|
903
|
-
|
904
|
-
rb_funcall( socket_io, id_autoclose, 1, Qfalse );
|
905
|
-
}
|
911
|
+
/* Disable autoclose feature */
|
912
|
+
rb_funcall( socket_io, id_autoclose, 1, Qfalse );
|
906
913
|
|
907
914
|
this->socket_io = socket_io;
|
908
915
|
}
|
@@ -973,9 +980,9 @@ static VALUE pgconn_exec_params( int, VALUE *, VALUE );
|
|
973
980
|
* and the PG::Result object will automatically be cleared when the block terminates.
|
974
981
|
* In this instance, <code>conn.exec</code> returns the value of the block.
|
975
982
|
*
|
976
|
-
* #
|
983
|
+
* #sync_exec is implemented on the synchronous command processing API of libpq, whereas
|
977
984
|
* #async_exec is implemented on the asynchronous API.
|
978
|
-
* #
|
985
|
+
* #sync_exec is somewhat faster that #async_exec, but blocks any signals to be processed until
|
979
986
|
* the query is finished. This is most notably visible by a delayed reaction to Control+C.
|
980
987
|
* Both methods ensure that other threads can process while waiting for the server to
|
981
988
|
* complete the request.
|
@@ -987,8 +994,8 @@ pgconn_exec(int argc, VALUE *argv, VALUE self)
|
|
987
994
|
PGresult *result = NULL;
|
988
995
|
VALUE rb_pgresult;
|
989
996
|
|
990
|
-
/* If called with no parameters, use PQexec */
|
991
|
-
if ( argc == 1 ) {
|
997
|
+
/* If called with no or nil parameters, use PQexec for compatibility */
|
998
|
+
if ( argc == 1 || (argc >= 2 && argc <= 4 && NIL_P(argv[1]) )) {
|
992
999
|
VALUE query_str = argv[0];
|
993
1000
|
|
994
1001
|
result = gvl_PQexec(conn, pg_cstr_enc(query_str, ENCODING_GET(self)));
|
@@ -999,11 +1006,10 @@ pgconn_exec(int argc, VALUE *argv, VALUE self)
|
|
999
1006
|
}
|
1000
1007
|
return rb_pgresult;
|
1001
1008
|
}
|
1009
|
+
rb_warning("forwarding exec to exec_params is deprecated");
|
1002
1010
|
|
1003
1011
|
/* Otherwise, just call #exec_params instead for backward-compatibility */
|
1004
|
-
|
1005
|
-
return pgconn_exec_params( argc, argv, self );
|
1006
|
-
}
|
1012
|
+
return pgconn_exec_params( argc, argv, self );
|
1007
1013
|
|
1008
1014
|
}
|
1009
1015
|
|
@@ -1306,14 +1312,16 @@ pgconn_exec_params( int argc, VALUE *argv, VALUE self )
|
|
1306
1312
|
int resultFormat;
|
1307
1313
|
struct query_params_data paramsData = { ENCODING_GET(self) };
|
1308
1314
|
|
1315
|
+
/* For compatibility we accept 1 to 4 parameters */
|
1309
1316
|
rb_scan_args(argc, argv, "13", &command, ¶msData.params, &in_res_fmt, ¶msData.typemap);
|
1310
1317
|
paramsData.with_types = 1;
|
1311
1318
|
|
1312
1319
|
/*
|
1313
|
-
*
|
1314
|
-
*
|
1320
|
+
* For backward compatibility no or +nil+ for the second parameter
|
1321
|
+
* is passed to #exec
|
1315
1322
|
*/
|
1316
1323
|
if ( NIL_P(paramsData.params) ) {
|
1324
|
+
rb_warning("forwarding exec_params to exec is deprecated");
|
1317
1325
|
return pgconn_exec( 1, argv, self );
|
1318
1326
|
}
|
1319
1327
|
pgconn_query_assign_typemap( self, ¶msData );
|
@@ -1812,15 +1820,54 @@ pgconn_set_single_row_mode(VALUE self)
|
|
1812
1820
|
return self;
|
1813
1821
|
}
|
1814
1822
|
|
1823
|
+
static VALUE pgconn_send_query_params(int argc, VALUE *argv, VALUE self);
|
1824
|
+
|
1815
1825
|
/*
|
1816
1826
|
* call-seq:
|
1817
|
-
* conn.send_query(sql
|
1827
|
+
* conn.send_query(sql) -> nil
|
1818
1828
|
*
|
1819
1829
|
* Sends SQL query request specified by _sql_ to PostgreSQL for
|
1820
1830
|
* asynchronous processing, and immediately returns.
|
1821
1831
|
* On failure, it raises a PG::Error.
|
1822
1832
|
*
|
1823
|
-
*
|
1833
|
+
* For backward compatibility, if you pass more than one parameter to this method,
|
1834
|
+
* it will call #send_query_params for you. New code should explicitly use #send_query_params if
|
1835
|
+
* argument placeholders are used.
|
1836
|
+
*
|
1837
|
+
*/
|
1838
|
+
static VALUE
|
1839
|
+
pgconn_send_query(int argc, VALUE *argv, VALUE self)
|
1840
|
+
{
|
1841
|
+
PGconn *conn = pg_get_pgconn(self);
|
1842
|
+
VALUE error;
|
1843
|
+
|
1844
|
+
/* If called with no or nil parameters, use PQexec for compatibility */
|
1845
|
+
if ( argc == 1 || (argc >= 2 && argc <= 4 && NIL_P(argv[1]) )) {
|
1846
|
+
if(gvl_PQsendQuery(conn, pg_cstr_enc(argv[0], ENCODING_GET(self))) == 0) {
|
1847
|
+
error = rb_exc_new2(rb_eUnableToSend, PQerrorMessage(conn));
|
1848
|
+
rb_iv_set(error, "@connection", self);
|
1849
|
+
rb_exc_raise(error);
|
1850
|
+
}
|
1851
|
+
return Qnil;
|
1852
|
+
}
|
1853
|
+
|
1854
|
+
rb_warning("forwarding async_exec to async_exec_params and send_query to send_query_params is deprecated");
|
1855
|
+
|
1856
|
+
/* If called with parameters, and optionally result_format,
|
1857
|
+
* use PQsendQueryParams
|
1858
|
+
*/
|
1859
|
+
return pgconn_send_query_params( argc, argv, self);
|
1860
|
+
}
|
1861
|
+
|
1862
|
+
/*
|
1863
|
+
* call-seq:
|
1864
|
+
* conn.send_query_params(sql, params [, result_format [, type_map ]] ) -> nil
|
1865
|
+
*
|
1866
|
+
* Sends SQL query request specified by _sql_ to PostgreSQL for
|
1867
|
+
* asynchronous processing, and immediately returns.
|
1868
|
+
* On failure, it raises a PG::Error.
|
1869
|
+
*
|
1870
|
+
* +params+ is an array of the bind parameters for the SQL query.
|
1824
1871
|
* Each element of the +params+ array may be either:
|
1825
1872
|
* a hash of the form:
|
1826
1873
|
* {:value => String (value of bind parameter)
|
@@ -1851,7 +1898,7 @@ pgconn_set_single_row_mode(VALUE self)
|
|
1851
1898
|
*
|
1852
1899
|
*/
|
1853
1900
|
static VALUE
|
1854
|
-
|
1901
|
+
pgconn_send_query_params(int argc, VALUE *argv, VALUE self)
|
1855
1902
|
{
|
1856
1903
|
PGconn *conn = pg_get_pgconn(self);
|
1857
1904
|
int result;
|
@@ -1861,23 +1908,9 @@ pgconn_send_query(int argc, VALUE *argv, VALUE self)
|
|
1861
1908
|
int resultFormat;
|
1862
1909
|
struct query_params_data paramsData = { ENCODING_GET(self) };
|
1863
1910
|
|
1864
|
-
rb_scan_args(argc, argv, "
|
1911
|
+
rb_scan_args(argc, argv, "22", &command, ¶msData.params, &in_res_fmt, ¶msData.typemap);
|
1865
1912
|
paramsData.with_types = 1;
|
1866
1913
|
|
1867
|
-
/* If called with no parameters, use PQsendQuery */
|
1868
|
-
if(NIL_P(paramsData.params)) {
|
1869
|
-
if(gvl_PQsendQuery(conn, pg_cstr_enc(command, paramsData.enc_idx)) == 0) {
|
1870
|
-
error = rb_exc_new2(rb_eUnableToSend, PQerrorMessage(conn));
|
1871
|
-
rb_iv_set(error, "@connection", self);
|
1872
|
-
rb_exc_raise(error);
|
1873
|
-
}
|
1874
|
-
return Qnil;
|
1875
|
-
}
|
1876
|
-
|
1877
|
-
/* If called with parameters, and optionally result_format,
|
1878
|
-
* use PQsendQueryParams
|
1879
|
-
*/
|
1880
|
-
|
1881
1914
|
pgconn_query_assign_typemap( self, ¶msData );
|
1882
1915
|
resultFormat = NIL_P(in_res_fmt) ? 0 : NUM2INT(in_res_fmt);
|
1883
1916
|
nParams = alloc_query_params( ¶msData );
|
@@ -2298,28 +2331,21 @@ pgconn_notifies(VALUE self)
|
|
2298
2331
|
#if defined( _WIN32 )
|
2299
2332
|
/*
|
2300
2333
|
* On Windows, use platform-specific strategies to wait for the socket
|
2301
|
-
* instead of
|
2334
|
+
* instead of rb_wait_for_single_fd().
|
2302
2335
|
*/
|
2303
2336
|
|
2304
2337
|
int rb_w32_wait_events( HANDLE *events, int num, DWORD timeout );
|
2305
2338
|
|
2306
|
-
/* If WIN32 and Ruby 1.9 do not use rb_thread_select() which sometimes hangs
|
2307
|
-
* and does not wait (nor sleep) any time even if timeout is given.
|
2308
|
-
* Instead use the Winsock events and rb_w32_wait_events(). */
|
2309
|
-
|
2310
2339
|
static void *
|
2311
|
-
wait_socket_readable(
|
2340
|
+
wait_socket_readable( t_pg_connection *this, struct timeval *ptimeout, void *(*is_readable)(PGconn *) )
|
2312
2341
|
{
|
2313
|
-
|
2342
|
+
PGconn *conn = this->pgconn;
|
2314
2343
|
void *retval;
|
2315
2344
|
struct timeval aborttime={0,0}, currtime, waittime;
|
2316
2345
|
DWORD timeout_milisec = INFINITE;
|
2317
2346
|
DWORD wait_ret;
|
2318
2347
|
WSAEVENT hEvent;
|
2319
2348
|
|
2320
|
-
if ( sd < 0 )
|
2321
|
-
rb_raise(rb_eConnectionBad, "PQsocket() can't get socket descriptor");
|
2322
|
-
|
2323
2349
|
hEvent = WSACreateEvent();
|
2324
2350
|
|
2325
2351
|
/* Check for connection errors (PQisBusy is true on connection errors) */
|
@@ -2334,7 +2360,7 @@ wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readabl
|
|
2334
2360
|
}
|
2335
2361
|
|
2336
2362
|
while ( !(retval=is_readable(conn)) ) {
|
2337
|
-
if ( WSAEventSelect(
|
2363
|
+
if ( WSAEventSelect(this->socket, hEvent, FD_READ|FD_CLOSE) == SOCKET_ERROR ) {
|
2338
2364
|
WSACloseEvent( hEvent );
|
2339
2365
|
rb_raise( rb_eConnectionBad, "WSAEventSelect socket error: %d", WSAGetLastError() );
|
2340
2366
|
}
|
@@ -2386,32 +2412,23 @@ wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readabl
|
|
2386
2412
|
/* non Win32 */
|
2387
2413
|
|
2388
2414
|
static void *
|
2389
|
-
wait_socket_readable(
|
2415
|
+
wait_socket_readable( t_pg_connection *this, struct timeval *ptimeout, void *(*is_readable)(PGconn *))
|
2390
2416
|
{
|
2391
|
-
|
2417
|
+
PGconn *conn = this->pgconn;
|
2392
2418
|
int ret;
|
2393
2419
|
void *retval;
|
2394
|
-
rb_fdset_t sd_rset;
|
2395
2420
|
struct timeval aborttime={0,0}, currtime, waittime;
|
2396
2421
|
|
2397
|
-
if ( sd < 0 )
|
2398
|
-
rb_raise(rb_eConnectionBad, "PQsocket() can't get socket descriptor");
|
2399
|
-
|
2400
2422
|
/* Check for connection errors (PQisBusy is true on connection errors) */
|
2401
2423
|
if ( PQconsumeInput(conn) == 0 )
|
2402
2424
|
rb_raise( rb_eConnectionBad, "PQconsumeInput() %s", PQerrorMessage(conn) );
|
2403
2425
|
|
2404
|
-
rb_fd_init( &sd_rset );
|
2405
|
-
|
2406
2426
|
if ( ptimeout ) {
|
2407
2427
|
gettimeofday(&currtime, NULL);
|
2408
2428
|
timeradd(&currtime, ptimeout, &aborttime);
|
2409
2429
|
}
|
2410
2430
|
|
2411
2431
|
while ( !(retval=is_readable(conn)) ) {
|
2412
|
-
rb_fd_zero( &sd_rset );
|
2413
|
-
rb_fd_set( sd, &sd_rset );
|
2414
|
-
|
2415
2432
|
if ( ptimeout ) {
|
2416
2433
|
gettimeofday(&currtime, NULL);
|
2417
2434
|
timersub(&aborttime, &currtime, &waittime);
|
@@ -2420,30 +2437,26 @@ wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readabl
|
|
2420
2437
|
/* Is the given timeout valid? */
|
2421
2438
|
if( !ptimeout || (waittime.tv_sec >= 0 && waittime.tv_usec >= 0) ){
|
2422
2439
|
/* Wait for the socket to become readable before checking again */
|
2423
|
-
ret =
|
2440
|
+
ret = rb_wait_for_single_fd( this->socket, RB_WAITFD_IN, ptimeout ? &waittime : NULL );
|
2424
2441
|
} else {
|
2425
2442
|
ret = 0;
|
2426
2443
|
}
|
2427
2444
|
|
2428
2445
|
if ( ret < 0 ){
|
2429
|
-
|
2430
|
-
rb_sys_fail( "rb_thread_select()" );
|
2446
|
+
rb_sys_fail( "rb_wait_for_single_fd()" );
|
2431
2447
|
}
|
2432
2448
|
|
2433
2449
|
/* Return false if the select() timed out */
|
2434
2450
|
if ( ret == 0 ){
|
2435
|
-
rb_fd_term( &sd_rset );
|
2436
2451
|
return NULL;
|
2437
2452
|
}
|
2438
2453
|
|
2439
2454
|
/* Check for connection errors (PQisBusy is true on connection errors) */
|
2440
2455
|
if ( PQconsumeInput(conn) == 0 ){
|
2441
|
-
rb_fd_term( &sd_rset );
|
2442
2456
|
rb_raise( rb_eConnectionBad, "PQconsumeInput() %s", PQerrorMessage(conn) );
|
2443
2457
|
}
|
2444
2458
|
}
|
2445
2459
|
|
2446
|
-
rb_fd_term( &sd_rset );
|
2447
2460
|
return retval;
|
2448
2461
|
}
|
2449
2462
|
|
@@ -2458,27 +2471,20 @@ notify_readable(PGconn *conn)
|
|
2458
2471
|
|
2459
2472
|
/*
|
2460
2473
|
* call-seq:
|
2461
|
-
* conn.wait_for_notify( [ timeout ] ) -> String
|
2462
|
-
* conn.wait_for_notify( [ timeout ] ) { |event, pid| block }
|
2463
|
-
* conn.wait_for_notify( [ timeout ] ) { |event, pid, payload| block } # PostgreSQL 9.0
|
2474
|
+
* conn.wait_for_notify( [ timeout ] ) { |event, pid, payload| block } -> String
|
2464
2475
|
*
|
2465
2476
|
* Blocks while waiting for notification(s), or until the optional
|
2466
2477
|
* _timeout_ is reached, whichever comes first. _timeout_ is
|
2467
2478
|
* measured in seconds and can be fractional.
|
2468
2479
|
*
|
2469
|
-
* Returns +nil+ if _timeout_ is reached, the name of the NOTIFY
|
2470
|
-
*
|
2471
|
-
*
|
2472
|
-
*
|
2473
|
-
* Under PostgreSQL 9.0 and later, if the notification is sent with
|
2474
|
-
* the optional +payload+ string, it will be given to the block as the
|
2475
|
-
* third argument.
|
2476
|
-
*
|
2480
|
+
* Returns +nil+ if _timeout_ is reached, the name of the NOTIFY event otherwise.
|
2481
|
+
* If used in block form, passes the name of the NOTIFY +event+, the generating
|
2482
|
+
* +pid+ and the optional +payload+ string into the block.
|
2477
2483
|
*/
|
2478
2484
|
static VALUE
|
2479
2485
|
pgconn_wait_for_notify(int argc, VALUE *argv, VALUE self)
|
2480
2486
|
{
|
2481
|
-
|
2487
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
2482
2488
|
PGnotify *pnotification;
|
2483
2489
|
struct timeval timeout;
|
2484
2490
|
struct timeval *ptimeout = NULL;
|
@@ -2494,7 +2500,7 @@ pgconn_wait_for_notify(int argc, VALUE *argv, VALUE self)
|
|
2494
2500
|
ptimeout = &timeout;
|
2495
2501
|
}
|
2496
2502
|
|
2497
|
-
pnotification = (PGnotify*) wait_socket_readable(
|
2503
|
+
pnotification = (PGnotify*) wait_socket_readable( this, ptimeout, notify_readable);
|
2498
2504
|
|
2499
2505
|
/* Return nil if the select timed out */
|
2500
2506
|
if ( !pnotification ) return Qnil;
|
@@ -2632,16 +2638,18 @@ pgconn_put_copy_end(int argc, VALUE *argv, VALUE self)
|
|
2632
2638
|
|
2633
2639
|
/*
|
2634
2640
|
* call-seq:
|
2635
|
-
* conn.get_copy_data( [ async = false [, decoder = nil ]] ) ->
|
2641
|
+
* conn.get_copy_data( [ async = false [, decoder = nil ]] ) -> Object
|
2636
2642
|
*
|
2637
|
-
* Return
|
2643
|
+
* Return one row of data, +nil+
|
2638
2644
|
* if the copy is done, or +false+ if the call would
|
2639
2645
|
* block (only possible if _async_ is true).
|
2640
2646
|
*
|
2641
|
-
* _decoder_
|
2642
|
-
*
|
2643
|
-
*
|
2644
|
-
*
|
2647
|
+
* If _decoder_ is not set or +nil+, data is returned as binary string.
|
2648
|
+
*
|
2649
|
+
* If _decoder_ is set to a PG::Coder derivation, the return type depends on this decoder.
|
2650
|
+
* PG::TextDecoder::CopyRow decodes the received data fields from one row of PostgreSQL's
|
2651
|
+
* COPY text format to an Array of Strings.
|
2652
|
+
* Optionally the decoder can type cast the single fields to various Ruby types in one step,
|
2645
2653
|
* if PG::TextDecoder::CopyRow#type_map is set accordingly.
|
2646
2654
|
*
|
2647
2655
|
* See also #copy_data.
|
@@ -3070,11 +3078,7 @@ get_result_readable(PGconn *conn)
|
|
3070
3078
|
*/
|
3071
3079
|
static VALUE
|
3072
3080
|
pgconn_block( int argc, VALUE *argv, VALUE self ) {
|
3073
|
-
|
3074
|
-
|
3075
|
-
/* If WIN32 and Ruby 1.9 do not use rb_thread_select() which sometimes hangs
|
3076
|
-
* and does not wait (nor sleep) any time even if timeout is given.
|
3077
|
-
* Instead use the Winsock events and rb_w32_wait_events(). */
|
3081
|
+
t_pg_connection *this = pg_get_connection_safe( self );
|
3078
3082
|
|
3079
3083
|
struct timeval timeout;
|
3080
3084
|
struct timeval *ptimeout = NULL;
|
@@ -3089,7 +3093,7 @@ pgconn_block( int argc, VALUE *argv, VALUE self ) {
|
|
3089
3093
|
ptimeout = &timeout;
|
3090
3094
|
}
|
3091
3095
|
|
3092
|
-
ret = wait_socket_readable(
|
3096
|
+
ret = wait_socket_readable( this, ptimeout, get_result_readable);
|
3093
3097
|
|
3094
3098
|
if( !ret )
|
3095
3099
|
return Qfalse;
|
@@ -3142,24 +3146,186 @@ pgconn_get_last_result(VALUE self)
|
|
3142
3146
|
|
3143
3147
|
/*
|
3144
3148
|
* call-seq:
|
3145
|
-
* conn.
|
3146
|
-
*
|
3149
|
+
* conn.discard_results()
|
3150
|
+
*
|
3151
|
+
* Silently discard any prior query result that application didn't eat.
|
3152
|
+
* This is done prior of Connection#exec and sibling methods and can
|
3153
|
+
* be called explicitly when using the async API.
|
3154
|
+
*/
|
3155
|
+
static VALUE
|
3156
|
+
pgconn_discard_results(VALUE self)
|
3157
|
+
{
|
3158
|
+
PGconn *conn = pg_get_pgconn(self);
|
3159
|
+
|
3160
|
+
PGresult *cur;
|
3161
|
+
while ((cur = gvl_PQgetResult(conn)) != NULL) {
|
3162
|
+
int status = PQresultStatus(cur);
|
3163
|
+
PQclear(cur);
|
3164
|
+
if (status == PGRES_COPY_IN){
|
3165
|
+
gvl_PQputCopyEnd(conn, "COPY terminated by new PQexec");
|
3166
|
+
}
|
3167
|
+
if (status == PGRES_COPY_OUT){
|
3168
|
+
char *buffer = NULL;
|
3169
|
+
while( gvl_PQgetCopyData(conn, &buffer, 0) > 0)
|
3170
|
+
PQfreemem(buffer);
|
3171
|
+
}
|
3172
|
+
}
|
3173
|
+
|
3174
|
+
return Qnil;
|
3175
|
+
}
|
3176
|
+
|
3177
|
+
/*
|
3178
|
+
* call-seq:
|
3179
|
+
* conn.async_exec(sql) -> PG::Result
|
3180
|
+
* conn.async_exec(sql) {|pg_result| block }
|
3147
3181
|
*
|
3148
|
-
* This function has the same behavior as #
|
3182
|
+
* This function has the same behavior as #sync_exec,
|
3149
3183
|
* but is implemented using the asynchronous command
|
3150
3184
|
* processing API of libpq.
|
3185
|
+
*
|
3186
|
+
* Both #sync_exec and #async_exec release the GVL while waiting for server response, so that concurrent threads will get executed.
|
3187
|
+
* However #async_exec has two advantages:
|
3188
|
+
*
|
3189
|
+
* 1. #async_exec can be aborted by signals (like Ctrl-C), while #exec blocks signal processing until the query is answered.
|
3190
|
+
* 2. Ruby VM gets notified about IO blocked operations.
|
3191
|
+
* It can therefore schedule thing like garbage collection, while queries are running like in this proposal: https://bugs.ruby-lang.org/issues/14723
|
3151
3192
|
*/
|
3152
3193
|
static VALUE
|
3153
3194
|
pgconn_async_exec(int argc, VALUE *argv, VALUE self)
|
3154
3195
|
{
|
3155
3196
|
VALUE rb_pgresult = Qnil;
|
3156
3197
|
|
3157
|
-
|
3198
|
+
pgconn_discard_results( self );
|
3199
|
+
pgconn_send_query( argc, argv, self );
|
3158
3200
|
pgconn_block( 0, NULL, self ); /* wait for input (without blocking) before reading the last result */
|
3159
|
-
pgconn_get_last_result( self );
|
3201
|
+
rb_pgresult = pgconn_get_last_result( self );
|
3160
3202
|
|
3161
|
-
|
3162
|
-
|
3203
|
+
if ( rb_block_given_p() ) {
|
3204
|
+
return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
|
3205
|
+
}
|
3206
|
+
return rb_pgresult;
|
3207
|
+
}
|
3208
|
+
|
3209
|
+
|
3210
|
+
/*
|
3211
|
+
* call-seq:
|
3212
|
+
* conn.async_exec_params(sql, params [, result_format [, type_map ]] ) -> nil
|
3213
|
+
* conn.async_exec_params(sql, params [, result_format [, type_map ]] ) {|pg_result| block }
|
3214
|
+
*
|
3215
|
+
* This function has the same behavior as #sync_exec_params, but is implemented using the asynchronous command processing API of libpq.
|
3216
|
+
* See #async_exec for the differences between the two API variants.
|
3217
|
+
*/
|
3218
|
+
static VALUE
|
3219
|
+
pgconn_async_exec_params(int argc, VALUE *argv, VALUE self)
|
3220
|
+
{
|
3221
|
+
VALUE rb_pgresult = Qnil;
|
3222
|
+
|
3223
|
+
pgconn_discard_results( self );
|
3224
|
+
/* If called with no or nil parameters, use PQsendQuery for compatibility */
|
3225
|
+
if ( argc == 1 || (argc >= 2 && argc <= 4 && NIL_P(argv[1]) )) {
|
3226
|
+
rb_warning("forwarding async_exec_params to async_exec is deprecated");
|
3227
|
+
pgconn_send_query( argc, argv, self );
|
3228
|
+
} else {
|
3229
|
+
pgconn_send_query_params( argc, argv, self );
|
3230
|
+
}
|
3231
|
+
pgconn_block( 0, NULL, self ); /* wait for input (without blocking) before reading the last result */
|
3232
|
+
rb_pgresult = pgconn_get_last_result( self );
|
3233
|
+
|
3234
|
+
if ( rb_block_given_p() ) {
|
3235
|
+
return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
|
3236
|
+
}
|
3237
|
+
return rb_pgresult;
|
3238
|
+
}
|
3239
|
+
|
3240
|
+
|
3241
|
+
/*
|
3242
|
+
* call-seq:
|
3243
|
+
* conn.async_prepare(stmt_name, sql [, param_types ] ) -> PG::Result
|
3244
|
+
*
|
3245
|
+
* This function has the same behavior as #sync_prepare, but is implemented using the asynchronous command processing API of libpq.
|
3246
|
+
* See #async_exec for the differences between the two API variants.
|
3247
|
+
*/
|
3248
|
+
static VALUE
|
3249
|
+
pgconn_async_prepare(int argc, VALUE *argv, VALUE self)
|
3250
|
+
{
|
3251
|
+
VALUE rb_pgresult = Qnil;
|
3252
|
+
|
3253
|
+
pgconn_discard_results( self );
|
3254
|
+
pgconn_send_prepare( argc, argv, self );
|
3255
|
+
pgconn_block( 0, NULL, self ); /* wait for input (without blocking) before reading the last result */
|
3256
|
+
rb_pgresult = pgconn_get_last_result( self );
|
3257
|
+
|
3258
|
+
if ( rb_block_given_p() ) {
|
3259
|
+
return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
|
3260
|
+
}
|
3261
|
+
return rb_pgresult;
|
3262
|
+
}
|
3263
|
+
|
3264
|
+
|
3265
|
+
/*
|
3266
|
+
* call-seq:
|
3267
|
+
* conn.async_exec_prepared(statement_name [, params, result_format[, type_map]] ) -> PG::Result
|
3268
|
+
* conn.async_exec_prepared(statement_name [, params, result_format[, type_map]] ) {|pg_result| block }
|
3269
|
+
*
|
3270
|
+
* This function has the same behavior as #sync_exec_prepared, but is implemented using the asynchronous command processing API of libpq.
|
3271
|
+
* See #async_exec for the differences between the two API variants.
|
3272
|
+
*/
|
3273
|
+
static VALUE
|
3274
|
+
pgconn_async_exec_prepared(int argc, VALUE *argv, VALUE self)
|
3275
|
+
{
|
3276
|
+
VALUE rb_pgresult = Qnil;
|
3277
|
+
|
3278
|
+
pgconn_discard_results( self );
|
3279
|
+
pgconn_send_query_prepared( argc, argv, self );
|
3280
|
+
pgconn_block( 0, NULL, self ); /* wait for input (without blocking) before reading the last result */
|
3281
|
+
rb_pgresult = pgconn_get_last_result( self );
|
3282
|
+
|
3283
|
+
if ( rb_block_given_p() ) {
|
3284
|
+
return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
|
3285
|
+
}
|
3286
|
+
return rb_pgresult;
|
3287
|
+
}
|
3288
|
+
|
3289
|
+
|
3290
|
+
/*
|
3291
|
+
* call-seq:
|
3292
|
+
* conn.async_describe_portal( portal_name ) -> PG::Result
|
3293
|
+
*
|
3294
|
+
* This function has the same behavior as #sync_describe_portal, but is implemented using the asynchronous command processing API of libpq.
|
3295
|
+
* See #async_exec for the differences between the two API variants.
|
3296
|
+
*/
|
3297
|
+
static VALUE
|
3298
|
+
pgconn_async_describe_portal(VALUE self, VALUE portal)
|
3299
|
+
{
|
3300
|
+
VALUE rb_pgresult = Qnil;
|
3301
|
+
|
3302
|
+
pgconn_discard_results( self );
|
3303
|
+
pgconn_send_describe_portal( self, portal );
|
3304
|
+
pgconn_block( 0, NULL, self ); /* wait for input (without blocking) before reading the last result */
|
3305
|
+
rb_pgresult = pgconn_get_last_result( self );
|
3306
|
+
|
3307
|
+
if ( rb_block_given_p() ) {
|
3308
|
+
return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
|
3309
|
+
}
|
3310
|
+
return rb_pgresult;
|
3311
|
+
}
|
3312
|
+
|
3313
|
+
|
3314
|
+
/*
|
3315
|
+
* call-seq:
|
3316
|
+
* conn.async_describe_prepared( statement_name ) -> PG::Result
|
3317
|
+
*
|
3318
|
+
* This function has the same behavior as #sync_describe_prepared, but is implemented using the asynchronous command processing API of libpq.
|
3319
|
+
* See #async_exec for the differences between the two API variants.
|
3320
|
+
*/
|
3321
|
+
static VALUE
|
3322
|
+
pgconn_async_describe_prepared(VALUE self, VALUE stmt_name)
|
3323
|
+
{
|
3324
|
+
VALUE rb_pgresult = Qnil;
|
3325
|
+
|
3326
|
+
pgconn_discard_results( self );
|
3327
|
+
pgconn_send_describe_prepared( self, stmt_name );
|
3328
|
+
pgconn_block( 0, NULL, self ); /* wait for input (without blocking) before reading the last result */
|
3163
3329
|
rb_pgresult = pgconn_get_last_result( self );
|
3164
3330
|
|
3165
3331
|
if ( rb_block_given_p() ) {
|
@@ -3690,7 +3856,7 @@ pgconn_set_default_encoding( VALUE self )
|
|
3690
3856
|
if (( enc = rb_default_internal_encoding() )) {
|
3691
3857
|
encname = pg_get_rb_encoding_as_pg_encoding( enc );
|
3692
3858
|
if ( pgconn_set_client_encoding_async(self, encname) != 0 )
|
3693
|
-
|
3859
|
+
rb_warning( "Failed to set the default_internal encoding to %s: '%s'",
|
3694
3860
|
encname, PQerrorMessage(conn) );
|
3695
3861
|
pgconn_set_internal_encoding_index( self );
|
3696
3862
|
return rb_enc_from_encoding( enc );
|
@@ -3879,6 +4045,20 @@ pgconn_decoder_for_get_copy_data_get(VALUE self)
|
|
3879
4045
|
return this->decoder_for_get_copy_data;
|
3880
4046
|
}
|
3881
4047
|
|
4048
|
+
/*
|
4049
|
+
* call-seq:
|
4050
|
+
* res.guess_result_memsize = enabled
|
4051
|
+
*
|
4052
|
+
* This method is for testing only and will probably be removed in the future.
|
4053
|
+
*/
|
4054
|
+
static VALUE
|
4055
|
+
pgconn_guess_result_memsize_set(VALUE self, VALUE enable)
|
4056
|
+
{
|
4057
|
+
t_pg_connection *this = pg_get_connection( self );
|
4058
|
+
this->guess_result_memsize = RTEST(enable);
|
4059
|
+
return enable;
|
4060
|
+
}
|
4061
|
+
|
3882
4062
|
|
3883
4063
|
/*
|
3884
4064
|
* Document-class: PG::Connection
|
@@ -3946,13 +4126,12 @@ init_pg_connection()
|
|
3946
4126
|
/* rb_define_method(rb_cPGconn, "getssl", pgconn_getssl, 0); */
|
3947
4127
|
|
3948
4128
|
/****** PG::Connection INSTANCE METHODS: Command Execution ******/
|
3949
|
-
rb_define_method(rb_cPGconn, "
|
3950
|
-
|
3951
|
-
rb_define_method(rb_cPGconn, "
|
3952
|
-
rb_define_method(rb_cPGconn, "
|
3953
|
-
rb_define_method(rb_cPGconn, "
|
3954
|
-
rb_define_method(rb_cPGconn, "
|
3955
|
-
rb_define_method(rb_cPGconn, "describe_portal", pgconn_describe_portal, 1);
|
4129
|
+
rb_define_method(rb_cPGconn, "sync_exec", pgconn_exec, -1);
|
4130
|
+
rb_define_method(rb_cPGconn, "sync_exec_params", pgconn_exec_params, -1);
|
4131
|
+
rb_define_method(rb_cPGconn, "sync_prepare", pgconn_prepare, -1);
|
4132
|
+
rb_define_method(rb_cPGconn, "sync_exec_prepared", pgconn_exec_prepared, -1);
|
4133
|
+
rb_define_method(rb_cPGconn, "sync_describe_prepared", pgconn_describe_prepared, 1);
|
4134
|
+
rb_define_method(rb_cPGconn, "sync_describe_portal", pgconn_describe_portal, 1);
|
3956
4135
|
rb_define_method(rb_cPGconn, "make_empty_pgresult", pgconn_make_empty_pgresult, 1);
|
3957
4136
|
rb_define_method(rb_cPGconn, "escape_string", pgconn_s_escape, 1);
|
3958
4137
|
rb_define_alias(rb_cPGconn, "escape", "escape_string");
|
@@ -3964,10 +4143,18 @@ init_pg_connection()
|
|
3964
4143
|
|
3965
4144
|
/****** PG::Connection INSTANCE METHODS: Asynchronous Command Processing ******/
|
3966
4145
|
rb_define_method(rb_cPGconn, "send_query", pgconn_send_query, -1);
|
4146
|
+
rb_define_method(rb_cPGconn, "send_query_params", pgconn_send_query_params, -1);
|
4147
|
+
rb_define_method(rb_cPGconn, "async_exec", pgconn_async_exec, -1);
|
4148
|
+
rb_define_method(rb_cPGconn, "async_exec_params", pgconn_async_exec_params, -1);
|
4149
|
+
rb_define_alias(rb_cPGconn, "async_query", "async_exec");
|
3967
4150
|
rb_define_method(rb_cPGconn, "send_prepare", pgconn_send_prepare, -1);
|
4151
|
+
rb_define_method(rb_cPGconn, "async_prepare", pgconn_async_prepare, -1);
|
3968
4152
|
rb_define_method(rb_cPGconn, "send_query_prepared", pgconn_send_query_prepared, -1);
|
4153
|
+
rb_define_method(rb_cPGconn, "async_exec_prepared", pgconn_async_exec_prepared, -1);
|
3969
4154
|
rb_define_method(rb_cPGconn, "send_describe_prepared", pgconn_send_describe_prepared, 1);
|
4155
|
+
rb_define_method(rb_cPGconn, "async_describe_prepared", pgconn_async_describe_prepared, 1);
|
3970
4156
|
rb_define_method(rb_cPGconn, "send_describe_portal", pgconn_send_describe_portal, 1);
|
4157
|
+
rb_define_method(rb_cPGconn, "async_describe_portal", pgconn_async_describe_portal, 1);
|
3971
4158
|
rb_define_method(rb_cPGconn, "get_result", pgconn_get_result, 0);
|
3972
4159
|
rb_define_method(rb_cPGconn, "consume_input", pgconn_consume_input, 0);
|
3973
4160
|
rb_define_method(rb_cPGconn, "is_busy", pgconn_is_busy, 0);
|
@@ -3975,6 +4162,7 @@ init_pg_connection()
|
|
3975
4162
|
rb_define_method(rb_cPGconn, "isnonblocking", pgconn_isnonblocking, 0);
|
3976
4163
|
rb_define_alias(rb_cPGconn, "nonblocking?", "isnonblocking");
|
3977
4164
|
rb_define_method(rb_cPGconn, "flush", pgconn_flush, 0);
|
4165
|
+
rb_define_method(rb_cPGconn, "discard_results", pgconn_discard_results, 0);
|
3978
4166
|
|
3979
4167
|
/****** PG::Connection INSTANCE METHODS: Cancelling Queries in Progress ******/
|
3980
4168
|
rb_define_method(rb_cPGconn, "cancel", pgconn_cancel, 0);
|
@@ -3991,6 +4179,7 @@ init_pg_connection()
|
|
3991
4179
|
rb_define_method(rb_cPGconn, "set_error_verbosity", pgconn_set_error_verbosity, 1);
|
3992
4180
|
rb_define_method(rb_cPGconn, "trace", pgconn_trace, 1);
|
3993
4181
|
rb_define_method(rb_cPGconn, "untrace", pgconn_untrace, 0);
|
4182
|
+
rb_define_method(rb_cPGconn, "guess_result_memsize=", pgconn_guess_result_memsize_set, 1);
|
3994
4183
|
|
3995
4184
|
/****** PG::Connection INSTANCE METHODS: Notice Processing ******/
|
3996
4185
|
rb_define_method(rb_cPGconn, "set_notice_receiver", pgconn_set_notice_receiver, 0);
|
@@ -4005,8 +4194,6 @@ init_pg_connection()
|
|
4005
4194
|
rb_define_method(rb_cPGconn, "wait_for_notify", pgconn_wait_for_notify, -1);
|
4006
4195
|
rb_define_alias(rb_cPGconn, "notifies_wait", "wait_for_notify");
|
4007
4196
|
rb_define_method(rb_cPGconn, "quote_ident", pgconn_s_quote_ident, 1);
|
4008
|
-
rb_define_method(rb_cPGconn, "async_exec", pgconn_async_exec, -1);
|
4009
|
-
rb_define_alias(rb_cPGconn, "async_query", "async_exec");
|
4010
4197
|
rb_define_method(rb_cPGconn, "get_last_result", pgconn_get_last_result, 0);
|
4011
4198
|
#ifdef HAVE_PQENCRYPTPASSWORDCONN
|
4012
4199
|
rb_define_method(rb_cPGconn, "encrypt_password", pgconn_encrypt_password, -1);
|