pg 1.4.6 → 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 (92) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/{History.md → CHANGELOG.md} +185 -3
  4. data/Gemfile +12 -3
  5. data/README-Windows.rdoc +1 -1
  6. data/README.ja.md +75 -41
  7. data/README.md +86 -31
  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 +165 -14
  14. data/ext/gvl_wrappers.c +13 -2
  15. data/ext/gvl_wrappers.h +33 -0
  16. data/ext/pg.c +28 -35
  17. data/ext/pg.h +18 -14
  18. data/ext/pg_binary_decoder.c +231 -0
  19. data/ext/pg_binary_encoder.c +427 -0
  20. data/ext/pg_cancel_connection.c +360 -0
  21. data/ext/pg_coder.c +70 -12
  22. data/ext/pg_connection.c +473 -208
  23. data/ext/pg_copy_coder.c +316 -23
  24. data/ext/pg_record_coder.c +12 -11
  25. data/ext/pg_result.c +102 -30
  26. data/ext/pg_text_decoder.c +31 -10
  27. data/ext/pg_text_encoder.c +58 -26
  28. data/ext/pg_tuple.c +36 -33
  29. data/ext/pg_type_map.c +4 -3
  30. data/ext/pg_type_map_all_strings.c +3 -3
  31. data/ext/pg_type_map_by_class.c +6 -4
  32. data/ext/pg_type_map_by_column.c +9 -4
  33. data/ext/pg_type_map_by_mri_type.c +1 -1
  34. data/ext/pg_type_map_by_oid.c +10 -5
  35. data/ext/pg_type_map_in_ruby.c +6 -3
  36. data/lib/pg/basic_type_map_based_on_result.rb +21 -1
  37. data/lib/pg/basic_type_map_for_queries.rb +23 -10
  38. data/lib/pg/basic_type_map_for_results.rb +26 -3
  39. data/lib/pg/basic_type_registry.rb +46 -36
  40. data/lib/pg/binary_decoder/date.rb +9 -0
  41. data/lib/pg/binary_decoder/timestamp.rb +26 -0
  42. data/lib/pg/binary_encoder/timestamp.rb +20 -0
  43. data/lib/pg/cancel_connection.rb +53 -0
  44. data/lib/pg/coder.rb +18 -14
  45. data/lib/pg/connection.rb +387 -172
  46. data/lib/pg/exceptions.rb +6 -0
  47. data/lib/pg/text_decoder/date.rb +21 -0
  48. data/lib/pg/text_decoder/inet.rb +9 -0
  49. data/lib/pg/text_decoder/json.rb +17 -0
  50. data/lib/pg/text_decoder/numeric.rb +9 -0
  51. data/lib/pg/text_decoder/timestamp.rb +30 -0
  52. data/lib/pg/text_encoder/date.rb +13 -0
  53. data/lib/pg/text_encoder/inet.rb +31 -0
  54. data/lib/pg/text_encoder/json.rb +17 -0
  55. data/lib/pg/text_encoder/numeric.rb +9 -0
  56. data/lib/pg/text_encoder/timestamp.rb +24 -0
  57. data/lib/pg/version.rb +1 -1
  58. data/lib/pg.rb +78 -17
  59. data/misc/yugabyte/Dockerfile +9 -0
  60. data/misc/yugabyte/docker-compose.yml +28 -0
  61. data/misc/yugabyte/pg-test.rb +45 -0
  62. data/pg.gemspec +9 -5
  63. data/ports/patches/krb5/1.21.3/0001-Allow-static-linking-krb5-library.patch +30 -0
  64. data/ports/patches/openssl/3.5.1/0001-aarch64-mingw.patch +21 -0
  65. data/ports/patches/postgresql/17.5/0001-Use-workaround-of-__builtin_setjmp-only-on-MINGW-on-.patch +42 -0
  66. data/ports/patches/postgresql/17.5/0001-libpq-Process-buffered-SSL-read-bytes-to-support-rec.patch +52 -0
  67. data/rakelib/pg_gem_helper.rb +64 -0
  68. data.tar.gz.sig +0 -0
  69. metadata +61 -49
  70. metadata.gz.sig +0 -0
  71. data/.appveyor.yml +0 -42
  72. data/.gems +0 -6
  73. data/.gemtest +0 -0
  74. data/.github/workflows/binary-gems.yml +0 -117
  75. data/.github/workflows/source-gem.yml +0 -137
  76. data/.gitignore +0 -19
  77. data/.hgsigs +0 -34
  78. data/.hgtags +0 -41
  79. data/.irbrc +0 -23
  80. data/.pryrc +0 -23
  81. data/.tm_properties +0 -21
  82. data/.travis.yml +0 -49
  83. data/Manifest.txt +0 -72
  84. data/Rakefile.cross +0 -298
  85. data/lib/pg/binary_decoder.rb +0 -23
  86. data/lib/pg/constants.rb +0 -12
  87. data/lib/pg/text_decoder.rb +0 -46
  88. data/lib/pg/text_encoder.rb +0 -59
  89. data/translation/.po4a-version +0 -7
  90. data/translation/po/all.pot +0 -875
  91. data/translation/po/ja.po +0 -868
  92. data/translation/po4a.cfg +0 -9
data/ext/pg_connection.c CHANGED
@@ -16,9 +16,6 @@ static ID s_id_autoclose_set;
16
16
  static VALUE sym_type, sym_format, sym_value;
17
17
  static VALUE sym_symbol, sym_string, sym_static_symbol;
18
18
 
19
- static PQnoticeReceiver default_notice_receiver = NULL;
20
- static PQnoticeProcessor default_notice_processor = NULL;
21
-
22
19
  static VALUE pgconn_finish( VALUE );
23
20
  static VALUE pgconn_set_default_encoding( VALUE self );
24
21
  static VALUE pgconn_wait_for_flush( VALUE self );
@@ -33,10 +30,7 @@ static VALUE pgconn_async_flush(VALUE self);
33
30
  /*
34
31
  * Convenience function to raise connection errors
35
32
  */
36
- #ifdef __GNUC__
37
- __attribute__((format(printf, 3, 4)))
38
- #endif
39
- static void
33
+ void
40
34
  pg_raise_conn_error( VALUE klass, VALUE self, const char *format, ...)
41
35
  {
42
36
  VALUE msg, error;
@@ -99,6 +93,20 @@ pg_get_pgconn( VALUE self )
99
93
  }
100
94
 
101
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
+
102
110
 
