pg 1.5.4 → 1.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/{History.md → CHANGELOG.md} +106 -4
  4. data/Gemfile +12 -3
  5. data/README-Windows.rdoc +1 -1
  6. data/README.ja.md +4 -4
  7. data/README.md +58 -17
  8. data/Rakefile +95 -14
  9. data/certs/kanis@comcard.de.pem +20 -0
  10. data/certs/larskanis-2024.pem +24 -0
  11. data/ext/errorcodes.def +4 -5
  12. data/ext/errorcodes.txt +2 -5
  13. data/ext/extconf.rb +161 -14
  14. data/ext/gvl_wrappers.c +13 -2
  15. data/ext/gvl_wrappers.h +33 -0
  16. data/ext/pg.c +17 -6
  17. data/ext/pg.h +9 -9
  18. data/ext/pg_binary_decoder.c +152 -0
  19. data/ext/pg_binary_encoder.c +211 -8
  20. data/ext/pg_cancel_connection.c +360 -0
  21. data/ext/pg_coder.c +54 -5
  22. data/ext/pg_connection.c +409 -167
  23. data/ext/pg_copy_coder.c +19 -15
  24. data/ext/pg_record_coder.c +7 -7
  25. data/ext/pg_result.c +11 -13
  26. data/ext/pg_text_decoder.c +4 -1
  27. data/ext/pg_text_encoder.c +37 -18
  28. data/ext/pg_tuple.c +2 -2
  29. data/ext/pg_type_map.c +1 -1
  30. data/ext/pg_type_map_all_strings.c +1 -1
  31. data/ext/pg_type_map_by_class.c +1 -1
  32. data/ext/pg_type_map_by_column.c +2 -1
  33. data/ext/pg_type_map_by_mri_type.c +1 -1
  34. data/ext/pg_type_map_by_oid.c +3 -1
  35. data/ext/pg_type_map_in_ruby.c +1 -1
  36. data/lib/pg/basic_type_map_for_queries.rb +15 -7
  37. data/lib/pg/basic_type_registry.rb +16 -4
  38. data/lib/pg/cancel_connection.rb +53 -0
  39. data/lib/pg/coder.rb +4 -2
  40. data/lib/pg/connection.rb +310 -167
  41. data/lib/pg/exceptions.rb +6 -0
  42. data/lib/pg/text_decoder/date.rb +3 -0
  43. data/lib/pg/text_decoder/json.rb +3 -0
  44. data/lib/pg/text_encoder/date.rb +1 -0
  45. data/lib/pg/text_encoder/inet.rb +3 -0
  46. data/lib/pg/text_encoder/json.rb +3 -0
  47. data/lib/pg/version.rb +1 -1
  48. data/lib/pg.rb +23 -8
  49. data/misc/yugabyte/Dockerfile +9 -0
  50. data/misc/yugabyte/docker-compose.yml +28 -0
  51. data/misc/yugabyte/pg-test.rb +45 -0
  52. data/pg.gemspec +8 -4
  53. data/ports/patches/krb5/1.21.3/0001-Allow-static-linking-krb5-library.patch +30 -0
  54. data/ports/patches/openssl/3.5.1/0001-aarch64-mingw.patch +21 -0
  55. data/ports/patches/postgresql/17.5/0001-Use-workaround-of-__builtin_setjmp-only-on-MINGW-on-.patch +42 -0
  56. data/ports/patches/postgresql/17.5/0001-libpq-Process-buffered-SSL-read-bytes-to-support-rec.patch +52 -0
  57. data/rakelib/pg_gem_helper.rb +64 -0
  58. data.tar.gz.sig +0 -0
  59. metadata +45 -47
  60. metadata.gz.sig +0 -0
  61. data/.appveyor.yml +0 -42
  62. data/.gems +0 -6
  63. data/.gemtest +0 -0
  64. data/.github/workflows/binary-gems.yml +0 -117
  65. data/.github/workflows/source-gem.yml +0 -141
  66. data/.gitignore +0 -22
  67. data/.hgsigs +0 -34
  68. data/.hgtags +0 -41
  69. data/.irbrc +0 -23
  70. data/.pryrc +0 -23
  71. data/.tm_properties +0 -21
  72. data/.travis.yml +0 -49
  73. data/Manifest.txt +0 -72
  74. data/Rakefile.cross +0 -298
  75. data/translation/.po4a-version +0 -7
  76. data/translation/po/all.pot +0 -936
  77. data/translation/po/ja.po +0 -1036
  78. data/translation/po4a.cfg +0 -12
data/ext/pg_connection.c CHANGED
@@ -30,10 +30,7 @@ static VALUE pgconn_async_flush(VALUE self);
30
30
  /*
31
31
  * Convenience function to raise connection errors
32
32
  */
33
- #ifdef __GNUC__
34
- __attribute__((format(printf, 3, 4)))
35
- #endif
36
- static void
33
+ void
37
34
  pg_raise_conn_error( VALUE klass, VALUE self, const char *format, ...)
38
35
  {
39
36
  VALUE msg, error;
@@ -96,6 +93,20 @@ pg_get_pgconn( VALUE self )
96
93
  }
97
94
 
98
95
 
96
+ void
97
+ pg_unwrap_socket_io( VALUE self, VALUE *p_socket_io, int ruby_sd )
98
+ {
99
+ if ( RTEST(*p_socket_io) ) {
100
+ #if defined(_WIN32)
101
+ if( rb_w32_unwrap_io_handle(ruby_sd) )
102
+ pg_raise_conn_error( rb_eConnectionBad, self, "Could not unwrap win32 socket handle");
103
+ #endif
104
+ rb_funcall( *p_socket_io, rb_intern("close"), 0 );
105
+ }
106
+
107
+ RB_OBJ_WRITE(self, p_socket_io, Qnil);
108
+ }
109
+
99
110
 
