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.
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);