103
111
  /*
104
112
  * Close the associated socket IO object if there is one.
@@ -107,17 +115,7 @@ static void
107
115
  pgconn_close_socket_io( VALUE self )
108
116
  {
109
117
  t_pg_connection *this = pg_get_connection( self );
110
- VALUE socket_io = this->socket_io;
111
-
112
- if ( RTEST(socket_io) ) {
113
- #if defined(_WIN32)
114
- if( rb_w32_unwrap_io_handle(this->ruby_sd) )
115
- pg_raise_conn_error( rb_eConnectionBad, self, "Could not unwrap win32 socket handle");
116
- #endif
117
- rb_funcall( socket_io, rb_intern("close"), 0 );
118
- }
119
-
120
- this->socket_io = Qnil;
118
+ pg_unwrap_socket_io( self, &this->socket_io, this->ruby_sd);
121
119
  }
122
120
 
123
121
 
@@ -233,11 +231,11 @@ static const rb_data_type_t pg_connection_type = {
233
231
  pgconn_gc_mark,
234
232
  pgconn_gc_free,
235
233
  pgconn_memsize,
236
- pg_compact_callback(pgconn_gc_compact),
234
+ pgconn_gc_compact,
237
235
  },
238
236
  0,
239
237
  0,
240
- 0,
238
+ RUBY_TYPED_WB_PROTECTED,
241
239
  };
242
240
 
243
241
 
@@ -258,15 +256,16 @@ pgconn_s_allocate( VALUE klass )
258
256
  VALUE self = TypedData_Make_Struct( klass, t_pg_connection, &pg_connection_type, this );
259
257
 
260
258
  this->pgconn = NULL;
261
- this->socket_io = Qnil;
262
- this->notice_receiver = Qnil;
263
- this->notice_processor = Qnil;
264
- this->type_map_for_queries = pg_typemap_all_strings;
265
- this->type_map_for_results = pg_typemap_all_strings;
266
- this->encoder_for_put_copy_data = Qnil;
267
- this->decoder_for_get_copy_data = Qnil;
268
- this->trace_stream = Qnil;
259
+ RB_OBJ_WRITE(self, &this->socket_io, Qnil);
260
+ RB_OBJ_WRITE(self, &this->notice_receiver, Qnil);
261
+ RB_OBJ_WRITE(self, &this->notice_processor, Qnil);
262
+ RB_OBJ_WRITE(self, &this->type_map_for_queries, pg_typemap_all_strings);
263
+ RB_OBJ_WRITE(self, &this->type_map_for_results, pg_typemap_all_strings);
264
+ RB_OBJ_WRITE(self, &this->encoder_for_put_copy_data, Qnil);
265
+ RB_OBJ_WRITE(self, &this->decoder_for_get_copy_data, Qnil);
266
+ RB_OBJ_WRITE(self, &this->trace_stream, Qnil);
269
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);
270
269
 
271
270
  return self;
272
271
  }
@@ -421,7 +420,6 @@ pgconn_s_conninfo_parse(VALUE self, VALUE conninfo)
421
420
  }
422
421
 
423
422
 
424
- #ifdef HAVE_PQENCRYPTPASSWORDCONN
425
423
  static VALUE
426
424
  pgconn_sync_encrypt_password(int argc, VALUE *argv, VALUE self)
427
425
  {
@@ -445,7 +443,6 @@ pgconn_sync_encrypt_password(int argc, VALUE *argv, VALUE self)
445
443
 
446
444
  return rval;
447
445
  }
448
- #endif
449
446
 
450
447
 
451
448
  /*
@@ -518,9 +515,9 @@ static VALUE
518
515
  pgconn_connect_poll(VALUE self)
519
516
  {
520
517
  PostgresPollingStatusType status;
521
- status = gvl_PQconnectPoll(pg_get_pgconn(self));
522
518
 
523
519
  pgconn_close_socket_io(self);
520
+ status = gvl_PQconnectPoll(pg_get_pgconn(self));
524
521
 
525
522
  return INT2FIX((int)status);
526
523
  }
@@ -566,6 +563,27 @@ pgconn_sync_reset( VALUE self )
566
563
  return self;
567
564
  }
568
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
+
569
587
  /*
570
588
  * call-seq:
571
589
  * conn.reset_start() -> nil
@@ -590,16 +608,16 @@ pgconn_reset_start(VALUE self)
590
608
  * conn.reset_poll -> Integer
591
609
  *
592
610
  * Checks the status of a connection reset operation.
593
- * See #connect_start and #connect_poll for
611
+ * See Connection.connect_start and #connect_poll for
594
612
  * usage information and return values.
595
613
  */
596
614
  static VALUE
597
615
  pgconn_reset_poll(VALUE self)
598
616
  {
599
617
  PostgresPollingStatusType status;
600
- status = gvl_PQresetPoll(pg_get_pgconn(self));
601
618
 
602
619
  pgconn_close_socket_io(self);
620
+ status = gvl_PQresetPoll(pg_get_pgconn(self));
603
621
 
604
622
  return INT2FIX((int)status);
605
623
  }
@@ -741,7 +759,6 @@ pgconn_options(VALUE self)
741
759
  *
742
760
  * Returns the connection options used by a live connection.
743
761
  *
744
- * Available since PostgreSQL-9.3
745
762
  */
746
763
  static VALUE
747
764
  pgconn_conninfo( VALUE self )
@@ -766,6 +783,10 @@ pgconn_conninfo( VALUE self )
766
783
  *
767
784
  * ... and other constants of kind PG::Constants::CONNECTION_*
768
785
  *
786
+ * This method returns the status of the last command from memory.
787
+ * It doesn't do any socket access hence is not suitable to test the connectivity.
788
+ * See check_socket for a way to verify the socket state.
789
+ *
769
790
  * Example:
770
791
  * PG.constants.grep(/CONNECTION_/).find{|c| PG.const_get(c) == conn.status} # => :CONNECTION_OK
771
792
  */
@@ -824,31 +845,52 @@ pgconn_parameter_status(VALUE self, VALUE param_name)
824
845
  * call-seq:
825
846
  * conn.protocol_version -> Integer
826
847
  *
827
- * The 3.0 protocol will normally be used when communicating with PostgreSQL 7.4
828
- * or later servers; pre-7.4 servers support only protocol 2.0. (Protocol 1.0 is
829
- * 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.
830
856
  */
831
857
  static VALUE
832
858
  pgconn_protocol_version(VALUE self)
833
859
  {
834
- 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);
835
865
  }
836
866
 
837
867
  /*
838
868
  * call-seq:
839
869
  * conn.server_version -> Integer
840
870
  *
841
- * The number is formed by converting the major, minor, and revision
842
- * numbers into two-decimal-digit numbers and appending them together.
843
- * For example, version 7.4.2 will be returned as 70402, and version
844
- * 8.1 will be returned as 80100 (leading zeroes are not shown). Zero
845
- * 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).
846
884
  *
847
885
  */
848
886
  static VALUE
849
887
  pgconn_server_version(VALUE self)
850
888
  {
851
- 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);
852
894
  }
853
895
 
854
896
  /*
@@ -897,13 +939,42 @@ pgconn_socket(VALUE self)
897
939
  return INT2NUM(sd);
898
940
  }
899
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
+
900
971
  /*
901
972
  * call-seq:
902
973
  * conn.socket_io() -> IO
903
974
  *
904
975
  * Fetch an IO object created from the Connection's underlying socket.
905
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.
906
- * <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>.
907
978
  *
908
979
  * The IO object can change while the connection is established, but is memorized afterwards.
909
980
  * So be sure not to cache the IO object, but repeat calling <tt>conn.socket_io</tt> instead.
@@ -914,37 +985,17 @@ pgconn_socket(VALUE self)
914
985
  static VALUE
915
986
  pgconn_socket_io(VALUE self)
916
987
  {
917
- int sd;
918
- int ruby_sd;
919
988
  t_pg_connection *this = pg_get_connection_safe( self );
920
- VALUE cSocket;
921
- VALUE socket_io = this->socket_io;
922
989
 
923
- if ( !RTEST(socket_io) ) {
990
+ if ( !RTEST(this->socket_io) ) {
991
+ int sd;
924
992
  if( (sd = PQsocket(this->pgconn)) < 0){
925
993
  pg_raise_conn_error( rb_eConnectionBad, self, "PQsocket() can't get socket descriptor");
926
994
  }
927
-
928
- #ifdef _WIN32
929
- ruby_sd = rb_w32_wrap_io_handle((HANDLE)(intptr_t)sd, O_RDWR|O_BINARY|O_NOINHERIT);
930
- if( ruby_sd == -1 )
931
- pg_raise_conn_error( rb_eConnectionBad, self, "Could not wrap win32 socket handle");
932
-
933
- this->ruby_sd = ruby_sd;
934
- #else
935
- ruby_sd = sd;
936
- #endif
937
-
938
- cSocket = rb_const_get(rb_cObject, rb_intern("BasicSocket"));
939
- socket_io = rb_funcall( cSocket, rb_intern("for_fd"), 1, INT2NUM(ruby_sd));
940
-
941
- /* Disable autoclose feature */
942
- rb_funcall( socket_io, s_id_autoclose_set, 1, Qfalse );
943
-
944
- this->socket_io = socket_io;
995
+ return pg_wrap_socket_io( sd, self, &this->socket_io, &this->ruby_sd);
945
996
  }