100
111
  /*
101
112
  * Close the associated socket IO object if there is one.
@@ -104,17 +115,7 @@ static void
104
115
  pgconn_close_socket_io( VALUE self )
105
116
  {
106
117
  t_pg_connection *this = pg_get_connection( self );
107
- VALUE socket_io = this->socket_io;
108
-
109
- if ( RTEST(socket_io) ) {
110
- #if defined(_WIN32)
111
- if( rb_w32_unwrap_io_handle(this->ruby_sd) )
112
- pg_raise_conn_error( rb_eConnectionBad, self, "Could not unwrap win32 socket handle");
113
- #endif
114
- rb_funcall( socket_io, rb_intern("close"), 0 );
115
- }
116
-
117
- RB_OBJ_WRITE(self, &this->socket_io, Qnil);
118
+ pg_unwrap_socket_io( self, &this->socket_io, this->ruby_sd);
118
119
  }
119
120
 
120
121
 
@@ -230,7 +231,7 @@ static const rb_data_type_t pg_connection_type = {
230
231
  pgconn_gc_mark,
231
232
  pgconn_gc_free,
232
233
  pgconn_memsize,
233
- pg_compact_callback(pgconn_gc_compact),
234
+ pgconn_gc_compact,
234
235
  },
235
236
  0,
236
237
  0,
@@ -264,6 +265,7 @@ pgconn_s_allocate( VALUE klass )
264
265
  RB_OBJ_WRITE(self, &this->decoder_for_get_copy_data, Qnil);
265
266
  RB_OBJ_WRITE(self, &this->trace_stream, Qnil);
266
267
  rb_ivar_set(self, rb_intern("@calls_to_put_copy_data"), INT2FIX(0));
268
+ rb_ivar_set(self, rb_intern("@iopts_for_reset"), Qnil);
267
269
 
268
270
  return self;
269
271
  }
@@ -418,7 +420,6 @@ pgconn_s_conninfo_parse(VALUE self, VALUE conninfo)
418
420
  }
419
421
 
420
422
 
421
- #ifdef HAVE_PQENCRYPTPASSWORDCONN
422
423
  static VALUE
423
424
  pgconn_sync_encrypt_password(int argc, VALUE *argv, VALUE self)
424
425
  {
@@ -442,7 +443,6 @@ pgconn_sync_encrypt_password(int argc, VALUE *argv, VALUE self)
442
443
 
443
444
  return rval;
444
445
  }
445
- #endif
446
446
 
447
447
 
448
448
  /*
@@ -515,9 +515,9 @@ static VALUE
515
515
  pgconn_connect_poll(VALUE self)
516
516
  {
517
517
  PostgresPollingStatusType status;
518
- status = gvl_PQconnectPoll(pg_get_pgconn(self));
519
518
 
520
519
  pgconn_close_socket_io(self);
520
+ status = gvl_PQconnectPoll(pg_get_pgconn(self));
521
521
 
522
522
  return INT2FIX((int)status);
523
523
  }
@@ -563,6 +563,27 @@ pgconn_sync_reset( VALUE self )
563
563
  return self;
564
564
  }
565
565
 
566
+ static VALUE
567
+ pgconn_reset_start2( VALUE self, VALUE conninfo )
568
+ {
569
+ t_pg_connection *this = pg_get_connection( self );
570
+
571
+ /* Close old connection */
572
+ pgconn_close_socket_io( self );
573
+ PQfinish( this->pgconn );
574
+
575
+ /* Start new connection */
576
+ this->pgconn = gvl_PQconnectStart( StringValueCStr(conninfo) );
577
+
578
+ if( this->pgconn == NULL )
579
+ rb_raise(rb_ePGerror, "PQconnectStart() unable to allocate PGconn structure");
580
+
581
+ if ( PQstatus(this->pgconn) == CONNECTION_BAD )
582
+ pg_raise_conn_error( rb_eConnectionBad, self, "%s", PQerrorMessage(this->pgconn));
583
+
584
+ return Qnil;
585
+ }
586
+
566
587
  /*
567
588
  * call-seq:
568
589
  * conn.reset_start() -> nil
@@ -587,16 +608,16 @@ pgconn_reset_start(VALUE self)
587
608
  * conn.reset_poll -> Integer
588
609
  *
589
610
  * Checks the status of a connection reset operation.
590
- * See #connect_start and #connect_poll for
611
+ * See Connection.connect_start and #connect_poll for
591
612
  * usage information and return values.
592
613
  */
593
614
  static VALUE
594
615
  pgconn_reset_poll(VALUE self)
595
616
  {
596
617
  PostgresPollingStatusType status;
597
- status = gvl_PQresetPoll(pg_get_pgconn(self));
598
618
 
599
619
  pgconn_close_socket_io(self);
620
+ status = gvl_PQresetPoll(pg_get_pgconn(self));
600
621
 
601
622
  return INT2FIX((int)status);
602
623
  }
@@ -738,7 +759,6 @@ pgconn_options(VALUE self)
738
759
  *
739
760
  * Returns the connection options used by a live connection.
740
761
  *
741
- * Available since PostgreSQL-9.3
742
762
  */
743
763
  static VALUE
744
764
  pgconn_conninfo( VALUE self )
@@ -825,31 +845,52 @@ pgconn_parameter_status(VALUE self, VALUE param_name)
825
845
  * call-seq:
826
846
  * conn.protocol_version -> Integer
827
847
  *
828
- * The 3.0 protocol will normally be used when communicating with PostgreSQL 7.4
829
- * or later servers; pre-7.4 servers support only protocol 2.0. (Protocol 1.0 is
830
- * obsolete and not supported by libpq.)
848
+ * Interrogates the frontend/backend protocol being used.
849
+ *
850
+ * Applications might wish to use this function to determine whether certain features are supported.
851
+ * Currently, the only value is 3 (3.0 protocol).
852
+ * The protocol version will not change after connection startup is complete, but it could theoretically change during a connection reset.
853
+ * The 3.0 protocol is supported by PostgreSQL server versions 7.4 and above.
854
+ *
855
+ * PG::ConnectionBad is raised if the connection is bad.
831
856
  */
832
857
  static VALUE
833
858
  pgconn_protocol_version(VALUE self)
834
859
  {
835
- return INT2NUM(PQprotocolVersion(pg_get_pgconn(self)));
860
+ int protocol_version = PQprotocolVersion(pg_get_pgconn(self));
861
+ if (protocol_version == 0) {
862
+ pg_raise_conn_error( rb_eConnectionBad, self, "PQprotocolVersion() can't get protocol version");
863
+ }
864
+ return INT2NUM(protocol_version);
836
865
  }
837
866
 
838
867
  /*
839
868
  * call-seq:
840
869
  * conn.server_version -> Integer
841
870
  *
842
- * The number is formed by converting the major, minor, and revision
843
- * numbers into two-decimal-digit numbers and appending them together.
844
- * For example, version 7.4.2 will be returned as 70402, and version
845
- * 8.1 will be returned as 80100 (leading zeroes are not shown). Zero
846
- * is returned if the connection is bad.
871
+ * Returns an integer representing the server version.
872
+ *
873
+ * Applications might use this function to determine the version of the database server they are connected to.
874
+ * The result is formed by multiplying the server's major version number by 10000 and adding the minor version number.
875
+ * For example, version 10.1 will be returned as 100001, and version 11.0 will be returned as 110000.
876
+ *
877
+ * PG::ConnectionBad is raised if the connection is bad.
878
+ *
879
+ * Prior to major version 10, PostgreSQL used three-part version numbers in which the first two parts together represented the major version.
880
+ * For those versions, PQserverVersion uses two digits for each part; for example version 9.1.5 will be returned as 90105, and version 9.2.0 will be returned as 90200.
881
+ *
882
+ * Therefore, for purposes of determining feature compatibility, applications should divide the result of PQserverVersion by 100 not 10000 to determine a logical major version number.
883
+ * In all release series, only the last two digits differ between minor releases (bug-fix releases).
847
884
  *
848
885
  */
849
886
  static VALUE
850
887
  pgconn_server_version(VALUE self)
851
888
  {
852
- return INT2NUM(PQserverVersion(pg_get_pgconn(self)));
889
+ int server_version = PQserverVersion(pg_get_pgconn(self));
890
+ if (server_version == 0) {
891
+ pg_raise_conn_error( rb_eConnectionBad, self, "PQserverVersion() can't get server version");
892
+ }
893
+ return INT2NUM(server_version);
853
894
  }
854
895
 
