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.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/ChangeLog +0 -6595
  5. data/History.rdoc +52 -0
  6. data/README.rdoc +11 -0
  7. data/Rakefile +1 -1
  8. data/Rakefile.cross +1 -1
  9. data/ext/errorcodes.rb +1 -1
  10. data/ext/extconf.rb +2 -0
  11. data/ext/pg.c +3 -2
  12. data/ext/pg.h +33 -5
  13. data/ext/pg_binary_decoder.c +69 -6
  14. data/ext/pg_binary_encoder.c +1 -1
  15. data/ext/pg_coder.c +52 -3
  16. data/ext/pg_connection.c +290 -103
  17. data/ext/pg_copy_coder.c +10 -5
  18. data/ext/pg_result.c +339 -113
  19. data/ext/pg_text_decoder.c +597 -37
  20. data/ext/pg_text_encoder.c +1 -1
  21. data/ext/pg_tuple.c +540 -0
  22. data/ext/pg_type_map.c +1 -1
  23. data/ext/pg_type_map_all_strings.c +1 -1
  24. data/ext/pg_type_map_by_class.c +1 -1
  25. data/ext/pg_type_map_by_column.c +1 -1
  26. data/ext/pg_type_map_by_mri_type.c +1 -1
  27. data/ext/pg_type_map_by_oid.c +1 -1
  28. data/ext/pg_type_map_in_ruby.c +1 -1
  29. data/ext/util.c +6 -6
  30. data/ext/util.h +2 -2
  31. data/lib/pg.rb +5 -3
  32. data/lib/pg/basic_type_mapping.rb +40 -7
  33. data/lib/pg/coder.rb +1 -1
  34. data/lib/pg/connection.rb +20 -1
  35. data/lib/pg/constants.rb +1 -1
  36. data/lib/pg/exceptions.rb +1 -1
  37. data/lib/pg/result.rb +1 -1
  38. data/lib/pg/text_decoder.rb +19 -23
  39. data/lib/pg/text_encoder.rb +35 -1
  40. data/lib/pg/type_map_by_column.rb +1 -1
  41. data/spec/helpers.rb +39 -7
  42. data/spec/pg/basic_type_mapping_spec.rb +230 -27
  43. data/spec/pg/connection_spec.rb +116 -77
  44. data/spec/pg/result_spec.rb +46 -11
  45. data/spec/pg/type_map_by_class_spec.rb +1 -1
  46. data/spec/pg/type_map_by_column_spec.rb +1 -1
  47. data/spec/pg/type_map_by_mri_type_spec.rb +1 -1
  48. data/spec/pg/type_map_by_oid_spec.rb +1 -1
  49. data/spec/pg/type_map_in_ruby_spec.rb +1 -1
  50. data/spec/pg/type_map_spec.rb +1 -1
  51. data/spec/pg/type_spec.rb +177 -11
  52. data/spec/pg_spec.rb +1 -1
  53. metadata +24 -28
  54. metadata.gz.sig +0 -0
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  * pg_connection.c - PG::Connection class extension
3
- * $Id: pg_connection.c,v 1f0926bfa9a5 2018/01/04 18:14:32 lars $
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, when supported */
903
- if( rb_respond_to(socket_io, id_autoclose) ){
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
- * #exec is implemented on the synchronous command processing API of libpq, whereas
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
- * #exec is somewhat faster that #async_exec, but blocks any signals to be processed until
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
- else {
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, &paramsData.params, &in_res_fmt, &paramsData.typemap);
1310
1317
  paramsData.with_types = 1;
1311
1318
 
1312
1319
  /*
1313
- * Handle the edge-case where the caller is coming from #exec, but passed an explict +nil+
1314
- * for the second parameter.
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, &paramsData );
@@ -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 [, params, result_format[, type_map ]] ) -> nil
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
- * +params+ is an optional array of the bind parameters for the SQL query.
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
- pgconn_send_query(int argc, VALUE *argv, VALUE self)
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, "13", &command, &paramsData.params, &in_res_fmt, &paramsData.typemap);
1911
+ rb_scan_args(argc, argv, "22", &command, &paramsData.params, &in_res_fmt, &paramsData.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, &paramsData );
1882
1915
  resultFormat = NIL_P(in_res_fmt) ? 0 : NUM2INT(in_res_fmt);
1883
1916
  nParams = alloc_query_params( &paramsData );
@@ -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 rb_thread_select().
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( PGconn *conn, struct timeval *ptimeout, void *(*is_readable)(PGconn *) )
2340
+ wait_socket_readable( t_pg_connection *this, struct timeval *ptimeout, void *(*is_readable)(PGconn *) )
2312
2341
  {
2313
- int sd = PQsocket( conn );
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(sd, hEvent, FD_READ|FD_CLOSE) == SOCKET_ERROR ) {
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( PGconn *conn, struct timeval *ptimeout, void *(*is_readable)(PGconn *))
2415
+ wait_socket_readable( t_pg_connection *this, struct timeval *ptimeout, void *(*is_readable)(PGconn *))
2390
2416
  {
2391
- int sd = PQsocket( conn );
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 = rb_thread_fd_select( sd+1, &sd_rset, NULL, NULL, ptimeout ? &waittime : NULL );
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
- rb_fd_term( &sd_rset );
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
- * event otherwise. If used in block form, passes the name of the
2471
- * NOTIFY +event+ and the generating +pid+ into the block.
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
- PGconn *conn = pg_get_pgconn( self );
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( conn, ptimeout, notify_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 ]] ) -> String
2641
+ * conn.get_copy_data( [ async = false [, decoder = nil ]] ) -> Object
2636
2642
  *
2637
- * Return a string containing one row of data, +nil+
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_ can be a PG::Coder derivation (typically PG::TextDecoder::CopyRow).
2642
- * This decodes the received data fields from PostgreSQL's COPY text format to an
2643
- * Array of Strings. Optionally
2644
- * the decoder can type cast the fields to various Ruby types in one step,
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
- PGconn *conn = pg_get_pgconn( self );
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( conn, ptimeout, get_result_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.async_exec(sql [, params, result_format ] ) -> PG::Result
3146
- * conn.async_exec(sql [, params, result_format ] ) {|pg_result| block }
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 #exec,
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
- /* remove any remaining results from the queue */
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
- pgconn_send_query( argc, argv, self );
3162
- pgconn_block( 0, NULL, self );
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
- rb_warn( "Failed to set the default_internal encoding to %s: '%s'",
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, "exec", pgconn_exec, -1);
3950
- rb_define_alias(rb_cPGconn, "query", "exec");
3951
- rb_define_method(rb_cPGconn, "exec_params", pgconn_exec_params, -1);
3952
- rb_define_method(rb_cPGconn, "prepare", pgconn_prepare, -1);
3953
- rb_define_method(rb_cPGconn, "exec_prepared", pgconn_exec_prepared, -1);
3954
- rb_define_method(rb_cPGconn, "describe_prepared", pgconn_describe_prepared, 1);
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);