946
997
 
947
- return socket_io;
998
+ return this->socket_io;
948
999
  }
949
1000
 
950
1001
  /*
@@ -961,6 +1012,7 @@ pgconn_backend_pid(VALUE self)
961
1012
  return INT2NUM(PQbackendPID(pg_get_pgconn(self)));
962
1013
  }
963
1014
 
1015
+ #ifndef HAVE_PQSETCHUNKEDROWSMODE
964
1016
  typedef struct
965
1017
  {
966
1018
  struct sockaddr_storage addr;
@@ -1005,6 +1057,7 @@ pgconn_backend_key(VALUE self)
1005
1057
 
1006
1058
  return INT2NUM(be_key);
1007
1059
  }
1060
+ #endif
1008
1061
 
1009
1062
  /*
1010
1063
  * call-seq:
@@ -1158,7 +1211,7 @@ static const rb_data_type_t pg_typecast_buffer_type = {
1158
1211
  },
1159
1212
  0,
1160
1213
  0,
1161
- RUBY_TYPED_FREE_IMMEDIATELY,
1214
+ RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
1162
1215
  };
1163
1216
 
1164
1217
  static char *
@@ -1191,7 +1244,7 @@ static const rb_data_type_t pg_query_heap_pool_type = {
1191
1244
  },
1192
1245
  0,
1193
1246
  0,
1194
- RUBY_TYPED_FREE_IMMEDIATELY,
1247
+ RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
1195
1248
  };
1196
1249
 
1197
1250
  static int
@@ -1277,7 +1330,7 @@ alloc_query_params(struct query_params_data *paramsData)
1277
1330
  paramsData->lengths[i] = 0;
1278
1331
  } else {
1279
1332
  t_pg_coder_enc_func enc_func = pg_coder_enc_func( conv );
1280
- VALUE intermediate;
1333
+ VALUE intermediate = Qnil;
1281
1334
 
1282
1335
  /* 1st pass for retiving the required memory space */
1283
1336
  int len = enc_func(conv, param_value, NULL, &intermediate, paramsData->enc_idx);
@@ -1317,8 +1370,6 @@ alloc_query_params(struct query_params_data *paramsData)
1317
1370
  required_pool_size += len;
1318
1371
  }
1319
1372
  }
1320
-
1321
- RB_GC_GUARD(intermediate);
1322
1373
  }
1323
1374
  }
1324
1375
  }
@@ -1493,6 +1544,19 @@ pgconn_sync_exec_prepared(int argc, VALUE *argv, VALUE self)
1493
1544
  return rb_pgresult;
1494
1545
  }
1495
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
+
1496
1560
  /*
1497
1561
  * call-seq:
1498
1562
  * conn.sync_describe_prepared( statement_name ) -> PG::Result
@@ -1504,20 +1568,7 @@ pgconn_sync_exec_prepared(int argc, VALUE *argv, VALUE self)
1504
1568
  static VALUE
1505
1569
  pgconn_sync_describe_prepared(VALUE self, VALUE stmt_name)
1506
1570
  {
1507
- PGresult *result;
1508
- VALUE rb_pgresult;
1509
- t_pg_connection *this = pg_get_connection_safe( self );
1510
- const char *stmt;
1511
- if(NIL_P(stmt_name)) {
1512
- stmt = NULL;
1513
- }
1514
- else {
1515
- stmt = pg_cstr_enc(stmt_name, this->enc_idx);
1516
- }
1517
- result = gvl_PQdescribePrepared(this->pgconn, stmt);
1518
- rb_pgresult = pg_new_result(result, self);
1519
- pg_result_check(rb_pgresult);
1520
- return rb_pgresult;
1571
+ return pgconn_sync_describe_close_prepared_portal(self, stmt_name, gvl_PQdescribePrepared);
1521
1572
  }
1522
1573
 
1523
1574
 
@@ -1532,23 +1583,44 @@ pgconn_sync_describe_prepared(VALUE self, VALUE stmt_name)
1532
1583
  static VALUE
1533
1584
  pgconn_sync_describe_portal(VALUE self, VALUE stmt_name)
1534
1585
  {
1535
- PGresult *result;
1536
- VALUE rb_pgresult;
1537
- t_pg_connection *this = pg_get_connection_safe( self );
1538
- const char *stmt;
1539
- if(NIL_P(stmt_name)) {
1540
- stmt = NULL;
1541
- }
1542
- else {
1543
- stmt = pg_cstr_enc(stmt_name, this->enc_idx);
1544
- }
1545
- result = gvl_PQdescribePortal(this->pgconn, stmt);
1546
- rb_pgresult = pg_new_result(result, self);
1547
- pg_result_check(rb_pgresult);
1548
- return rb_pgresult;
1586
+ return pgconn_sync_describe_close_prepared_portal(self, stmt_name, gvl_PQdescribePortal);
1549
1587
  }
1550
1588
 
1551
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
+
1552
1624
  /*
1553
1625
  * call-seq:
1554
1626
  * conn.make_empty_pgresult( status ) -> PG::Result
@@ -1565,6 +1637,7 @@ pgconn_sync_describe_portal(VALUE self, VALUE stmt_name)
1565
1637
  * * +PGRES_FATAL_ERROR+
1566
1638
  * * +PGRES_COPY_BOTH+
1567
1639
  * * +PGRES_SINGLE_TUPLE+
1640
+ * * +PGRES_TUPLES_CHUNK+
1568
1641
  * * +PGRES_PIPELINE_SYNC+
1569
1642
  * * +PGRES_PIPELINE_ABORTED+
1570
1643
  */
@@ -1789,14 +1862,11 @@ pgconn_escape_identifier(VALUE self, VALUE string)
1789
1862
  * (column names, types, etc) that an ordinary Result object for the query
1790
1863
  * would have.
1791
1864
  *
1792
- * *Caution:* While processing a query, the server may return some rows and
1793
- * then encounter an error, causing the query to be aborted. Ordinarily, pg
1794
- * discards any such rows and reports only the error. But in single-row mode,
1795
- * those rows will have already been returned to the application. Hence, the
1796
- * application will see some Result objects followed by an Error raised in get_result.
1797
- * For proper transactional behavior, the application must be designed to discard
1798
- * or undo whatever has been done with the previously-processed rows, if the query
1799
- * 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.
1800
1870
  *
1801
1871
  * Example:
1802
1872
  * conn.send_query( "your SQL command" )
@@ -1814,11 +1884,51 @@ pgconn_set_single_row_mode(VALUE self)
1814
1884
  {
1815
1885
  PGconn *conn = pg_get_pgconn(self);
1816
1886
 
1887
+ rb_check_frozen(self);
1817
1888
  if( PQsetSingleRowMode(conn) == 0 )
1818
- 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));
1819
1928
 
