pg 1.5.9 → 1.7.0

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 (67) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/{History.md → CHANGELOG.md} +126 -0
  4. data/Gemfile +11 -7
  5. data/README-Windows.rdoc +1 -1
  6. data/README.ja.md +83 -32
  7. data/README.md +79 -29
  8. data/Rakefile +84 -19
  9. data/certs/larskanis-2026.pem +24 -0
  10. data/ext/errorcodes.def +9 -0
  11. data/ext/errorcodes.rb +1 -1
  12. data/ext/errorcodes.txt +8 -1
  13. data/ext/extconf.rb +194 -30
  14. data/ext/gvl_wrappers.c +13 -2
  15. data/ext/gvl_wrappers.h +47 -134
  16. data/ext/pg.c +23 -16
  17. data/ext/pg.h +23 -24
  18. data/ext/pg_binary_decoder.c +157 -3
  19. data/ext/pg_binary_encoder.c +219 -9
  20. data/ext/pg_cancel_connection.c +360 -0
  21. data/ext/pg_coder.c +58 -9
  22. data/ext/pg_connection.c +558 -291
  23. data/ext/pg_copy_coder.c +36 -23
  24. data/ext/pg_record_coder.c +11 -7
  25. data/ext/pg_result.c +144 -76
  26. data/ext/pg_text_decoder.c +7 -7
  27. data/ext/pg_text_encoder.c +29 -11
  28. data/ext/pg_tuple.c +9 -9
  29. data/ext/pg_type_map.c +45 -3
  30. data/ext/pg_type_map_all_strings.c +3 -3
  31. data/ext/pg_type_map_by_class.c +2 -2
  32. data/ext/pg_type_map_by_column.c +4 -3
  33. data/ext/pg_type_map_by_mri_type.c +1 -1
  34. data/ext/pg_type_map_by_oid.c +4 -2
  35. data/ext/pg_type_map_in_ruby.c +2 -2
  36. data/ext/pg_util.c +2 -2
  37. data/ext/pg_util.h +2 -2
  38. data/lib/pg/basic_type_map_based_on_result.rb +5 -0
  39. data/lib/pg/basic_type_map_for_queries.rb +16 -5
  40. data/lib/pg/basic_type_map_for_results.rb +5 -0
  41. data/lib/pg/basic_type_registry.rb +2 -2
  42. data/lib/pg/cancel_connection.rb +53 -0
  43. data/lib/pg/coder.rb +4 -2
  44. data/lib/pg/connection.rb +393 -180
  45. data/lib/pg/text_decoder/date.rb +1 -1
  46. data/lib/pg/text_decoder/json.rb +1 -1
  47. data/lib/pg/text_encoder/date.rb +7 -1
  48. data/lib/pg/text_encoder/json.rb +1 -1
  49. data/lib/pg/version.rb +2 -1
  50. data/lib/pg.rb +156 -130
  51. data/misc/glibc/Dockerfile +20 -0
  52. data/misc/glibc/docker-compose.yml +9 -0
  53. data/misc/glibc/glibc_spec.rb +5 -0
  54. data/misc/yugabyte/Dockerfile +9 -0
  55. data/misc/yugabyte/docker-compose.yml +28 -0
  56. data/misc/yugabyte/pg-test.rb +45 -0
  57. data/pg.gemspec +5 -3
  58. data/ports/patches/krb5/1.22.2/0001-Allow-static-linking-krb5-library.patch +30 -0
  59. data/ports/patches/krb5/1.22.2/0002-unknown-command-line-option-on-clang.patch +12 -0
  60. data/ports/patches/postgresql/18.6/0001-Use-workaround-of-__builtin_setjmp-only-on-MINGW-on-.patch +42 -0
  61. data/rakelib/pg_gem_helper.rb +64 -0
  62. data/sample/async_mixed.rb +1 -1
  63. data.tar.gz.sig +0 -0
  64. metadata +36 -22
  65. metadata.gz.sig +0 -0
  66. data/Manifest.txt +0 -72
  67. data/Rakefile.cross +0 -303
data/ext/pg_connection.c CHANGED
@@ -14,7 +14,7 @@ VALUE rb_cPGconn;
14
14
  static ID s_id_encode;
15
15
  static ID s_id_autoclose_set;
16
16
  static VALUE sym_type, sym_format, sym_value;
17
- static VALUE sym_symbol, sym_string, sym_static_symbol;
17
+ static VALUE sym_symbol, sym_string;
18
18
 
19
19
  static VALUE pgconn_finish( VALUE );
20
20
  static VALUE pgconn_set_default_encoding( VALUE self );
@@ -30,11 +30,8 @@ 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
- NORETURN( static void
37
- pg_raise_conn_error( VALUE klass, VALUE self, const char *format, ...))
33
+ void
34
+ pg_raise_conn_error( VALUE klass, VALUE self, const char *format, ...)
38
35
  {
39
36
  VALUE msg, error;
40
37
  va_list ap;
@@ -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
 
@@ -151,13 +153,13 @@ pgconn_make_conninfo_array( const PQconninfoOption *options )
151
153
  return ary;
152
154
  }
153
155
 
154
- static const char *pg_cstr_enc(VALUE str, int enc_idx){
156
+ static const char *pg_cstr_enc(VALUE str, int enc_idx, VALUE *transcoded_str){
155
157
  const char *ptr = StringValueCStr(str);
156
158
  if( ENCODING_GET(str) == enc_idx ){
157
159
  return ptr;
158
160
  } else {
159
- str = rb_str_export_to_enc(str, rb_enc_from_index(enc_idx));
160
- return StringValueCStr(str);
161
+ *transcoded_str = rb_str_export_to_enc(str, rb_enc_from_index(enc_idx));
162
+ return StringValueCStr(*transcoded_str);
161
163
  }
162
164
  }
163
165
 
@@ -186,6 +188,7 @@ pgconn_gc_compact( void *_this )
186
188
  pg_gc_location( this->socket_io );
187
189
  pg_gc_location( this->notice_receiver );
188
190
  pg_gc_location( this->notice_processor );
191
+ pg_gc_location( this->self );
189
192
  pg_gc_location( this->type_map_for_queries );
190
193
  pg_gc_location( this->type_map_for_results );
191
194
  pg_gc_location( this->trace_stream );
@@ -230,7 +233,7 @@ static const rb_data_type_t pg_connection_type = {
230
233
  pgconn_gc_mark,
231
234
  pgconn_gc_free,
232
235
  pgconn_memsize,
233
- pg_compact_callback(pgconn_gc_compact),
236
+ pgconn_gc_compact,
234
237
  },
235
238
  0,
236
239
  0,
@@ -258,6 +261,7 @@ pgconn_s_allocate( VALUE klass )
258
261
  RB_OBJ_WRITE(self, &this->socket_io, Qnil);
259
262
  RB_OBJ_WRITE(self, &this->notice_receiver, Qnil);
260
263
  RB_OBJ_WRITE(self, &this->notice_processor, Qnil);
264
+ RB_OBJ_WRITE(self, &this->self, self);
261
265
  RB_OBJ_WRITE(self, &this->type_map_for_queries, pg_typemap_all_strings);
262
266
  RB_OBJ_WRITE(self, &this->type_map_for_results, pg_typemap_all_strings);
263
267
  RB_OBJ_WRITE(self, &this->encoder_for_put_copy_data, Qnil);
@@ -278,7 +282,8 @@ pgconn_s_sync_connect(int argc, VALUE *argv, VALUE klass)
278
282
 
279
283
  this = pg_get_connection( self );
280
284
  conninfo = rb_funcall2( rb_cPGconn, rb_intern("parse_connect_args"), argc, argv );
281
- this->pgconn = gvl_PQconnectdb(StringValueCStr(conninfo));
285
+ this->pgconn = PQconnectdb(StringValueCStr(conninfo));
286
+ RB_GC_GUARD(conninfo);
282
287
 
283
288
  if(this->pgconn == NULL)
284
289
  rb_raise(rb_ePGerror, "PQconnectdb() unable to allocate PGconn structure");
@@ -327,6 +332,7 @@ pgconn_s_connect_start( int argc, VALUE *argv, VALUE klass )
327
332
  this = pg_get_connection( rb_conn );
328
333
  conninfo = rb_funcall2( klass, rb_intern("parse_connect_args"), argc, argv );
329
334
  this->pgconn = gvl_PQconnectStart( StringValueCStr(conninfo) );
335
+ RB_GC_GUARD(conninfo);
330
336
 
331
337
  if( this->pgconn == NULL )
332
338
  rb_raise(rb_ePGerror, "PQconnectStart() unable to allocate PGconn structure");
@@ -348,6 +354,7 @@ pgconn_s_sync_ping( int argc, VALUE *argv, VALUE klass )
348
354
 
349
355
  conninfo = rb_funcall2( klass, rb_intern("parse_connect_args"), argc, argv );
350
356
  ping = gvl_PQping( StringValueCStr(conninfo) );
357
+ RB_GC_GUARD(conninfo);
351
358
 
352
359
  return INT2FIX((int)ping);
353
360
  }
@@ -419,7 +426,6 @@ pgconn_s_conninfo_parse(VALUE self, VALUE conninfo)
419
426
  }
420
427
 
421
428
 
422
- #ifdef HAVE_PQENCRYPTPASSWORDCONN
423
429
  static VALUE
424
430
  pgconn_sync_encrypt_password(int argc, VALUE *argv, VALUE self)