855
896
  /*
@@ -898,13 +939,42 @@ pgconn_socket(VALUE self)
898
939
  return INT2NUM(sd);
899
940
  }
900
941
 
942
+
943
+ VALUE
944
+ pg_wrap_socket_io(int sd, VALUE self, VALUE *p_socket_io, int *p_ruby_sd)
945
+ {
946
+ int ruby_sd;
947
+ VALUE cSocket;
948
+ VALUE socket_io = *p_socket_io;
949
+
950
+ #ifdef _WIN32
951
+ ruby_sd = rb_w32_wrap_io_handle((HANDLE)(intptr_t)sd, O_RDWR|O_BINARY|O_NOINHERIT);
952
+ if( ruby_sd == -1 )
953
+ pg_raise_conn_error( rb_eConnectionBad, self, "Could not wrap win32 socket handle");
954
+
955
+ *p_ruby_sd = ruby_sd;
956
+ #else
957
+ *p_ruby_sd = ruby_sd = sd;
958
+ #endif
959
+
960
+ cSocket = rb_const_get(rb_cObject, rb_intern("BasicSocket"));
961
+ socket_io = rb_funcall( cSocket, rb_intern("for_fd"), 1, INT2NUM(ruby_sd));
962
+
963
+ /* Disable autoclose feature */
964
+ rb_funcall( socket_io, s_id_autoclose_set, 1, Qfalse );
965
+
966
+ RB_OBJ_WRITE(self, p_socket_io, socket_io);
967
+
968
+ return socket_io;
969
+ }
970
+
901
971
  /*
902
972
  * call-seq:
903
973
  * conn.socket_io() -> IO
904
974
  *
905
975
  * Fetch an IO object created from the Connection's underlying socket.
906
976
  * This object can be used per <tt>socket_io.wait_readable</tt>, <tt>socket_io.wait_writable</tt> or for <tt>IO.select</tt> to wait for events while running asynchronous API calls.
907
- * <tt>IO#wait_*able</tt> is is <tt>Fiber.scheduler</tt> compatible in contrast to <tt>IO.select</tt>.
977
+ * <tt>IO#wait_*able</tt> is <tt>Fiber.scheduler</tt> compatible in contrast to <tt>IO.select</tt>.
908
978
  *
909
979
  * The IO object can change while the connection is established, but is memorized afterwards.
910
980
  * So be sure not to cache the IO object, but repeat calling <tt>conn.socket_io</tt> instead.
@@ -915,37 +985,17 @@ pgconn_socket(VALUE self)
915
985
  static VALUE
916
986
  pgconn_socket_io(VALUE self)
917
987
  {
918
- int sd;
919
- int ruby_sd;
920
988
  t_pg_connection *this = pg_get_connection_safe( self );
921
- VALUE cSocket;
922
- VALUE socket_io = this->socket_io;
923
989
 
924
- if ( !RTEST(socket_io) ) {
990
+ if ( !RTEST(this->socket_io) ) {
991
+ int sd;
925
992
  if( (sd = PQsocket(this->pgconn)) < 0){
926
993
  pg_raise_conn_error( rb_eConnectionBad, self, "PQsocket() can't get socket descriptor");
927
994
  }
928
-
929
- #ifdef _WIN32
930
- ruby_sd = rb_w32_wrap_io_handle((HANDLE)(intptr_t)sd, O_RDWR|O_BINARY|O_NOINHERIT);
931
- if( ruby_sd == -1 )
932
- pg_raise_conn_error( rb_eConnectionBad, self, "Could not wrap win32 socket handle");
933
-
934
- this->ruby_sd = ruby_sd;
935
- #else
936
- ruby_sd = sd;
937
- #endif
938
-
939
- cSocket = rb_const_get(rb_cObject, rb_intern("BasicSocket"));
940
- socket_io = rb_funcall( cSocket, rb_intern("for_fd"), 1, INT2NUM(ruby_sd));
941
-
942
- /* Disable autoclose feature */
943
- rb_funcall( socket_io, s_id_autoclose_set, 1, Qfalse );
944
-
945
- RB_OBJ_WRITE(self, &this->socket_io, socket_io);
995
+ return pg_wrap_socket_io( sd, self, &this->socket_io, &this->ruby_sd);
946
996
  }
947
997
 
948
- return socket_io;
998
+ return this->socket_io;
949
999
  }
950
1000
 
951
1001
  /*
@@ -962,6 +1012,7 @@ pgconn_backend_pid(VALUE self)
962
1012
  return INT2NUM(PQbackendPID(pg_get_pgconn(self)));
963
1013
  }
964
1014
 
1015
+ #ifndef HAVE_PQSETCHUNKEDROWSMODE
965
1016
  typedef struct
966
1017
  {
967
1018
  struct sockaddr_storage addr;
@@ -1006,6 +1057,7 @@ pgconn_backend_key(VALUE self)
1006
1057
 
1007
1058
  return INT2NUM(be_key);
1008
1059
  }
1060
+ #endif
1009
1061
 
1010
1062
  /*
1011
1063
  * call-seq:
@@ -1278,7 +1330,7 @@ alloc_query_params(struct query_params_data *paramsData)
1278
1330
  paramsData->lengths[i] = 0;
1279
1331
  } else {
1280
1332
  t_pg_coder_enc_func enc_func = pg_coder_enc_func( conv );
1281
- VALUE intermediate;
1333
+ VALUE intermediate = Qnil;
1282
1334
 
1283
1335
  /* 1st pass for retiving the required memory space */
1284
1336
  int len = enc_func(conv, param_value, NULL, &intermediate, paramsData->enc_idx);
@@ -1318,8 +1370,6 @@ alloc_query_params(struct query_params_data *paramsData)
1318
1370
  required_pool_size += len;
1319
1371
  }
1320
1372
  }
1321
-
1322
- RB_GC_GUARD(intermediate);
1323
1373
  }
1324
1374
  }
1325
1375
  }
@@ -1494,6 +1544,19 @@ pgconn_sync_exec_prepared(int argc, VALUE *argv, VALUE self)
1494
1544
  return rb_pgresult;
1495
1545
  }
1496
1546
 
1547
+ static VALUE
1548
+ pgconn_sync_describe_close_prepared_portal(VALUE self, VALUE name, PGresult *(*func)(PGconn *, const char *))
1549
+ {
1550
+ PGresult *result;
1551
+ VALUE rb_pgresult;
1552
+ t_pg_connection *this = pg_get_connection_safe( self );
1553
+ const char *stmt = NIL_P(name) ? NULL : pg_cstr_enc(name, this->enc_idx);
1554
+ result = func(this->pgconn, stmt);
1555
+ rb_pgresult = pg_new_result(result, self);
1556
+ pg_result_check(rb_pgresult);
1557
+ return rb_pgresult;
1558
+ }
1559
+
1497
1560
  /*
1498
1561
  * call-seq:
1499
1562
  * conn.sync_describe_prepared( statement_name ) -> PG::Result
@@ -1505,20 +1568,7 @@ pgconn_sync_exec_prepared(int argc, VALUE *argv, VALUE self)
1505
1568
  static VALUE
1506
1569
  pgconn_sync_describe_prepared(VALUE self, VALUE stmt_name)
1507
1570
  {
1508
- PGresult *result;
1509
- VALUE rb_pgresult;
1510
- t_pg_connection *this = pg_get_connection_safe( self );
1511
- const char *stmt;
1512
- if(NIL_P(stmt_name)) {
1513
- stmt = NULL;
1514
- }
1515
- else {
1516
- stmt = pg_cstr_enc(stmt_name, this->enc_idx);
1517
- }
1518
- result = gvl_PQdescribePrepared(this->pgconn, stmt);
1519
- rb_pgresult = pg_new_result(result, self);
1520
- pg_result_check(rb_pgresult);
1521
- return rb_pgresult;
1571
+ return pgconn_sync_describe_close_prepared_portal(self, stmt_name, gvl_PQdescribePrepared);
1522
1572
  }
1523
1573
 
1524
1574
 
@@ -1533,23 +1583,44 @@ pgconn_sync_describe_prepared(VALUE self, VALUE stmt_name)
1533
1583
  static VALUE
1534
1584
  pgconn_sync_describe_portal(VALUE self, VALUE stmt_name)
1535
1585
  {
1536
- PGresult *result;
1537
- VALUE rb_pgresult;
1538
- t_pg_connection *this = pg_get_connection_safe( self );
1539
- const char *stmt;
1540
- if(NIL_P(stmt_name)) {
1541
- stmt = NULL;
1542
- }
1543
- else {
1544
- stmt = pg_cstr_enc(stmt_name, this->enc_idx);
1545
- }
1546
- result = gvl_PQdescribePortal(this->pgconn, stmt);
1547
- rb_pgresult = pg_new_result(result, self);
1548
- pg_result_check(rb_pgresult);
1549
- return rb_pgresult;
1586
+ return pgconn_sync_describe_close_prepared_portal(self, stmt_name, gvl_PQdescribePortal);
1550
1587
  }
1551
1588
 
1552
1589
 
1590
+ #ifdef HAVE_PQSETCHUNKEDROWSMODE
1591
+ /*
1592
+ * call-seq:
1593
+ * conn.sync_close_prepared( stmt_name ) -> PG::Result
1594
+ *
1595
+ * This function has the same behavior as #async_close_prepared, but is implemented using the synchronous command processing API of libpq.
1596
+ * See #async_exec for the differences between the two API variants.
1597
+ * It's not recommended to use explicit sync or async variants but #close_prepared instead, unless you have a good reason to do so.
1598
+ *
1599
+ * Available since PostgreSQL-17.
1600
+ */
1601
+ static VALUE
1602
+ pgconn_sync_close_prepared(VALUE self, VALUE stmt_name)
1603
+ {
1604
+ return pgconn_sync_describe_close_prepared_portal(self, stmt_name, gvl_PQclosePrepared);
1605
+ }
1606
+
1607
+ /*
1608
+ * call-seq:
1609
+ * conn.sync_close_portal( portal_name ) -> PG::Result
1610
+ *
1611
+ * This function has the same behavior as #async_close_portal, but is implemented using the synchronous command processing API of libpq.
1612
+ * See #async_exec for the differences between the two API variants.
1613
+ * It's not recommended to use explicit sync or async variants but #close_portal instead, unless you have a good reason to do so.
1614
+ *
1615
+ * Available since PostgreSQL-17.
1616
+ */
1617
+ static VALUE
1618
+ pgconn_sync_close_portal(VALUE self, VALUE stmt_name)
1619
+ {
1620
+ return pgconn_sync_describe_close_prepared_portal(self, stmt_name, gvl_PQclosePortal);
1621
+ }
1622
+ #endif
1623
+
1553
1624
  /*
1554
1625
  * call-seq:
1555
1626
  * conn.make_empty_pgresult( status ) -> PG::Result
@@ -1566,6 +1637,7 @@ pgconn_sync_describe_portal(VALUE self, VALUE stmt_name)
1566
1637
  * * +PGRES_FATAL_ERROR+
1567
1638
  * * +PGRES_COPY_BOTH+
1568
1639
  * * +PGRES_SINGLE_TUPLE+
1640
+ * * +PGRES_TUPLES_CHUNK+
1569
1641
  * * +PGRES_PIPELINE_SYNC+
1570
1642
  * * +PGRES_PIPELINE_ABORTED+
1571
1643
  */