1820
1929
  return self;
1821
1930
  }
1931
+ #endif
1822
1932
 
1823
1933
  static VALUE pgconn_send_query_params(int argc, VALUE *argv, VALUE self);
1824
1934
 
@@ -1843,7 +1953,7 @@ pgconn_send_query(int argc, VALUE *argv, VALUE self)
1843
1953
  /* If called with no or nil parameters, use PQexec for compatibility */
1844
1954
  if ( argc == 1 || (argc >= 2 && argc <= 4 && NIL_P(argv[1]) )) {
1845
1955
  if(gvl_PQsendQuery(this->pgconn, pg_cstr_enc(argv[0], this->enc_idx)) == 0)
1846
- pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
1956
+ pg_raise_conn_error( rb_eUnableToSend, self, "PQsendQuery %s", PQerrorMessage(this->pgconn));
1847
1957
 
1848
1958
  pgconn_wait_for_flush( self );
1849
1959
  return Qnil;
@@ -1918,7 +2028,7 @@ pgconn_send_query_params(int argc, VALUE *argv, VALUE self)
1918
2028
  free_query_params( &paramsData );
1919
2029
 
1920
2030
  if(result == 0)
1921
- pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
2031
+ pg_raise_conn_error( rb_eUnableToSend, self, "PQsendQueryParams %s", PQerrorMessage(this->pgconn));
1922
2032
 
1923
2033
  pgconn_wait_for_flush( self );
1924
2034
  return Qnil;
@@ -1979,7 +2089,7 @@ pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
1979
2089
  xfree(paramTypes);
1980
2090
 
1981
2091
  if(result == 0) {
1982
- pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
2092
+ pg_raise_conn_error( rb_eUnableToSend, self, "PQsendPrepare %s", PQerrorMessage(this->pgconn));
1983
2093
  }
1984
2094
  pgconn_wait_for_flush( self );
1985
2095
  return Qnil;
@@ -2045,7 +2155,21 @@ pgconn_send_query_prepared(int argc, VALUE *argv, VALUE self)
2045
2155
  free_query_params( &paramsData );
2046
2156
 
2047
2157
  if(result == 0)
2048
- 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));
2049
2173
 
2050
2174
  pgconn_wait_for_flush( self );
2051
2175
  return Qnil;
@@ -2061,13 +2185,9 @@ pgconn_send_query_prepared(int argc, VALUE *argv, VALUE self)
2061
2185
  static VALUE
2062
2186
  pgconn_send_describe_prepared(VALUE self, VALUE stmt_name)
2063
2187
  {
2064
- t_pg_connection *this = pg_get_connection_safe( self );
2065
- /* returns 0 on failure */
2066
- if(gvl_PQsendDescribePrepared(this->pgconn, pg_cstr_enc(stmt_name, this->enc_idx)) == 0)
2067
- pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
2068
-
2069
- pgconn_wait_for_flush( self );
2070
- return Qnil;
2188
+ return pgconn_send_describe_close_prepared_portal(
2189
+ self, stmt_name, gvl_PQsendDescribePrepared,
2190
+ "PQsendDescribePrepared");
2071
2191
  }
2072
2192
 
2073
2193
 
@@ -2081,16 +2201,48 @@ pgconn_send_describe_prepared(VALUE self, VALUE stmt_name)
2081
2201
  static VALUE
2082
2202
  pgconn_send_describe_portal(VALUE self, VALUE portal)
2083
2203
  {
2084
- t_pg_connection *this = pg_get_connection_safe( self );
2085
- /* returns 0 on failure */
2086
- if(gvl_PQsendDescribePortal(this->pgconn, pg_cstr_enc(portal, this->enc_idx)) == 0)
2087
- 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
+ }
2088
2208
 
2089
- pgconn_wait_for_flush( self );
2090
- 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");
2091
2225
  }
2092
2226
 
2093
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
+
2094
2246
  static VALUE
2095
2247
  pgconn_sync_get_result(VALUE self)
2096
2248
  {
@@ -2148,6 +2300,7 @@ pgconn_sync_setnonblocking(VALUE self, VALUE state)
2148
2300
  {
2149
2301
  int arg;
2150
2302
  PGconn *conn = pg_get_pgconn(self);
2303
+ rb_check_frozen(self);
2151
2304
  if(state == Qtrue)
2152
2305
  arg = 1;
2153
2306
  else if (state == Qfalse)
@@ -2179,6 +2332,7 @@ pgconn_sync_flush(VALUE self)
2179
2332
  return (ret) ? Qfalse : Qtrue;
2180
2333
  }
2181
2334
 
2335
+ #ifndef HAVE_PQSETCHUNKEDROWSMODE
2182
2336
  static VALUE
2183
2337
  pgconn_sync_cancel(VALUE self)
2184
2338
  {
@@ -2200,6 +2354,7 @@ pgconn_sync_cancel(VALUE self)
2200
2354
  PQfreeCancel(cancel);
2201
2355
  return retval;
2202
2356
  }
2357
+ #endif
2203
2358
 
2204
2359
 
2205
2360
  /*
@@ -2242,6 +2397,18 @@ pgconn_notifies(VALUE self)
2242
2397
  return hash;
2243
2398
  }
2244
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
+
2245
2412
  #if defined(_WIN32)
2246
2413
 
2247
2414
  /* We use a specialized implementation of rb_io_wait() on Windows.
@@ -2262,7 +2429,6 @@ int rb_w32_wait_events( HANDLE *events, int num, DWORD timeout );
2262
2429
 
2263
2430
  static VALUE
2264
2431
  pg_rb_thread_io_wait(VALUE io, VALUE events, VALUE timeout) {
2265
- rb_io_t *fptr;
2266
2432
  struct timeval ptimeout;
2267
2433
 
2268
2434
  struct timeval aborttime={0,0}, currtime, waittime;
@@ -2273,7 +2439,6 @@ pg_rb_thread_io_wait(VALUE io, VALUE events, VALUE timeout) {
2273
2439
  long w32_events = 0;
2274
2440
  DWORD wait_ret;
2275
2441
 
2276
- GetOpenFile((io), fptr);
2277
2442
  if( !NIL_P(timeout) ){
2278
2443
  ptimeout.tv_sec = (time_t)(NUM2DBL(timeout));
2279
2444
  ptimeout.tv_usec = (time_t)((NUM2DBL(timeout) - (double)ptimeout.tv_sec) * 1e6);
@@ -2287,7 +2452,7 @@ pg_rb_thread_io_wait(VALUE io, VALUE events, VALUE timeout) {
2287
2452
  if(rb_events & PG_RUBY_IO_PRIORITY) w32_events |= FD_OOB;
2288
2453
 
2289
2454
  for(;;) {
2290
- 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 ) {
2291
2456
  WSACloseEvent( hEvent );
2292
2457
  rb_raise( rb_eConnectionBad, "WSAEventSelect socket error: %d", WSAGetLastError() );
2293
2458
  }
@@ -2330,7 +2495,7 @@ static VALUE
2330
2495
  pg_rb_io_wait(VALUE io, VALUE events, VALUE timeout) {
2331
2496
  #if defined(HAVE_RUBY_FIBER_SCHEDULER_H)
2332
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.
2333
- * Fortunatelly ruby-3.1 offers a C-API for it.
2498
+ * Fortunately ruby-3.1 offers a C-API for it.
2334
2499
  */
2335
2500
  VALUE scheduler = rb_fiber_scheduler_current();
2336
2501
 
@@ -2360,16 +2525,14 @@ typedef enum {
2360
2525
 
2361
2526
  static VALUE
2362
2527
  pg_rb_io_wait(VALUE io, VALUE events, VALUE timeout) {
2363
- rb_io_t *fptr;
2364
2528
  struct timeval waittime;
2365
2529
  int res;
2366
2530
 
2367
- GetOpenFile((io), fptr);
2368
2531
  if( !NIL_P(timeout) ){
2369
2532
  waittime.tv_sec = (time_t)(NUM2DBL(timeout));
2370
2533
  waittime.tv_usec = (time_t)((NUM2DBL(timeout) - (double)waittime.tv_sec) * 1e6);
2371
2534
  }
2372
- 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);
2373
2536
 
2374
2537
  return UINT2NUM(res);
2375
2538
  }
@@ -2464,6 +2627,7 @@ pgconn_wait_for_flush( VALUE self ){
2464
2627
  static VALUE
2465
2628
  pgconn_flush_data_set( VALUE self, VALUE enabled ){
2466
2629
  t_pg_connection *conn = pg_get_connection(self);
2630
+ rb_check_frozen(self);
2467
2631
  conn->flush_data = RTEST(enabled);
2468
2632
  return enabled;
2469
2633
  }
@@ -2535,7 +2699,7 @@ pgconn_sync_put_copy_data(int argc, VALUE *argv, VALUE self)
2535
2699
  VALUE value;
2536
2700
  VALUE buffer = Qnil;
2537
2701
  VALUE encoder;
2538
- VALUE intermediate;
2702
+ VALUE intermediate = Qnil;
2539
2703
  t_pg_coder *p_coder = NULL;
2540
2704
 
2541
2705
  rb_scan_args( argc, argv, "11", &value, &encoder );
@@ -2574,7 +2738,6 @@ pgconn_sync_put_copy_data(int argc, VALUE *argv, VALUE self)
2574
2738
  if(ret == -1)
2575
2739
  pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(this->pgconn));
2576
2740
 
2577
- RB_GC_GUARD(intermediate);
2578
2741
  RB_GC_GUARD(buffer);
2579
2742
 
2580
2743
  return (ret) ? Qtrue : Qfalse;
@@ -2669,7 +2832,6 @@ pgconn_set_error_verbosity(VALUE self, VALUE in_verbosity)
2669
2832
  return INT2FIX(PQsetErrorVerbosity(conn, verbosity));
2670
2833
  }
