pg 1.5.4 → 1.6.3

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 (85) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/{History.md → CHANGELOG.md} +132 -4
  4. data/Gemfile +15 -6
  5. data/README-Windows.rdoc +1 -1
  6. data/README.ja.md +4 -4
  7. data/README.md +66 -23
  8. data/Rakefile +81 -14
  9. data/certs/kanis@comcard.de.pem +20 -0
  10. data/certs/larskanis-2024.pem +24 -0
  11. data/ext/errorcodes.def +11 -3
  12. data/ext/errorcodes.rb +1 -1
  13. data/ext/errorcodes.txt +9 -5
  14. data/ext/extconf.rb +192 -15
  15. data/ext/gvl_wrappers.c +13 -2
  16. data/ext/gvl_wrappers.h +33 -0
  17. data/ext/pg.c +17 -6
  18. data/ext/pg.h +15 -13
  19. data/ext/pg_binary_decoder.c +153 -1
  20. data/ext/pg_binary_encoder.c +213 -10
  21. data/ext/pg_cancel_connection.c +360 -0
  22. data/ext/pg_coder.c +54 -5
  23. data/ext/pg_connection.c +431 -169
  24. data/ext/pg_copy_coder.c +19 -15
  25. data/ext/pg_record_coder.c +7 -7
  26. data/ext/pg_result.c +106 -54
  27. data/ext/pg_text_decoder.c +5 -2
  28. data/ext/pg_text_encoder.c +39 -20
  29. data/ext/pg_tuple.c +8 -8
  30. data/ext/pg_type_map.c +4 -2
  31. data/ext/pg_type_map_all_strings.c +1 -1
  32. data/ext/pg_type_map_by_class.c +1 -1
  33. data/ext/pg_type_map_by_column.c +2 -1
  34. data/ext/pg_type_map_by_mri_type.c +1 -1
  35. data/ext/pg_type_map_by_oid.c +3 -1
  36. data/ext/pg_type_map_in_ruby.c +1 -1
  37. data/ext/pg_util.c +2 -2
  38. data/ext/pg_util.h +2 -2
  39. data/lib/pg/basic_type_map_for_queries.rb +15 -7
  40. data/lib/pg/basic_type_registry.rb +16 -4
  41. data/lib/pg/cancel_connection.rb +53 -0
  42. data/lib/pg/coder.rb +4 -2
  43. data/lib/pg/connection.rb +310 -167
  44. data/lib/pg/exceptions.rb +6 -0
  45. data/lib/pg/text_decoder/date.rb +3 -0
  46. data/lib/pg/text_decoder/json.rb +3 -0
  47. data/lib/pg/text_encoder/date.rb +1 -0
  48. data/lib/pg/text_encoder/inet.rb +3 -0
  49. data/lib/pg/text_encoder/json.rb +3 -0
  50. data/lib/pg/version.rb +2 -1
  51. data/lib/pg.rb +156 -120
  52. data/misc/glibc/Dockerfile +20 -0
  53. data/misc/glibc/docker-compose.yml +9 -0
  54. data/misc/glibc/glibc_spec.rb +5 -0
  55. data/misc/yugabyte/Dockerfile +9 -0
  56. data/misc/yugabyte/docker-compose.yml +28 -0
  57. data/misc/yugabyte/pg-test.rb +45 -0
  58. data/pg.gemspec +8 -4
  59. data/ports/patches/krb5/1.22.1/0001-Allow-static-linking-krb5-library.patch +30 -0
  60. data/ports/patches/krb5/1.22.1/0002-unknown-command-line-option-on-clang.patch +12 -0
  61. data/ports/patches/openssl/3.5.2/0001-aarch64-mingw.patch +21 -0
  62. data/ports/patches/postgresql/18.1/0001-Use-workaround-of-__builtin_setjmp-only-on-MINGW-on-.patch +42 -0
  63. data/ports/patches/postgresql/18.1/0001-libpq-Process-buffered-SSL-read-bytes-to-support-rec.patch +52 -0
  64. data/rakelib/pg_gem_helper.rb +64 -0
  65. data.tar.gz.sig +0 -0
  66. metadata +49 -47
  67. metadata.gz.sig +0 -0
  68. data/.appveyor.yml +0 -42
  69. data/.gems +0 -6
  70. data/.gemtest +0 -0
  71. data/.github/workflows/binary-gems.yml +0 -117
  72. data/.github/workflows/source-gem.yml +0 -141
  73. data/.gitignore +0 -22
  74. data/.hgsigs +0 -34
  75. data/.hgtags +0 -41
  76. data/.irbrc +0 -23
  77. data/.pryrc +0 -23
  78. data/.tm_properties +0 -21
  79. data/.travis.yml +0 -49
  80. data/Manifest.txt +0 -72
  81. data/Rakefile.cross +0 -298
  82. data/translation/.po4a-version +0 -7
  83. data/translation/po/all.pot +0 -936
  84. data/translation/po/ja.po +0 -1036
  85. 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;
@@ -69,6 +66,7 @@ pg_get_connection_safe( VALUE self )
69
66
  t_pg_connection *this;
70
67
  TypedData_Get_Struct( self, t_pg_connection, &pg_connection_type, this);
71
68
 
69
+ rb_check_frozen(self);
72
70
  if ( !this->pgconn )
73
71
  pg_raise_conn_error( rb_eConnectionBad, self, "connection is closed");
74
72
 
@@ -96,6 +94,20 @@ pg_get_pgconn( VALUE self )
96
94
  }
97
95
 
98
96
 
97
+ void
98
+ pg_unwrap_socket_io( VALUE self, VALUE *p_socket_io, int ruby_sd )
99
+ {
100
+ if ( RTEST(*p_socket_io) ) {
101
+ #if defined(_WIN32)
102
+ if( rb_w32_unwrap_io_handle(ruby_sd) )
103
+ pg_raise_conn_error( rb_eConnectionBad, self, "Could not unwrap win32 socket handle");
104
+ #endif
105
+ rb_funcall( *p_socket_io, rb_intern("close"), 0 );
106
+ }
107
+
108
+ RB_OBJ_WRITE(self, p_socket_io, Qnil);
109
+ }
110
+
99
111
 