@@ -1790,14 +1862,11 @@ pgconn_escape_identifier(VALUE self, VALUE string)
1790
1862
  * (column names, types, etc) that an ordinary Result object for the query
1791
1863
  * would have.
1792
1864
  *
1793
- * *Caution:* While processing a query, the server may return some rows and
1794
- * then encounter an error, causing the query to be aborted. Ordinarily, pg
1795
- * discards any such rows and reports only the error. But in single-row mode,
1796
- * those rows will have already been returned to the application. Hence, the
1797
- * application will see some Result objects followed by an Error raised in get_result.
1798
- * For proper transactional behavior, the application must be designed to discard
1799
- * or undo whatever has been done with the previously-processed rows, if the query
1800
- * ultimately fails.
1865
+ * *Caution:* While processing a query, the server may return some rows and then encounter an error, causing the query to be aborted.
1866
+ * Ordinarily, pg discards any such rows and reports only the error.
1867
+ * But in single-row or chunked mode, some rows may have already been returned to the application.
1868
+ * Hence, the application will see some PGRES_SINGLE_TUPLE or PGRES_TUPLES_CHUNK PG::Result objects followed by a PG::Error raised in get_result.
1869
+ * For proper transactional behavior, the application must be designed to discard or undo whatever has been done with the previously-processed rows, if the query ultimately fails.
1801
1870
  *
1802
1871
  * Example:
1803
1872
  * conn.send_query( "your SQL command" )
@@ -1817,10 +1886,49 @@ pgconn_set_single_row_mode(VALUE self)
1817
1886
 
1818
1887
  rb_check_frozen(self);
1819
1888
  if( PQsetSingleRowMode(conn) == 0 )
1820
- pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
1889
+ pg_raise_conn_error( rb_ePGerror, self, "PQsetSingleRowMode %s", PQerrorMessage(conn));
1890
+
1891
+ return self;
1892
+ }
1893
+
1894
+ #ifdef HAVE_PQSETCHUNKEDROWSMODE
1895
+ /*
1896
+ * call-seq:
1897
+ * conn.set_chunked_rows_mode -> self
1898
+ *
1899
+ * Select chunked mode for the currently-executing query.
1900
+ *
1901
+ * This function is similar to set_single_row_mode, except that it specifies retrieval of up to +chunk_size+ rows per PGresult, not necessarily just one row.
1902
+ * This function can only be called immediately after send_query or one of its sibling functions, before any other operation on the connection such as consume_input or get_result.
1903
+ * If called at the correct time, the function activates chunked mode for the current query.
1904
+ * Otherwise the mode stays unchanged and the function raises an error.
1905
+ * In any case, the mode reverts to normal after completion of the current query.
1906
+ *
1907
+ * Example:
1908
+ * conn.send_query( "your SQL command" )
1909
+ * conn.set_chunked_rows_mode(10)
1910
+ * loop do
1911
+ * res = conn.get_result or break
1912
+ * res.check
1913
+ * res.each do |row|
1914
+ * # do something with the received max. 10 rows
1915
+ * end
1916
+ * end
1917
+ *
1918
+ * Available since PostgreSQL-17
1919
+ */
1920
+ static VALUE
1921
+ pgconn_set_chunked_rows_mode(VALUE self, VALUE chunk_size)
1922
+ {
1923
+ PGconn *conn = pg_get_pgconn(self);
1924
+
1925
+ rb_check_frozen(self);
1926
+ if( PQsetChunkedRowsMode(conn, NUM2INT(chunk_size)) == 0 )
1927
+ pg_raise_conn_error( rb_ePGerror, self, "PQsetChunkedRowsMode %s", PQerrorMessage(conn));
1821
1928
 
1822
1929
  return self;
1823
1930
  }
1931
+ #endif
1824
1932
 
1825
1933
  static VALUE pgconn_send_query_params(int argc, VALUE *argv, VALUE self);
1826
1934
 
@@ -1845,7 +1953,7 @@ pgconn_send_query(int argc, VALUE *argv, VALUE self)
1845
1953
  /* If called with no or nil parameters, use PQexec for compatibility */