2671
2834
 
2672
- #ifdef HAVE_PQRESULTVERBOSEERRORMESSAGE
2673
2835
  /*
2674
2836
  * call-seq:
2675
2837
  * conn.set_error_context_visibility( context_visibility ) -> Integer
@@ -2689,7 +2851,6 @@ pgconn_set_error_verbosity(VALUE self, VALUE in_verbosity)
2689
2851
  *
2690
2852
  * See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-control.html#LIBPQ-PQSETERRORCONTEXTVISIBILITY].
2691
2853
  *
2692
- * Available since PostgreSQL-9.6
2693
2854
  */
2694
2855
  static VALUE
2695
2856
  pgconn_set_error_context_visibility(VALUE self, VALUE in_context_visibility)
@@ -2698,7 +2859,6 @@ pgconn_set_error_context_visibility(VALUE self, VALUE in_context_visibility)
2698
2859
  PGContextVisibility context_visibility = NUM2INT(in_context_visibility);
2699
2860
  return INT2FIX(PQsetErrorContextVisibility(conn, context_visibility));
2700
2861
  }
2701
- #endif
2702
2862
 
2703
2863
  /*
2704
2864
  * call-seq:
@@ -2718,6 +2878,7 @@ pgconn_trace(VALUE self, VALUE stream)
2718
2878
  VALUE new_file;
2719
2879
  t_pg_connection *this = pg_get_connection_safe( self );
2720
2880
 
2881
+ rb_check_frozen(self);
2721
2882
  if(!rb_respond_to(stream,rb_intern("fileno")))
2722
2883
  rb_raise(rb_eArgError, "stream does not respond to method: fileno");
2723
2884
 
@@ -2739,7 +2900,7 @@ pgconn_trace(VALUE self, VALUE stream)
2739
2900
  rb_raise(rb_eArgError, "stream is not writable");
2740
2901
 
2741
2902
  new_file = rb_funcall(rb_cIO, rb_intern("new"), 1, INT2NUM(new_fd));
2742
- this->trace_stream = new_file;
2903
+ RB_OBJ_WRITE(self, &this->trace_stream, new_file);
2743
2904
 
2744
2905
  PQtrace(this->pgconn, new_fp);
2745
2906
  return Qnil;
@@ -2758,7 +2919,7 @@ pgconn_untrace(VALUE self)
2758
2919
 
2759
2920
  PQuntrace(this->pgconn);
2760
2921
  rb_funcall(this->trace_stream, rb_intern("close"), 0);
2761
- this->trace_stream = Qnil;
2922
+ RB_OBJ_WRITE(self, &this->trace_stream, Qnil);
2762
2923
  return Qnil;
2763
2924
  }
2764
2925
 
@@ -2817,13 +2978,14 @@ pgconn_set_notice_receiver(VALUE self)
2817
2978
  VALUE proc, old_proc;
2818
2979
  t_pg_connection *this = pg_get_connection_safe( self );
2819
2980
 
2981
+ rb_check_frozen(self);
2820
2982
  /* If default_notice_receiver is unset, assume that the current
2821
2983
  * notice receiver is the default, and save it to a global variable.
2822
2984
  * This should not be a problem because the default receiver is
2823
2985
  * always the same, so won't vary among connections.
2824
2986
  */
2825
- if(default_notice_receiver == NULL)
2826
- default_notice_receiver = PQsetNoticeReceiver(this->pgconn, NULL, NULL);
2987
+ if(this->default_notice_receiver == NULL)
2988
+ this->default_notice_receiver = PQsetNoticeReceiver(this->pgconn, NULL, NULL);
2827
2989
 
2828
2990
  old_proc = this->notice_receiver;
2829
2991
  if( rb_block_given_p() ) {
@@ -2832,10 +2994,10 @@ pgconn_set_notice_receiver(VALUE self)
2832
2994
  } else {
2833
2995
  /* if no block is given, set back to default */
2834
2996
  proc = Qnil;
2835
- PQsetNoticeReceiver(this->pgconn, default_notice_receiver, NULL);
2997
+ PQsetNoticeReceiver(this->pgconn, this->default_notice_receiver, NULL);
2836
2998
  }
2837
2999
 
2838
- this->notice_receiver = proc;
3000
+ RB_OBJ_WRITE(self, &this->notice_receiver, proc);
2839
3001
  return old_proc;
2840
3002
  }
2841
3003
 
@@ -2850,10 +3012,10 @@ notice_processor_proxy(void *arg, const char *message)
2850
3012
  VALUE self = (VALUE)arg;
2851
3013
  t_pg_connection *this = pg_get_connection( self );
2852
3014
 
2853
- if (this->notice_receiver != Qnil) {
3015
+ if (this->notice_processor != Qnil) {
2854
3016
  VALUE message_str = rb_str_new2(message);
2855
3017
  PG_ENCODING_SET_NOCHECK( message_str, this->enc_idx );
2856
- rb_funcall(this->notice_receiver, rb_intern("call"), 1, message_str);
3018
+ rb_funcall(this->notice_processor, rb_intern("call"), 1, message_str);
2857
3019
  }
2858
3020
  return;
2859
3021
  }