425
431
  {
@@ -433,7 +439,7 @@ pgconn_sync_encrypt_password(int argc, VALUE *argv, VALUE self)
433
439
  Check_Type(password, T_STRING);
434
440
  Check_Type(username, T_STRING);
435
441
 
436
- encrypted = gvl_PQencryptPasswordConn(conn, StringValueCStr(password), StringValueCStr(username), RTEST(algorithm) ? StringValueCStr(algorithm) : NULL);
442
+ encrypted = PQencryptPasswordConn(conn, StringValueCStr(password), StringValueCStr(username), RTEST(algorithm) ? StringValueCStr(algorithm) : NULL);
437
443
  if ( encrypted ) {
438
444
  rval = rb_str_new2( encrypted );
439
445
  PQfreemem( encrypted );
@@ -443,7 +449,6 @@ pgconn_sync_encrypt_password(int argc, VALUE *argv, VALUE self)
443
449
 
444
450
  return rval;
445
451
  }
446
- #endif
447
452
 
448
453
 
449
454
  /*
@@ -560,7 +565,7 @@ static VALUE
560
565
  pgconn_sync_reset( VALUE self )
561
566
  {
562
567
  pgconn_close_socket_io( self );
563
- gvl_PQreset( pg_get_pgconn(self) );
568
+ PQreset( pg_get_pgconn(self) );
564
569
  return self;
565
570
  }
566
571
 
@@ -568,13 +573,17 @@ static VALUE
568
573
  pgconn_reset_start2( VALUE self, VALUE conninfo )
569
574
  {
570
575
  t_pg_connection *this = pg_get_connection( self );
576
+ /* Ensure conninfo is a valid C string before closing the connection. */
577
+ char *p_conninfo = StringValueCStr(conninfo);
571
578
 
572
579
  /* Close old connection */
573
580
  pgconn_close_socket_io( self );
574
581
  PQfinish( this->pgconn );
582
+ this->pgconn = NULL; /* Ensure no double free can happen. */
575
583
 
576
584
  /* Start new connection */
577
- this->pgconn = gvl_PQconnectStart( StringValueCStr(conninfo) );
585
+ this->pgconn = gvl_PQconnectStart( p_conninfo );
586
+ RB_GC_GUARD(conninfo);
578
587
 
579
588
  if( this->pgconn == NULL )
580
589
  rb_raise(rb_ePGerror, "PQconnectStart() unable to allocate PGconn structure");
@@ -609,7 +618,7 @@ pgconn_reset_start(VALUE self)
609
618
  * conn.reset_poll -> Integer
610
619
  *
611
620
  * Checks the status of a connection reset operation.
612
- * See #connect_start and #connect_poll for
621
+ * See Connection.connect_start and #connect_poll for
613
622
  * usage information and return values.
614
623
  */
615
624
  static VALUE
@@ -760,7 +769,6 @@ pgconn_options(VALUE self)
760
769
  *
761
770
  * Returns the connection options used by a live connection.
762
771
  *
763
- * Available since PostgreSQL-9.3
764
772
  */
765
773
  static VALUE
766
774
  pgconn_conninfo( VALUE self )
@@ -847,31 +855,79 @@ pgconn_parameter_status(VALUE self, VALUE param_name)
847
855
  * call-seq:
848
856
  * conn.protocol_version -> Integer
849
857
  *
850
- * The 3.0 protocol will normally be used when communicating with PostgreSQL 7.4
851
- * or later servers; pre-7.4 servers support only protocol 2.0. (Protocol 1.0 is
852
- * obsolete and not supported by libpq.)
858
+ * Interrogates the frontend/backend protocol being used.
859
+ *
860
+ * Applications might wish to use this function to determine whether certain features are supported.
861
+ * Currently, the only value is 3 (3.0 protocol).
862
+ * The protocol version will not change after connection startup is complete, but it could theoretically change during a connection reset.
863
+ * The 3.0 protocol is supported by PostgreSQL server versions 7.4 and above.
864
+ *
865
+ * PG::ConnectionBad is raised if the connection is bad.
853
866
  */
854
867
  static VALUE
855
868
  pgconn_protocol_version(VALUE self)
856
869
  {
857
- return INT2NUM(PQprotocolVersion(pg_get_pgconn(self)));
870
+ int protocol_version = PQprotocolVersion(pg_get_pgconn(self));
871
+ if (protocol_version == 0) {
872
+ pg_raise_conn_error( rb_eConnectionBad, self, "PQprotocolVersion() can't get protocol version");
873
+ }
874
+ return INT2NUM(protocol_version);
875
+ }
876
+
877
+ #ifdef LIBPQ_HAS_FULL_PROTOCOL_VERSION
878
+ /*
879
+ * call-seq:
880
+ * conn.full_protocol_version -> Integer
881
+ *
882
+ * Interrogates the frontend/backend protocol being used, including minor version.
883
+ *
884
+ * Applications might wish to use this function to determine whether certain features are supported.
885
+ * The result is the major version multiplied by 10000 added to the minor version, e.g. 30002 for version 3.2.
886
+ * The protocol version will not change after connection startup is complete, but it could theoretically change during a connection reset.
887
+ * The 3.0 protocol is supported by PostgreSQL server versions 7.4 and above.
888
+ *
889
+ * PG::ConnectionBad is raised if the connection is bad.
890
+ *
891
+ * Available since PostgreSQL-18.
892
+ */
893
+ static VALUE
894
+ pgconn_full_protocol_version(VALUE self)
895
+ {
896
+ int protocol_version = PQfullProtocolVersion(pg_get_pgconn(self));
897
+ if (protocol_version == 0) {
898
+ pg_raise_conn_error( rb_eConnectionBad, self, "PQfullProtocolVersion() can't get protocol version");
899
+ }
900
+ return INT2NUM(protocol_version);
858
901
  }
902
+ #endif
859
903
 
860
904
  /*
861
905
  * call-seq:
862
906
  * conn.server_version -> Integer
863
907
  *
864
- * The number is formed by converting the major, minor, and revision
865
- * numbers into two-decimal-digit numbers and appending them together.
866
- * For example, version 7.4.2 will be returned as 70402, and version
867
- * 8.1 will be returned as 80100 (leading zeroes are not shown). Zero
868
- * is returned if the connection is bad.
908
+ * Returns an integer representing the server version.
909
+ *
910
+ * Applications might use this function to determine the version of the database server they are connected to.
911
+ * The result is formed by multiplying the server's major version number by 10000 and adding the minor version number.
912
+ * For example, version 10.1 will be returned as 100001, and version 11.0 will be returned as 110000.
913
+ *
914
+ * PG::ConnectionBad is raised if the connection is bad.
915
+ *
916
+ * Prior to major version 10, PostgreSQL used three-part version numbers in which the first two parts together represented the major version.
917
+ * 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.
918
+ *
919
+ * 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.
920
+ * In all release series, only the last two digits differ between minor releases (bug-fix releases).
869
921
  *
870
922
  */
871
923
  static VALUE
872
924
  pgconn_server_version(VALUE self)
873
925
  {
874
- return INT2NUM(PQserverVersion(pg_get_pgconn(self)));
926
+ int server_version = PQserverVersion(pg_get_pgconn(self));
927
+ if (server_version == 0) {
928
+ pg_raise_conn_error( rb_eConnectionBad, self, "PQserverVersion() can't get server version");
929
+ }
930
+ return INT2NUM(server_version);
875
931
  }
876
932
 
877
933
  /*
@@ -920,13 +976,42 @@ pgconn_socket(VALUE self)
920
976
  return INT2NUM(sd);
921
977
  }
922
978
 
979
+
980
+ VALUE
981
+ pg_wrap_socket_io(int sd, VALUE self, VALUE *p_socket_io, int *p_ruby_sd)
982
+ {
983
+ int ruby_sd;
984
+ VALUE cSocket;
985
+ VALUE socket_io = *p_socket_io;
986
+
987
+ #ifdef _WIN32
988
+ ruby_sd = rb_w32_wrap_io_handle((HANDLE)(intptr_t)sd, O_RDWR|O_BINARY|O_NOINHERIT);
989
+ if( ruby_sd == -1 )
990
+ pg_raise_conn_error( rb_eConnectionBad, self, "Could not wrap win32 socket handle");
991
+
992
+ *p_ruby_sd = ruby_sd;
993
+ #else
994
+ *p_ruby_sd = ruby_sd = sd;
995
+ #endif
996
+
997
+ cSocket = rb_const_get(rb_cObject, rb_intern("BasicSocket"));
998
+ socket_io = rb_funcall( cSocket, rb_intern("for_fd"), 1, INT2NUM(ruby_sd));
999
+
1000
+ /* Disable autoclose feature */
1001
+ rb_funcall( socket_io, s_id_autoclose_set, 1, Qfalse );
1002
+
1003
+ RB_OBJ_WRITE(self, p_socket_io, socket_io);
1004
+
1005
+ return socket_io;
1006
+ }
1007
+
923
1008
  /*
924
1009
  * call-seq:
925
1010
  * conn.socket_io() -> IO
926
1011
  *
927
1012
  * Fetch an IO object created from the Connection's underlying socket.
928
1013
  * 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.
929
- * <tt>IO#wait_*able</tt> is is <tt>Fiber.scheduler</tt> compatible in contrast to <tt>IO.select</tt>.
1014
+ * <tt>IO#wait_*able</tt> is <tt>Fiber.scheduler</tt> compatible in contrast to <tt>IO.select</tt>.
930
1015
  *
931
1016
  * The IO object can change while the connection is established, but is memorized afterwards.
932
1017
  * So be sure not to cache the IO object, but repeat calling <tt>conn.socket_io</tt> instead.
@@ -937,37 +1022,17 @@ pgconn_socket(VALUE self)
937
1022
  static VALUE
938
1023
  pgconn_socket_io(VALUE self)
939
1024
  {
940
- int sd;
941
- int ruby_sd;
942
1025
  t_pg_connection *this = pg_get_connection_safe( self );
943
- VALUE cSocket;
944
- VALUE socket_io = this->socket_io;
945
1026
 
946
- if ( !RTEST(socket_io) ) {
1027
+ if ( !RTEST(this->socket_io) ) {
1028
+ int sd;
947
1029
  if( (sd = PQsocket(this->pgconn)) < 0){
948
1030
  pg_raise_conn_error( rb_eConnectionBad, self, "PQsocket() can't get socket descriptor");
949
1031
  }
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
- this->ruby_sd = ruby_sd;
957
- #else
958
- 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, &this->socket_io, socket_io);
1032
+ return pg_wrap_socket_io( sd, self, &this->socket_io, &this->ruby_sd);
968
1033
  }
969
1034
 
970
- return socket_io;
1035
+ return this->socket_io;
971
1036
  }
972
1037
 
973
1038
  /*
@@ -984,6 +1049,7 @@ pgconn_backend_pid(VALUE self)
984
1049
  return INT2NUM(PQbackendPID(pg_get_pgconn(self)));
985
1050
  }
986
1051
 
1052
+ #ifndef LIBPQ_HAS_CHUNK_MODE
987
1053
  typedef struct
988
1054
  {
989
1055
  struct sockaddr_storage addr;
@@ -1028,6 +1094,7 @@ pgconn_backend_key(VALUE self)
1028
1094
 
1029
1095
  return INT2NUM(be_key);
1030
1096
  }
1097
+ #endif
1031
1098
 
1032
1099
  /*
1033
1100
  * call-seq:
@@ -1069,11 +1136,11 @@ static VALUE pgconn_sync_exec_params( int, VALUE *, VALUE );
1069
1136
  * This function has the same behavior as #async_exec, but is implemented using the synchronous command processing API of libpq.
1070
1137
  * It's not recommended to use explicit sync or async variants but #exec instead, unless you have a good reason to do so.
1071
1138
  *
1072
- * Both #sync_exec and #async_exec release the GVL while waiting for server response, so that concurrent threads will get executed.
1073
- * However #async_exec has two advantages:
1139
+ * However #async_exec has some advantages:
1074
1140
  *
1075
- * 1. #async_exec can be aborted by signals (like Ctrl-C), while #exec blocks signal processing until the query is answered.
1076
- * 2. Ruby VM gets notified about IO blocked operations and can pass them through <tt>Fiber.scheduler</tt>.
1141
+ * 1. Only #async_exec allows concurrent threads to run, while waiting for a server response.
1142
+ * 2. #async_exec can be aborted by signals (like Ctrl-C), while #exec blocks signal processing until the query is answered.
1143
+ * 3. Ruby VM gets notified about IO blocked operations and can pass them through <tt>Fiber.scheduler</tt>.
1077
1144
  * So only <tt>async_*</tt> methods are compatible to event based schedulers like the async gem.
1078
1145
  */
1079
1146
  static VALUE
@@ -1086,8 +1153,10 @@ pgconn_sync_exec(int argc, VALUE *argv, VALUE self)
1086
1153
  /* If called with no or nil parameters, use PQexec for compatibility */
1087
1154
  if ( argc == 1 || (argc >= 2 && argc <= 4 && NIL_P(argv[1]) )) {
1088
1155
  VALUE query_str = argv[0];
1156
+ VALUE transcoded_str;
1089
1157
 
1090
- result = gvl_PQexec(this->pgconn, pg_cstr_enc(query_str, this->enc_idx));
1158
+ result = PQexec(this->pgconn, pg_cstr_enc(query_str, this->enc_idx, &transcoded_str));
1159
+ RB_GC_GUARD(transcoded_str);
1091
1160
  rb_pgresult = pg_new_result(result, self);
1092
1161
  pg_result_check(rb_pgresult);
1093
1162
  if (rb_block_given_p()) {
@@ -1225,7 +1294,7 @@ alloc_query_params(struct query_params_data *paramsData)
1225
1294
  int nParams;
1226
1295
  int i=0;
1227
1296
  t_pg_coder *conv;
1228
- unsigned int required_pool_size;
1297
+ size_t required_pool_size;
1229
1298
  char *memory_pool;
1230
1299
 
1231
1300
  Check_Type(paramsData->params, T_ARRAY);
@@ -1237,7 +1306,7 @@ alloc_query_params(struct query_params_data *paramsData)
1237
1306
  paramsData->typecast_heap_chain = Qnil;
1238
1307
  paramsData->gc_array = Qnil;
1239
1308
 
1240
- nParams = (int)RARRAY_LEN(paramsData->params);
1309
+ nParams = RARRAY_LENINT(paramsData->params);
1241
1310
 
1242
1311
  required_pool_size = nParams * (
1243
1312
  sizeof(char *) +
@@ -1300,7 +1369,7 @@ alloc_query_params(struct query_params_data *paramsData)
1300
1369
  paramsData->lengths[i] = 0;
1301
1370
  } else {
1302
1371
  t_pg_coder_enc_func enc_func = pg_coder_enc_func( conv );
1303
- VALUE intermediate;
1372
+ VALUE intermediate = Qnil;
1304
1373
 
1305
1374
  /* 1st pass for retiving the required memory space */
1306
1375
  int len = enc_func(conv, param_value, NULL, &intermediate, paramsData->enc_idx);
@@ -1340,8 +1409,6 @@ alloc_query_params(struct query_params_data *paramsData)
1340
1409
  required_pool_size += len;
1341
1410
  }
1342
1411
  }
1343
-
1344
- RB_GC_GUARD(intermediate);
1345
1412
  }
1346
1413
  }
1347
1414
  }
@@ -1386,6 +1453,7 @@ pgconn_sync_exec_params( int argc, VALUE *argv, VALUE self )
1386
1453
  PGresult *result = NULL;
1387
1454
  VALUE rb_pgresult;
1388
1455
  VALUE command, in_res_fmt;
1456
+ VALUE transcoded_str;
1389
1457
  int nParams;
1390
1458
  int resultFormat;
1391
1459
  struct query_params_data paramsData = { this->enc_idx };
@@ -1407,9 +1475,10 @@ pgconn_sync_exec_params( int argc, VALUE *argv, VALUE self )
1407
1475
  resultFormat = NIL_P(in_res_fmt) ? 0 : NUM2INT(in_res_fmt);
1408
1476
  nParams = alloc_query_params( &paramsData );
1409
1477
 