1846
1954
  if ( argc == 1 || (argc >= 2 && argc <= 4 && NIL_P(argv[1]) )) {
1847
1955
  if(gvl_PQsendQuery(this->pgconn, pg_cstr_enc(argv[0], this->enc_idx)) == 0)
1848
- pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
1956
+ pg_raise_conn_error( rb_eUnableToSend, self, "PQsendQuery %s", PQerrorMessage(this->pgconn));
1849
1957
 
1850
1958
  pgconn_wait_for_flush( self );
1851
1959
  return Qnil;
@@ -1920,7 +2028,7 @@ pgconn_send_query_params(int argc, VALUE *argv, VALUE self)
1920
2028
  free_query_params( &paramsData );
1921
2029
 
1922
2030
  if(result == 0)
1923
- pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
2031
+ pg_raise_conn_error( rb_eUnableToSend, self, "PQsendQueryParams %s", PQerrorMessage(this->pgconn));
1924
2032
 
1925
2033
  pgconn_wait_for_flush( self );
1926
2034
  return Qnil;
@@ -1981,7 +2089,7 @@ pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
1981
2089
  xfree(paramTypes);
1982
2090
 
1983
2091
  if(result == 0) {
1984
- pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
2092
+ pg_raise_conn_error( rb_eUnableToSend, self, "PQsendPrepare %s", PQerrorMessage(this->pgconn));
1985
2093
  }
1986
2094
  pgconn_wait_for_flush( self );
1987
2095
  return Qnil;
@@ -2047,7 +2155,21 @@ pgconn_send_query_prepared(int argc, VALUE *argv, VALUE self)
2047
2155
  free_query_params( &paramsData );
2048
2156
 
2049
2157
  if(result == 0)
2050
- pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
2158
+ pg_raise_conn_error( rb_eUnableToSend, self, "PQsendQueryPrepared %s", PQerrorMessage(this->pgconn));
2159
+
2160
+ pgconn_wait_for_flush( self );
2161
+ return Qnil;
2162
+ }
2163
+
2164
+
2165
+ static VALUE
2166
+ pgconn_send_describe_close_prepared_portal(VALUE self, VALUE name, int (*func)(PGconn *, const char *), const char *funame)
2167
+ {
2168
+ t_pg_connection *this = pg_get_connection_safe( self );
2169
+ const char *stmt = NIL_P(name) ? NULL : pg_cstr_enc(name, this->enc_idx);
2170
+ /* returns 0 on failure */
2171
+ if(func(this->pgconn, stmt) == 0)
2172
+ pg_raise_conn_error( rb_eUnableToSend, self, "%s %s", funame, PQerrorMessage(this->pgconn));
2051
2173
 
2052
2174
  pgconn_wait_for_flush( self );
2053
2175
  return Qnil;
@@ -2063,13 +2185,9 @@ pgconn_send_query_prepared(int argc, VALUE *argv, VALUE self)
2063
2185
  static VALUE
2064
2186
  pgconn_send_describe_prepared(VALUE self, VALUE stmt_name)
2065
2187
  {
2066
- t_pg_connection *this = pg_get_connection_safe( self );
2067
- /* returns 0 on failure */
2068
- if(gvl_PQsendDescribePrepared(this->pgconn, pg_cstr_enc(stmt_name, this->enc_idx)) == 0)
2069
- pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
2070
-
2071
- pgconn_wait_for_flush( self );
2072
- return Qnil;
2188
+ return pgconn_send_describe_close_prepared_portal(
2189
+ self, stmt_name, gvl_PQsendDescribePrepared,
2190
+ "PQsendDescribePrepared");
2073
2191
  }
2074
2192
 
2075
2193
 
@@ -2083,16 +2201,48 @@ pgconn_send_describe_prepared(VALUE self, VALUE stmt_name)
2083
2201
  static VALUE
2084
2202
  pgconn_send_describe_portal(VALUE self, VALUE portal)
2085
2203
  {
2086
- t_pg_connection *this = pg_get_connection_safe( self );
2087
- /* returns 0 on failure */
2088
- if(gvl_PQsendDescribePortal(this->pgconn, pg_cstr_enc(portal, this->enc_idx)) == 0)
2089
- pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
2204
+ return pgconn_send_describe_close_prepared_portal(
2205
+ self, portal, gvl_PQsendDescribePortal,
2206
+ "PQsendDescribePortal");
2207
+ }
2090
2208
 
2091
- pgconn_wait_for_flush( self );
2092
- return Qnil;
2209
+ #ifdef HAVE_PQSETCHUNKEDROWSMODE
2210
+ /*
2211
+ * call-seq:
2212
+ * conn.send_close_prepared( statement_name ) -> nil
2213
+ *
2214
+ * Asynchronously send _command_ to the server. Does not block.
2215
+ * Use in combination with +conn.get_result+.
2216
+ *
2217
+ * Available since PostgreSQL-17.
2218
+ */
2219
+ static VALUE
2220
+ pgconn_send_close_prepared(VALUE self, VALUE stmt_name)
2221
+ {
2222
+ return pgconn_send_describe_close_prepared_portal(
2223
+ self, stmt_name, gvl_PQsendClosePrepared,
2224
+ "PQsendClosePrepared");
2093
2225
  }
2094
2226
 
2095
2227
 
2228
+ /*
2229
+ * call-seq:
2230
+ * conn.send_close_portal( portal_name ) -> nil
2231
+ *
2232
+ * Asynchronously send _command_ to the server. Does not block.
2233
+ * Use in combination with +conn.get_result+.
2234
+ *
2235
+ * Available since PostgreSQL-17.
2236
+ */
2237
+ static VALUE
2238
+ pgconn_send_close_portal(VALUE self, VALUE portal)
2239
+ {
2240
+ return pgconn_send_describe_close_prepared_portal(
2241
+ self, portal, gvl_PQsendClosePortal,
2242
+ "PQsendClosePortal");
2243
+ }
2244
+ #endif
2245
+
2096
2246
  static VALUE
2097
2247
  pgconn_sync_get_result(VALUE self)
2098
2248
  {
@@ -2182,6 +2332,7 @@ pgconn_sync_flush(VALUE self)
2182
2332
  return (ret) ? Qfalse : Qtrue;
2183
2333
  }
2184
2334
 
2335
+ #ifndef HAVE_PQSETCHUNKEDROWSMODE
2185
2336
  static VALUE
2186
2337
  pgconn_sync_cancel(VALUE self)
2187
2338
  {
@@ -2203,6 +2354,7 @@ pgconn_sync_cancel(VALUE self)
2203
2354
  PQfreeCancel(cancel);
2204
2355
  return retval;
2205
2356
  }
2357
+ #endif
2206
2358
 
2207
2359
 
2208
2360
  /*
@@ -2245,6 +2397,18 @@ pgconn_notifies(VALUE self)
2245
2397
  return hash;
2246
2398
  }
2247
2399
 
2400
+ #ifndef HAVE_RB_IO_DESCRIPTOR
2401
+ static int
2402
+ rb_io_descriptor(VALUE io)
2403
+ {
2404
+ rb_io_t *fptr;
2405
+ Check_Type(io, T_FILE);
2406
+ fptr = RFILE(io)->fptr;
2407
+ rb_io_check_closed(fptr);
2408
+ return fptr->fd;
2409
+ }
2410
+ #endif
2411
+
2248
2412
  #if defined(_WIN32)
2249
2413
 
2250
2414
  /* We use a specialized implementation of rb_io_wait() on Windows.
@@ -2265,7 +2429,6 @@ int rb_w32_wait_events( HANDLE *events, int num, DWORD timeout );
2265
2429
 
2266
2430
  static VALUE
2267
2431
  pg_rb_thread_io_wait(VALUE io, VALUE events, VALUE timeout) {
2268
- rb_io_t *fptr;
2269
2432
  struct timeval ptimeout;
2270
2433
 
2271
2434
  struct timeval aborttime={0,0}, currtime, waittime;
@@ -2276,7 +2439,6 @@ pg_rb_thread_io_wait(VALUE io, VALUE events, VALUE timeout) {
2276
2439
  long w32_events = 0;
2277
2440
  DWORD wait_ret;
2278
2441
 
2279
- GetOpenFile((io), fptr);
2280
2442
  if( !NIL_P(timeout) ){
2281
2443
  ptimeout.tv_sec = (time_t)(NUM2DBL(timeout));
2282
2444
  ptimeout.tv_usec = (time_t)((NUM2DBL(timeout) - (double)ptimeout.tv_sec) * 1e6);
@@ -2290,7 +2452,7 @@ pg_rb_thread_io_wait(VALUE io, VALUE events, VALUE timeout) {
2290
2452
  if(rb_events & PG_RUBY_IO_PRIORITY) w32_events |= FD_OOB;
2291
2453
 
2292
2454
  for(;;) {
2293
- if ( WSAEventSelect(_get_osfhandle(fptr->fd), hEvent, w32_events) == SOCKET_ERROR ) {
2455
+ if ( WSAEventSelect(_get_osfhandle(rb_io_descriptor(io)), hEvent, w32_events) == SOCKET_ERROR ) {
2294
2456
  WSACloseEvent( hEvent );
2295
2457
  rb_raise( rb_eConnectionBad, "WSAEventSelect socket error: %d", WSAGetLastError() );
2296
2458
  }
@@ -2333,7 +2495,7 @@ static VALUE
2333
2495
  pg_rb_io_wait(VALUE io, VALUE events, VALUE timeout) {
2334
2496
  #if defined(HAVE_RUBY_FIBER_SCHEDULER_H)
2335
2497
  /* We don't support Fiber.scheduler on Windows ruby-3.0 because there is no fast way to check whether a scheduler is active.
2336
- * Fortunatelly ruby-3.1 offers a C-API for it.
2498
+ * Fortunately ruby-3.1 offers a C-API for it.
2337
2499
  */
2338
2500
  VALUE scheduler = rb_fiber_scheduler_current();
2339
2501
 
@@ -2363,16 +2525,14 @@ typedef enum {
2363
2525
 
2364
2526
  static VALUE
2365
2527
  pg_rb_io_wait(VALUE io, VALUE events, VALUE timeout) {
2366
- rb_io_t *fptr;
2367
2528
  struct timeval waittime;
2368
2529
  int res;
2369
2530
 
2370
- GetOpenFile((io), fptr);
2371
2531
  if( !NIL_P(timeout) ){
2372
2532
  waittime.tv_sec = (time_t)(NUM2DBL(timeout));
2373
2533
  waittime.tv_usec = (time_t)((NUM2DBL(timeout) - (double)waittime.tv_sec) * 1e6);
2374
2534
  }
2375
- res = rb_wait_for_single_fd(fptr->fd, NUM2UINT(events), NIL_P(timeout) ? NULL : &waittime);
2535
+ res = rb_wait_for_single_fd(rb_io_descriptor(io), NUM2UINT(events), NIL_P(timeout) ? NULL : &waittime);
2376
2536
 
2377
2537
  return UINT2NUM(res);
2378
2538
  }
@@ -2539,7 +2699,7 @@ pgconn_sync_put_copy_data(int argc, VALUE *argv, VALUE self)
2539
2699
  VALUE value;
2540
2700
  VALUE buffer = Qnil;
2541
2701
  VALUE encoder;
2542
- VALUE intermediate;
2702
+ VALUE intermediate = Qnil;
2543
2703
  t_pg_coder *p_coder = NULL;
2544
2704
 
2545
2705
  rb_scan_args( argc, argv, "11", &value, &encoder );
@@ -2578,7 +2738,6 @@ pgconn_sync_put_copy_data(int argc, VALUE *argv, VALUE self)
2578
2738
  if(ret == -1)
2579
2739
  pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(this->pgconn));
2580
2740
 
2581
- RB_GC_GUARD(intermediate);
2582
2741
  RB_GC_GUARD(buffer);
2583
2742
 
2584
2743
  return (ret) ? Qtrue : Qfalse;
@@ -2673,7 +2832,6 @@ pgconn_set_error_verbosity(VALUE self, VALUE in_verbosity)
2673
2832
  return INT2FIX(PQsetErrorVerbosity(conn, verbosity));
2674
2833
  }