100
112
  /*
101
113
  * Close the associated socket IO object if there is one.
@@ -104,17 +116,7 @@ static void
104
116
  pgconn_close_socket_io( VALUE self )
105
117
  {
106
118
  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);
119
+ pg_unwrap_socket_io( self, &this->socket_io, this->ruby_sd);
118
120
  }
119
121
 
120
122
 
@@ -230,7 +232,7 @@ static const rb_data_type_t pg_connection_type = {
230
232
  pgconn_gc_mark,
231
233
  pgconn_gc_free,
232
234
  pgconn_memsize,
233
- pg_compact_callback(pgconn_gc_compact),
235
+ pgconn_gc_compact,
234
236
  },
235
237
  0,
236
238
  0,
@@ -264,6 +266,7 @@ pgconn_s_allocate( VALUE klass )
264
266
  RB_OBJ_WRITE(self, &this->decoder_for_get_copy_data, Qnil);
265
267
  RB_OBJ_WRITE(self, &this->trace_stream, Qnil);
266
268
  rb_ivar_set(self, rb_intern("@calls_to_put_copy_data"), INT2FIX(0));
269
+ rb_ivar_set(self, rb_intern("@iopts_for_reset"), Qnil);
267
270
 
268
271
  return self;
269
272
  }
@@ -418,7 +421,6 @@ pgconn_s_conninfo_parse(VALUE self, VALUE conninfo)
418
421
  }
419
422
 
420
423
 
421
- #ifdef HAVE_PQENCRYPTPASSWORDCONN
422
424
  static VALUE
423
425
  pgconn_sync_encrypt_password(int argc, VALUE *argv, VALUE self)
424
426
  {
@@ -442,7 +444,6 @@ pgconn_sync_encrypt_password(int argc, VALUE *argv, VALUE self)
442
444
 
443
445
  return rval;
444
446
  }
445
- #endif
446
447
 
447
448
 
448
449
  /*
@@ -515,9 +516,9 @@ static VALUE
515
516
  pgconn_connect_poll(VALUE self)
516
517
  {
517
518
  PostgresPollingStatusType status;
518
- status = gvl_PQconnectPoll(pg_get_pgconn(self));
519
519
 
520
520
  pgconn_close_socket_io(self);
521
+ status = gvl_PQconnectPoll(pg_get_pgconn(self));
521
522
 
522
523
  return INT2FIX((int)status);
523
524
  }
@@ -563,6 +564,27 @@ pgconn_sync_reset( VALUE self )
563
564
  return self;
564
565
  }
565
566
 
567
+ static VALUE
568
+ pgconn_reset_start2( VALUE self, VALUE conninfo )
569
+ {
570
+ t_pg_connection *this = pg_get_connection( self );
571
+
572
+ /* Close old connection */
573
+ pgconn_close_socket_io( self );
574
+ PQfinish( this->pgconn );
575
+
576
+ /* Start new connection */
577
+ this->pgconn = gvl_PQconnectStart( StringValueCStr(conninfo) );
578
+
579
+ if( this->pgconn == NULL )
580
+ rb_raise(rb_ePGerror, "PQconnectStart() unable to allocate PGconn structure");
581
+
582
+ if ( PQstatus(this->pgconn) == CONNECTION_BAD )
583
+ pg_raise_conn_error( rb_eConnectionBad, self, "%s", PQerrorMessage(this->pgconn));
584
+
585
+ return Qnil;
586
+ }
587
+
566
588
  /*
567
589
  * call-seq:
568
590
  * conn.reset_start() -> nil
@@ -587,16 +609,16 @@ pgconn_reset_start(VALUE self)
587
609
  * conn.reset_poll -> Integer
588
610
  *
589
611
  * Checks the status of a connection reset operation.
590
- * See #connect_start and #connect_poll for
612
+ * See Connection.connect_start and #connect_poll for
591
613
  * usage information and return values.
592
614
  */
593
615
  static VALUE
594
616
  pgconn_reset_poll(VALUE self)
595
617
  {
596
618
  PostgresPollingStatusType status;
597
- status = gvl_PQresetPoll(pg_get_pgconn(self));
598
619
 
599
620
  pgconn_close_socket_io(self);
621
+ status = gvl_PQresetPoll(pg_get_pgconn(self));
600
622
 
601
623
  return INT2FIX((int)status);
602
624
  }
@@ -738,7 +760,6 @@ pgconn_options(VALUE self)
738
760
  *
739
761
  * Returns the connection options used by a live connection.
740
762
  *
741
- * Available since PostgreSQL-9.3
742
763
  */
743
764
  static VALUE
744
765
  pgconn_conninfo( VALUE self )
@@ -825,31 +846,52 @@ pgconn_parameter_status(VALUE self, VALUE param_name)
825
846
  * call-seq:
826
847
  * conn.protocol_version -> Integer
827
848
  *
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.)
849
+ * Interrogates the frontend/backend protocol being used.
850
+ *
851
+ * Applications might wish to use this function to determine whether certain features are supported.
852
+ * Currently, the only value is 3 (3.0 protocol).
853
+ * The protocol version will not change after connection startup is complete, but it could theoretically change during a connection reset.
854
+ * The 3.0 protocol is supported by PostgreSQL server versions 7.4 and above.
855
+ *
856
+ * PG::ConnectionBad is raised if the connection is bad.
831
857
  */
832
858
  static VALUE
833
859
  pgconn_protocol_version(VALUE self)
834
860
  {
835
- return INT2NUM(PQprotocolVersion(pg_get_pgconn(self)));
861
+ int protocol_version = PQprotocolVersion(pg_get_pgconn(self));
862
+ if (protocol_version == 0) {
863
+ pg_raise_conn_error( rb_eConnectionBad, self, "PQprotocolVersion() can't get protocol version");
864
+ }
865
+ return INT2NUM(protocol_version);
836
866
  }
837
867
 
838
868
  /*
839
869
  * call-seq:
840
870
  * conn.server_version -> Integer
841
871
  *
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.
872
+ * Returns an integer representing the server version.
873
+ *
874
+ * Applications might use this function to determine the version of the database server they are connected to.
875
+ * The result is formed by multiplying the server's major version number by 10000 and adding the minor version number.
876
+ * For example, version 10.1 will be returned as 100001, and version 11.0 will be returned as 110000.
877
+ *
878
+ * PG::ConnectionBad is raised if the connection is bad.
879
+ *
880
+ * Prior to major version 10, PostgreSQL used three-part version numbers in which the first two parts together represented the major version.
881
+ * 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.
882
+ *
883
+ * 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.
884
+ * In all release series, only the last two digits differ between minor releases (bug-fix releases).
847
885
  *
848
886
  */
849
887
  static VALUE
850
888
  pgconn_server_version(VALUE self)
851
889
  {
852
- return INT2NUM(PQserverVersion(pg_get_pgconn(self)));
890
+ int server_version = PQserverVersion(pg_get_pgconn(self));
891
+ if (server_version == 0) {
892
+ pg_raise_conn_error( rb_eConnectionBad, self, "PQserverVersion() can't get server version");
893
+ }
894
+ return INT2NUM(server_version);
853
895
  }
854
896
 
855
897
  /*
@@ -898,13 +940,42 @@ pgconn_socket(VALUE self)
898
940
  return INT2NUM(sd);
899
941
  }
900
942
 
943
+
944
+ VALUE
945
+ pg_wrap_socket_io(int sd, VALUE self, VALUE *p_socket_io, int *p_ruby_sd)
946
+ {
947
+ int ruby_sd;
948
+ VALUE cSocket;
949
+ VALUE socket_io = *p_socket_io;
950
+
951
+ #ifdef _WIN32
952
+ ruby_sd = rb_w32_wrap_io_handle((HANDLE)(intptr_t)sd, O_RDWR|O_BINARY|O_NOINHERIT);
953
+ if( ruby_sd == -1 )
954
+ pg_raise_conn_error( rb_eConnectionBad, self, "Could not wrap win32 socket handle");
955
+
956
+ *p_ruby_sd = ruby_sd;
957
+ #else
958
+ *p_ruby_sd = ruby_sd = sd;
959
+ #endif
960
+
961
+ cSocket = rb_const_get(rb_cObject, rb_intern("BasicSocket"));
962
+ socket_io = rb_funcall( cSocket, rb_intern("for_fd"), 1, INT2NUM(ruby_sd));
963
+
964
+ /* Disable autoclose feature */
965
+ rb_funcall( socket_io, s_id_autoclose_set, 1, Qfalse );
966
+
967
+ RB_OBJ_WRITE(self, p_socket_io, socket_io);
968
+
969
+ return socket_io;
970
+ }
971
+
901
972
  /*
902
973
  * call-seq:
903
974
  * conn.socket_io() -> IO
904
975
  *
905
976
  * Fetch an IO object created from the Connection's underlying socket.
906
977
  * 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>.
978
+ * <tt>IO#wait_*able</tt> is <tt>Fiber.scheduler</tt> compatible in contrast to <tt>IO.select</tt>.
908
979
  *
909
980
  * The IO object can change while the connection is established, but is memorized afterwards.
910
981
  * So be sure not to cache the IO object, but repeat calling <tt>conn.socket_io</tt> instead.
@@ -915,37 +986,17 @@ pgconn_socket(VALUE self)
915
986
  static VALUE
916
987
  pgconn_socket_io(VALUE self)
917
988
  {
918
- int sd;
919
- int ruby_sd;
920
989
  t_pg_connection *this = pg_get_connection_safe( self );
921
- VALUE cSocket;
922
- VALUE socket_io = this->socket_io;
923
990
 
924
- if ( !RTEST(socket_io) ) {
991
+ if ( !RTEST(this->socket_io) ) {
992
+ int sd;
925
993
  if( (sd = PQsocket(this->pgconn)) < 0){
926
994
  pg_raise_conn_error( rb_eConnectionBad, self, "PQsocket() can't get socket descriptor");
927
995
  }
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);
996
+ return pg_wrap_socket_io( sd, self, &this->socket_io, &this->ruby_sd);
946
997
  }
947
998
 
948
- return socket_io;
999
+ return this->socket_io;
949
1000
  }
950
1001
 
951
1002
  /*
@@ -962,6 +1013,7 @@ pgconn_backend_pid(VALUE self)
962
1013
  return INT2NUM(PQbackendPID(pg_get_pgconn(self)));
963
1014
  }
964
1015
 
1016
+ #ifndef HAVE_PQSETCHUNKEDROWSMODE
965
1017
  typedef struct
966
1018
  {
967
1019
  struct sockaddr_storage addr;
@@ -1006,6 +1058,7 @@ pgconn_backend_key(VALUE self)
1006
1058
 
1007
1059
  return INT2NUM(be_key);
1008
1060
  }
1061
+ #endif
1009
1062
 
1010
1063
  /*
1011
1064
  * call-seq:
@@ -1278,7 +1331,7 @@ alloc_query_params(struct query_params_data *paramsData)
1278
1331
  paramsData->lengths[i] = 0;
1279
1332
  } else {
1280
1333
  t_pg_coder_enc_func enc_func = pg_coder_enc_func( conv );
1281
- VALUE intermediate;
1334
+ VALUE intermediate = Qnil;
1282
1335
 
1283
1336
  /* 1st pass for retiving the required memory space */
