pg 1.0.0 → 1.1.0.pre20180730144600
Sign up to get free protection for your applications and to get access to all the features.
- 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);
|