1410
- result = gvl_PQexecParams(this->pgconn, pg_cstr_enc(command, paramsData.enc_idx), nParams, paramsData.types,
1478
+ result = PQexecParams(this->pgconn, pg_cstr_enc(command, paramsData.enc_idx, &transcoded_str), nParams, paramsData.types,
1411
1479
  (const char * const *)paramsData.values, paramsData.lengths, paramsData.formats, resultFormat);
1412
1480
 
1481
+ RB_GC_GUARD(transcoded_str);
1413
1482
  free_query_params( &paramsData );
1414
1483
 
1415
1484
  rb_pgresult = pg_new_result(result, self);
@@ -1438,6 +1507,7 @@ pgconn_sync_prepare(int argc, VALUE *argv, VALUE self)
1438
1507
  VALUE rb_pgresult;
1439
1508
  VALUE name, command, in_paramtypes;
1440
1509
  VALUE param;
1510
+ VALUE transcoded_str1, transcoded_str2;
1441
1511
  int i = 0;
1442
1512
  int nParams = 0;
1443
1513
  Oid *paramTypes = NULL;
@@ -1446,12 +1516,12 @@ pgconn_sync_prepare(int argc, VALUE *argv, VALUE self)
1446
1516
  int enc_idx = this->enc_idx;
1447
1517
 
1448
1518
  rb_scan_args(argc, argv, "21", &name, &command, &in_paramtypes);
1449
- name_cstr = pg_cstr_enc(name, enc_idx);
1450
- command_cstr = pg_cstr_enc(command, enc_idx);
1519
+ name_cstr = pg_cstr_enc(name, enc_idx, &transcoded_str1);
1520
+ command_cstr = pg_cstr_enc(command, enc_idx, &transcoded_str2);
1451
1521
 
1452
1522
  if(! NIL_P(in_paramtypes)) {
1453
1523
  Check_Type(in_paramtypes, T_ARRAY);
1454
- nParams = (int)RARRAY_LEN(in_paramtypes);
1524
+ nParams = RARRAY_LENINT(in_paramtypes);
1455
1525
  paramTypes = ALLOC_N(Oid, nParams);
1456
1526
  for(i = 0; i < nParams; i++) {
1457
1527
  param = rb_ary_entry(in_paramtypes, i);
@@ -1461,8 +1531,10 @@ pgconn_sync_prepare(int argc, VALUE *argv, VALUE self)
1461
1531
  paramTypes[i] = NUM2UINT(param);
1462
1532
  }
1463
1533
  }
1464
- result = gvl_PQprepare(this->pgconn, name_cstr, command_cstr, nParams, paramTypes);
1534
+ result = PQprepare(this->pgconn, name_cstr, command_cstr, nParams, paramTypes);
1465
1535
 
1536
+ RB_GC_GUARD(transcoded_str1);
1537
+ RB_GC_GUARD(transcoded_str2);
1466
1538
  xfree(paramTypes);
1467
1539
 
1468
1540
  rb_pgresult = pg_new_result(result, self);
@@ -1486,6 +1558,7 @@ pgconn_sync_exec_prepared(int argc, VALUE *argv, VALUE self)
1486
1558
  PGresult *result = NULL;
1487
1559
  VALUE rb_pgresult;
1488
1560
  VALUE name, in_res_fmt;
1561
+ VALUE transcoded_str;
1489
1562
  int nParams;
1490
1563
  int resultFormat;
1491
1564
  struct query_params_data paramsData = { this->enc_idx };
@@ -1501,10 +1574,11 @@ pgconn_sync_exec_prepared(int argc, VALUE *argv, VALUE self)
1501
1574
  resultFormat = NIL_P(in_res_fmt) ? 0 : NUM2INT(in_res_fmt);
1502
1575
  nParams = alloc_query_params( &paramsData );
1503
1576
 
1504
- result = gvl_PQexecPrepared(this->pgconn, pg_cstr_enc(name, paramsData.enc_idx), nParams,
1577
+ result = PQexecPrepared(this->pgconn, pg_cstr_enc(name, paramsData.enc_idx, &transcoded_str), nParams,
1505
1578
  (const char * const *)paramsData.values, paramsData.lengths, paramsData.formats,
1506
1579
  resultFormat);
1507
1580
 
1581
+ RB_GC_GUARD(transcoded_str);
1508
1582
  free_query_params( &paramsData );
1509
1583
 
1510
1584
  rb_pgresult = pg_new_result(result, self);
@@ -1516,6 +1590,23 @@ pgconn_sync_exec_prepared(int argc, VALUE *argv, VALUE self)
1516
1590
  return rb_pgresult;
1517
1591
  }
1518
1592
 
1593
+ static VALUE
1594
+ pgconn_sync_describe_close_prepared_portal(VALUE self, VALUE name, PGresult *(*func)(PGconn *, const char *))
1595
+ {
1596
+ PGresult *result;
1597
+ VALUE rb_pgresult;
1598
+ VALUE transcoded_str;
1599
+ t_pg_connection *this = pg_get_connection_safe( self );
1600
+ const char *stmt = NIL_P(name) ? NULL : pg_cstr_enc(name, this->enc_idx, &transcoded_str);
1601
+
1602
+ result = func(this->pgconn, stmt);
1603
+
1604
+ RB_GC_GUARD(transcoded_str);
1605
+ rb_pgresult = pg_new_result(result, self);
1606
+ pg_result_check(rb_pgresult);
1607
+ return rb_pgresult;
1608
+ }
1609
+
1519
1610
  /*
1520
1611
  * call-seq:
1521
1612
  * conn.sync_describe_prepared( statement_name ) -> PG::Result
@@ -1527,20 +1618,7 @@ pgconn_sync_exec_prepared(int argc, VALUE *argv, VALUE self)
1527
1618
  static VALUE
1528
1619
  pgconn_sync_describe_prepared(VALUE self, VALUE stmt_name)
1529
1620
  {
1530
- PGresult *result;
1531
- VALUE rb_pgresult;
1532
- t_pg_connection *this = pg_get_connection_safe( self );
1533
- const char *stmt;
1534
- if(NIL_P(stmt_name)) {
1535
- stmt = NULL;
1536
- }
1537
- else {
1538
- stmt = pg_cstr_enc(stmt_name, this->enc_idx);
1539
- }
1540
- result = gvl_PQdescribePrepared(this->pgconn, stmt);
1541
- rb_pgresult = pg_new_result(result, self);
1542
- pg_result_check(rb_pgresult);
1543
- return rb_pgresult;
1621
+ return pgconn_sync_describe_close_prepared_portal(self, stmt_name, PQdescribePrepared);
1544
1622
  }
1545
1623
 
1546
1624
 
@@ -1555,22 +1633,43 @@ pgconn_sync_describe_prepared(VALUE self, VALUE stmt_name)
1555
1633
  static VALUE
1556
1634
  pgconn_sync_describe_portal(VALUE self, VALUE stmt_name)
1557
1635
  {
1558
- PGresult *result;
1559
- VALUE rb_pgresult;
1560
- t_pg_connection *this = pg_get_connection_safe( self );
1561
- const char *stmt;
1562
- if(NIL_P(stmt_name)) {
1563
- stmt = NULL;
1564
- }
1565
- else {
1566
- stmt = pg_cstr_enc(stmt_name, this->enc_idx);
1567
- }
1568
- result = gvl_PQdescribePortal(this->pgconn, stmt);
1569
- rb_pgresult = pg_new_result(result, self);
1570
- pg_result_check(rb_pgresult);
1571
- return rb_pgresult;
1636
+ return pgconn_sync_describe_close_prepared_portal(self, stmt_name, PQdescribePortal);
1637
+ }
1638
+
1639
+
1640
+ #ifdef LIBPQ_HAS_CHUNK_MODE
1641
+ /*
1642
+ * call-seq:
1643
+ * conn.sync_close_prepared( stmt_name ) -> PG::Result
1644
+ *
1645
+ * This function has the same behavior as #async_close_prepared, but is implemented using the synchronous command processing API of libpq.
1646
+ * See #async_exec for the differences between the two API variants.
1647
+ * It's not recommended to use explicit sync or async variants but #close_prepared instead, unless you have a good reason to do so.
1648
+ *
1649
+ * Available since PostgreSQL-17.
1650
+ */
1651
+ static VALUE
1652
+ pgconn_sync_close_prepared(VALUE self, VALUE stmt_name)
1653
+ {
1654
+ return pgconn_sync_describe_close_prepared_portal(self, stmt_name, PQclosePrepared);
1572
1655
  }
1573
1656
 
1657
+ /*
1658
+ * call-seq:
1659
+ * conn.sync_close_portal( portal_name ) -> PG::Result
1660
+ *
1661
+ * This function has the same behavior as #async_close_portal, but is implemented using the synchronous command processing API of libpq.
1662
+ * See #async_exec for the differences between the two API variants.
1663
+ * It's not recommended to use explicit sync or async variants but #close_portal instead, unless you have a good reason to do so.
1664
+ *
1665
+ * Available since PostgreSQL-17.
1666
+ */
1667
+ static VALUE
1668
+ pgconn_sync_close_portal(VALUE self, VALUE stmt_name)
1669
+ {
1670
+ return pgconn_sync_describe_close_prepared_portal(self, stmt_name, PQclosePortal);
1671
+ }
1672
+ #endif
1574
1673
 
1575
1674
  /*
1576
1675
  * call-seq:
@@ -1588,6 +1687,7 @@ pgconn_sync_describe_portal(VALUE self, VALUE stmt_name)
1588
1687
  * * +PGRES_FATAL_ERROR+
1589
1688
  * * +PGRES_COPY_BOTH+
1590
1689
  * * +PGRES_SINGLE_TUPLE+
1690
+ * * +PGRES_TUPLES_CHUNK+
1591
1691
  * * +PGRES_PIPELINE_SYNC+
1592
1692
  * * +PGRES_PIPELINE_ABORTED+
1593
1693
  */
@@ -1812,14 +1912,11 @@ pgconn_escape_identifier(VALUE self, VALUE string)
1812
1912
  * (column names, types, etc) that an ordinary Result object for the query
1813
1913
  * would have.
1814
1914
  *
1815
- * *Caution:* While processing a query, the server may return some rows and
1816
- * then encounter an error, causing the query to be aborted. Ordinarily, pg
1817
- * discards any such rows and reports only the error. But in single-row mode,
1818
- * those rows will have already been returned to the application. Hence, the
1819
- * application will see some Result objects followed by an Error raised in get_result.
1820
- * For proper transactional behavior, the application must be designed to discard
1821
- * or undo whatever has been done with the previously-processed rows, if the query
1822
- * ultimately fails.
1915
+ * *Caution:* While processing a query, the server may return some rows and then encounter an error, causing the query to be aborted.
1916
+ * Ordinarily, pg discards any such rows and reports only the error.
1917
+ * But in single-row or chunked mode, some rows may have already been returned to the application.
1918
+ * 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.
1919
+ * 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.
1823
1920
  *
1824
1921
  * Example:
1825
1922
  * conn.send_query( "your SQL command" )
@@ -1839,10 +1936,49 @@ pgconn_set_single_row_mode(VALUE self)
1839
1936
 
1840
1937
  rb_check_frozen(self);
1841
1938
  if( PQsetSingleRowMode(conn) == 0 )
1842
- pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
1939
+ pg_raise_conn_error( rb_ePGerror, self, "PQsetSingleRowMode %s", PQerrorMessage(conn));
1940
+
1941
+ return self;
1942
+ }
1943
+
1944
+ #ifdef LIBPQ_HAS_CHUNK_MODE
1945
+ /*
1946
+ * call-seq:
1947
+ * conn.set_chunked_rows_mode -> self
1948
+ *
1949
+ * Select chunked mode for the currently-executing query.
1950
+ *
1951
+ * 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.
1952
+ * 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.
1953
+ * If called at the correct time, the function activates chunked mode for the current query.
1954
+ * Otherwise the mode stays unchanged and the function raises an error.
1955
+ * In any case, the mode reverts to normal after completion of the current query.
1956
+ *
1957
+ * Example:
1958
+ * conn.send_query( "your SQL command" )
1959
+ * conn.set_chunked_rows_mode(10)
1960
+ * loop do
1961
+ * res = conn.get_result or break
1962
+ * res.check
1963
+ * res.each do |row|
1964
+ * # do something with the received max. 10 rows
1965
+ * end
1966
+ * end
1967
+ *
1968
+ * Available since PostgreSQL-17
1969
+ */
1970
+ static VALUE
1971
+ pgconn_set_chunked_rows_mode(VALUE self, VALUE chunk_size)
1972
+ {
1973
+ PGconn *conn = pg_get_pgconn(self);
1974
+
1975
+ rb_check_frozen(self);
1976
+ if( PQsetChunkedRowsMode(conn, NUM2INT(chunk_size)) == 0 )
1977
+ pg_raise_conn_error( rb_ePGerror, self, "PQsetChunkedRowsMode %s", PQerrorMessage(conn));
1843
1978
 
1844
1979
  return self;
1845
1980
  }
1981
+ #endif
1846
1982
 
1847
1983
  static VALUE pgconn_send_query_params(int argc, VALUE *argv, VALUE self);
1848
1984
 
@@ -1862,13 +1998,15 @@ static VALUE pgconn_send_query_params(int argc, VALUE *argv, VALUE self);
1862
1998
  static VALUE
1863
1999
  pgconn_send_query(int argc, VALUE *argv, VALUE self)