@@ -2877,25 +3039,26 @@ pgconn_set_notice_processor(VALUE self)
2877
3039
  VALUE proc, old_proc;
2878
3040
  t_pg_connection *this = pg_get_connection_safe( self );
2879
3041
 
3042
+ rb_check_frozen(self);
2880
3043
  /* If default_notice_processor is unset, assume that the current
2881
3044
  * notice processor is the default, and save it to a global variable.
2882
3045
  * This should not be a problem because the default processor is
2883
3046
  * always the same, so won't vary among connections.
2884
3047
  */
2885
- if(default_notice_processor == NULL)
2886
- default_notice_processor = PQsetNoticeProcessor(this->pgconn, NULL, NULL);
3048
+ if(this->default_notice_processor == NULL)
3049
+ this->default_notice_processor = PQsetNoticeProcessor(this->pgconn, NULL, NULL);
2887
3050
 
2888
- old_proc = this->notice_receiver;
3051
+ old_proc = this->notice_processor;
2889
3052
  if( rb_block_given_p() ) {
2890
3053
  proc = rb_block_proc();
2891
3054
  PQsetNoticeProcessor(this->pgconn, gvl_notice_processor_proxy, (void *)self);
2892
3055
  } else {
2893
3056
  /* if no block is given, set back to default */
2894
3057
  proc = Qnil;
2895
- PQsetNoticeProcessor(this->pgconn, default_notice_processor, NULL);
3058
+ PQsetNoticeProcessor(this->pgconn, this->default_notice_processor, NULL);
2896
3059
  }
2897
3060
 
2898
- this->notice_receiver = proc;
3061
+ RB_OBJ_WRITE(self, &this->notice_processor, proc);
2899
3062
  return old_proc;
2900
3063
  }
2901
3064
 
@@ -2927,6 +3090,7 @@ pgconn_sync_set_client_encoding(VALUE self, VALUE str)
2927
3090
  {
2928
3091
  PGconn *conn = pg_get_pgconn( self );
2929
3092
 
3093
+ rb_check_frozen(self);
2930
3094
  Check_Type(str, T_STRING);
2931
3095
 
2932
3096
  if ( (gvl_PQsetClientEncoding(conn, StringValueCStr(str))) == -1 )
@@ -3095,11 +3259,13 @@ pgconn_async_get_last_result(VALUE self)
3095
3259
  VALUE rb_pgresult = Qnil;
3096
3260
  PGresult *cur, *prev;
3097
3261
 
3098
- cur = prev = NULL;
3262
+ cur = prev = NULL;
3099
3263
  for(;;) {
3100
3264
  int status;
3101
3265
 
3102
- /* 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
+ */
3103
3269
  wait_socket_readable(self, NULL, get_result_readable);
3104
3270
 
3105
3271
  cur = gvl_PQgetResult(conn);
@@ -3133,7 +3299,7 @@ pgconn_async_get_last_result(VALUE self)
3133
3299
  * Returns:
3134
3300
  * * +nil+ when the connection is already idle
3135
3301
  * * +true+ when some results have been discarded
3136
- * * +false+ when a failure occured and the connection was closed
3302
+ * * +false+ when a failure occurred and the connection was closed
3137
3303
  *
3138
3304
  */
3139
3305
  static VALUE
@@ -3420,6 +3586,21 @@ pgconn_async_exec_prepared(int argc, VALUE *argv, VALUE self)
3420
3586
  return rb_pgresult;
3421
3587
  }
3422
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
+ }
3423
3604
 
3424
3605
  /*
3425
3606
  * call-seq:
@@ -3432,16 +3613,7 @@ pgconn_async_exec_prepared(int argc, VALUE *argv, VALUE self)
3432
3613
  static VALUE
3433
3614
  pgconn_async_describe_portal(VALUE self, VALUE portal)
3434
3615
  {
3435
- VALUE rb_pgresult = Qnil;
3436
-
3437
- pgconn_discard_results( self );
3438
- pgconn_send_describe_portal( self, portal );
3439
- rb_pgresult = pgconn_async_get_last_result( self );
3440
-
3441
- if ( rb_block_given_p() ) {
3442
- return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
3443
- }
3444
- return rb_pgresult;
3616
+ return pgconn_async_describe_close_prepared_potral(self, portal, pgconn_send_describe_portal);
3445
3617
  }
3446
3618
 
3447
3619
 
@@ -3456,27 +3628,64 @@ pgconn_async_describe_portal(VALUE self, VALUE portal)
3456
3628
  static VALUE
3457
3629
  pgconn_async_describe_prepared(VALUE self, VALUE stmt_name)
3458
3630
  {
3459
- VALUE rb_pgresult = Qnil;
3460
-
3461
- pgconn_discard_results( self );
3462
- pgconn_send_describe_prepared( self, stmt_name );
3463
- rb_pgresult = pgconn_async_get_last_result( self );
3631
+ return pgconn_async_describe_close_prepared_potral(self, stmt_name, pgconn_send_describe_prepared);
3632
+ }
3464
3633
 
3465
- if ( rb_block_given_p() ) {
3466
- return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
3467
- }
3468
- 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);
3469
3656
  }
3470
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
3471
3682
 
3472
- #ifdef HAVE_PQSSLATTRIBUTE
3473
3683
  /*
3474
3684
  * call-seq:
3475
3685
  * conn.ssl_in_use? -> Boolean
3476
3686
  *
3477
3687
  * Returns +true+ if the connection uses SSL/TLS, +false+ if not.
3478
3688
  *
3479
- * Available since PostgreSQL-9.5
3480
3689
  */
3481
3690
  static VALUE
3482
3691
  pgconn_ssl_in_use(VALUE self)
@@ -3510,7 +3719,6 @@ pgconn_ssl_in_use(VALUE self)
3510
3719
  *
3511
3720
  * See also #ssl_attribute_names and the {corresponding libpq function}[https://www.postgresql.org/docs/current/libpq-status.html#LIBPQ-PQSSLATTRIBUTE].
3512
3721
  *
3513
- * Available since PostgreSQL-9.5
3514
3722
  */
3515
3723
  static VALUE
3516
3724
  pgconn_ssl_attribute(VALUE self, VALUE attribute_name)
@@ -3529,7 +3737,6 @@ pgconn_ssl_attribute(VALUE self, VALUE attribute_name)
3529
3737
  *
3530
3738
  * See also #ssl_attribute
3531
3739
  *
3532
- * Available since PostgreSQL-9.5
3533
3740
  */
3534
3741
  static VALUE
3535
3742
  pgconn_ssl_attribute_names(VALUE self)
@@ -3545,8 +3752,6 @@ pgconn_ssl_attribute_names(VALUE self)
3545
3752
  }
3546
3753
 
3547
3754
 
3548
- #endif
3549
-
3550
3755
 
3551
3756
  #ifdef HAVE_PQENTERPIPELINEMODE
3552
3757
  /*
@@ -3581,6 +3786,8 @@ pgconn_pipeline_status(VALUE self)
3581
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.
3582
3787
  * This function does not actually send anything to the server, it just changes the libpq connection state.
3583
3788
  *
3789
+ * See the {PostgreSQL documentation}[https://www.postgresql.org/docs/17/libpq-pipeline-mode.html#LIBPQ-PIPELINE-MODE].
3790
+ *
3584
3791
  * Available since PostgreSQL-14
3585
3792
  */
3586
3793
  static VALUE
@@ -3619,29 +3826,55 @@ pgconn_exit_pipeline_mode(VALUE self)
3619
3826
 