1284
1337
  int len = enc_func(conv, param_value, NULL, &intermediate, paramsData->enc_idx);
@@ -1318,8 +1371,6 @@ alloc_query_params(struct query_params_data *paramsData)
1318
1371
  required_pool_size += len;
1319
1372
  }
1320
1373
  }
1321
-
1322
- RB_GC_GUARD(intermediate);
1323
1374
  }
1324
1375
  }
1325
1376
  }
@@ -1494,6 +1545,19 @@ pgconn_sync_exec_prepared(int argc, VALUE *argv, VALUE self)
1494
1545
  return rb_pgresult;
1495
1546
  }
1496
1547
 
1548
+ static VALUE
1549
+ pgconn_sync_describe_close_prepared_portal(VALUE self, VALUE name, PGresult *(*func)(PGconn *, const char *))
1550
+ {
1551
+ PGresult *result;
1552
+ VALUE rb_pgresult;
1553
+ t_pg_connection *this = pg_get_connection_safe( self );
1554
+ const char *stmt = NIL_P(name) ? NULL : pg_cstr_enc(name, this->enc_idx);
1555
+ result = func(this->pgconn, stmt);
1556
+ rb_pgresult = pg_new_result(result, self);
1557
+ pg_result_check(rb_pgresult);
1558
+ return rb_pgresult;
1559
+ }
1560
+
1497
1561
  /*
1498
1562
  * call-seq:
1499
1563
  * conn.sync_describe_prepared( statement_name ) -> PG::Result
@@ -1505,20 +1569,7 @@ pgconn_sync_exec_prepared(int argc, VALUE *argv, VALUE self)
1505
1569
  static VALUE
1506
1570
  pgconn_sync_describe_prepared(VALUE self, VALUE stmt_name)
1507
1571
  {
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;
1572
+ return pgconn_sync_describe_close_prepared_portal(self, stmt_name, gvl_PQdescribePrepared);
1522
1573
  }
1523
1574
 
1524
1575
 
@@ -1533,22 +1584,43 @@ pgconn_sync_describe_prepared(VALUE self, VALUE stmt_name)
1533
1584
  static VALUE
1534
1585
  pgconn_sync_describe_portal(VALUE self, VALUE stmt_name)
1535
1586
  {
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;
1587
+ return pgconn_sync_describe_close_prepared_portal(self, stmt_name, gvl_PQdescribePortal);
1588
+ }
1589
+
1590
+
1591
+ #ifdef HAVE_PQSETCHUNKEDROWSMODE
1592
+ /*
1593
+ * call-seq:
1594
+ * conn.sync_close_prepared( stmt_name ) -> PG::Result
1595
+ *
1596
+ * This function has the same behavior as #async_close_prepared, but is implemented using the synchronous command processing API of libpq.
1597
+ * See #async_exec for the differences between the two API variants.
1598
+ * It's not recommended to use explicit sync or async variants but #close_prepared instead, unless you have a good reason to do so.
1599
+ *
1600
+ * Available since PostgreSQL-17.
1601
+ */
1602
+ static VALUE
1603
+ pgconn_sync_close_prepared(VALUE self, VALUE stmt_name)
1604
+ {
1605
+ return pgconn_sync_describe_close_prepared_portal(self, stmt_name, gvl_PQclosePrepared);
1550
1606
  }
1551
1607
 
1608
+ /*
1609
+ * call-seq:
1610
+ * conn.sync_close_portal( portal_name ) -> PG::Result
1611
+ *
1612
+ * This function has the same behavior as #async_close_portal, but is implemented using the synchronous command processing API of libpq.
1613
+ * See #async_exec for the differences between the two API variants.
1614
+ * It's not recommended to use explicit sync or async variants but #close_portal instead, unless you have a good reason to do so.
1615
+ *
1616
+ * Available since PostgreSQL-17.
1617
+ */
1618
+ static VALUE
1619
+ pgconn_sync_close_portal(VALUE self, VALUE stmt_name)
1620
+ {
1621
+ return pgconn_sync_describe_close_prepared_portal(self, stmt_name, gvl_PQclosePortal);
1622
+ }
1623
+ #endif
1552
1624
 
1553
1625
  /*
1554
1626
  * call-seq:
@@ -1566,6 +1638,7 @@ pgconn_sync_describe_portal(VALUE self, VALUE stmt_name)
1566
1638
  * * +PGRES_FATAL_ERROR+
1567
1639
  * * +PGRES_COPY_BOTH+
1568
1640
  * * +PGRES_SINGLE_TUPLE+
1641
+ * * +PGRES_TUPLES_CHUNK+
1569
1642
  * * +PGRES_PIPELINE_SYNC+
1570
1643
  * * +PGRES_PIPELINE_ABORTED+
1571
1644
  */
@@ -1790,14 +1863,11 @@ pgconn_escape_identifier(VALUE self, VALUE string)
1790
1863
  * (column names, types, etc) that an ordinary Result object for the query
1791
1864
  * would have.
1792
1865
  *
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.
1866
+ * *Caution:* While processing a query, the server may return some rows and then encounter an error, causing the query to be aborted.
1867
+ * Ordinarily, pg discards any such rows and reports only the error.
1868
+ * But in single-row or chunked mode, some rows may have already been returned to the application.
1869
+ * 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.
1870
+ * 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
1871
  *
1802
1872
  * Example:
1803
1873
  * conn.send_query( "your SQL command" )
@@ -1817,10 +1887,49 @@ pgconn_set_single_row_mode(VALUE self)
1817
1887
 
1818
1888
  rb_check_frozen(self);
1819
1889
  if( PQsetSingleRowMode(conn) == 0 )