2675
2834
 
2676
- #ifdef HAVE_PQRESULTVERBOSEERRORMESSAGE
2677
2835
  /*
2678
2836
  * call-seq:
2679
2837
  * conn.set_error_context_visibility( context_visibility ) -> Integer
@@ -2693,7 +2851,6 @@ pgconn_set_error_verbosity(VALUE self, VALUE in_verbosity)
2693
2851
  *
2694
2852
  * See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-control.html#LIBPQ-PQSETERRORCONTEXTVISIBILITY].
2695
2853
  *
2696
- * Available since PostgreSQL-9.6
2697
2854
  */
2698
2855
  static VALUE
2699
2856
  pgconn_set_error_context_visibility(VALUE self, VALUE in_context_visibility)
@@ -2702,7 +2859,6 @@ pgconn_set_error_context_visibility(VALUE self, VALUE in_context_visibility)
2702
2859
  PGContextVisibility context_visibility = NUM2INT(in_context_visibility);
2703
2860
  return INT2FIX(PQsetErrorContextVisibility(conn, context_visibility));
2704
2861
  }
2705
- #endif
2706
2862
 
2707
2863
  /*
2708
2864
  * call-seq:
@@ -3107,7 +3263,9 @@ pgconn_async_get_last_result(VALUE self)
3107
3263
  for(;;) {
3108
3264
  int status;
3109
3265
 
3110
- /* wait for input (without blocking) before reading each result */
3266
+ /* Wait for input before reading each result.
3267
+ * That way we support the ruby-3.x IO scheduler and don't block other ruby threads.
3268
+ */
3111
3269
  wait_socket_readable(self, NULL, get_result_readable);
3112
3270
 
3113
3271
  cur = gvl_PQgetResult(conn);
@@ -3141,7 +3299,7 @@ pgconn_async_get_last_result(VALUE self)
3141
3299
  * Returns:
3142
3300
  * * +nil+ when the connection is already idle
3143
3301
  * * +true+ when some results have been discarded
3144
- * * +false+ when a failure occured and the connection was closed
3302
+ * * +false+ when a failure occurred and the connection was closed
3145
3303
  *
3146
3304
  */
3147
3305
  static VALUE
@@ -3428,6 +3586,21 @@ pgconn_async_exec_prepared(int argc, VALUE *argv, VALUE self)
3428
3586
  return rb_pgresult;
3429
3587
  }
3430
3588
 
3589
+ static VALUE
3590
+ pgconn_async_describe_close_prepared_potral(VALUE self, VALUE name, VALUE
3591
+ (*func)(VALUE, VALUE))
3592
+ {
3593
+ VALUE rb_pgresult = Qnil;
3594
+
3595
+ pgconn_discard_results( self );
3596
+ func( self, name );
3597
+ rb_pgresult = pgconn_async_get_last_result( self );
3598
+
3599
+ if ( rb_block_given_p() ) {
3600
+ return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
3601
+ }
3602
+ return rb_pgresult;
3603
+ }
3431
3604
 
3432
3605
  /*
3433
3606
  * call-seq:
@@ -3440,16 +3613,7 @@ pgconn_async_exec_prepared(int argc, VALUE *argv, VALUE self)
3440
3613
  static VALUE
3441
3614
  pgconn_async_describe_portal(VALUE self, VALUE portal)
3442
3615
  {
3443
- VALUE rb_pgresult = Qnil;
3444
-
3445
- pgconn_discard_results( self );
3446
- pgconn_send_describe_portal( self, portal );
3447
- rb_pgresult = pgconn_async_get_last_result( self );
3448
-
3449
- if ( rb_block_given_p() ) {
3450
- return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
3451
- }
3452
- return rb_pgresult;
3616
+ return pgconn_async_describe_close_prepared_potral(self, portal, pgconn_send_describe_portal);
3453
3617
  }
3454
3618
 
3455
3619
 
@@ -3464,27 +3628,64 @@ pgconn_async_describe_portal(VALUE self, VALUE portal)
3464
3628
  static VALUE
3465
3629
  pgconn_async_describe_prepared(VALUE self, VALUE stmt_name)
3466
3630
  {
3467
- VALUE rb_pgresult = Qnil;
3468
-
3469
- pgconn_discard_results( self );
3470
- pgconn_send_describe_prepared( self, stmt_name );
3471
- rb_pgresult = pgconn_async_get_last_result( self );
3631
+ return pgconn_async_describe_close_prepared_potral(self, stmt_name, pgconn_send_describe_prepared);
3632
+ }
3472
3633
 
3473
- if ( rb_block_given_p() ) {
3474
- return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
3475
- }
3476
- return rb_pgresult;
3634
+ #ifdef HAVE_PQSETCHUNKEDROWSMODE
3635
+ /*
3636
+ * call-seq:
3637
+ * conn.close_prepared( statement_name ) -> PG::Result
3638
+ *
3639
+ * Submits a request to close the specified prepared statement, and waits for completion.
3640
+ * close_prepared allows an application to close a previously prepared statement.
3641
+ * Closing a statement releases all of its associated resources on the server and allows its name to be reused.
3642
+ * It's the same as using the +DEALLOCATE+ SQL statement, but on a lower protocol level.
3643
+ *
3644
+ * +statement_name+ can be "" or +nil+ to reference the unnamed statement.
3645
+ * It is fine if no statement exists with this name, in that case the operation is a no-op.
3646
+ * On success, a PG::Result with status PGRES_COMMAND_OK is returned.
3647
+ *
3648
+ * See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQCLOSEPREPARED].
3649
+ *
3650
+ * Available since PostgreSQL-17.
3651
+ */
3652
+ static VALUE
3653
+ pgconn_async_close_prepared(VALUE self, VALUE stmt_name)
3654
+ {
3655
+ return pgconn_async_describe_close_prepared_potral(self, stmt_name, pgconn_send_close_prepared);
3477
3656
  }