3620
3827
  /*
3621
3828
  * call-seq:
3622
- * conn.pipeline_sync -> nil
3829
+ * conn.sync_pipeline_sync -> nil
3830
+ *
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.
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
3623
3853
  *
3624
- * Marks a synchronization point in a pipeline by sending a sync message and flushing the send buffer.
3625
- * This serves as the delimiter of an implicit transaction and an error recovery point; see Section 34.5.1.3 of the PostgreSQL documentation.
3854
+ * Marks a synchronization point in a pipeline by sending a sync message without flushing the send buffer.
3626
3855
  *
3856
+ * This serves as the delimiter of an implicit transaction and an error recovery point.
3627
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.
3628
3859
  *
3629
- * Available since PostgreSQL-14
3860
+ * Available since PostgreSQL-17
3630
3861
  */
3631
3862
  static VALUE
3632
- pgconn_pipeline_sync(VALUE self)
3863
+ pgconn_send_pipeline_sync(VALUE self)
3633
3864
  {
3634
3865
  PGconn *conn = pg_get_pgconn(self);
3635
- int res = PQpipelineSync(conn);
3866
+ int res = gvl_PQsendPipelineSync(conn);
3636
3867
  if( res != 1 )
3637
3868
  pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
3638
3869
 
3639
3870
  return Qnil;
3640
3871
  }
3872
+ #endif
3873
+
3641
3874
 
3642
3875
  /*
3643
3876
  * call-seq:
3644
- * conn.pipeline_sync -> nil
3877
+ * conn.send_flush_request -> nil
3645
3878
  *
3646
3879
  * Sends a request for the server to flush its output buffer.
3647
3880
  *
@@ -4058,6 +4291,7 @@ static VALUE pgconn_external_encoding(VALUE self);
4058
4291
  static VALUE
4059
4292
  pgconn_internal_encoding_set(VALUE self, VALUE enc)
4060
4293
  {
4294
+ rb_check_frozen(self);
4061
4295
  if (NIL_P(enc)) {
4062
4296
  pgconn_sync_set_client_encoding( self, rb_usascii_str_new_cstr("SQL_ASCII") );
4063
4297
  return enc;
@@ -4112,6 +4346,7 @@ pgconn_async_set_client_encoding(VALUE self, VALUE encname)
4112
4346
  {
4113
4347
  VALUE query_format, query;
4114
4348
 
4349
+ rb_check_frozen(self);
4115
4350
  Check_Type(encname, T_STRING);
4116
4351
  query_format = rb_str_new_cstr("set client_encoding to '%s'");
4117
4352
  query = rb_funcall(query_format, rb_intern("%"), 1, encname);
@@ -4161,15 +4396,23 @@ static VALUE
4161
4396
  pgconn_set_default_encoding( VALUE self )
4162
4397
  {
4163
4398
  PGconn *conn = pg_get_pgconn( self );
4164
- rb_encoding *enc;
4165
- const char *encname;
4166
-
4167
- if (( enc = rb_default_internal_encoding() )) {
4168
- encname = pg_get_rb_encoding_as_pg_encoding( enc );
4169
- if ( pgconn_set_client_encoding_async(self, rb_str_new_cstr(encname)) != 0 )
4170
- rb_warning( "Failed to set the default_internal encoding to %s: '%s'",
4171
- encname, PQerrorMessage(conn) );
4172
- return rb_enc_from_encoding( enc );
4399
+ rb_encoding *rb_enc;
4400
+
4401
+ rb_check_frozen(self);
4402
+ if (( rb_enc = rb_default_internal_encoding() )) {
4403
+ rb_encoding * conn_encoding = pg_conn_enc_get( conn );
4404
+
4405
+ /* Don't set the server encoding, if it's unnecessary.
4406
+ * This is important for connection proxies, who disallow configuration settings.
4407
+ */
4408
+ if ( conn_encoding != rb_enc ) {
4409
+ const char *encname = pg_get_rb_encoding_as_pg_encoding( rb_enc );
4410
+ if ( pgconn_set_client_encoding_async(self, rb_str_new_cstr(encname)) != 0 )
4411
+ rb_warning( "Failed to set the default_internal encoding to %s: '%s'",
4412
+ encname, PQerrorMessage(conn) );
4413
+ }
4414
+ pgconn_set_internal_encoding_index( self );
4415
+ return rb_enc_from_encoding( rb_enc );
4173
4416
  } else {
4174
4417
  pgconn_set_internal_encoding_index( self );
4175
4418
  return Qnil;
@@ -4193,10 +4436,11 @@ pgconn_type_map_for_queries_set(VALUE self, VALUE typemap)
4193
4436
  t_typemap *tm;
4194
4437
  UNUSED(tm);
4195
4438
 
4439
+ rb_check_frozen(self);
4196
4440
  /* Check type of method param */
4197
4441
  TypedData_Get_Struct(typemap, t_typemap, &pg_typemap_type, tm);
4198
4442
 
4199
- this->type_map_for_queries = typemap;
4443
+ RB_OBJ_WRITE(self, &this->type_map_for_queries, typemap);
4200
4444
 
4201
4445
  return typemap;
4202
4446
  }
@@ -4233,8 +4477,9 @@ pgconn_type_map_for_results_set(VALUE self, VALUE typemap)
4233
4477
  t_typemap *tm;
4234
4478
  UNUSED(tm);
4235
4479
 
4480
+ rb_check_frozen(self);
4236
4481
  TypedData_Get_Struct(typemap, t_typemap, &pg_typemap_type, tm);
4237
- this->type_map_for_results = typemap;
4482
+ RB_OBJ_WRITE(self, &this->type_map_for_results, typemap);
4238
4483
 
4239
4484
  return typemap;
4240
4485
  }
@@ -4272,13 +4517,14 @@ pgconn_encoder_for_put_copy_data_set(VALUE self, VALUE encoder)
4272
4517
  {
4273
4518
  t_pg_connection *this = pg_get_connection( self );
4274
4519
 
4520
+ rb_check_frozen(self);
4275
4521
  if( encoder != Qnil ){
4276
4522
  t_pg_coder *co;
4277
4523
  UNUSED(co);
4278
4524
  /* Check argument type */
4279
4525
  TypedData_Get_Struct(encoder, t_pg_coder, &pg_coder_type, co);
4280
4526
  }
4281
- this->encoder_for_put_copy_data = encoder;
4527
+ RB_OBJ_WRITE(self, &this->encoder_for_put_copy_data, encoder);
4282
4528
 
4283
4529
  return encoder;
4284
4530
  }
@@ -4320,13 +4566,14 @@ pgconn_decoder_for_get_copy_data_set(VALUE self, VALUE decoder)
4320
4566
  {
4321
4567
  t_pg_connection *this = pg_get_connection( self );
4322
4568
 
4569
+ rb_check_frozen(self);
4323
4570
  if( decoder != Qnil ){
4324
4571
  t_pg_coder *co;
4325
4572
  UNUSED(co);
4326
4573
  /* Check argument type */
4327
4574
  TypedData_Get_Struct(decoder, t_pg_coder, &pg_coder_type, co);
4328
4575
  }
4329
- this->decoder_for_get_copy_data = decoder;
4576
+ RB_OBJ_WRITE(self, &this->decoder_for_get_copy_data, decoder);
4330
4577
 
4331
4578
  return decoder;
4332
4579
  }