1820
- pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
1890
+ pg_raise_conn_error( rb_ePGerror, self, "PQsetSingleRowMode %s", PQerrorMessage(conn));
1891
+
1892
+ return self;
1893
+ }
1894
+
1895
+ #ifdef HAVE_PQSETCHUNKEDROWSMODE
1896
+ /*
1897
+ * call-seq:
1898
+ * conn.set_chunked_rows_mode -> self
1899
+ *
1900
+ * Select chunked mode for the currently-executing query.
1901
+ *
1902
+ * 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.
1903
+ * 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.
1904
+ * If called at the correct time, the function activates chunked mode for the current query.
1905
+ * Otherwise the mode stays unchanged and the function raises an error.
1906
+ * In any case, the mode reverts to normal after completion of the current query.
1907
+ *
1908
+ * Example:
1909
+ * conn.send_query( "your SQL command" )
1910
+ * conn.set_chunked_rows_mode(10)
1911
+ * loop do
1912
+ * res = conn.get_result or break
1913
+ * res.check
1914
+ * res.each do |row|
1915
+ * # do something with the received max. 10 rows
1916
+ * end
1917
+ * end
1918
+ *
1919
+ * Available since PostgreSQL-17
1920
+ */
1921
+ static VALUE
1922
+ pgconn_set_chunked_rows_mode(VALUE self, VALUE chunk_size)
1923
+ {
1924
+ PGconn *conn = pg_get_pgconn(self);
1925
+
1926
+ rb_check_frozen(self);
1927
+ if( PQsetChunkedRowsMode(conn, NUM2INT(chunk_size)) == 0 )
1928
+ pg_raise_conn_error( rb_ePGerror, self, "PQsetChunkedRowsMode %s", PQerrorMessage(conn));
1821
1929
 
1822
1930
  return self;
1823
1931
  }
1932
+ #endif
1824
1933
 
1825
1934
  static VALUE pgconn_send_query_params(int argc, VALUE *argv, VALUE self);
1826
1935
 
@@ -1845,7 +1954,7 @@ pgconn_send_query(int argc, VALUE *argv, VALUE self)
1845
1954
  /* If called with no or nil parameters, use PQexec for compatibility */
1846
1955
  if ( argc == 1 || (argc >= 2 && argc <= 4 && NIL_P(argv[1]) )) {
1847
1956
  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));
1957
+ pg_raise_conn_error( rb_eUnableToSend, self, "PQsendQuery %s", PQerrorMessage(this->pgconn));
1849
1958
 
1850
1959
  pgconn_wait_for_flush( self );
1851
1960
  return Qnil;
@@ -1920,7 +2029,7 @@ pgconn_send_query_params(int argc, VALUE *argv, VALUE self)
1920
2029
  free_query_params( &paramsData );
1921
2030
 
1922
2031
  if(result == 0)
1923
- pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
2032
+ pg_raise_conn_error( rb_eUnableToSend, self, "PQsendQueryParams %s", PQerrorMessage(this->pgconn));
1924
2033
 
1925
2034
  pgconn_wait_for_flush( self );
1926
2035
  return Qnil;
@@ -1981,7 +2090,7 @@ pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
1981
2090
  xfree(paramTypes);
1982
2091
 
1983
2092
  if(result == 0) {
1984
- pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
2093
+ pg_raise_conn_error( rb_eUnableToSend, self, "PQsendPrepare %s", PQerrorMessage(this->pgconn));
1985
2094
  }
1986
2095
  pgconn_wait_for_flush( self );
1987
2096
  return Qnil;
@@ -2047,7 +2156,21 @@ pgconn_send_query_prepared(int argc, VALUE *argv, VALUE self)
2047
2156
  free_query_params( &paramsData );
2048
2157
 
2049
2158
  if(result == 0)
2050
- pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
2159
+ pg_raise_conn_error( rb_eUnableToSend, self, "PQsendQueryPrepared %s", PQerrorMessage(this->pgconn));
2160
+
2161
+ pgconn_wait_for_flush( self );
2162
+ return Qnil;
2163
+ }
2164
+
2165
+
2166
+ static VALUE
2167
+ pgconn_send_describe_close_prepared_portal(VALUE self, VALUE name, int (*func)(PGconn *, const char *), const char *funame)
2168
+ {
2169
+ t_pg_connection *this = pg_get_connection_safe( self );
2170
+ const char *stmt = NIL_P(name) ? NULL : pg_cstr_enc(name, this->enc_idx);
2171
+ /* returns 0 on failure */
2172
+ if(func(this->pgconn, stmt) == 0)
2173
+ pg_raise_conn_error( rb_eUnableToSend, self, "%s %s", funame, PQerrorMessage(this->pgconn));
2051
2174
 
2052
2175
  pgconn_wait_for_flush( self );
2053
2176
  return Qnil;
@@ -2063,13 +2186,9 @@ pgconn_send_query_prepared(int argc, VALUE *argv, VALUE self)
2063
2186
  static VALUE
2064
2187
  pgconn_send_describe_prepared(VALUE self, VALUE stmt_name)
2065
2188
  {
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;
2189
+ return pgconn_send_describe_close_prepared_portal(
2190
+ self, stmt_name, gvl_PQsendDescribePrepared,
2191
+ "PQsendDescribePrepared");
2073
2192
  }
2074
2193
 
2075
2194
 
@@ -2083,16 +2202,48 @@ pgconn_send_describe_prepared(VALUE self, VALUE stmt_name)
2083
2202
  static VALUE
2084
2203
  pgconn_send_describe_portal(VALUE self, VALUE portal)
2085
2204
  {
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));
2205
+ return pgconn_send_describe_close_prepared_portal(
2206
+ self, portal, gvl_PQsendDescribePortal,
2207
+ "PQsendDescribePortal");
2208
+ }
2090
2209
 
2091
- pgconn_wait_for_flush( self );
2092
- return Qnil;
2210
+ #ifdef HAVE_PQSETCHUNKEDROWSMODE
2211
+ /*
2212
+ * call-seq:
2213
+ * conn.send_close_prepared( statement_name ) -> nil
2214
+ *
2215
+ * Asynchronously send _command_ to the server. Does not block.
2216
+ * Use in combination with +conn.get_result+.
2217
+ *
2218
+ * Available since PostgreSQL-17.
2219
+ */
2220
+ static VALUE
2221
+ pgconn_send_close_prepared(VALUE self, VALUE stmt_name)
2222
+ {
2223
+ return pgconn_send_describe_close_prepared_portal(
2224
+ self, stmt_name, gvl_PQsendClosePrepared,
2225
+ "PQsendClosePrepared");
2093
2226
  }
2094
2227
 
2095
2228
 
2229
+ /*
2230
+ * call-seq:
2231
+ * conn.send_close_portal( portal_name ) -> nil
2232
+ *
2233
+ * Asynchronously send _command_ to the server. Does not block.
2234
+ * Use in combination with +conn.get_result+.
2235
+ *
2236
+ * Available since PostgreSQL-17.
2237
+ */
2238
+ static VALUE
2239
+ pgconn_send_close_portal(VALUE self, VALUE portal)
2240
+ {
2241
+ return pgconn_send_describe_close_prepared_portal(
2242
+ self, portal, gvl_PQsendClosePortal,
2243
+ "PQsendClosePortal");
2244
+ }
2245
+ #endif
2246
+
2096
2247
  static VALUE
2097
2248
  pgconn_sync_get_result(VALUE self)
2098
2249
  {
@@ -2182,6 +2333,7 @@ pgconn_sync_flush(VALUE self)
2182
2333
  return (ret) ? Qfalse : Qtrue;
2183
2334
  }
2184
2335
 
2336
+ #ifndef HAVE_PQSETCHUNKEDROWSMODE
2185
2337
  static VALUE
2186
2338
  pgconn_sync_cancel(VALUE self)
2187
2339
  {
@@ -2203,6 +2355,7 @@ pgconn_sync_cancel(VALUE self)
2203
2355
  PQfreeCancel(cancel);
2204
2356
  return retval;
2205
2357
  }
2358
+ #endif
2206
2359
 
2207
2360
 