3478
3657
 
3658
+ /*
3659
+ * call-seq:
3660
+ * conn.close_portal( portal_name ) -> PG::Result
3661
+ *
3662
+ * Submits a request to close the specified portal, and waits for completion.
3663
+ *
3664
+ * close_portal allows an application to trigger a close of a previously created portal.
3665
+ * Closing a portal releases all of its associated resources on the server and allows its name to be reused.
3666
+ * (pg does not provide any direct access to portals, but you can use this function to close a cursor created with a DECLARE CURSOR SQL command.)
3667
+ *
3668
+ * +portal_name+ can be "" or +nil+ to reference the unnamed portal.
3669
+ * It is fine if no portal exists with this name, in that case the operation is a no-op.
3670
+ * On success, a PG::Result with status PGRES_COMMAND_OK is returned.
3671
+ *
3672
+ * See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQCLOSEPORTAL].
3673
+ *
3674
+ * Available since PostgreSQL-17.
3675
+ */
3676
+ static VALUE
3677
+ pgconn_async_close_portal(VALUE self, VALUE portal)
3678
+ {
3679
+ return pgconn_async_describe_close_prepared_potral(self, portal, pgconn_send_close_portal);
3680
+ }
3681
+ #endif
3479
3682
 
3480
- #ifdef HAVE_PQSSLATTRIBUTE
3481
3683
  /*
3482
3684
  * call-seq:
3483
3685
  * conn.ssl_in_use? -> Boolean
3484
3686
  *
3485
3687
  * Returns +true+ if the connection uses SSL/TLS, +false+ if not.
3486
3688
  *
3487
- * Available since PostgreSQL-9.5
3488
3689
  */
3489
3690
  static VALUE
3490
3691
  pgconn_ssl_in_use(VALUE self)
@@ -3518,7 +3719,6 @@ pgconn_ssl_in_use(VALUE self)
3518
3719
  *
3519
3720
  * See also #ssl_attribute_names and the {corresponding libpq function}[https://www.postgresql.org/docs/current/libpq-status.html#LIBPQ-PQSSLATTRIBUTE].
3520
3721
  *
3521
- * Available since PostgreSQL-9.5
3522
3722
  */
3523
3723
  static VALUE
3524
3724
  pgconn_ssl_attribute(VALUE self, VALUE attribute_name)
@@ -3537,7 +3737,6 @@ pgconn_ssl_attribute(VALUE self, VALUE attribute_name)
3537
3737
  *
3538
3738
  * See also #ssl_attribute
3539
3739
  *
3540
- * Available since PostgreSQL-9.5
3541
3740
  */
3542
3741
  static VALUE
3543
3742
  pgconn_ssl_attribute_names(VALUE self)
@@ -3553,8 +3752,6 @@ pgconn_ssl_attribute_names(VALUE self)
3553
3752
  }
3554
3753
 
3555
3754
 
3556
- #endif
3557
-
3558
3755
 
3559
3756
  #ifdef HAVE_PQENTERPIPELINEMODE
3560
3757
  /*
@@ -3589,6 +3786,8 @@ pgconn_pipeline_status(VALUE self)
3589
3786
  * Raises PG::Error and has no effect if the connection is not currently idle, i.e., it has a result ready, or it is waiting for more input from the server, etc.
3590
3787
  * This function does not actually send anything to the server, it just changes the libpq connection state.
3591
3788
  *
3789
+ * See the {PostgreSQL documentation}[https://www.postgresql.org/docs/17/libpq-pipeline-mode.html#LIBPQ-PIPELINE-MODE].
3790
+ *
3592
3791
  * Available since PostgreSQL-14
3593
3792
  */
3594
3793
  static VALUE
@@ -3627,29 +3826,55 @@ pgconn_exit_pipeline_mode(VALUE self)
3627
3826
 
3628
3827
  /*
3629
3828
  * call-seq:
3630
- * conn.pipeline_sync -> nil
3829
+ * conn.sync_pipeline_sync -> nil
3631
3830
  *
3632
- * Marks a synchronization point in a pipeline by sending a sync message and flushing the send buffer.
3633
- * This serves as the delimiter of an implicit transaction and an error recovery point; see Section 34.5.1.3 of the PostgreSQL documentation.
3831
+ * This function has the same behavior as #async_pipeline_sync, but is implemented using the synchronous command processing API of libpq.
3832
+ * See #async_exec for the differences between the two API variants.
3833
+ * It's not recommended to use explicit sync or async variants but #pipeline_sync instead, unless you have a good reason to do so.
3634
3834
  *
3835
+ * Available since PostgreSQL-14
3836
+ */
3837
+ static VALUE
3838
+ pgconn_sync_pipeline_sync(VALUE self)
3839
+ {
3840
+ PGconn *conn = pg_get_pgconn(self);
3841
+ int res = gvl_PQpipelineSync(conn);
3842
+ if( res != 1 )
3843
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
3844
+
3845
+ return Qnil;
3846
+ }
3847
+
3848
+
3849
+ #ifdef HAVE_PQSETCHUNKEDROWSMODE
3850
+ /*
3851
+ * call-seq:
3852
+ * conn.send_pipeline_sync -> nil
3853
+ *
3854
+ * Marks a synchronization point in a pipeline by sending a sync message without flushing the send buffer.
3855
+ *
3856
+ * This serves as the delimiter of an implicit transaction and an error recovery point.
3635
3857
  * Raises PG::Error if the connection is not in pipeline mode or sending a sync message failed.
3858
+ * Note that the message is not itself flushed to the server automatically; use flush if necessary.
3636
3859
  *
3637
- * Available since PostgreSQL-14
3860
+ * Available since PostgreSQL-17
3638
3861
  */
3639
3862
  static VALUE
3640
- pgconn_pipeline_sync(VALUE self)
3863
+ pgconn_send_pipeline_sync(VALUE self)
3641
3864
  {
3642
3865
  PGconn *conn = pg_get_pgconn(self);
3643
- int res = PQpipelineSync(conn);
3866
+ int res = gvl_PQsendPipelineSync(conn);
3644
3867
  if( res != 1 )
3645
3868
  pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
3646
3869
 
3647
3870
  return Qnil;
3648
3871
  }
3872
+ #endif
3873
+
3649
3874
 
3650
3875
  /*
3651
3876
  * call-seq:
3652
- * conn.pipeline_sync -> nil
3877
+ * conn.send_flush_request -> nil
3653
3878
  *
3654
3879
  * Sends a request for the server to flush its output buffer.
3655
3880
  *
@@ -4468,6 +4693,7 @@ init_pg_connection(void)
4468
4693
  rb_define_method(rb_cPGconn, "finished?", pgconn_finished_p, 0);
4469
4694
  rb_define_method(rb_cPGconn, "sync_reset", pgconn_sync_reset, 0);
4470
4695
  rb_define_method(rb_cPGconn, "reset_start", pgconn_reset_start, 0);
4696
+ rb_define_private_method(rb_cPGconn, "reset_start2", pgconn_reset_start2, 1);
4471
4697
  rb_define_method(rb_cPGconn, "reset_poll", pgconn_reset_poll, 0);
4472
4698
  rb_define_alias(rb_cPGconn, "close", "finish");
4473
4699
 
@@ -4492,7 +4718,9 @@ init_pg_connection(void)
4492
4718
  rb_define_method(rb_cPGconn, "socket", pgconn_socket, 0);
4493
4719
  rb_define_method(rb_cPGconn, "socket_io", pgconn_socket_io, 0);
4494
4720
  rb_define_method(rb_cPGconn, "backend_pid", pgconn_backend_pid, 0);
4721
+ #ifndef HAVE_PQSETCHUNKEDROWSMODE
4495
4722
  rb_define_method(rb_cPGconn, "backend_key", pgconn_backend_key, 0);
4723
+ #endif
4496
4724
  rb_define_method(rb_cPGconn, "connection_needs_password", pgconn_connection_needs_password, 0);
4497
4725
  rb_define_method(rb_cPGconn, "connection_used_password", pgconn_connection_used_password, 0);
4498
4726
  /* rb_define_method(rb_cPGconn, "getssl", pgconn_getssl, 0); */