1864
2000
  {
2001
+ VALUE transcoded_str;
1865
2002
  t_pg_connection *this = pg_get_connection_safe( self );
1866
2003
 
1867
2004
  /* If called with no or nil parameters, use PQexec for compatibility */
1868
2005
  if ( argc == 1 || (argc >= 2 && argc <= 4 && NIL_P(argv[1]) )) {
1869
- if(gvl_PQsendQuery(this->pgconn, pg_cstr_enc(argv[0], this->enc_idx)) == 0)
1870
- pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
2006
+ if(PQsendQuery(this->pgconn, pg_cstr_enc(argv[0], this->enc_idx, &transcoded_str)) == 0)
2007
+ pg_raise_conn_error( rb_eUnableToSend, self, "PQsendQuery %s", PQerrorMessage(this->pgconn));
1871
2008
 
2009
+ RB_GC_GUARD(transcoded_str);
1872
2010
  pgconn_wait_for_flush( self );
1873
2011
  return Qnil;
1874
2012
  }
@@ -1925,6 +2063,7 @@ pgconn_send_query_params(int argc, VALUE *argv, VALUE self)
1925
2063
  t_pg_connection *this = pg_get_connection_safe( self );
1926
2064
  int result;
1927
2065
  VALUE command, in_res_fmt;
2066
+ VALUE transcoded_str;
1928
2067
  int nParams;
1929
2068
  int resultFormat;
1930
2069
  struct query_params_data paramsData = { this->enc_idx };
@@ -1936,13 +2075,14 @@ pgconn_send_query_params(int argc, VALUE *argv, VALUE self)
1936
2075
  resultFormat = NIL_P(in_res_fmt) ? 0 : NUM2INT(in_res_fmt);
1937
2076
  nParams = alloc_query_params( &paramsData );
1938
2077
 
1939
- result = gvl_PQsendQueryParams(this->pgconn, pg_cstr_enc(command, paramsData.enc_idx), nParams, paramsData.types,
2078
+ result = PQsendQueryParams(this->pgconn, pg_cstr_enc(command, paramsData.enc_idx, &transcoded_str), nParams, paramsData.types,
1940
2079
  (const char * const *)paramsData.values, paramsData.lengths, paramsData.formats, resultFormat);
1941
2080
 
2081
+ RB_GC_GUARD(transcoded_str);
1942
2082
  free_query_params( &paramsData );
1943
2083
 
1944
2084
  if(result == 0)
1945
- pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
2085
+ pg_raise_conn_error( rb_eUnableToSend, self, "PQsendQueryParams %s", PQerrorMessage(this->pgconn));
1946
2086
 
1947
2087
  pgconn_wait_for_flush( self );
1948
2088
  return Qnil;
@@ -1975,6 +2115,7 @@ pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
1975
2115
  int result;
1976
2116
  VALUE name, command, in_paramtypes;
1977
2117
  VALUE param;
2118
+ VALUE transcoded_str1, transcoded_str2;
1978
2119
  int i = 0;
1979
2120
  int nParams = 0;
1980
2121
  Oid *paramTypes = NULL;
@@ -1983,12 +2124,12 @@ pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
1983
2124
  int enc_idx = this->enc_idx;
1984
2125
 
1985
2126
  rb_scan_args(argc, argv, "21", &name, &command, &in_paramtypes);
1986
- name_cstr = pg_cstr_enc(name, enc_idx);
1987
- command_cstr = pg_cstr_enc(command, enc_idx);
2127
+ name_cstr = pg_cstr_enc(name, enc_idx, &transcoded_str1);
2128
+ command_cstr = pg_cstr_enc(command, enc_idx, &transcoded_str2);
1988
2129
 
1989
2130
  if(! NIL_P(in_paramtypes)) {
1990
2131
  Check_Type(in_paramtypes, T_ARRAY);
1991
- nParams = (int)RARRAY_LEN(in_paramtypes);
2132
+ nParams = RARRAY_LENINT(in_paramtypes);
1992
2133
  paramTypes = ALLOC_N(Oid, nParams);
1993
2134
  for(i = 0; i < nParams; i++) {
1994
2135
  param = rb_ary_entry(in_paramtypes, i);
@@ -1998,12 +2139,14 @@ pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
1998
2139
  paramTypes[i] = NUM2UINT(param);
1999
2140
  }
2000
2141
  }
2001
- result = gvl_PQsendPrepare(this->pgconn, name_cstr, command_cstr, nParams, paramTypes);
2142
+ result = PQsendPrepare(this->pgconn, name_cstr, command_cstr, nParams, paramTypes);
2002
2143
 
2144
+ RB_GC_GUARD(transcoded_str1);
2145
+ RB_GC_GUARD(transcoded_str2);
2003
2146
  xfree(paramTypes);
2004
2147
 
2005
2148
  if(result == 0) {
2006
- pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
2149
+ pg_raise_conn_error( rb_eUnableToSend, self, "PQsendPrepare %s", PQerrorMessage(this->pgconn));
2007
2150
  }
2008
2151
  pgconn_wait_for_flush( self );
2009
2152
  return Qnil;
@@ -2047,6 +2190,7 @@ pgconn_send_query_prepared(int argc, VALUE *argv, VALUE self)
2047
2190
  t_pg_connection *this = pg_get_connection_safe( self );
2048
2191
  int result;
2049
2192
  VALUE name, in_res_fmt;
2193
+ VALUE transcoded_str;
2050
2194
  int nParams;
2051
2195
  int resultFormat;
2052
2196
  struct query_params_data paramsData = { this->enc_idx };
@@ -2062,15 +2206,32 @@ pgconn_send_query_prepared(int argc, VALUE *argv, VALUE self)
2062
2206
  resultFormat = NIL_P(in_res_fmt) ? 0 : NUM2INT(in_res_fmt);
2063
2207
  nParams = alloc_query_params( &paramsData );
2064
2208
 
2065
- result = gvl_PQsendQueryPrepared(this->pgconn, pg_cstr_enc(name, paramsData.enc_idx), nParams,
2209
+ result = PQsendQueryPrepared(this->pgconn, pg_cstr_enc(name, paramsData.enc_idx, &transcoded_str), nParams,
2066
2210
  (const char * const *)paramsData.values, paramsData.lengths, paramsData.formats,
2067
2211
  resultFormat);
2068
2212
 
2213
+ RB_GC_GUARD(transcoded_str);
2069
2214
  free_query_params( &paramsData );
2070
2215
 
2071
2216
  if(result == 0)
2072
- pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
2217
+ pg_raise_conn_error( rb_eUnableToSend, self, "PQsendQueryPrepared %s", PQerrorMessage(this->pgconn));
2218
+
2219
+ pgconn_wait_for_flush( self );
2220
+ return Qnil;
2221
+ }
2222
+
2223
+
2224
+ static VALUE
2225
+ pgconn_send_describe_close_prepared_portal(VALUE self, VALUE name, int (*func)(PGconn *, const char *), const char *funame)
2226
+ {
2227
+ VALUE transcoded_str;
2228
+ t_pg_connection *this = pg_get_connection_safe( self );
2229
+ const char *stmt = NIL_P(name) ? NULL : pg_cstr_enc(name, this->enc_idx, &transcoded_str);
2230
+ /* returns 0 on failure */
2231
+ if(func(this->pgconn, stmt) == 0)
2232
+ pg_raise_conn_error( rb_eUnableToSend, self, "%s %s", funame, PQerrorMessage(this->pgconn));
2073
2233
 
2234
+ RB_GC_GUARD(transcoded_str);
2074
2235
  pgconn_wait_for_flush( self );
2075
2236
  return Qnil;
2076
2237
  }
@@ -2085,13 +2246,9 @@ pgconn_send_query_prepared(int argc, VALUE *argv, VALUE self)
2085
2246
  static VALUE
2086
2247
  pgconn_send_describe_prepared(VALUE self, VALUE stmt_name)
2087
2248
  {
2088
- t_pg_connection *this = pg_get_connection_safe( self );
2089
- /* returns 0 on failure */
2090
- if(gvl_PQsendDescribePrepared(this->pgconn, pg_cstr_enc(stmt_name, this->enc_idx)) == 0)
2091
- pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
2092
-
2093
- pgconn_wait_for_flush( self );
2094
- return Qnil;
2249
+ return pgconn_send_describe_close_prepared_portal(
2250
+ self, stmt_name, PQsendDescribePrepared,
2251
+ "PQsendDescribePrepared");
2095
2252
  }
2096
2253
 
2097
2254
 
@@ -2105,16 +2262,48 @@ pgconn_send_describe_prepared(VALUE self, VALUE stmt_name)
2105
2262
  static VALUE
2106
2263
  pgconn_send_describe_portal(VALUE self, VALUE portal)
2107
2264
  {
2108
- t_pg_connection *this = pg_get_connection_safe( self );
2109
- /* returns 0 on failure */
2110
- if(gvl_PQsendDescribePortal(this->pgconn, pg_cstr_enc(portal, this->enc_idx)) == 0)
2111
- pg_raise_conn_error( rb_eUnableToSend, self, "%s", PQerrorMessage(this->pgconn));
2265
+ return pgconn_send_describe_close_prepared_portal(
2266
+ self, portal, PQsendDescribePortal,
2267
+ "PQsendDescribePortal");
2268
+ }
2112
2269
 
2113
- pgconn_wait_for_flush( self );
2114
- return Qnil;
2270
+ #ifdef LIBPQ_HAS_CHUNK_MODE
2271
+ /*
2272
+ * call-seq:
2273
+ * conn.send_close_prepared( statement_name ) -> nil
2274
+ *
2275
+ * Asynchronously send _command_ to the server. Does not block.
2276
+ * Use in combination with +conn.get_result+.
2277
+ *
2278
+ * Available since PostgreSQL-17.
2279
+ */
2280
+ static VALUE
2281
+ pgconn_send_close_prepared(VALUE self, VALUE stmt_name)
2282
+ {
2283
+ return pgconn_send_describe_close_prepared_portal(
2284
+ self, stmt_name, PQsendClosePrepared,
2285
+ "PQsendClosePrepared");
2115
2286
  }
2116
2287
 
2117
2288
 
2289
+ /*
2290
+ * call-seq:
2291
+ * conn.send_close_portal( portal_name ) -> nil
2292
+ *
2293
+ * Asynchronously send _command_ to the server. Does not block.
2294
+ * Use in combination with +conn.get_result+.
2295
+ *
2296
+ * Available since PostgreSQL-17.
2297
+ */
2298
+ static VALUE
2299
+ pgconn_send_close_portal(VALUE self, VALUE portal)
2300
+ {
2301
+ return pgconn_send_describe_close_prepared_portal(
2302
+ self, portal, PQsendClosePortal,
2303
+ "PQsendClosePortal");
2304
+ }
2305
+ #endif
2306
+
2118
2307
  static VALUE
2119
2308
  pgconn_sync_get_result(VALUE self)
2120
2309
  {
@@ -2122,7 +2311,7 @@ pgconn_sync_get_result(VALUE self)
2122
2311
  PGresult *result;
2123
2312
  VALUE rb_pgresult;
2124
2313
 
2125
- result = gvl_PQgetResult(conn);
2314
+ result = PQgetResult(conn);
2126
2315
  if(result == NULL)
2127
2316
  return Qnil;
2128
2317
  rb_pgresult = pg_new_result(result, self);
@@ -2164,7 +2353,7 @@ pgconn_consume_input(VALUE self)
2164
2353
  static VALUE
2165
2354
  pgconn_is_busy(VALUE self)
2166
2355
  {
2167
- return gvl_PQisBusy(pg_get_pgconn(self)) ? Qtrue : Qfalse;
2356
+ return PQisBusy(pg_get_pgconn(self)) ? Qtrue : Qfalse;
2168
2357
  }
2169
2358
 
2170
2359
  static VALUE
@@ -2204,6 +2393,7 @@ pgconn_sync_flush(VALUE self)
2204
2393
  return (ret) ? Qfalse : Qtrue;
2205
2394
  }
2206
2395
 
2396
+ #ifndef LIBPQ_HAS_CHUNK_MODE
2207
2397
  static VALUE
2208
2398
  pgconn_sync_cancel(VALUE self)
2209
2399
  {
@@ -2216,7 +2406,7 @@ pgconn_sync_cancel(VALUE self)
2216
2406
  if(cancel == NULL)
2217
2407
  pg_raise_conn_error( rb_ePGerror, self, "Invalid connection!");
2218
2408
 
2219
- ret = gvl_PQcancel(cancel, errbuf, sizeof(errbuf));
2409
+ ret = PQcancel(cancel, errbuf, sizeof(errbuf));
2220
2410
  if(ret == 1)
2221
2411
  retval = Qnil;
2222
2412
  else
@@ -2225,6 +2415,7 @@ pgconn_sync_cancel(VALUE self)
2225
2415
  PQfreeCancel(cancel);
2226
2416
  return retval;
2227
2417
  }
2418
+ #endif
2228
2419
 
2229
2420
 
2230
2421
  /*
@@ -2247,12 +2438,12 @@ pgconn_notifies(VALUE self)
2247
2438
  sym_be_pid = ID2SYM(rb_intern("be_pid"));
2248
2439
  sym_extra = ID2SYM(rb_intern("extra"));
2249
2440
 
2250
- notification = gvl_PQnotifies(this->pgconn);
2441
+ notification = PQnotifies(this->pgconn);
2251
2442
  if (notification == NULL) {
2252
2443
  return Qnil;
2253
2444
  }
2254
2445
 
2255
- hash = rb_hash_new();
2446
+ hash = rb_hash_new_capa(3);
2256
2447
  relname = rb_str_new2(notification->relname);
2257
2448
  be_pid = INT2NUM(notification->be_pid);
2258
2449
  extra = rb_str_new2(notification->extra);
@@ -2267,32 +2458,13 @@ pgconn_notifies(VALUE self)
2267
2458
  return hash;
2268
2459
  }
2269
2460
 
2270
- #ifndef HAVE_RB_IO_DESCRIPTOR
2271
- static int
2272
- rb_io_descriptor(VALUE io)
2273
- {
2274
- Check_Type(io, T_FILE);
2275
- rb_io_t *fptr = RFILE(io)->fptr;
2276
- rb_io_check_closed(fptr);
2277
- return fptr->fd;
2278
- }
2279
- #endif
2280
-
2281
2461
  #if defined(_WIN32)
2282
2462
 
2283
2463
  /* We use a specialized implementation of rb_io_wait() on Windows.
2284
2464
  * This is because rb_io_wait() and rb_wait_for_single_fd() are very slow on Windows.
2285
2465
  */
2286
2466
 
2287
- #if defined(HAVE_RUBY_FIBER_SCHEDULER_H)
2288
2467
  #include <ruby/fiber/scheduler.h>
2289
- #endif
2290
-
2291
- typedef enum {
2292
- PG_RUBY_IO_READABLE = RB_WAITFD_IN,
2293
- PG_RUBY_IO_WRITABLE = RB_WAITFD_OUT,
2294
- PG_RUBY_IO_PRIORITY = RB_WAITFD_PRI,
2295
- } pg_rb_io_event_t;
2296
2468
 
2297
2469
  int rb_w32_wait_events( HANDLE *events, int num, DWORD timeout );
2298
2470
 
@@ -2316,9 +2488,9 @@ pg_rb_thread_io_wait(VALUE io, VALUE events, VALUE timeout) {
2316
2488
  timeradd(&currtime, &ptimeout, &aborttime);
2317
2489
  }
2318
2490
 
2319
- if(rb_events & PG_RUBY_IO_READABLE) w32_events |= FD_READ | FD_ACCEPT | FD_CLOSE;
2320
- if(rb_events & PG_RUBY_IO_WRITABLE) w32_events |= FD_WRITE | FD_CONNECT;
2321
- if(rb_events & PG_RUBY_IO_PRIORITY) w32_events |= FD_OOB;
2491
+ if(rb_events & RUBY_IO_READABLE) w32_events |= FD_READ | FD_ACCEPT | FD_CLOSE;
2492
+ if(rb_events & RUBY_IO_WRITABLE) w32_events |= FD_WRITE | FD_CONNECT;
2493
+ if(rb_events & RUBY_IO_PRIORITY) w32_events |= FD_OOB;
2322
2494
 
2323
2495
  for(;;) {
2324
2496
  if ( WSAEventSelect(_get_osfhandle(rb_io_descriptor(io)), hEvent, w32_events) == SOCKET_ERROR ) {
@@ -2362,49 +2534,20 @@ pg_rb_thread_io_wait(VALUE io, VALUE events, VALUE timeout) {
2362
2534
 
2363
2535
  static VALUE
2364
2536
  pg_rb_io_wait(VALUE io, VALUE events, VALUE timeout) {
2365
- #if defined(HAVE_RUBY_FIBER_SCHEDULER_H)
2366
- /* We don't support Fiber.scheduler on Windows ruby-3.0 because there is no fast way to check whether a scheduler is active.
2367
- * Fortunately ruby-3.1 offers a C-API for it.
2368
- */
2537
+ /* Avoid slow rb_io_wait() on Windows, if no scheduler is active. */
2369
2538
  VALUE scheduler = rb_fiber_scheduler_current();
2370
2539
 
2371
2540
  if (!NIL_P(scheduler)) {
2372
2541
  return rb_io_wait(io, events, timeout);
2373
2542
  }
2374
- #endif
2375
2543
  return pg_rb_thread_io_wait(io, events, timeout);
2376
2544
  }
2377
2545
 
2378
- #elif defined(HAVE_RB_IO_WAIT)
2379
-
2380
- /* Use our own function and constants names, to avoid conflicts with truffleruby-head on its road to ruby-3.0 compatibility. */
2381
- #define pg_rb_io_wait rb_io_wait
2382
- #define PG_RUBY_IO_READABLE RUBY_IO_READABLE
2383
- #define PG_RUBY_IO_WRITABLE RUBY_IO_WRITABLE
2384
- #define PG_RUBY_IO_PRIORITY RUBY_IO_PRIORITY
2385
-
2386
2546
  #else
2387
- /* For compat with ruby < 3.0 */
2388
-
2389
- typedef enum {
2390
- PG_RUBY_IO_READABLE = RB_WAITFD_IN,
2391
- PG_RUBY_IO_WRITABLE = RB_WAITFD_OUT,
2392
- PG_RUBY_IO_PRIORITY = RB_WAITFD_PRI,
2393
- } pg_rb_io_event_t;
2394
-
2395
- static VALUE
2396
- pg_rb_io_wait(VALUE io, VALUE events, VALUE timeout) {
2397
- struct timeval waittime;
2398
- int res;
2399
2547
 
2400
- if( !NIL_P(timeout) ){
2401
- waittime.tv_sec = (time_t)(NUM2DBL(timeout));
2402
- waittime.tv_usec = (time_t)((NUM2DBL(timeout) - (double)waittime.tv_sec) * 1e6);
2403
- }
2404
- res = rb_wait_for_single_fd(rb_io_descriptor(io), NUM2UINT(events), NIL_P(timeout) ? NULL : &waittime);
2548
+ /* Use rb_io_wait on non-Windows systems */
2549
+ #define pg_rb_io_wait rb_io_wait
2405
2550
 
2406
- return UINT2NUM(res);
2407
- }
2408
2551
  #endif
2409
2552
 
2410
2553
  static void *
@@ -2439,7 +2582,7 @@ wait_socket_readable( VALUE self, struct timeval *ptimeout, void *(*is_readable)
2439
2582
 
2440
2583
  socket_io = pgconn_socket_io(self);
2441
2584
  /* Wait for the socket to become readable before checking again */
2442
- ret = pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE), wait_timeout);
2585
+ ret = pg_rb_io_wait(socket_io, RB_INT2NUM(RUBY_IO_READABLE), wait_timeout);
2443
2586
  } else {
2444
2587
  ret = Qfalse;
2445
2588
  }
@@ -2476,9 +2619,9 @@ pgconn_async_flush(VALUE self)
2476
2619
  /* wait for the socket to become read- or write-ready */
2477
2620
  int events;
2478
2621
  VALUE socket_io = pgconn_socket_io(self);
2479
- events = RB_NUM2INT(pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE | PG_RUBY_IO_WRITABLE), Qnil));
2622
+ events = RB_NUM2INT(pg_rb_io_wait(socket_io, RB_INT2NUM(RUBY_IO_READABLE | RUBY_IO_WRITABLE), Qnil));
2480
2623
 
2481
- if (events & PG_RUBY_IO_READABLE){
2624
+ if (events & RUBY_IO_READABLE){
2482
2625
  pgconn_consume_input(self);
2483
2626
  }
2484
2627
  }
@@ -2504,7 +2647,7 @@ pgconn_flush_data_set( VALUE self, VALUE enabled ){
2504
2647
  static void *
2505
2648
  notify_readable(PGconn *conn)
2506
2649
  {
2507
- return (void*)gvl_PQnotifies(conn);
2650
+ return (void*)PQnotifies(conn);
2508
2651
  }
2509
2652
 
2510
2653
  /*
@@ -2568,7 +2711,7 @@ pgconn_sync_put_copy_data(int argc, VALUE *argv, VALUE self)
2568
2711
  VALUE value;
2569
2712
  VALUE buffer = Qnil;
2570
2713
  VALUE encoder;
2571
- VALUE intermediate;
2714
+ VALUE intermediate = Qnil;
2572
2715
  t_pg_coder *p_coder = NULL;
2573
2716
 
2574
2717
  rb_scan_args( argc, argv, "11", &value, &encoder );
@@ -2603,11 +2746,10 @@ pgconn_sync_put_copy_data(int argc, VALUE *argv, VALUE self)
2603
2746
 
2604
2747
  Check_Type(buffer, T_STRING);
2605
2748
 
2606
- ret = gvl_PQputCopyData(this->pgconn, RSTRING_PTR(buffer), RSTRING_LENINT(buffer));
2749
+ ret = PQputCopyData(this->pgconn, RSTRING_PTR(buffer), RSTRING_LENINT(buffer));
2607
2750
  if(ret == -1)
2608
2751
  pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(this->pgconn));
2609
2752
 
2610
- RB_GC_GUARD(intermediate);
2611
2753
  RB_GC_GUARD(buffer);
2612
2754
 
2613
2755
  return (ret) ? Qtrue : Qfalse;
@@ -2617,6 +2759,7 @@ static VALUE
2617
2759
  pgconn_sync_put_copy_end(int argc, VALUE *argv, VALUE self)
2618
2760
  {
2619
2761
  VALUE str;
2762
+ VALUE transcoded_str;
2620
2763
  int ret;
2621
2764
  const char *error_message = NULL;
2622
2765
  t_pg_connection *this = pg_get_connection_safe( self );
@@ -2624,15 +2767,41 @@ pgconn_sync_put_copy_end(int argc, VALUE *argv, VALUE self)
2624
2767
  if (rb_scan_args(argc, argv, "01", &str) == 0)
2625
2768
  error_message = NULL;
2626
2769
  else
2627
- error_message = pg_cstr_enc(str, this->enc_idx);
2770
+ error_message = pg_cstr_enc(str, this->enc_idx, &transcoded_str);
2628
2771
 
2629
- ret = gvl_PQputCopyEnd(this->pgconn, error_message);
2772
+ ret = PQputCopyEnd(this->pgconn, error_message);
2630
2773
  if(ret == -1)
2631
2774
  pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(this->pgconn));
2632
2775
 
2776
+ RB_GC_GUARD(transcoded_str);
2633
2777
  return (ret) ? Qtrue : Qfalse;
2634
2778
  }
2635
2779
 
2780
+ struct pgconn_copy_data {
2781
+ t_pg_coder *coder;
2782
+ char *buffer;
2783
+ int length;
2784
+ int enc_idx;
2785
+ };
2786
+
2787
+ static VALUE
2788
+ pgconn_decode_copy_data(VALUE data_ptr)
2789
+ {
2790
+ struct pgconn_copy_data *data = (struct pgconn_copy_data *)data_ptr;
2791
+ t_pg_coder_dec_func dec_func = pg_coder_dec_func(data->coder, data->coder->format);
2792
+
2793
+ return dec_func(data->coder, data->buffer, data->length, 0, 0, data->enc_idx);
2794
+ }
2795
+
2796
+ static VALUE
2797
+ pgconn_free_copy_data(VALUE data_ptr)
2798
+ {
2799
+ struct pgconn_copy_data *data = (struct pgconn_copy_data *)data_ptr;
2800
+
2801
+ PQfreemem(data->buffer);
2802
+ return Qnil;
2803
+ }
2804
+
2636
2805
  static VALUE
2637
2806
  pgconn_sync_get_copy_data(int argc, VALUE *argv, VALUE self )
2638
2807
  {
@@ -2655,7 +2824,7 @@ pgconn_sync_get_copy_data(int argc, VALUE *argv, VALUE self )
2655
2824
  TypedData_Get_Struct(decoder, t_pg_coder, &pg_coder_type, p_coder);
2656
2825
  }
2657
2826
 
2658
- ret = gvl_PQgetCopyData(this->pgconn, &buffer, RTEST(async_in));
2827
+ ret = PQgetCopyData(this->pgconn, &buffer, RTEST(async_in));
2659
2828
  if(ret == -2){ /* error */
2660
2829
  pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(this->pgconn));
2661
2830
  }