2208
2361
  /*
@@ -2230,7 +2383,7 @@ pgconn_notifies(VALUE self)
2230
2383
  return Qnil;
2231
2384
  }
2232
2385
 
2233
- hash = rb_hash_new();
2386
+ hash = rb_hash_new_capa(3);
2234
2387
  relname = rb_str_new2(notification->relname);
2235
2388
  be_pid = INT2NUM(notification->be_pid);
2236
2389
  extra = rb_str_new2(notification->extra);
@@ -2245,6 +2398,18 @@ pgconn_notifies(VALUE self)
2245
2398
  return hash;
2246
2399
  }
2247
2400
 
2401
+ #ifndef HAVE_RB_IO_DESCRIPTOR
2402
+ static int
2403
+ rb_io_descriptor(VALUE io)
2404
+ {
2405
+ rb_io_t *fptr;
2406
+ Check_Type(io, T_FILE);
2407
+ fptr = RFILE(io)->fptr;
2408
+ rb_io_check_closed(fptr);
2409
+ return fptr->fd;
2410
+ }
2411
+ #endif
2412
+
2248
2413
  #if defined(_WIN32)
2249
2414
 
2250
2415
  /* We use a specialized implementation of rb_io_wait() on Windows.
@@ -2265,7 +2430,6 @@ int rb_w32_wait_events( HANDLE *events, int num, DWORD timeout );
2265
2430
 
2266
2431
  static VALUE
2267
2432
  pg_rb_thread_io_wait(VALUE io, VALUE events, VALUE timeout) {
2268
- rb_io_t *fptr;
2269
2433
  struct timeval ptimeout;
2270
2434
 
2271
2435
  struct timeval aborttime={0,0}, currtime, waittime;
@@ -2276,7 +2440,6 @@ pg_rb_thread_io_wait(VALUE io, VALUE events, VALUE timeout) {
2276
2440
  long w32_events = 0;
2277
2441
  DWORD wait_ret;
2278
2442
 
2279
- GetOpenFile((io), fptr);
2280
2443
  if( !NIL_P(timeout) ){
2281
2444
  ptimeout.tv_sec = (time_t)(NUM2DBL(timeout));
2282
2445
  ptimeout.tv_usec = (time_t)((NUM2DBL(timeout) - (double)ptimeout.tv_sec) * 1e6);
@@ -2290,7 +2453,7 @@ pg_rb_thread_io_wait(VALUE io, VALUE events, VALUE timeout) {
2290
2453
  if(rb_events & PG_RUBY_IO_PRIORITY) w32_events |= FD_OOB;
2291
2454
 
2292
2455
  for(;;) {
2293
- if ( WSAEventSelect(_get_osfhandle(fptr->fd), hEvent, w32_events) == SOCKET_ERROR ) {
2456
+ if ( WSAEventSelect(_get_osfhandle(rb_io_descriptor(io)), hEvent, w32_events) == SOCKET_ERROR ) {
2294
2457
  WSACloseEvent( hEvent );
2295
2458
  rb_raise( rb_eConnectionBad, "WSAEventSelect socket error: %d", WSAGetLastError() );
2296
2459
  }
@@ -2333,7 +2496,7 @@ static VALUE
2333
2496
  pg_rb_io_wait(VALUE io, VALUE events, VALUE timeout) {
2334
2497
  #if defined(HAVE_RUBY_FIBER_SCHEDULER_H)
2335
2498
  /* 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.
2499
+ * Fortunately ruby-3.1 offers a C-API for it.
2337
2500
  */
2338
2501
  VALUE scheduler = rb_fiber_scheduler_current();
2339
2502
 
@@ -2363,16 +2526,14 @@ typedef enum {
2363
2526
 
2364
2527
  static VALUE
2365
2528
  pg_rb_io_wait(VALUE io, VALUE events, VALUE timeout) {
2366
- rb_io_t *fptr;
2367
2529
  struct timeval waittime;
2368
2530
  int res;
2369
2531
 
2370
- GetOpenFile((io), fptr);
2371
2532
  if( !NIL_P(timeout) ){
2372
2533
  waittime.tv_sec = (time_t)(NUM2DBL(timeout));
2373
2534
  waittime.tv_usec = (time_t)((NUM2DBL(timeout) - (double)waittime.tv_sec) * 1e6);
2374
2535
  }
2375
- res = rb_wait_for_single_fd(fptr->fd, NUM2UINT(events), NIL_P(timeout) ? NULL : &waittime);
2536
+ res = rb_wait_for_single_fd(rb_io_descriptor(io), NUM2UINT(events), NIL_P(timeout) ? NULL : &waittime);
2376
2537
 
2377
2538
  return UINT2NUM(res);
2378
2539
  }
@@ -2539,7 +2700,7 @@ pgconn_sync_put_copy_data(int argc, VALUE *argv, VALUE self)
2539
2700
  VALUE value;
2540
2701
  VALUE buffer = Qnil;
2541
2702
  VALUE encoder;
2542
- VALUE intermediate;
2703
+ VALUE intermediate = Qnil;
2543
2704
  t_pg_coder *p_coder = NULL;
2544
2705
 
2545
2706
  rb_scan_args( argc, argv, "11", &value, &encoder );
@@ -2578,7 +2739,6 @@ pgconn_sync_put_copy_data(int argc, VALUE *argv, VALUE self)
2578
2739
  if(ret == -1)
2579
2740
  pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(this->pgconn));
2580
2741
 
2581
- RB_GC_GUARD(intermediate);
2582
2742
  RB_GC_GUARD(buffer);
2583
2743
 
2584
2744
  return (ret) ? Qtrue : Qfalse;
@@ -2673,7 +2833,6 @@ pgconn_set_error_verbosity(VALUE self, VALUE in_verbosity)
2673
2833
  return INT2FIX(PQsetErrorVerbosity(conn, verbosity));
2674
2834
  }
2675
2835
 
2676
- #ifdef HAVE_PQRESULTVERBOSEERRORMESSAGE
2677
2836
  /*
2678
2837
  * call-seq:
2679
2838
  * conn.set_error_context_visibility( context_visibility ) -> Integer
@@ -2693,7 +2852,6 @@ pgconn_set_error_verbosity(VALUE self, VALUE in_verbosity)
2693
2852
  *
2694
2853
  * See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-control.html#LIBPQ-PQSETERRORCONTEXTVISIBILITY].
2695
2854
  *
2696
- * Available since PostgreSQL-9.6
2697
2855
  */
2698
2856
  static VALUE
2699
2857
  pgconn_set_error_context_visibility(VALUE self, VALUE in_context_visibility)
@@ -2702,7 +2860,6 @@ pgconn_set_error_context_visibility(VALUE self, VALUE in_context_visibility)
2702
2860
  PGContextVisibility context_visibility = NUM2INT(in_context_visibility);
2703
2861
  return INT2FIX(PQsetErrorContextVisibility(conn, context_visibility));
2704
2862
  }
2705
- #endif
2706
2863
 
2707
2864
  /*
2708
2865
  * call-seq:
@@ -3107,7 +3264,9 @@ pgconn_async_get_last_result(VALUE self)
3107
3264
  for(;;) {
3108
3265
  int status;
3109
3266
 
3110
- /* wait for input (without blocking) before reading each result */
3267
+ /* Wait for input before reading each result.
3268
+ * That way we support the ruby-3.x IO scheduler and don't block other ruby threads.
3269
+ */
3111
3270
  wait_socket_readable(self, NULL, get_result_readable);
3112
3271
 
3113
3272
  cur = gvl_PQgetResult(conn);
@@ -3141,7 +3300,7 @@ pgconn_async_get_last_result(VALUE self)
3141
3300
  * Returns:
3142
3301
  * * +nil+ when the connection is already idle
3143
3302
  * * +true+ when some results have been discarded
3144
- * * +false+ when a failure occured and the connection was closed
3303
+ * * +false+ when a failure occurred and the connection was closed
3145
3304
  *
3146
3305
  */
3147
3306
  static VALUE