@@ -4372,6 +4619,7 @@ pgconn_field_name_type_set(VALUE self, VALUE sym)
4372
4619
  {
4373
4620
  t_pg_connection *this = pg_get_connection( self );
4374
4621
 
4622
+ rb_check_frozen(self);
4375
4623
  this->flags &= ~PG_RESULT_FIELD_NAMES_MASK;
4376
4624
  if( sym == sym_symbol ) this->flags |= PG_RESULT_FIELD_NAMES_SYMBOL;
4377
4625
  else if ( sym == sym_static_symbol ) this->flags |= PG_RESULT_FIELD_NAMES_STATIC_SYMBOL;
@@ -4445,6 +4693,7 @@ init_pg_connection(void)
4445
4693
  rb_define_method(rb_cPGconn, "finished?", pgconn_finished_p, 0);
4446
4694
  rb_define_method(rb_cPGconn, "sync_reset", pgconn_sync_reset, 0);
4447
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);
4448
4697
  rb_define_method(rb_cPGconn, "reset_poll", pgconn_reset_poll, 0);
4449
4698
  rb_define_alias(rb_cPGconn, "close", "finish");
4450
4699
 
@@ -4469,7 +4718,9 @@ init_pg_connection(void)
4469
4718
  rb_define_method(rb_cPGconn, "socket", pgconn_socket, 0);
4470
4719
  rb_define_method(rb_cPGconn, "socket_io", pgconn_socket_io, 0);
4471
4720
  rb_define_method(rb_cPGconn, "backend_pid", pgconn_backend_pid, 0);
4721
+ #ifndef HAVE_PQSETCHUNKEDROWSMODE
4472
4722
  rb_define_method(rb_cPGconn, "backend_key", pgconn_backend_key, 0);
4723
+ #endif
4473
4724
  rb_define_method(rb_cPGconn, "connection_needs_password", pgconn_connection_needs_password, 0);
4474
4725
  rb_define_method(rb_cPGconn, "connection_used_password", pgconn_connection_used_password, 0);
4475
4726
  /* rb_define_method(rb_cPGconn, "getssl", pgconn_getssl, 0); */
@@ -4481,6 +4732,10 @@ init_pg_connection(void)
4481
4732
  rb_define_method(rb_cPGconn, "sync_exec_prepared", pgconn_sync_exec_prepared, -1);
4482
4733
  rb_define_method(rb_cPGconn, "sync_describe_prepared", pgconn_sync_describe_prepared, 1);
4483
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
4484
4739
 
4485
4740
  rb_define_method(rb_cPGconn, "exec", pgconn_async_exec, -1);
4486
4741
  rb_define_method(rb_cPGconn, "exec_params", pgconn_async_exec_params, -1);
@@ -4488,6 +4743,10 @@ init_pg_connection(void)
4488
4743
  rb_define_method(rb_cPGconn, "exec_prepared", pgconn_async_exec_prepared, -1);
4489
4744
  rb_define_method(rb_cPGconn, "describe_prepared", pgconn_async_describe_prepared, 1);
4490
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
4491
4750
 
4492
4751
  rb_define_alias(rb_cPGconn, "async_exec", "exec");
4493
4752
  rb_define_alias(rb_cPGconn, "async_query", "async_exec");
@@ -4496,6 +4755,10 @@ init_pg_connection(void)
4496
4755
  rb_define_alias(rb_cPGconn, "async_exec_prepared", "exec_prepared");
4497
4756
  rb_define_alias(rb_cPGconn, "async_describe_prepared", "describe_prepared");
4498
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
4499
4762
 
4500
4763
  rb_define_method(rb_cPGconn, "make_empty_pgresult", pgconn_make_empty_pgresult, 1);
4501
4764
  rb_define_method(rb_cPGconn, "escape_string", pgconn_s_escape, 1);
@@ -4505,6 +4768,9 @@ init_pg_connection(void)
4505
4768
  rb_define_method(rb_cPGconn, "escape_bytea", pgconn_s_escape_bytea, 1);
4506
4769
  rb_define_method(rb_cPGconn, "unescape_bytea", pgconn_s_unescape_bytea, 1);
4507
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
4508
4774
 
4509
4775
  /****** PG::Connection INSTANCE METHODS: Asynchronous Command Processing ******/
4510
4776
  rb_define_method(rb_cPGconn, "send_query", pgconn_send_query, -1);
@@ -4524,7 +4790,9 @@ init_pg_connection(void)
4524
4790
  rb_define_method(rb_cPGconn, "discard_results", pgconn_discard_results, 0);
4525
4791
 
4526
4792
  /****** PG::Connection INSTANCE METHODS: Cancelling Queries in Progress ******/
4793
+ #ifndef HAVE_PQSETCHUNKEDROWSMODE
4527
4794
  rb_define_method(rb_cPGconn, "sync_cancel", pgconn_sync_cancel, 0);
4795
+ #endif
4528
4796
 
4529
4797
  /****** PG::Connection INSTANCE METHODS: NOTIFY ******/
4530
4798
  rb_define_method(rb_cPGconn, "notifies", pgconn_notifies, 0);
@@ -4536,9 +4804,7 @@ init_pg_connection(void)
4536
4804
 
4537
4805
  /****** PG::Connection INSTANCE METHODS: Control Functions ******/
4538
4806
  rb_define_method(rb_cPGconn, "set_error_verbosity", pgconn_set_error_verbosity, 1);
4539
- #ifdef HAVE_PQRESULTVERBOSEERRORMESSAGE
4540
4807
  rb_define_method(rb_cPGconn, "set_error_context_visibility", pgconn_set_error_context_visibility, 1 );
4541
- #endif
4542
4808
  rb_define_method(rb_cPGconn, "trace", pgconn_trace, 1);
4543
4809
  rb_define_method(rb_cPGconn, "untrace", pgconn_untrace, 0);
4544
4810
 
@@ -4560,22 +4826,21 @@ init_pg_connection(void)
4560
4826
  rb_define_method(rb_cPGconn, "sync_get_last_result", pgconn_sync_get_last_result, 0);
4561
4827
  rb_define_method(rb_cPGconn, "get_last_result", pgconn_async_get_last_result, 0);
4562
4828
  rb_define_alias(rb_cPGconn, "async_get_last_result", "get_last_result");
4563
- #ifdef HAVE_PQENCRYPTPASSWORDCONN
4564
4829
  rb_define_method(rb_cPGconn, "sync_encrypt_password", pgconn_sync_encrypt_password, -1);
4565
- #endif
4566
4830
 
4567
- #ifdef HAVE_PQSSLATTRIBUTE
4568
4831
  rb_define_method(rb_cPGconn, "ssl_in_use?", pgconn_ssl_in_use, 0);
4569
4832
  rb_define_method(rb_cPGconn, "ssl_attribute", pgconn_ssl_attribute, 1);
4570
4833
  rb_define_method(rb_cPGconn, "ssl_attribute_names", pgconn_ssl_attribute_names, 0);
4571
- #endif
4572
4834
 
4573
4835
  #ifdef HAVE_PQENTERPIPELINEMODE
4574
4836
  rb_define_method(rb_cPGconn, "pipeline_status", pgconn_pipeline_status, 0);
4575
4837
  rb_define_method(rb_cPGconn, "enter_pipeline_mode", pgconn_enter_pipeline_mode, 0);
4576
4838
  rb_define_method(rb_cPGconn, "exit_pipeline_mode", pgconn_exit_pipeline_mode, 0);
4577
- 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);
4578
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
4579
4844
  #endif
4580
4845
 
4581
4846
  /****** PG::Connection INSTANCE METHODS: Large Object Support ******/