@@ -2667,8 +2836,9 @@ pgconn_sync_get_copy_data(int argc, VALUE *argv, VALUE self )
2667
2836
  }
2668
2837
 
2669
2838
  if( p_coder ){
2670
- t_pg_coder_dec_func dec_func = pg_coder_dec_func( p_coder, p_coder->format );
2671
- result = dec_func( p_coder, buffer, ret, 0, 0, this->enc_idx );
2839
+ struct pgconn_copy_data data = { p_coder, buffer, ret, this->enc_idx };
2840
+
2841
+ return rb_ensure(pgconn_decode_copy_data, (VALUE)&data, pgconn_free_copy_data, (VALUE)&data);
2672
2842
  } else {
2673
2843
  result = rb_str_new(buffer, ret);
2674
2844
  }
@@ -2702,7 +2872,6 @@ pgconn_set_error_verbosity(VALUE self, VALUE in_verbosity)
2702
2872
  return INT2FIX(PQsetErrorVerbosity(conn, verbosity));
2703
2873
  }
2704
2874
 
2705
- #ifdef HAVE_PQRESULTVERBOSEERRORMESSAGE
2706
2875
  /*
2707
2876
  * call-seq:
2708
2877
  * conn.set_error_context_visibility( context_visibility ) -> Integer
@@ -2722,7 +2891,6 @@ pgconn_set_error_verbosity(VALUE self, VALUE in_verbosity)
2722
2891
  *
2723
2892
  * See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-control.html#LIBPQ-PQSETERRORCONTEXTVISIBILITY].
2724
2893
  *
2725
- * Available since PostgreSQL-9.6
2726
2894
  */