@@ -3428,6 +3587,21 @@ pgconn_async_exec_prepared(int argc, VALUE *argv, VALUE self)
3428
3587
  return rb_pgresult;
3429
3588
  }
3430
3589
 
3590
+ static VALUE
3591
+ pgconn_async_describe_close_prepared_potral(VALUE self, VALUE name, VALUE
3592
+ (*func)(VALUE, VALUE))
3593
+ {
3594
+ VALUE rb_pgresult = Qnil;
3595
+
3596
+ pgconn_discard_results( self );
3597
+ func( self, name );
3598
+ rb_pgresult = pgconn_async_get_last_result( self );
3599
+
3600
+ if ( rb_block_given_p() ) {
3601
+ return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
3602
+ }
3603
+ return rb_pgresult;
3604
+ }
3431
3605
 
3432
3606
  /*
3433
3607
  * call-seq:
@@ -3440,16 +3614,7 @@ pgconn_async_exec_prepared(int argc, VALUE *argv, VALUE self)
3440
3614
  static VALUE
3441
3615
  pgconn_async_describe_portal(VALUE self, VALUE portal)
3442
3616
  {
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;
3617
+ return pgconn_async_describe_close_prepared_potral(self, portal, pgconn_send_describe_portal);
3453
3618
  }
3454
3619
 
3455
3620
 
@@ -3464,27 +3629,64 @@ pgconn_async_describe_portal(VALUE self, VALUE portal)
3464
3629
  static VALUE
3465
3630
  pgconn_async_describe_prepared(VALUE self, VALUE stmt_name)
3466
3631
  {
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 );
3632
+ return pgconn_async_describe_close_prepared_potral(self, stmt_name, pgconn_send_describe_prepared);
3633
+ }
3472
3634
 
3473
- if ( rb_block_given_p() ) {
3474
- return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
3475
- }
3476
- return rb_pgresult;
3635
+ #ifdef HAVE_PQSETCHUNKEDROWSMODE
3636
+ /*
3637
+ * call-seq:
3638
+ * conn.close_prepared( statement_name ) -> PG::Result
3639
+ *
3640
+ * Submits a request to close the specified prepared statement, and waits for completion.
3641
+ * close_prepared allows an application to close a previously prepared statement.
3642
+ * Closing a statement releases all of its associated resources on the server and allows its name to be reused.
3643
+ * It's the same as using the +DEALLOCATE+ SQL statement, but on a lower protocol level.
3644
+ *
3645
+ * +statement_name+ can be "" or +nil+ to reference the unnamed statement.
3646
+ * It is fine if no statement exists with this name, in that case the operation is a no-op.
3647
+ * On success, a PG::Result with status PGRES_COMMAND_OK is returned.
3648
+ *
3649
+ * See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQCLOSEPREPARED].
3650
+ *
3651
+ * Available since PostgreSQL-17.
3652
+ */
3653
+ static VALUE
3654
+ pgconn_async_close_prepared(VALUE self, VALUE stmt_name)
3655
+ {
3656
+ return pgconn_async_describe_close_prepared_potral(self, stmt_name, pgconn_send_close_prepared);
3477
3657
  }
3478
3658
 
3659
+ /*
3660
+ * call-seq:
3661
+ * conn.close_portal( portal_name ) -> PG::Result
3662
+ *
3663
+ * Submits a request to close the specified portal, and waits for completion.
3664
+ *
3665
+ * close_portal allows an application to trigger a close of a previously created portal.
3666
+ * Closing a portal releases all of its associated resources on the server and allows its name to be reused.
3667
+ * (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.)
3668
+ *
3669
+ * +portal_name+ can be "" or +nil+ to reference the unnamed portal.
3670
+ * It is fine if no portal exists with this name, in that case the operation is a no-op.
3671
+ * On success, a PG::Result with status PGRES_COMMAND_OK is returned.
3672
+ *
3673
+ * See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQCLOSEPORTAL].
3674
+ *
3675
+ * Available since PostgreSQL-17.
3676
+ */
3677
+ static VALUE
3678
+ pgconn_async_close_portal(VALUE self, VALUE portal)
3679
+ {
3680
+ return pgconn_async_describe_close_prepared_potral(self, portal, pgconn_send_close_portal);
3681
+ }
3682
+ #endif
3479
3683
 
3480
- #ifdef HAVE_PQSSLATTRIBUTE
3481
3684
  /*
3482
3685
  * call-seq:
3483
3686
  * conn.ssl_in_use? -> Boolean
3484
3687
  *
3485
3688
  * Returns +true+ if the connection uses SSL/TLS, +false+ if not.
3486
3689
  *
3487
- * Available since PostgreSQL-9.5
3488
3690
  */
3489
3691
  static VALUE
3490
3692
  pgconn_ssl_in_use(VALUE self)
@@ -3518,7 +3720,6 @@ pgconn_ssl_in_use(VALUE self)
3518
3720
  *
3519
3721
  * See also #ssl_attribute_names and the {corresponding libpq function}[https://www.postgresql.org/docs/current/libpq-status.html#LIBPQ-PQSSLATTRIBUTE].
3520
3722
  *
3521
- * Available since PostgreSQL-9.5
3522
3723
  */
3523
3724
  static VALUE
3524
3725
  pgconn_ssl_attribute(VALUE self, VALUE attribute_name)
@@ -3537,7 +3738,6 @@ pgconn_ssl_attribute(VALUE self, VALUE attribute_name)
3537
3738
  *
3538
3739
  * See also #ssl_attribute
3539
3740
  *
3540
- * Available since PostgreSQL-9.5
3541
3741
  */
3542
3742
  static VALUE
3543
3743
  pgconn_ssl_attribute_names(VALUE self)
@@ -3553,8 +3753,6 @@ pgconn_ssl_attribute_names(VALUE self)
3553
3753
  }
3554
3754
 
3555
3755
 
3556
- #endif
3557
-
3558
3756
 
3559
3757
  #ifdef HAVE_PQENTERPIPELINEMODE
3560
3758
  /*
@@ -3589,6 +3787,8 @@ pgconn_pipeline_status(VALUE self)
3589
3787
  * 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
3788
  * This function does not actually send anything to the server, it just changes the libpq connection state.
3591
3789
  *
3790
+ * See the {PostgreSQL documentation}[https://www.postgresql.org/docs/17/libpq-pipeline-mode.html#LIBPQ-PIPELINE-MODE].
3791
+ *
3592
3792
  * Available since PostgreSQL-14
3593
3793
  */
3594
3794
  static VALUE
@@ -3627,29 +3827,55 @@ pgconn_exit_pipeline_mode(VALUE self)
3627
3827
 
3628
3828
  /*
3629
3829
  * call-seq:
3630
- * conn.pipeline_sync -> nil
3830
+ * conn.sync_pipeline_sync -> nil
3831
+ *
3832
+ * This function has the same behavior as #async_pipeline_sync, but is implemented using the synchronous command processing API of libpq.
3833
+ * See #async_exec for the differences between the two API variants.
3834
+ * It's not recommended to use explicit sync or async variants but #pipeline_sync instead, unless you have a good reason to do so.
3835
+ *
3836
+ * Available since PostgreSQL-14
3837
+ */
3838
+ static VALUE
3839
+ pgconn_sync_pipeline_sync(VALUE self)
3840
+ {
3841
+ PGconn *conn = pg_get_pgconn(self);
3842
+ int res = gvl_PQpipelineSync(conn);
3843
+ if( res != 1 )
3844
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
3845
+
3846
+ return Qnil;
3847
+ }
3848
+
3849
+
3850
+ #ifdef HAVE_PQSETCHUNKEDROWSMODE
3851
+ /*
3852
+ * call-seq:
3853
+ * conn.send_pipeline_sync -> nil
3631
3854
  *
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.
3855
+ * Marks a synchronization point in a pipeline by sending a sync message without flushing the send buffer.
3634
3856
  *
3857
+ * This serves as the delimiter of an implicit transaction and an error recovery point.
3635
3858
  * Raises PG::Error if the connection is not in pipeline mode or sending a sync message failed.
3859
+ * Note that the message is not itself flushed to the server automatically; use flush if necessary.
3636
3860
  *
3637
- * Available since PostgreSQL-14
3861
+ * Available since PostgreSQL-17
3638
3862
  */