@@ -4504,6 +4732,10 @@ init_pg_connection(void)
4504
4732
  rb_define_method(rb_cPGconn, "sync_exec_prepared", pgconn_sync_exec_prepared, -1);
4505
4733
  rb_define_method(rb_cPGconn, "sync_describe_prepared", pgconn_sync_describe_prepared, 1);
4506
4734
  rb_define_method(rb_cPGconn, "sync_describe_portal", pgconn_sync_describe_portal, 1);
4735
+ #ifdef HAVE_PQSETCHUNKEDROWSMODE
4736
+ rb_define_method(rb_cPGconn, "sync_close_prepared", pgconn_sync_close_prepared, 1);
4737
+ rb_define_method(rb_cPGconn, "sync_close_portal", pgconn_sync_close_portal, 1);
4738
+ #endif
4507
4739
 
4508
4740
  rb_define_method(rb_cPGconn, "exec", pgconn_async_exec, -1);
4509
4741
  rb_define_method(rb_cPGconn, "exec_params", pgconn_async_exec_params, -1);
@@ -4511,6 +4743,10 @@ init_pg_connection(void)
4511
4743
  rb_define_method(rb_cPGconn, "exec_prepared", pgconn_async_exec_prepared, -1);
4512
4744
  rb_define_method(rb_cPGconn, "describe_prepared", pgconn_async_describe_prepared, 1);
4513
4745
  rb_define_method(rb_cPGconn, "describe_portal", pgconn_async_describe_portal, 1);
4746
+ #ifdef HAVE_PQSETCHUNKEDROWSMODE
4747
+ rb_define_method(rb_cPGconn, "close_prepared", pgconn_async_close_prepared, 1);
4748
+ rb_define_method(rb_cPGconn, "close_portal", pgconn_async_close_portal, 1);
4749
+ #endif
4514
4750
 
4515
4751
  rb_define_alias(rb_cPGconn, "async_exec", "exec");
4516
4752
  rb_define_alias(rb_cPGconn, "async_query", "async_exec");
@@ -4519,6 +4755,10 @@ init_pg_connection(void)
4519
4755
  rb_define_alias(rb_cPGconn, "async_exec_prepared", "exec_prepared");
4520
4756
  rb_define_alias(rb_cPGconn, "async_describe_prepared", "describe_prepared");
4521
4757
  rb_define_alias(rb_cPGconn, "async_describe_portal", "describe_portal");
4758
+ #ifdef HAVE_PQSETCHUNKEDROWSMODE
4759
+ rb_define_alias(rb_cPGconn, "async_close_prepared", "close_prepared");
4760
+ rb_define_alias(rb_cPGconn, "async_close_portal", "close_portal");
4761
+ #endif
4522
4762
 
4523
4763
  rb_define_method(rb_cPGconn, "make_empty_pgresult", pgconn_make_empty_pgresult, 1);
4524
4764
  rb_define_method(rb_cPGconn, "escape_string", pgconn_s_escape, 1);
@@ -4528,6 +4768,9 @@ init_pg_connection(void)
4528
4768
  rb_define_method(rb_cPGconn, "escape_bytea", pgconn_s_escape_bytea, 1);
4529
4769
  rb_define_method(rb_cPGconn, "unescape_bytea", pgconn_s_unescape_bytea, 1);
4530
4770
  rb_define_method(rb_cPGconn, "set_single_row_mode", pgconn_set_single_row_mode, 0);
4771
+ #ifdef HAVE_PQSETCHUNKEDROWSMODE
4772
+ rb_define_method(rb_cPGconn, "set_chunked_rows_mode", pgconn_set_chunked_rows_mode, 1);
4773
+ #endif
4531
4774
 
4532
4775
  /****** PG::Connection INSTANCE METHODS: Asynchronous Command Processing ******/
4533
4776
  rb_define_method(rb_cPGconn, "send_query", pgconn_send_query, -1);
@@ -4547,7 +4790,9 @@ init_pg_connection(void)
4547
4790
  rb_define_method(rb_cPGconn, "discard_results", pgconn_discard_results, 0);
4548
4791
 
4549
4792
  /****** PG::Connection INSTANCE METHODS: Cancelling Queries in Progress ******/
4793
+ #ifndef HAVE_PQSETCHUNKEDROWSMODE
4550
4794
  rb_define_method(rb_cPGconn, "sync_cancel", pgconn_sync_cancel, 0);
4795
+ #endif
4551
4796
 
4552
4797
  /****** PG::Connection INSTANCE METHODS: NOTIFY ******/
4553
4798
  rb_define_method(rb_cPGconn, "notifies", pgconn_notifies, 0);
@@ -4559,9 +4804,7 @@ init_pg_connection(void)
4559
4804
 
4560
4805
  /****** PG::Connection INSTANCE METHODS: Control Functions ******/
4561
4806
  rb_define_method(rb_cPGconn, "set_error_verbosity", pgconn_set_error_verbosity, 1);
4562
- #ifdef HAVE_PQRESULTVERBOSEERRORMESSAGE
4563
4807
  rb_define_method(rb_cPGconn, "set_error_context_visibility", pgconn_set_error_context_visibility, 1 );
4564
- #endif
4565
4808
  rb_define_method(rb_cPGconn, "trace", pgconn_trace, 1);
4566
4809
  rb_define_method(rb_cPGconn, "untrace", pgconn_untrace, 0);
4567
4810
 
@@ -4583,22 +4826,21 @@ init_pg_connection(void)
4583
4826
  rb_define_method(rb_cPGconn, "sync_get_last_result", pgconn_sync_get_last_result, 0);
4584
4827
  rb_define_method(rb_cPGconn, "get_last_result", pgconn_async_get_last_result, 0);
4585
4828
  rb_define_alias(rb_cPGconn, "async_get_last_result", "get_last_result");
4586
- #ifdef HAVE_PQENCRYPTPASSWORDCONN
4587
4829
  rb_define_method(rb_cPGconn, "sync_encrypt_password", pgconn_sync_encrypt_password, -1);
4588
- #endif
4589
4830
 
4590
- #ifdef HAVE_PQSSLATTRIBUTE
4591
4831
  rb_define_method(rb_cPGconn, "ssl_in_use?", pgconn_ssl_in_use, 0);
4592
4832
  rb_define_method(rb_cPGconn, "ssl_attribute", pgconn_ssl_attribute, 1);
4593
4833
  rb_define_method(rb_cPGconn, "ssl_attribute_names", pgconn_ssl_attribute_names, 0);
4594
- #endif
4595
4834
 
4596
4835
  #ifdef HAVE_PQENTERPIPELINEMODE
4597
4836
  rb_define_method(rb_cPGconn, "pipeline_status", pgconn_pipeline_status, 0);
4598
4837
  rb_define_method(rb_cPGconn, "enter_pipeline_mode", pgconn_enter_pipeline_mode, 0);
4599
4838
  rb_define_method(rb_cPGconn, "exit_pipeline_mode", pgconn_exit_pipeline_mode, 0);
4600
- rb_define_method(rb_cPGconn, "pipeline_sync", pgconn_pipeline_sync, 0);
4839
+ rb_define_method(rb_cPGconn, "sync_pipeline_sync", pgconn_sync_pipeline_sync, 0);
4601
4840
  rb_define_method(rb_cPGconn, "send_flush_request", pgconn_send_flush_request, 0);
4841
+ #ifdef HAVE_PQSETCHUNKEDROWSMODE
4842
+ rb_define_method(rb_cPGconn, "send_pipeline_sync", pgconn_send_pipeline_sync, 0);
4843
+ #endif
4602
4844
  #endif
4603
4845
 
4604
4846
  /****** PG::Connection INSTANCE METHODS: Large Object Support ******/