2727
2895
  static VALUE
2728
2896
  pgconn_set_error_context_visibility(VALUE self, VALUE in_context_visibility)
@@ -2731,7 +2899,6 @@ pgconn_set_error_context_visibility(VALUE self, VALUE in_context_visibility)
2731
2899
  PGContextVisibility context_visibility = NUM2INT(in_context_visibility);
2732
2900
  return INT2FIX(PQsetErrorContextVisibility(conn, context_visibility));
2733
2901
  }
2734
- #endif
2735
2902
 
2736
2903
  /*
2737
2904
  * call-seq:
@@ -2804,11 +2971,10 @@ pgconn_untrace(VALUE self)
2804
2971
  void
2805
2972
  notice_receiver_proxy(void *arg, const PGresult *pgresult)
2806
2973
  {
2807
- VALUE self = (VALUE)arg;
2808
- t_pg_connection *this = pg_get_connection( self );
2974
+ t_pg_connection *this = (t_pg_connection*)arg;
2809
2975
 
2810
2976
  if (this->notice_receiver != Qnil) {
2811
- VALUE result = pg_new_result_autoclear( (PGresult *)pgresult, self );
2977
+ VALUE result = pg_new_result_autoclear( (PGresult *)pgresult, this->self );
2812
2978
 
2813
2979
  rb_funcall(this->notice_receiver, rb_intern("call"), 1, result);
2814
2980
  pg_result_clear( result );
@@ -2863,7 +3029,7 @@ pgconn_set_notice_receiver(VALUE self)
2863
3029
  old_proc = this->notice_receiver;
2864
3030
  if( rb_block_given_p() ) {
2865
3031
  proc = rb_block_proc();
2866
- PQsetNoticeReceiver(this->pgconn, gvl_notice_receiver_proxy, (void *)self);
3032
+ PQsetNoticeReceiver(this->pgconn, gvl_notice_receiver_proxy, (void *)this);
2867
3033
  } else {
2868
3034
  /* if no block is given, set back to default */
2869
3035
  proc = Qnil;
@@ -2882,8 +3048,7 @@ pgconn_set_notice_receiver(VALUE self)
2882
3048
  void
2883
3049
  notice_processor_proxy(void *arg, const char *message)