3639
3863
  static VALUE
3640
- pgconn_pipeline_sync(VALUE self)
3864
+ pgconn_send_pipeline_sync(VALUE self)
3641
3865
  {
3642
3866
  PGconn *conn = pg_get_pgconn(self);
3643
- int res = PQpipelineSync(conn);
3867
+ int res = gvl_PQsendPipelineSync(conn);
3644
3868
  if( res != 1 )
3645
3869
  pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
3646
3870
 
3647
3871
  return Qnil;
3648
3872
  }
3873
+ #endif
3874
+
3649
3875
 
3650
3876
  /*
3651
3877
  * call-seq:
3652
- * conn.pipeline_sync -> nil
3878
+ * conn.send_flush_request -> nil
3653
3879
  *
3654
3880
  * Sends a request for the server to flush its output buffer.
3655
3881
  *
@@ -4200,9 +4426,11 @@ pgconn_set_default_encoding( VALUE self )
4200
4426
  * res.type_map_for_queries = typemap
4201
4427
  *
4202
4428
  * Set the default TypeMap that is used for type casts of query bind parameters.
4429
+ * It can be overwritten per +type_map+ parameter of #exec_params and siblings.
4203
4430
  *
4204
4431
  * +typemap+ must be a kind of PG::TypeMap .
4205
4432
  *
4433
+ * See also #type_map_for_queries
4206
4434
  */
4207
4435
  static VALUE
4208
4436
  pgconn_type_map_for_queries_set(VALUE self, VALUE typemap)
@@ -4227,6 +4455,9 @@ pgconn_type_map_for_queries_set(VALUE self, VALUE typemap)
4227
4455
  * Returns the default TypeMap that is currently set for type casts of query
4228
4456
  * bind parameters.
4229
4457
  *
4458
+ * Default is PG::TypeMapAllStrings .
4459
+ *
4460
+ * See also #type_map_for_queries=
4230
4461
  */
4231
4462
  static VALUE
4232
4463
  pgconn_type_map_for_queries_get(VALUE self)
@@ -4241,9 +4472,11 @@ pgconn_type_map_for_queries_get(VALUE self)
4241
4472
  * res.type_map_for_results = typemap
4242
4473
  *
4243
4474
  * Set the default TypeMap that is used for type casts of result values.
4475
+ * It can be overwritten per PG::Result#type_map= .
4244
4476
  *
4245
4477
  * +typemap+ must be a kind of PG::TypeMap .
4246
4478
  *
4479
+ * See also #type_map_for_results
4247
4480
  */
4248
4481
  static VALUE
4249
4482
  pgconn_type_map_for_results_set(VALUE self, VALUE typemap)
@@ -4265,6 +4498,9 @@ pgconn_type_map_for_results_set(VALUE self, VALUE typemap)
4265
4498
  *
4266
4499
  * Returns the default TypeMap that is currently set for type casts of result values.
4267
4500
  *
4501
+ * Default is PG::TypeMapAllStrings .
4502
+ *
4503
+ * See also #type_map_for_results=
4268
4504
  */
4269
4505
  static VALUE
4270
4506
  pgconn_type_map_for_results_get(VALUE self)
@@ -4281,11 +4517,13 @@ pgconn_type_map_for_results_get(VALUE self)
4281
4517
  *
4282
4518
  * Set the default coder that is used for type casting of parameters
4283
4519
  * to #put_copy_data .
4520
+ * It can be overwritten per +encoder+ parameter of #put_copy_data and +coder+ parameter of #copy_data.
4284
4521
  *
4285
4522
  * +encoder+ can be:
4286
4523
  * * a kind of PG::Coder
4287
4524
  * * +nil+ - disable type encoding, data must be a String.
4288
4525
  *
4526
+ * See also #encoder_for_put_copy_data
4289
4527
  */
4290
4528
  static VALUE
4291
4529
  pgconn_encoder_for_put_copy_data_set(VALUE self, VALUE encoder)
@@ -4315,6 +4553,8 @@ pgconn_encoder_for_put_copy_data_set(VALUE self, VALUE encoder)
4315
4553
  * * a kind of PG::Coder
4316
4554
  * * +nil+ - type encoding is disabled, data must be a String.
4317
4555
  *
4556
+ * Default is +nil+ .
4557
+ * See also #encoder_for_put_copy_data=
4318
4558
  */
4319
4559
  static VALUE
4320
4560
  pgconn_encoder_for_put_copy_data_get(VALUE self)
@@ -4330,11 +4570,13 @@ pgconn_encoder_for_put_copy_data_get(VALUE self)
4330
4570
  *
4331
4571
  * Set the default coder that is used for type casting of received data
4332
4572
  * by #get_copy_data .
4573
+ * It can be overwritten per +decoder+ parameter of #get_copy_data and +coder+ parameter of #copy_data.
4333
4574
  *
4334
4575
  * +decoder+ can be:
4335
4576
  * * a kind of PG::Coder
4336
4577
  * * +nil+ - disable type decoding, returned data will be a String.
4337
4578
  *
4579
+ * See also #decoder_for_get_copy_data
4338
4580
  */
4339
4581
  static VALUE
4340
4582
  pgconn_decoder_for_get_copy_data_set(VALUE self, VALUE decoder)
@@ -4364,6 +4606,9 @@ pgconn_decoder_for_get_copy_data_set(VALUE self, VALUE decoder)
4364
4606
  * * a kind of PG::Coder
4365
4607
  * * +nil+ - type encoding is disabled, returned data will be a String.
4366
4608
  *
4609
+ * Default is +nil+ .
4610
+ *
4611
+ * See also #decoder_for_get_copy_data=
4367
4612
  */
4368
4613
  static VALUE
4369
4614
  pgconn_decoder_for_get_copy_data_get(VALUE self)
@@ -4386,7 +4631,7 @@ pgconn_decoder_for_get_copy_data_get(VALUE self)
4386
4631
  *
4387
4632
  * Settings the type of field names affects only future results.
4388
4633
  *
4389
- * See further description at PG::Result#field_name_type=
4634
+ * See further description at PG::Result#field_name_type= and #field_name_type .
4390
4635
  *
4391
4636
  */
4392
4637
  static VALUE
@@ -4468,6 +4713,7 @@ init_pg_connection(void)
4468
4713
  rb_define_method(rb_cPGconn, "finished?", pgconn_finished_p, 0);
4469
4714
  rb_define_method(rb_cPGconn, "sync_reset", pgconn_sync_reset, 0);
4470
4715
  rb_define_method(rb_cPGconn, "reset_start", pgconn_reset_start, 0);
4716
+ rb_define_private_method(rb_cPGconn, "reset_start2", pgconn_reset_start2, 1);
4471
4717
  rb_define_method(rb_cPGconn, "reset_poll", pgconn_reset_poll, 0);
4472
4718
  rb_define_alias(rb_cPGconn, "close", "finish");
4473
4719
 
@@ -4492,7 +4738,9 @@ init_pg_connection(void)
4492
4738
  rb_define_method(rb_cPGconn, "socket", pgconn_socket, 0);
4493
4739
  rb_define_method(rb_cPGconn, "socket_io", pgconn_socket_io, 0);
4494
4740
  rb_define_method(rb_cPGconn, "backend_pid", pgconn_backend_pid, 0);
4741
+ #ifndef HAVE_PQSETCHUNKEDROWSMODE
4495
4742
  rb_define_method(rb_cPGconn, "backend_key", pgconn_backend_key, 0);
4743
+ #endif
4496
4744
  rb_define_method(rb_cPGconn, "connection_needs_password", pgconn_connection_needs_password, 0);
4497
4745
  rb_define_method(rb_cPGconn, "connection_used_password", pgconn_connection_used_password, 0);
4498
4746
  /* rb_define_method(rb_cPGconn, "getssl", pgconn_getssl, 0); */
@@ -4504,6 +4752,10 @@ init_pg_connection(void)
4504
4752
  rb_define_method(rb_cPGconn, "sync_exec_prepared", pgconn_sync_exec_prepared, -1);
4505
4753
  rb_define_method(rb_cPGconn, "sync_describe_prepared", pgconn_sync_describe_prepared, 1);
4506
4754
  rb_define_method(rb_cPGconn, "sync_describe_portal", pgconn_sync_describe_portal, 1);
4755
+ #ifdef HAVE_PQSETCHUNKEDROWSMODE
4756
+ rb_define_method(rb_cPGconn, "sync_close_prepared", pgconn_sync_close_prepared, 1);
4757
+ rb_define_method(rb_cPGconn, "sync_close_portal", pgconn_sync_close_portal, 1);
4758
+ #endif
4507
4759
 
4508
4760
  rb_define_method(rb_cPGconn, "exec", pgconn_async_exec, -1);
4509
4761
  rb_define_method(rb_cPGconn, "exec_params", pgconn_async_exec_params, -1);
@@ -4511,6 +4763,10 @@ init_pg_connection(void)
4511
4763
  rb_define_method(rb_cPGconn, "exec_prepared", pgconn_async_exec_prepared, -1);
4512
4764
  rb_define_method(rb_cPGconn, "describe_prepared", pgconn_async_describe_prepared, 1);
4513
4765
  rb_define_method(rb_cPGconn, "describe_portal", pgconn_async_describe_portal, 1);
4766
+ #ifdef HAVE_PQSETCHUNKEDROWSMODE
4767
+ rb_define_method(rb_cPGconn, "close_prepared", pgconn_async_close_prepared, 1);
4768
+ rb_define_method(rb_cPGconn, "close_portal", pgconn_async_close_portal, 1);
4769
+ #endif
4514
4770
 
4515
4771
  rb_define_alias(rb_cPGconn, "async_exec", "exec");
4516
4772
  rb_define_alias(rb_cPGconn, "async_query", "async_exec");
@@ -4519,6 +4775,10 @@ init_pg_connection(void)
4519
4775
  rb_define_alias(rb_cPGconn, "async_exec_prepared", "exec_prepared");
4520
4776
  rb_define_alias(rb_cPGconn, "async_describe_prepared", "describe_prepared");
4521
4777
  rb_define_alias(rb_cPGconn, "async_describe_portal", "describe_portal");
4778
+ #ifdef HAVE_PQSETCHUNKEDROWSMODE
4779
+ rb_define_alias(rb_cPGconn, "async_close_prepared", "close_prepared");
4780
+ rb_define_alias(rb_cPGconn, "async_close_portal", "close_portal");
4781
+ #endif
4522
4782
 
4523
4783
  rb_define_method(rb_cPGconn, "make_empty_pgresult", pgconn_make_empty_pgresult, 1);
4524
4784
  rb_define_method(rb_cPGconn, "escape_string", pgconn_s_escape, 1);
@@ -4528,6 +4788,9 @@ init_pg_connection(void)
4528
4788
  rb_define_method(rb_cPGconn, "escape_bytea", pgconn_s_escape_bytea, 1);
4529
4789
  rb_define_method(rb_cPGconn, "unescape_bytea", pgconn_s_unescape_bytea, 1);
4530
4790
  rb_define_method(rb_cPGconn, "set_single_row_mode", pgconn_set_single_row_mode, 0);
4791
+ #ifdef HAVE_PQSETCHUNKEDROWSMODE
4792
+ rb_define_method(rb_cPGconn, "set_chunked_rows_mode", pgconn_set_chunked_rows_mode, 1);
4793
+ #endif
4531
4794
 
4532
4795
  /****** PG::Connection INSTANCE METHODS: Asynchronous Command Processing ******/
4533
4796
  rb_define_method(rb_cPGconn, "send_query", pgconn_send_query, -1);
@@ -4547,7 +4810,9 @@ init_pg_connection(void)
4547
4810
  rb_define_method(rb_cPGconn, "discard_results", pgconn_discard_results, 0);
4548
4811
 
4549
4812
  /****** PG::Connection INSTANCE METHODS: Cancelling Queries in Progress ******/
4813
+ #ifndef HAVE_PQSETCHUNKEDROWSMODE
4550
4814
  rb_define_method(rb_cPGconn, "sync_cancel", pgconn_sync_cancel, 0);
4815
+ #endif
4551
4816
 
4552
4817
  /****** PG::Connection INSTANCE METHODS: NOTIFY ******/
4553
4818
  rb_define_method(rb_cPGconn, "notifies", pgconn_notifies, 0);
@@ -4559,9 +4824,7 @@ init_pg_connection(void)
4559
4824
 
4560
4825
  /****** PG::Connection INSTANCE METHODS: Control Functions ******/
4561
4826
  rb_define_method(rb_cPGconn, "set_error_verbosity", pgconn_set_error_verbosity, 1);
4562
- #ifdef HAVE_PQRESULTVERBOSEERRORMESSAGE
4563
4827
  rb_define_method(rb_cPGconn, "set_error_context_visibility", pgconn_set_error_context_visibility, 1 );
4564
- #endif
4565
4828
  rb_define_method(rb_cPGconn, "trace", pgconn_trace, 1);
4566
4829
  rb_define_method(rb_cPGconn, "untrace", pgconn_untrace, 0);
4567
4830
 
@@ -4583,22 +4846,21 @@ init_pg_connection(void)
4583
4846
  rb_define_method(rb_cPGconn, "sync_get_last_result", pgconn_sync_get_last_result, 0);
4584
4847
  rb_define_method(rb_cPGconn, "get_last_result", pgconn_async_get_last_result, 0);
4585
4848
  rb_define_alias(rb_cPGconn, "async_get_last_result", "get_last_result");
4586
- #ifdef HAVE_PQENCRYPTPASSWORDCONN
4587
4849
  rb_define_method(rb_cPGconn, "sync_encrypt_password", pgconn_sync_encrypt_password, -1);
4588
- #endif
4589
4850
 
4590
- #ifdef HAVE_PQSSLATTRIBUTE
4591
4851
  rb_define_method(rb_cPGconn, "ssl_in_use?", pgconn_ssl_in_use, 0);
4592
4852
  rb_define_method(rb_cPGconn, "ssl_attribute", pgconn_ssl_attribute, 1);
4593
4853
  rb_define_method(rb_cPGconn, "ssl_attribute_names", pgconn_ssl_attribute_names, 0);
4594
- #endif
4595
4854
 
4596
4855
  #ifdef HAVE_PQENTERPIPELINEMODE
4597
4856
  rb_define_method(rb_cPGconn, "pipeline_status", pgconn_pipeline_status, 0);
4598
4857
  rb_define_method(rb_cPGconn, "enter_pipeline_mode", pgconn_enter_pipeline_mode, 0);
4599
4858
  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);
4859
+ rb_define_method(rb_cPGconn, "sync_pipeline_sync", pgconn_sync_pipeline_sync, 0);
4601
4860
  rb_define_method(rb_cPGconn, "send_flush_request", pgconn_send_flush_request, 0);
4861
+ #ifdef HAVE_PQSETCHUNKEDROWSMODE
4862
+ rb_define_method(rb_cPGconn, "send_pipeline_sync", pgconn_send_pipeline_sync, 0);
4863
+ #endif
4602
4864
  #endif
4603
4865
 
4604
4866
  /****** PG::Connection INSTANCE METHODS: Large Object Support ******/