2884
3050
  {
2885
- VALUE self = (VALUE)arg;
2886
- t_pg_connection *this = pg_get_connection( self );
3051
+ t_pg_connection *this = (t_pg_connection*)arg;
2887
3052
 
2888
3053
  if (this->notice_processor != Qnil) {
2889
3054
  VALUE message_str = rb_str_new2(message);
@@ -2924,7 +3089,7 @@ pgconn_set_notice_processor(VALUE self)
2924
3089
  old_proc = this->notice_processor;
2925
3090
  if( rb_block_given_p() ) {
2926
3091
  proc = rb_block_proc();
2927
- PQsetNoticeProcessor(this->pgconn, gvl_notice_processor_proxy, (void *)self);
3092
+ PQsetNoticeProcessor(this->pgconn, gvl_notice_processor_proxy, (void *)this);
2928
3093
  } else {
2929
3094
  /* if no block is given, set back to default */
2930
3095
  proc = Qnil;
@@ -2966,7 +3131,7 @@ pgconn_sync_set_client_encoding(VALUE self, VALUE str)
2966
3131
  rb_check_frozen(self);
2967
3132
  Check_Type(str, T_STRING);
2968
3133
 
2969
- if ( (gvl_PQsetClientEncoding(conn, StringValueCStr(str))) == -1 )
3134
+ if ( (PQsetClientEncoding(conn, StringValueCStr(str))) == -1 )
2970
3135
  pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
2971
3136
 
2972
3137
  pgconn_set_internal_encoding_index( self );
@@ -3031,7 +3196,7 @@ pgconn_s_quote_ident(VALUE self, VALUE str_or_array)
3031
3196
  static void *
3032
3197
  get_result_readable(PGconn *conn)
3033
3198
  {
3034
- return gvl_PQisBusy(conn) ? NULL : (void*)1;
3199
+ return PQisBusy(conn) ? NULL : (void*)1;
3035
3200
  }
3036
3201
 
3037
3202
 
@@ -3089,7 +3254,7 @@ pgconn_sync_get_last_result(VALUE self)
3089
3254
 
3090
3255
 
3091
3256
  cur = prev = NULL;
3092
- while ((cur = gvl_PQgetResult(conn)) != NULL) {
3257
+ while ((cur = PQgetResult(conn)) != NULL) {
3093
3258
  int status;
3094
3259
 
3095
3260
  if (prev) PQclear(prev);
@@ -3141,7 +3306,7 @@ pgconn_async_get_last_result(VALUE self)
3141
3306
  */
3142
3307
  wait_socket_readable(self, NULL, get_result_readable);
3143
3308
 
3144
- cur = gvl_PQgetResult(conn);
3309
+ cur = PQgetResult(conn);
3145
3310
  if (cur == NULL)
3146
3311
  break;
3147
3312
 
@@ -3198,18 +3363,18 @@ pgconn_discard_results(VALUE self)
3198
3363
  /* pgconn_block() raises an exception in case of errors.
3199
3364
  * To avoid this call pg_rb_io_wait() and PQconsumeInput() without rb_raise().
3200
3365
  */
3201
- while( gvl_PQisBusy(conn) ){
3366
+ while( PQisBusy(conn) ){
3202
3367
  int events;
3203
3368
 
3204
3369
  switch( PQflush(conn) ) {
3205
3370
  case 1:
3206
- events = RB_NUM2INT(pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE | PG_RUBY_IO_WRITABLE), Qnil));
3207
- if (events & PG_RUBY_IO_READABLE){
3371
+ events = RB_NUM2INT(pg_rb_io_wait(socket_io, RB_INT2NUM(RUBY_IO_READABLE | RUBY_IO_WRITABLE), Qnil));
3372
+ if (events & RUBY_IO_READABLE){
3208
3373
  if ( PQconsumeInput(conn) == 0 ) goto error;
3209
3374
  }
3210
3375
  break;
3211
3376
  case 0:
3212
- pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE), Qnil);
3377
+ pg_rb_io_wait(socket_io, RB_INT2NUM(RUBY_IO_READABLE), Qnil);
3213
3378
  if ( PQconsumeInput(conn) == 0 ) goto error;
3214
3379
  break;
3215
3380
  default:
@@ -3217,23 +3382,23 @@ pgconn_discard_results(VALUE self)
3217
3382
  }
3218
3383
  }
3219
3384
 
3220
- cur = gvl_PQgetResult(conn);
3385
+ cur = PQgetResult(conn);
3221
3386
  if( cur == NULL) break;
3222
3387
 
3223
3388
  status = PQresultStatus(cur);
3224
3389
  PQclear(cur);
3225
3390
  if (status == PGRES_COPY_IN){
3226
- while( gvl_PQputCopyEnd(conn, "COPY terminated by new query or discard_results") == 0 ){
3391
+ while( PQputCopyEnd(conn, "COPY terminated by new query or discard_results") == 0 ){
3227
3392
  pgconn_async_flush(self);
3228
3393
  }
3229
3394
  }
3230
3395
  if (status == PGRES_COPY_OUT){
3231
3396
  for(;;) {
3232
3397
  char *buffer = NULL;
3233
- int st = gvl_PQgetCopyData(conn, &buffer, 1);
3398
+ int st = PQgetCopyData(conn, &buffer, 1);
3234
3399
  if( st == 0 ) {
3235
3400
  /* would block -> wait for readable data */
3236
- pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE), Qnil);
3401
+ pg_rb_io_wait(socket_io, RB_INT2NUM(RUBY_IO_READABLE), Qnil);
3237
3402
  if ( PQconsumeInput(conn) == 0 ) goto error;
3238
3403
  } else if( st > 0 ) {
3239
3404
  /* some data retrieved -> discard it */
@@ -3270,12 +3435,12 @@ error:
3270
3435
  * and the PG::Result object will automatically be cleared when the block terminates.
3271
3436
  * In this instance, <code>conn.exec</code> returns the value of the block.
3272
3437
  *
3273
- * #exec is an alias for #async_exec which is almost identical to #sync_exec .
3438
+ * #exec is an alias for #async_exec which is functional identical to #sync_exec .
3274
3439
  * #sync_exec is implemented on the simpler synchronous command processing API of libpq, whereas
3275
3440
  * #async_exec is implemented on the asynchronous API and on ruby's IO mechanisms.
3276
3441
  * Only #async_exec is compatible to <tt>Fiber.scheduler</tt> based asynchronous IO processing introduced in ruby-3.0.
3277
- * Both methods ensure that other threads can process while waiting for the server to
3278
- * complete the request, but #sync_exec blocks all signals to be processed until the query is finished.
3442
+ * Only #async_exec ensures that other threads can process while waiting for the server to complete the request.
3443
+ * In contrast #sync_exec blocks all threads and signals to be processed until the query is finished.
3279
3444
  * This is most notably visible by a delayed reaction to Control+C.
3280
3445
  * It's not recommended to use explicit sync or async variants but #exec instead, unless you have a good reason to do so.
3281
3446
  *
@@ -3310,12 +3475,13 @@ pgconn_async_exec(int argc, VALUE *argv, VALUE self)
3310
3475
  * +params+ is an array of the bind parameters for the SQL query.
3311
3476
  * Each element of the +params+ array may be either:
3312
3477
  * a hash of the form:
3313
- * {:value => String (value of bind parameter)
3314
- * :type => Integer (oid of type of bind parameter)
3315
- * :format => Integer (0 for text, 1 for binary)
3478
+ * {:value => String (value of bind parameter)
3479
+ * :type => Integer (oid of type of bind parameter)
3480
+ * :typename => String (name of type of bind parameter, only used for conn.embed_params )
3481
+ * :format => Integer (0 for text, 1 for binary)
3316
3482
  * }
3317
3483
  * or, it may be a String. If it is a string, that is equivalent to the hash:
3318
- * { :value => <string value>, :type => 0, :format => 0 }
3484
+ * { :value => <string value>, :type => 0, :format => 0 }
3319
3485
  *
3320
3486
  * PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
3321
3487
  * inside the SQL query. The 0th element of the +params+ array is bound
@@ -3459,6 +3625,21 @@ pgconn_async_exec_prepared(int argc, VALUE *argv, VALUE self)
3459
3625
  return rb_pgresult;
3460
3626
  }
3461
3627
 
3628
+ static VALUE
3629
+ pgconn_async_describe_close_prepared_potral(VALUE self, VALUE name, VALUE
3630
+ (*func)(VALUE, VALUE))
3631
+ {
3632
+ VALUE rb_pgresult = Qnil;
3633
+
3634
+ pgconn_discard_results( self );
3635
+ func( self, name );
3636
+ rb_pgresult = pgconn_async_get_last_result( self );
3637
+
3638
+ if ( rb_block_given_p() ) {
3639
+ return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
3640
+ }
3641
+ return rb_pgresult;
3642
+ }
3462
3643
 
3463
3644
  /*
3464
3645
  * call-seq:
@@ -3471,16 +3652,7 @@ pgconn_async_exec_prepared(int argc, VALUE *argv, VALUE self)
3471
3652
  static VALUE
3472
3653
  pgconn_async_describe_portal(VALUE self, VALUE portal)
3473
3654
  {
3474
- VALUE rb_pgresult = Qnil;
3475
-
3476
- pgconn_discard_results( self );
3477
- pgconn_send_describe_portal( self, portal );
3478
- rb_pgresult = pgconn_async_get_last_result( self );
3479
-
3480
- if ( rb_block_given_p() ) {
3481
- return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
3482
- }
3483
- return rb_pgresult;
3655
+ return pgconn_async_describe_close_prepared_potral(self, portal, pgconn_send_describe_portal);
3484
3656
  }
3485
3657
 
3486
3658
 
@@ -3495,27 +3667,64 @@ pgconn_async_describe_portal(VALUE self, VALUE portal)
3495
3667
  static VALUE
3496
3668
  pgconn_async_describe_prepared(VALUE self, VALUE stmt_name)
3497
3669
  {
3498
- VALUE rb_pgresult = Qnil;
3499
-
3500
- pgconn_discard_results( self );
3501
- pgconn_send_describe_prepared( self, stmt_name );
3502
- rb_pgresult = pgconn_async_get_last_result( self );
3670
+ return pgconn_async_describe_close_prepared_potral(self, stmt_name, pgconn_send_describe_prepared);
3671
+ }
3503
3672
 
3504
- if ( rb_block_given_p() ) {
3505
- return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
3506
- }
3507
- return rb_pgresult;
3673
+ #ifdef LIBPQ_HAS_CHUNK_MODE
3674
+ /*
3675
+ * call-seq:
3676
+ * conn.close_prepared( statement_name ) -> PG::Result
3677
+ *
3678
+ * Submits a request to close the specified prepared statement, and waits for completion.
3679
+ * close_prepared allows an application to close a previously prepared statement.
3680
+ * Closing a statement releases all of its associated resources on the server and allows its name to be reused.
3681
+ * It's the same as using the +DEALLOCATE+ SQL statement, but on a lower protocol level.
3682
+ *
3683
+ * +statement_name+ can be "" or +nil+ to reference the unnamed statement.
3684
+ * It is fine if no statement exists with this name, in that case the operation is a no-op.
3685
+ * On success, a PG::Result with status PGRES_COMMAND_OK is returned.
3686
+ *
3687
+ * See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQCLOSEPREPARED].
3688
+ *
3689
+ * Available since PostgreSQL-17.
3690
+ */
3691
+ static VALUE
3692
+ pgconn_async_close_prepared(VALUE self, VALUE stmt_name)
3693
+ {
3694
+ return pgconn_async_describe_close_prepared_potral(self, stmt_name, pgconn_send_close_prepared);
3508
3695
  }
3509
3696
 
3697
+ /*
3698
+ * call-seq:
3699
+ * conn.close_portal( portal_name ) -> PG::Result
3700
+ *
3701
+ * Submits a request to close the specified portal, and waits for completion.
3702
+ *
3703
+ * close_portal allows an application to trigger a close of a previously created portal.
3704
+ * Closing a portal releases all of its associated resources on the server and allows its name to be reused.
3705
+ * (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.)
3706
+ *
3707
+ * +portal_name+ can be "" or +nil+ to reference the unnamed portal.
3708
+ * It is fine if no portal exists with this name, in that case the operation is a no-op.
3709
+ * On success, a PG::Result with status PGRES_COMMAND_OK is returned.
3710
+ *
3711
+ * See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQCLOSEPORTAL].
3712
+ *
3713
+ * Available since PostgreSQL-17.
3714
+ */
3715
+ static VALUE
3716
+ pgconn_async_close_portal(VALUE self, VALUE portal)
3717
+ {
3718
+ return pgconn_async_describe_close_prepared_potral(self, portal, pgconn_send_close_portal);
3719
+ }
3720
+ #endif
3510
3721
 
3511
- #ifdef HAVE_PQSSLATTRIBUTE
3512
3722
  /*
3513
3723
  * call-seq:
3514
3724
  * conn.ssl_in_use? -> Boolean
3515
3725
  *
3516
3726
  * Returns +true+ if the connection uses SSL/TLS, +false+ if not.
3517
3727
  *
3518
- * Available since PostgreSQL-9.5
3519
3728
  */
3520
3729
  static VALUE
3521
3730
  pgconn_ssl_in_use(VALUE self)
@@ -3549,7 +3758,6 @@ pgconn_ssl_in_use(VALUE self)
3549
3758
  *
3550
3759
  * See also #ssl_attribute_names and the {corresponding libpq function}[https://www.postgresql.org/docs/current/libpq-status.html#LIBPQ-PQSSLATTRIBUTE].
3551
3760
  *
3552
- * Available since PostgreSQL-9.5
3553
3761
  */
3554
3762
  static VALUE
3555
3763
  pgconn_ssl_attribute(VALUE self, VALUE attribute_name)
@@ -3568,7 +3776,6 @@ pgconn_ssl_attribute(VALUE self, VALUE attribute_name)
3568
3776
  *
3569
3777
  * See also #ssl_attribute
3570
3778
  *
3571
- * Available since PostgreSQL-9.5
3572
3779
  */
3573
3780
  static VALUE
3574
3781
  pgconn_ssl_attribute_names(VALUE self)
@@ -3584,10 +3791,8 @@ pgconn_ssl_attribute_names(VALUE self)
3584
3791
  }
3585
3792
 
3586
3793
 
3587
- #endif
3588
-
3589
3794
 
3590
- #ifdef HAVE_PQENTERPIPELINEMODE
3795
+ #ifdef LIBPQ_HAS_PIPELINING
3591
3796
  /*
3592
3797
  * call-seq:
3593
3798
  * conn.pipeline_status -> Integer
@@ -3620,6 +3825,8 @@ pgconn_pipeline_status(VALUE self)
3620
3825
  * 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.
3621
3826
  * This function does not actually send anything to the server, it just changes the libpq connection state.
3622
3827
  *
3828
+ * See the {PostgreSQL documentation}[https://www.postgresql.org/docs/17/libpq-pipeline-mode.html#LIBPQ-PIPELINE-MODE].
3829
+ *
3623
3830
  * Available since PostgreSQL-14
3624
3831
  */
3625
3832
  static VALUE
@@ -3658,17 +3865,16 @@ pgconn_exit_pipeline_mode(VALUE self)
3658
3865
 
3659
3866
  /*
3660
3867
  * call-seq:
3661
- * conn.pipeline_sync -> nil
3868
+ * conn.sync_pipeline_sync -> nil
3662
3869
  *
3663
- * Marks a synchronization point in a pipeline by sending a sync message and flushing the send buffer.
3664
- * This serves as the delimiter of an implicit transaction and an error recovery point; see Section 34.5.1.3 of the PostgreSQL documentation.
3665
- *
3666
- * Raises PG::Error if the connection is not in pipeline mode or sending a sync message failed.
3870
+ * This function has the same behavior as #async_pipeline_sync, but is implemented using the synchronous command processing API of libpq.
3871
+ * See #async_exec for the differences between the two API variants.
3872
+ * It's not recommended to use explicit sync or async variants but #pipeline_sync instead, unless you have a good reason to do so.
3667
3873
  *
3668
3874
  * Available since PostgreSQL-14
3669
3875
  */
3670
3876
  static VALUE
3671
- pgconn_pipeline_sync(VALUE self)
3877
+ pgconn_sync_pipeline_sync(VALUE self)
3672
3878
  {
3673
3879
  PGconn *conn = pg_get_pgconn(self);
3674
3880
  int res = PQpipelineSync(conn);
@@ -3678,9 +3884,36 @@ pgconn_pipeline_sync(VALUE self)
3678
3884
  return Qnil;
3679
3885
  }
3680
3886
 
3887
+
3888
+ #ifdef LIBPQ_HAS_CHUNK_MODE
3681
3889
  /*
3682
3890
  * call-seq:
3683
- * conn.pipeline_sync -> nil
3891
+ * conn.send_pipeline_sync -> nil
3892
+ *
3893
+ * Marks a synchronization point in a pipeline by sending a sync message without flushing the send buffer.
3894
+ *
3895
+ * This serves as the delimiter of an implicit transaction and an error recovery point.
3896
+ * Raises PG::Error if the connection is not in pipeline mode or sending a sync message failed.
3897
+ * Note that the message is not itself flushed to the server automatically; use flush if necessary.
3898
+ *
3899
+ * Available since PostgreSQL-17
3900
+ */
3901
+ static VALUE
3902
+ pgconn_send_pipeline_sync(VALUE self)
3903
+ {
3904
+ PGconn *conn = pg_get_pgconn(self);
3905
+ int res = PQsendPipelineSync(conn);
3906
+ if( res != 1 )
3907
+ pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
3908
+
3909
+ return Qnil;
3910
+ }
3911
+ #endif
3912
+
3913
+
3914
+ /*
3915
+ * call-seq:
3916
+ * conn.send_flush_request -> nil
3684
3917
  *
3685
3918
  * Sends a request for the server to flush its output buffer.
3686
3919
  *
@@ -4110,7 +4343,7 @@ pgconn_internal_encoding_set(VALUE self, VALUE enc)
4110
4343
  rb_encoding *rbenc = rb_to_encoding( enc );
4111
4344
  const char *name = pg_get_rb_encoding_as_pg_encoding( rbenc );
4112
4345
 
4113
- if ( gvl_PQsetClientEncoding(pg_get_pgconn( self ), name) == -1 ) {
4346
+ if ( PQsetClientEncoding(pg_get_pgconn( self ), name) == -1 ) {
4114
4347
  VALUE server_encoding = pgconn_external_encoding( self );
4115
4348
  rb_raise( rb_eEncCompatError, "incompatible character encodings: %s and %s",
4116
4349
  rb_enc_name(rb_to_encoding(server_encoding)), name );
@@ -4150,12 +4383,12 @@ pgconn_external_encoding(VALUE self)
4150
4383
  static VALUE
4151
4384
  pgconn_async_set_client_encoding(VALUE self, VALUE encname)
4152
4385
  {
4153
- VALUE query_format, query;
4386
+ VALUE query;
4154
4387
 
4155
4388
  rb_check_frozen(self);
4156
4389
  Check_Type(encname, T_STRING);
4157
- query_format = rb_str_new_cstr("set client_encoding to '%s'");
4158
- query = rb_funcall(query_format, rb_intern("%"), 1, encname);
4390
+ query = rb_str_new_cstr("set client_encoding to ");
4391
+ rb_str_concat(query, pgconn_escape_literal(self, encname));
4159
4392
 
4160
4393
  pgconn_async_exec(1, &query, self);
4161
4394
  pgconn_set_internal_encoding_index( self );
@@ -4231,9 +4464,11 @@ pgconn_set_default_encoding( VALUE self )
4231
4464
  * res.type_map_for_queries = typemap
4232
4465
  *
4233
4466
  * Set the default TypeMap that is used for type casts of query bind parameters.
4467
+ * It can be overwritten per +type_map+ parameter of #exec_params and siblings.
4234
4468
  *
4235
4469
  * +typemap+ must be a kind of PG::TypeMap .
4236
4470
  *
4471
+ * See also #type_map_for_queries
4237
4472
  */
4238
4473
  static VALUE
4239
4474
  pgconn_type_map_for_queries_set(VALUE self, VALUE typemap)
@@ -4258,6 +4493,9 @@ pgconn_type_map_for_queries_set(VALUE self, VALUE typemap)
4258
4493
  * Returns the default TypeMap that is currently set for type casts of query
4259
4494
  * bind parameters.
4260
4495
  *
4496
+ * Default is PG::TypeMapAllStrings .
4497
+ *
4498
+ * See also #type_map_for_queries=
4261
4499
  */
4262
4500
  static VALUE
4263
4501
  pgconn_type_map_for_queries_get(VALUE self)
@@ -4272,9 +4510,11 @@ pgconn_type_map_for_queries_get(VALUE self)
4272
4510
  * res.type_map_for_results = typemap
4273
4511
  *
4274
4512
  * Set the default TypeMap that is used for type casts of result values.
4513
+ * It can be overwritten per PG::Result#type_map= .
4275
4514
  *
4276
4515
  * +typemap+ must be a kind of PG::TypeMap .
4277
4516
  *
4517
+ * See also #type_map_for_results
4278
4518
  */
4279
4519
  static VALUE
4280
4520
  pgconn_type_map_for_results_set(VALUE self, VALUE typemap)
@@ -4296,6 +4536,9 @@ pgconn_type_map_for_results_set(VALUE self, VALUE typemap)
4296
4536
  *
4297
4537
  * Returns the default TypeMap that is currently set for type casts of result values.
4298
4538
  *
4539
+ * Default is PG::TypeMapAllStrings .
4540
+ *
4541
+ * See also #type_map_for_results=
4299
4542
  */
4300
4543
  static VALUE
4301
4544
  pgconn_type_map_for_results_get(VALUE self)
@@ -4312,11 +4555,13 @@ pgconn_type_map_for_results_get(VALUE self)
4312
4555
  *
4313
4556
  * Set the default coder that is used for type casting of parameters
4314
4557
  * to #put_copy_data .
4558
+ * It can be overwritten per +encoder+ parameter of #put_copy_data and +coder+ parameter of #copy_data.
4315
4559
  *
4316
4560
  * +encoder+ can be:
4317
4561
  * * a kind of PG::Coder
4318
4562
  * * +nil+ - disable type encoding, data must be a String.
4319
4563
  *
4564
+ * See also #encoder_for_put_copy_data
4320
4565
  */
4321
4566
  static VALUE
4322
4567
  pgconn_encoder_for_put_copy_data_set(VALUE self, VALUE encoder)
@@ -4346,6 +4591,8 @@ pgconn_encoder_for_put_copy_data_set(VALUE self, VALUE encoder)
4346
4591
  * * a kind of PG::Coder
4347
4592
  * * +nil+ - type encoding is disabled, data must be a String.
4348
4593
  *
4594
+ * Default is +nil+ .
4595
+ * See also #encoder_for_put_copy_data=
4349
4596
  */
4350
4597
  static VALUE
4351
4598
  pgconn_encoder_for_put_copy_data_get(VALUE self)
@@ -4361,11 +4608,13 @@ pgconn_encoder_for_put_copy_data_get(VALUE self)
4361
4608
  *
4362
4609
  * Set the default coder that is used for type casting of received data
4363
4610
  * by #get_copy_data .
4611
+ * It can be overwritten per +decoder+ parameter of #get_copy_data and +coder+ parameter of #copy_data.
4364
4612
  *
4365
4613
  * +decoder+ can be:
4366
4614
  * * a kind of PG::Coder
4367
4615
  * * +nil+ - disable type decoding, returned data will be a String.
4368
4616
  *
4617
+ * See also #decoder_for_get_copy_data
4369
4618
  */
4370
4619
  static VALUE
4371
4620
  pgconn_decoder_for_get_copy_data_set(VALUE self, VALUE decoder)
@@ -4395,6 +4644,9 @@ pgconn_decoder_for_get_copy_data_set(VALUE self, VALUE decoder)
4395
4644
  * * a kind of PG::Coder
4396
4645
  * * +nil+ - type encoding is disabled, returned data will be a String.
4397
4646
  *
4647
+ * Default is +nil+ .
4648
+ *
4649
+ * See also #decoder_for_get_copy_data=
4398
4650
  */
4399
4651
  static VALUE
4400
4652
  pgconn_decoder_for_get_copy_data_get(VALUE self)
@@ -4417,7 +4669,7 @@ pgconn_decoder_for_get_copy_data_get(VALUE self)
4417
4669
  *
4418
4670
  * Settings the type of field names affects only future results.
4419
4671
  *
4420
- * See further description at PG::Result#field_name_type=
4672
+ * See further description at PG::Result#field_name_type= and #field_name_type .
4421
4673
  *
4422
4674
  */
4423
4675
  static VALUE
@@ -4428,7 +4680,6 @@ pgconn_field_name_type_set(VALUE self, VALUE sym)
4428
4680
  rb_check_frozen(self);
4429
4681
  this->flags &= ~PG_RESULT_FIELD_NAMES_MASK;
4430
4682
  if( sym == sym_symbol ) this->flags |= PG_RESULT_FIELD_NAMES_SYMBOL;
4431
- else if ( sym == sym_static_symbol ) this->flags |= PG_RESULT_FIELD_NAMES_STATIC_SYMBOL;
4432
4683
  else if ( sym == sym_string );
4433
4684
  else rb_raise(rb_eArgError, "invalid argument %+"PRIsVALUE, sym);
4434
4685
 
@@ -4450,8 +4701,6 @@ pgconn_field_name_type_get(VALUE self)
4450
4701
 
4451
4702
  if( this->flags & PG_RESULT_FIELD_NAMES_SYMBOL ){
4452
4703
  return sym_symbol;
4453
- } else if( this->flags & PG_RESULT_FIELD_NAMES_STATIC_SYMBOL ){
4454
- return sym_static_symbol;
4455
4704
  } else {
4456
4705
  return sym_string;
4457
4706
  }
@@ -4471,7 +4720,6 @@ init_pg_connection(void)
4471
4720
  sym_value = ID2SYM(rb_intern("value"));
4472
4721
  sym_string = ID2SYM(rb_intern("string"));
4473
4722
  sym_symbol = ID2SYM(rb_intern("symbol"));
4474
- sym_static_symbol = ID2SYM(rb_intern("static_symbol"));
4475
4723
 
4476
4724
  rb_cPGconn = rb_define_class_under( rb_mPG, "Connection", rb_cObject );
4477
4725
  /* Help rdoc to known the Constants module */
@@ -4519,12 +4767,17 @@ init_pg_connection(void)
4519
4767
  rb_define_method(rb_cPGconn, "transaction_status", pgconn_transaction_status, 0);
4520
4768
  rb_define_method(rb_cPGconn, "parameter_status", pgconn_parameter_status, 1);
4521
4769
  rb_define_method(rb_cPGconn, "protocol_version", pgconn_protocol_version, 0);
4770
+ #ifdef LIBPQ_HAS_FULL_PROTOCOL_VERSION
4771
+ rb_define_method(rb_cPGconn, "full_protocol_version", pgconn_full_protocol_version, 0);
4772
+ #endif
4522
4773
  rb_define_method(rb_cPGconn, "server_version", pgconn_server_version, 0);
4523
4774
  rb_define_method(rb_cPGconn, "error_message", pgconn_error_message, 0);
4524
4775
  rb_define_method(rb_cPGconn, "socket", pgconn_socket, 0);
4525
4776
  rb_define_method(rb_cPGconn, "socket_io", pgconn_socket_io, 0);
4526
4777
  rb_define_method(rb_cPGconn, "backend_pid", pgconn_backend_pid, 0);
4778
+ #ifndef LIBPQ_HAS_CHUNK_MODE
4527
4779
  rb_define_method(rb_cPGconn, "backend_key", pgconn_backend_key, 0);
4780
+ #endif
4528
4781
  rb_define_method(rb_cPGconn, "connection_needs_password", pgconn_connection_needs_password, 0);
4529
4782
  rb_define_method(rb_cPGconn, "connection_used_password", pgconn_connection_used_password, 0);
4530
4783
  /* rb_define_method(rb_cPGconn, "getssl", pgconn_getssl, 0); */
@@ -4536,6 +4789,10 @@ init_pg_connection(void)
4536
4789
  rb_define_method(rb_cPGconn, "sync_exec_prepared", pgconn_sync_exec_prepared, -1);
4537
4790
  rb_define_method(rb_cPGconn, "sync_describe_prepared", pgconn_sync_describe_prepared, 1);
4538
4791
  rb_define_method(rb_cPGconn, "sync_describe_portal", pgconn_sync_describe_portal, 1);
4792
+ #ifdef LIBPQ_HAS_CHUNK_MODE
4793
+ rb_define_method(rb_cPGconn, "sync_close_prepared", pgconn_sync_close_prepared, 1);
4794
+ rb_define_method(rb_cPGconn, "sync_close_portal", pgconn_sync_close_portal, 1);
4795
+ #endif
4539
4796
 
4540
4797
  rb_define_method(rb_cPGconn, "exec", pgconn_async_exec, -1);
4541
4798
  rb_define_method(rb_cPGconn, "exec_params", pgconn_async_exec_params, -1);
@@ -4543,6 +4800,10 @@ init_pg_connection(void)
4543
4800
  rb_define_method(rb_cPGconn, "exec_prepared", pgconn_async_exec_prepared, -1);
4544
4801
  rb_define_method(rb_cPGconn, "describe_prepared", pgconn_async_describe_prepared, 1);
4545
4802
  rb_define_method(rb_cPGconn, "describe_portal", pgconn_async_describe_portal, 1);
4803
+ #ifdef LIBPQ_HAS_CHUNK_MODE
4804
+ rb_define_method(rb_cPGconn, "close_prepared", pgconn_async_close_prepared, 1);
4805
+ rb_define_method(rb_cPGconn, "close_portal", pgconn_async_close_portal, 1);
4806
+ #endif
4546
4807
 
4547
4808
  rb_define_alias(rb_cPGconn, "async_exec", "exec");
4548
4809
  rb_define_alias(rb_cPGconn, "async_query", "async_exec");
@@ -4551,6 +4812,10 @@ init_pg_connection(void)
4551
4812
  rb_define_alias(rb_cPGconn, "async_exec_prepared", "exec_prepared");
4552
4813
  rb_define_alias(rb_cPGconn, "async_describe_prepared", "describe_prepared");
4553
4814
  rb_define_alias(rb_cPGconn, "async_describe_portal", "describe_portal");
4815
+ #ifdef LIBPQ_HAS_CHUNK_MODE
4816
+ rb_define_alias(rb_cPGconn, "async_close_prepared", "close_prepared");
4817
+ rb_define_alias(rb_cPGconn, "async_close_portal", "close_portal");
4818
+ #endif
4554
4819
 
4555
4820
  rb_define_method(rb_cPGconn, "make_empty_pgresult", pgconn_make_empty_pgresult, 1);
4556
4821
  rb_define_method(rb_cPGconn, "escape_string", pgconn_s_escape, 1);
@@ -4560,6 +4825,9 @@ init_pg_connection(void)
4560
4825
  rb_define_method(rb_cPGconn, "escape_bytea", pgconn_s_escape_bytea, 1);
4561
4826
  rb_define_method(rb_cPGconn, "unescape_bytea", pgconn_s_unescape_bytea, 1);
4562
4827
  rb_define_method(rb_cPGconn, "set_single_row_mode", pgconn_set_single_row_mode, 0);
4828
+ #ifdef LIBPQ_HAS_CHUNK_MODE
4829
+ rb_define_method(rb_cPGconn, "set_chunked_rows_mode", pgconn_set_chunked_rows_mode, 1);
4830
+ #endif
4563
4831
 
4564
4832
  /****** PG::Connection INSTANCE METHODS: Asynchronous Command Processing ******/
4565
4833
  rb_define_method(rb_cPGconn, "send_query", pgconn_send_query, -1);
@@ -4579,7 +4847,9 @@ init_pg_connection(void)
4579
4847
  rb_define_method(rb_cPGconn, "discard_results", pgconn_discard_results, 0);
4580
4848
 
4581
4849
  /****** PG::Connection INSTANCE METHODS: Cancelling Queries in Progress ******/
4850
+ #ifndef LIBPQ_HAS_CHUNK_MODE
4582
4851
  rb_define_method(rb_cPGconn, "sync_cancel", pgconn_sync_cancel, 0);
4852
+ #endif
4583
4853
 
4584
4854
  /****** PG::Connection INSTANCE METHODS: NOTIFY ******/
4585
4855
  rb_define_method(rb_cPGconn, "notifies", pgconn_notifies, 0);
@@ -4591,9 +4861,7 @@ init_pg_connection(void)
4591
4861
 
4592
4862
  /****** PG::Connection INSTANCE METHODS: Control Functions ******/
4593
4863
  rb_define_method(rb_cPGconn, "set_error_verbosity", pgconn_set_error_verbosity, 1);
4594
- #ifdef HAVE_PQRESULTVERBOSEERRORMESSAGE
4595
4864
  rb_define_method(rb_cPGconn, "set_error_context_visibility", pgconn_set_error_context_visibility, 1 );
4596
- #endif
4597
4865
  rb_define_method(rb_cPGconn, "trace", pgconn_trace, 1);
4598
4866
  rb_define_method(rb_cPGconn, "untrace", pgconn_untrace, 0);
4599
4867
 
@@ -4615,22 +4883,21 @@ init_pg_connection(void)
4615
4883
  rb_define_method(rb_cPGconn, "sync_get_last_result", pgconn_sync_get_last_result, 0);
4616
4884
  rb_define_method(rb_cPGconn, "get_last_result", pgconn_async_get_last_result, 0);
4617
4885
  rb_define_alias(rb_cPGconn, "async_get_last_result", "get_last_result");
4618
- #ifdef HAVE_PQENCRYPTPASSWORDCONN
4619
4886
  rb_define_method(rb_cPGconn, "sync_encrypt_password", pgconn_sync_encrypt_password, -1);
4620
- #endif
4621
4887
 
4622
- #ifdef HAVE_PQSSLATTRIBUTE
4623
4888
  rb_define_method(rb_cPGconn, "ssl_in_use?", pgconn_ssl_in_use, 0);
4624
4889
  rb_define_method(rb_cPGconn, "ssl_attribute", pgconn_ssl_attribute, 1);
4625
4890
  rb_define_method(rb_cPGconn, "ssl_attribute_names", pgconn_ssl_attribute_names, 0);
4626
- #endif
4627
4891
 
4628
- #ifdef HAVE_PQENTERPIPELINEMODE
4892
+ #ifdef LIBPQ_HAS_PIPELINING
4629
4893
  rb_define_method(rb_cPGconn, "pipeline_status", pgconn_pipeline_status, 0);
4630
4894
  rb_define_method(rb_cPGconn, "enter_pipeline_mode", pgconn_enter_pipeline_mode, 0);
4631
4895
  rb_define_method(rb_cPGconn, "exit_pipeline_mode", pgconn_exit_pipeline_mode, 0);
4632
- rb_define_method(rb_cPGconn, "pipeline_sync", pgconn_pipeline_sync, 0);
4896
+ rb_define_method(rb_cPGconn, "sync_pipeline_sync", pgconn_sync_pipeline_sync, 0);
4633
4897
  rb_define_method(rb_cPGconn, "send_flush_request", pgconn_send_flush_request, 0);
4898
+ #ifdef LIBPQ_HAS_CHUNK_MODE
4899
+ rb_define_method(rb_cPGconn, "send_pipeline_sync", pgconn_send_pipeline_sync, 0);
4900
+ #endif
4634
4901
  #endif
4635
4902
 
4636
4903
  /****** PG::Connection INSTANCE METHODS: Large Object Support ******/