pg 1.2.3 → 1.3.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (103) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/.appveyor.yml +36 -0
  4. data/.gems +6 -0
  5. data/.github/workflows/binary-gems.yml +80 -0
  6. data/.github/workflows/source-gem.yml +129 -0
  7. data/.gitignore +13 -0
  8. data/.hgsigs +34 -0
  9. data/.hgtags +41 -0
  10. data/.irbrc +23 -0
  11. data/.pryrc +23 -0
  12. data/.tm_properties +21 -0
  13. data/.travis.yml +49 -0
  14. data/Gemfile +14 -0
  15. data/History.rdoc +75 -7
  16. data/Manifest.txt +0 -1
  17. data/README.rdoc +7 -6
  18. data/Rakefile +27 -138
  19. data/Rakefile.cross +5 -5
  20. data/certs/ged.pem +24 -0
  21. data/ext/errorcodes.def +8 -0
  22. data/ext/errorcodes.txt +3 -1
  23. data/ext/extconf.rb +90 -19
  24. data/ext/gvl_wrappers.c +4 -0
  25. data/ext/gvl_wrappers.h +23 -0
  26. data/ext/pg.c +35 -1
  27. data/ext/pg.h +18 -1
  28. data/ext/pg_coder.c +82 -28
  29. data/ext/pg_connection.c +538 -279
  30. data/ext/pg_copy_coder.c +45 -16
  31. data/ext/pg_record_coder.c +38 -10
  32. data/ext/pg_result.c +61 -31
  33. data/ext/pg_text_decoder.c +1 -1
  34. data/ext/pg_text_encoder.c +6 -6
  35. data/ext/pg_tuple.c +47 -21
  36. data/ext/pg_type_map.c +41 -8
  37. data/ext/pg_type_map_all_strings.c +14 -1
  38. data/ext/pg_type_map_by_class.c +49 -24
  39. data/ext/pg_type_map_by_column.c +64 -28
  40. data/ext/pg_type_map_by_mri_type.c +47 -18
  41. data/ext/pg_type_map_by_oid.c +52 -23
  42. data/ext/pg_type_map_in_ruby.c +50 -19
  43. data/ext/pg_util.c +2 -2
  44. data/lib/pg/basic_type_map_based_on_result.rb +47 -0
  45. data/lib/pg/basic_type_map_for_queries.rb +193 -0
  46. data/lib/pg/basic_type_map_for_results.rb +81 -0
  47. data/lib/pg/basic_type_registry.rb +296 -0
  48. data/lib/pg/coder.rb +1 -1
  49. data/lib/pg/connection.rb +369 -56
  50. data/lib/pg/version.rb +4 -0
  51. data/lib/pg.rb +38 -25
  52. data/misc/openssl-pg-segfault.rb +31 -0
  53. data/misc/postgres/History.txt +9 -0
  54. data/misc/postgres/Manifest.txt +5 -0
  55. data/misc/postgres/README.txt +21 -0
  56. data/misc/postgres/Rakefile +21 -0
  57. data/misc/postgres/lib/postgres.rb +16 -0
  58. data/misc/ruby-pg/History.txt +9 -0
  59. data/misc/ruby-pg/Manifest.txt +5 -0
  60. data/misc/ruby-pg/README.txt +21 -0
  61. data/misc/ruby-pg/Rakefile +21 -0
  62. data/misc/ruby-pg/lib/ruby/pg.rb +16 -0
  63. data/pg.gemspec +32 -0
  64. data/sample/array_insert.rb +20 -0
  65. data/sample/async_api.rb +106 -0
  66. data/sample/async_copyto.rb +39 -0
  67. data/sample/async_mixed.rb +56 -0
  68. data/sample/check_conn.rb +21 -0
  69. data/sample/copydata.rb +71 -0
  70. data/sample/copyfrom.rb +81 -0
  71. data/sample/copyto.rb +19 -0
  72. data/sample/cursor.rb +21 -0
  73. data/sample/disk_usage_report.rb +177 -0
  74. data/sample/issue-119.rb +94 -0
  75. data/sample/losample.rb +69 -0
  76. data/sample/minimal-testcase.rb +17 -0
  77. data/sample/notify_wait.rb +72 -0
  78. data/sample/pg_statistics.rb +285 -0
  79. data/sample/replication_monitor.rb +222 -0
  80. data/sample/test_binary_values.rb +33 -0
  81. data/sample/wal_shipper.rb +434 -0
  82. data/sample/warehouse_partitions.rb +311 -0
  83. data.tar.gz.sig +0 -0
  84. metadata +79 -226
  85. metadata.gz.sig +0 -0
  86. data/ChangeLog +0 -0
  87. data/lib/pg/basic_type_mapping.rb +0 -522
  88. data/spec/data/expected_trace.out +0 -26
  89. data/spec/data/random_binary_data +0 -0
  90. data/spec/helpers.rb +0 -380
  91. data/spec/pg/basic_type_mapping_spec.rb +0 -630
  92. data/spec/pg/connection_spec.rb +0 -1949
  93. data/spec/pg/connection_sync_spec.rb +0 -41
  94. data/spec/pg/result_spec.rb +0 -681
  95. data/spec/pg/tuple_spec.rb +0 -333
  96. data/spec/pg/type_map_by_class_spec.rb +0 -138
  97. data/spec/pg/type_map_by_column_spec.rb +0 -226
  98. data/spec/pg/type_map_by_mri_type_spec.rb +0 -136
  99. data/spec/pg/type_map_by_oid_spec.rb +0 -149
  100. data/spec/pg/type_map_in_ruby_spec.rb +0 -164
  101. data/spec/pg/type_map_spec.rb +0 -22
  102. data/spec/pg/type_spec.rb +0 -1123
  103. data/spec/pg_spec.rb +0 -50
data/ext/pg_connection.c CHANGED
@@ -12,6 +12,7 @@
12
12
 
13
13
  VALUE rb_cPGconn;
14
14
  static ID s_id_encode;
15
+ static ID s_id_autoclose_set;
15
16
  static VALUE sym_type, sym_format, sym_value;
16
17
  static VALUE sym_symbol, sym_string, sym_static_symbol;
17
18
 
@@ -20,7 +21,9 @@ static PQnoticeProcessor default_notice_processor = NULL;
20
21
 
21
22
  static VALUE pgconn_finish( VALUE );
22
23
  static VALUE pgconn_set_default_encoding( VALUE self );
24
+ static VALUE pgconn_wait_for_flush( VALUE self );
23
25
  static void pgconn_set_internal_encoding_index( VALUE );
26
+ static const rb_data_type_t pg_connection_type;
24
27
 
25
28
  /*
26
29
  * Global functions
@@ -33,7 +36,7 @@ t_pg_connection *
33
36
  pg_get_connection( VALUE self )
34
37
  {
35
38
  t_pg_connection *this;
36
- Data_Get_Struct( self, t_pg_connection, this);
39
+ TypedData_Get_Struct( self, t_pg_connection, &pg_connection_type, this);
37
40
 
38
41
  return this;
39
42
  }
@@ -46,7 +49,7 @@ static t_pg_connection *
46
49
  pg_get_connection_safe( VALUE self )
47
50
  {
48
51
  t_pg_connection *this;
49
- Data_Get_Struct( self, t_pg_connection, this);
52
+ TypedData_Get_Struct( self, t_pg_connection, &pg_connection_type, this);
50
53
 
51
54
  if ( !this->pgconn )
52
55
  rb_raise( rb_eConnectionBad, "connection is closed" );
@@ -65,7 +68,7 @@ PGconn *
65
68
  pg_get_pgconn( VALUE self )
66
69
  {
67
70
  t_pg_connection *this;
68
- Data_Get_Struct( self, t_pg_connection, this);
71
+ TypedData_Get_Struct( self, t_pg_connection, &pg_connection_type, this);
69
72
 
70
73
  if ( !this->pgconn )
71
74
  rb_raise( rb_eConnectionBad, "connection is closed" );
@@ -145,16 +148,31 @@ static const char *pg_cstr_enc(VALUE str, int enc_idx){
145
148
  * GC Mark function
146
149
  */
147
150
  static void
148
- pgconn_gc_mark( t_pg_connection *this )
151
+ pgconn_gc_mark( void *_this )
149
152
  {
150
- rb_gc_mark( this->socket_io );
151
- rb_gc_mark( this->notice_receiver );
152
- rb_gc_mark( this->notice_processor );
153
- rb_gc_mark( this->type_map_for_queries );
154
- rb_gc_mark( this->type_map_for_results );
155
- rb_gc_mark( this->trace_stream );
156
- rb_gc_mark( this->encoder_for_put_copy_data );
157
- rb_gc_mark( this->decoder_for_get_copy_data );
153
+ t_pg_connection *this = (t_pg_connection *)_this;
154
+ rb_gc_mark_movable( this->socket_io );
155
+ rb_gc_mark_movable( this->notice_receiver );
156
+ rb_gc_mark_movable( this->notice_processor );
157
+ rb_gc_mark_movable( this->type_map_for_queries );
158
+ rb_gc_mark_movable( this->type_map_for_results );
159
+ rb_gc_mark_movable( this->trace_stream );
160
+ rb_gc_mark_movable( this->encoder_for_put_copy_data );
161
+ rb_gc_mark_movable( this->decoder_for_get_copy_data );
162
+ }
163
+
164
+ static void
165
+ pgconn_gc_compact( void *_this )
166
+ {
167
+ t_pg_connection *this = (t_pg_connection *)_this;
168
+ pg_gc_location( this->socket_io );
169
+ pg_gc_location( this->notice_receiver );
170
+ pg_gc_location( this->notice_processor );
171
+ pg_gc_location( this->type_map_for_queries );
172
+ pg_gc_location( this->type_map_for_results );
173
+ pg_gc_location( this->trace_stream );
174
+ pg_gc_location( this->encoder_for_put_copy_data );
175
+ pg_gc_location( this->decoder_for_get_copy_data );
158
176
  }
159
177
 
160
178
 
@@ -162,11 +180,15 @@ pgconn_gc_mark( t_pg_connection *this )
162
180
  * GC Free function
163
181
  */
164
182
  static void
165
- pgconn_gc_free( t_pg_connection *this )
183
+ pgconn_gc_free( void *_this )
166
184
  {
185
+ t_pg_connection *this = (t_pg_connection *)_this;
167
186
  #if defined(_WIN32)
168
- if ( RTEST(this->socket_io) )
169
- rb_w32_unwrap_io_handle( this->ruby_sd );
187
+ if ( RTEST(this->socket_io) ) {
188
+ if( rb_w32_unwrap_io_handle(this->ruby_sd) ){
189
+ rb_warn("pg: Could not unwrap win32 socket handle by garbage collector");
190
+ }
191
+ }
170
192
  #endif
171
193
  if (this->pgconn != NULL)
172
194
  PQfinish( this->pgconn );
@@ -174,6 +196,29 @@ pgconn_gc_free( t_pg_connection *this )
174
196
  xfree(this);
175
197
  }
176
198
 
199
+ /*
200
+ * Object Size function
201
+ */
202
+ static size_t
203
+ pgconn_memsize( const void *_this )
204
+ {
205
+ const t_pg_connection *this = (const t_pg_connection *)_this;
206
+ return sizeof(*this);
207
+ }
208
+
209
+ static const rb_data_type_t pg_connection_type = {
210
+ "PG::Connection",
211
+ {
212
+ pgconn_gc_mark,
213
+ pgconn_gc_free,
214
+ pgconn_memsize,
215
+ pg_compact_callback(pgconn_gc_compact),
216
+ },
217
+ 0,
218
+ 0,
219
+ 0,
220
+ };
221
+
177
222
 
178
223
  /**************************************************************************
179
224
  * Class Methods
@@ -189,7 +234,7 @@ static VALUE
189
234
  pgconn_s_allocate( VALUE klass )
190
235
  {
191
236
  t_pg_connection *this;
192
- VALUE self = Data_Make_Struct( klass, t_pg_connection, pgconn_gc_mark, pgconn_gc_free, this );
237
+ VALUE self = TypedData_Make_Struct( klass, t_pg_connection, &pg_connection_type, this );
193
238
 
194
239
  this->pgconn = NULL;
195
240
  this->socket_io = Qnil;
@@ -230,7 +275,7 @@ pgconn_s_allocate( VALUE klass )
230
275
  * [+options+]
231
276
  * backend options
232
277
  * [+tty+]
233
- * (ignored in newer versions of PostgreSQL)
278
+ * (ignored in all versions of PostgreSQL)
234
279
  * [+dbname+]
235
280
  * connecting database name
236
281
  * [+user+]
@@ -244,7 +289,7 @@ pgconn_s_allocate( VALUE klass )
244
289
  * PG::Connection.new
245
290
  *
246
291
  * # As a Hash
247
- * PG::Connection.new( :dbname => 'test', :port => 5432 )
292
+ * PG::Connection.new( dbname: 'test', port: 5432 )
248
293
  *
249
294
  * # As a String
250
295
  * PG::Connection.new( "dbname=test port=5432" )
@@ -252,6 +297,9 @@ pgconn_s_allocate( VALUE klass )
252
297
  * # As an Array
253
298
  * PG::Connection.new( nil, 5432, nil, nil, 'test', nil, nil )
254
299
  *
300
+ * # As an URI
301
+ * PG::Connection.new( "postgresql://user:pass@pgsql.example.com:5432/testdb?sslmode=require" )
302
+ *
255
303
  * If the Ruby default internal encoding is set (i.e., <code>Encoding.default_internal != nil</code>), the
256
304
  * connection will have its +client_encoding+ set accordingly.
257
305
  *
@@ -362,7 +410,7 @@ pgconn_s_ping( int argc, VALUE *argv, VALUE klass )
362
410
  VALUE conninfo;
363
411
 
364
412
  conninfo = rb_funcall2( klass, rb_intern("parse_connect_args"), argc, argv );
365
- ping = PQping( StringValueCStr(conninfo) );
413
+ ping = gvl_PQping( StringValueCStr(conninfo) );
366
414
 
367
415
  return INT2FIX((int)ping);
368
416
  }
@@ -676,21 +724,19 @@ static VALUE
676
724
  pgconn_port(VALUE self)
677
725
  {
678
726
  char* port = PQport(pg_get_pgconn(self));
679
- return INT2NUM(atol(port));
727
+ return INT2NUM(atoi(port));
680
728
  }
681
729
 
682
730
  /*
683
731
  * call-seq:
684
732
  * conn.tty()
685
733
  *
686
- * Returns the connected pgtty. (Obsolete)
734
+ * Obsolete function.
687
735
  */
688
736
  static VALUE
689
737
  pgconn_tty(VALUE self)
690
738
  {
691
- char *tty = PQtty(pg_get_pgconn(self));
692
- if (!tty) return Qnil;
693
- return rb_str_new2(tty);
739
+ return rb_str_new2("");
694
740
  }
695
741
 
696
742
  /*
@@ -708,7 +754,6 @@ pgconn_options(VALUE self)
708
754
  }
709
755
 
710
756
 
711
- #ifdef HAVE_PQCONNINFO
712
757
  /*
713
758
  * call-seq:
714
759
  * conn.conninfo -> hash
@@ -728,7 +773,6 @@ pgconn_conninfo( VALUE self )
728
773
 
729
774
  return array;
730
775
  }
731
- #endif
732
776
 
733
777
 
734
778
  /*
@@ -823,7 +867,10 @@ pgconn_server_version(VALUE self)
823
867
  * call-seq:
824
868
  * conn.error_message -> String
825
869
  *
826
- * Returns the error message about connection.
870
+ * Returns the error message most recently generated by an operation on the connection.
871
+ *
872
+ * Nearly all libpq functions will set a message for conn.error_message if they fail.
873
+ * Note that by libpq convention, a nonempty error_message result can consist of multiple lines, and will include a trailing newline.
827
874
  */
828
875
  static VALUE
829
876
  pgconn_error_message(VALUE self)
@@ -878,8 +925,8 @@ pgconn_socket_io(VALUE self)
878
925
  {
879
926
  int sd;
880
927
  int ruby_sd;
881
- ID id_autoclose = rb_intern("autoclose=");
882
928
  t_pg_connection *this = pg_get_connection_safe( self );
929
+ VALUE cSocket;
883
930
  VALUE socket_io = this->socket_io;
884
931
 
885
932
  if ( !RTEST(socket_io) ) {
@@ -888,15 +935,19 @@ pgconn_socket_io(VALUE self)
888
935
 
889
936
  #ifdef _WIN32
890
937
  ruby_sd = rb_w32_wrap_io_handle((HANDLE)(intptr_t)sd, O_RDWR|O_BINARY|O_NOINHERIT);
938
+ if( ruby_sd == -1 ){
939
+ rb_raise(rb_eConnectionBad, "Could not wrap win32 socket handle");
940
+ }
891
941
  this->ruby_sd = ruby_sd;
892
942
  #else
893
943
  ruby_sd = sd;
894
944
  #endif
895
945
 
896
- socket_io = rb_funcall( rb_cIO, rb_intern("for_fd"), 1, INT2NUM(ruby_sd) );
946
+ cSocket = rb_const_get(rb_cObject, rb_intern("BasicSocket"));
947
+ socket_io = rb_funcall( cSocket, rb_intern("for_fd"), 1, INT2NUM(ruby_sd));
897
948
 
898
949
  /* Disable autoclose feature */
899
- rb_funcall( socket_io, id_autoclose, 1, Qfalse );
950
+ rb_funcall( socket_io, s_id_autoclose_set, 1, Qfalse );
900
951
 
901
952
  this->socket_io = socket_io;
902
953
  }
@@ -918,6 +969,51 @@ pgconn_backend_pid(VALUE self)
918
969
  return INT2NUM(PQbackendPID(pg_get_pgconn(self)));
919
970
  }
920
971
 
972
+ typedef struct
973
+ {
974
+ struct sockaddr_storage addr;
975
+ socklen_t salen;
976
+ } SockAddr;
977
+
978
+ /* Copy of struct pg_cancel from libpq-int.h
979
+ *
980
+ * See https://github.com/postgres/postgres/blame/master/src/interfaces/libpq/libpq-int.h#L577-L586
981
+ */
982
+ struct pg_cancel
983
+ {
984
+ SockAddr raddr; /* Remote address */
985
+ int be_pid; /* PID of backend --- needed for cancels */
986
+ int be_key; /* key of backend --- needed for cancels */
987
+ };
988
+
989
+ /*
990
+ * call-seq:
991
+ * conn.backend_key() -> Integer
992
+ *
993
+ * Returns the key of the backend server process for this connection.
994
+ * This key can be used to cancel queries on the server.
995
+ */
996
+ static VALUE
997
+ pgconn_backend_key(VALUE self)
998
+ {
999
+ int be_key;
1000
+ struct pg_cancel *cancel;
1001
+ PGconn *conn = pg_get_pgconn(self);
1002
+
1003
+ cancel = (struct pg_cancel*)PQgetCancel(conn);
1004
+ if(cancel == NULL)
1005
+ rb_raise(rb_ePGerror,"Invalid connection!");
1006
+
1007
+ if( cancel->be_pid != PQbackendPID(conn) )
1008
+ rb_raise(rb_ePGerror,"Unexpected binary struct layout - please file a bug report at ruby-pg!");
1009
+
1010
+ be_key = cancel->be_key;
1011
+
1012
+ PQfreeCancel(cancel);
1013
+
1014
+ return INT2NUM(be_key);
1015
+ }
1016
+
921
1017
  /*
922
1018
  * call-seq:
923
1019
  * conn.connection_needs_password() -> Boolean
@@ -1019,7 +1115,7 @@ struct query_params_data {
1019
1115
  * Filled by alloc_query_params()
1020
1116
  */
1021
1117
 
1022
- /* Wraps the pointer of allocated memory, if function parameters dont't
1118
+ /* Wraps the pointer of allocated memory, if function parameters don't
1023
1119
  * fit in the memory_pool below.
1024
1120
  */
1025
1121
  VALUE heap_pool;
@@ -1037,7 +1133,7 @@ struct query_params_data {
1037
1133
  Oid *types;
1038
1134
 
1039
1135
  /* This array takes the string values for the timeframe of the query,
1040
- * if param value convertion is required
1136
+ * if param value conversion is required
1041
1137
  */
1042
1138
  VALUE gc_array;
1043
1139
 
@@ -1051,8 +1147,9 @@ struct query_params_data {
1051
1147
  };
1052
1148
 
1053
1149
  static void
1054
- free_typecast_heap_chain(struct linked_typecast_data *chain_entry)
1150
+ free_typecast_heap_chain(void *_chain_entry)
1055
1151
  {
1152
+ struct linked_typecast_data *chain_entry = (struct linked_typecast_data *)_chain_entry;
1056
1153
  while(chain_entry){
1057
1154
  struct linked_typecast_data *next = chain_entry->next;
1058
1155
  xfree(chain_entry);
@@ -1060,6 +1157,18 @@ free_typecast_heap_chain(struct linked_typecast_data *chain_entry)
1060
1157
  }
1061
1158
  }
1062
1159
 
1160
+ static const rb_data_type_t pg_typecast_buffer_type = {
1161
+ "PG::Connection typecast buffer chain",
1162
+ {
1163
+ (RUBY_DATA_FUNC) NULL,
1164
+ free_typecast_heap_chain,
1165
+ (size_t (*)(const void *))NULL,
1166
+ },
1167
+ 0,
1168
+ 0,
1169
+ RUBY_TYPED_FREE_IMMEDIATELY,
1170
+ };
1171
+
1063
1172
  static char *
1064
1173
  alloc_typecast_buf( VALUE *typecast_heap_chain, int len )
1065
1174
  {
@@ -1070,17 +1179,28 @@ alloc_typecast_buf( VALUE *typecast_heap_chain, int len )
1070
1179
  /* Did we already wrap a memory chain per T_DATA object? */
1071
1180
  if( NIL_P( *typecast_heap_chain ) ){
1072
1181
  /* Leave free'ing of the buffer chain to the GC, when paramsData has left the stack */
1073
- *typecast_heap_chain = Data_Wrap_Struct( rb_cObject, NULL, free_typecast_heap_chain, allocated );
1182
+ *typecast_heap_chain = TypedData_Wrap_Struct( rb_cObject, &pg_typecast_buffer_type, allocated );
1074
1183
  allocated->next = NULL;
1075
1184
  } else {
1076
1185
  /* Append to the chain */
1077
- allocated->next = DATA_PTR( *typecast_heap_chain );
1078
- DATA_PTR( *typecast_heap_chain ) = allocated;
1186
+ allocated->next = RTYPEDDATA_DATA( *typecast_heap_chain );
1187
+ RTYPEDDATA_DATA( *typecast_heap_chain ) = allocated;
1079
1188
  }
1080
1189
 
1081
1190
  return &allocated->data[0];
1082
1191
  }
1083
1192
 
1193
+ static const rb_data_type_t pg_query_heap_pool_type = {
1194
+ "PG::Connection query heap pool",
1195
+ {
1196
+ (RUBY_DATA_FUNC) NULL,
1197
+ RUBY_TYPED_DEFAULT_FREE,
1198
+ (size_t (*)(const void *))NULL,
1199
+ },
1200
+ 0,
1201
+ 0,
1202
+ RUBY_TYPED_FREE_IMMEDIATELY,
1203
+ };
1084
1204
 
1085
1205
  static int
1086
1206
  alloc_query_params(struct query_params_data *paramsData)
@@ -1095,7 +1215,7 @@ alloc_query_params(struct query_params_data *paramsData)
1095
1215
 
1096
1216
  Check_Type(paramsData->params, T_ARRAY);
1097
1217
 
1098
- p_typemap = DATA_PTR( paramsData->typemap );
1218
+ p_typemap = RTYPEDDATA_DATA( paramsData->typemap );
1099
1219
  p_typemap->funcs.fit_to_query( paramsData->typemap, paramsData->params );
1100
1220
 
1101
1221
  paramsData->heap_pool = Qnil;
@@ -1114,7 +1234,7 @@ alloc_query_params(struct query_params_data *paramsData)
1114
1234
  /* Allocate one combined memory pool for all possible function parameters */
1115
1235
  memory_pool = (char*)xmalloc( required_pool_size );
1116
1236
  /* Leave free'ing of the buffer to the GC, when paramsData has left the stack */
1117
- paramsData->heap_pool = Data_Wrap_Struct( rb_cObject, NULL, -1, memory_pool );
1237
+ paramsData->heap_pool = TypedData_Wrap_Struct( rb_cObject, &pg_query_heap_pool_type, memory_pool );
1118
1238
  required_pool_size = 0;
1119
1239
  }else{
1120
1240
  /* Use stack memory for function parameters */
@@ -1227,12 +1347,11 @@ pgconn_query_assign_typemap( VALUE self, struct query_params_data *paramsData )
1227
1347
  /* Use default typemap for queries. It's type is checked when assigned. */
1228
1348
  paramsData->typemap = pg_get_connection(self)->type_map_for_queries;
1229
1349
  }else{
1350
+ t_typemap *tm;
1351
+ UNUSED(tm);
1352
+
1230
1353
  /* Check type of method param */
1231
- if ( !rb_obj_is_kind_of(paramsData->typemap, rb_cTypeMap) ) {
1232
- rb_raise( rb_eTypeError, "wrong argument type %s (expected kind of PG::TypeMap)",
1233
- rb_obj_classname( paramsData->typemap ) );
1234
- }
1235
- Check_Type( paramsData->typemap, T_DATA );
1354
+ TypedData_Get_Struct(paramsData->typemap, t_typemap, &pg_typemap_type, tm);
1236
1355
  }
1237
1356
  }
1238
1357
 
@@ -1454,6 +1573,9 @@ pgconn_describe_portal(self, stmt_name)
1454
1573
  * * +PGRES_NONFATAL_ERROR+
1455
1574
  * * +PGRES_FATAL_ERROR+
1456
1575
  * * +PGRES_COPY_BOTH+
1576
+ * * +PGRES_SINGLE_TUPLE+
1577
+ * * +PGRES_PIPELINE_SYNC+
1578
+ * * +PGRES_PIPELINE_ABORTED+
1457
1579
  */
1458
1580
  static VALUE
1459
1581
  pgconn_make_empty_pgresult(VALUE self, VALUE status)
@@ -1750,6 +1872,7 @@ pgconn_send_query(int argc, VALUE *argv, VALUE self)
1750
1872
  rb_iv_set(error, "@connection", self);
1751
1873
  rb_exc_raise(error);
1752
1874
  }
1875
+ pgconn_wait_for_flush( self );
1753
1876
  return Qnil;
1754
1877
  }
1755
1878
 
@@ -1779,7 +1902,7 @@ pgconn_send_query(int argc, VALUE *argv, VALUE self)
1779
1902
  * or, it may be a String. If it is a string, that is equivalent to the hash:
1780
1903
  * { :value => <string value>, :type => 0, :format => 0 }
1781
1904
  *
1782
- * PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
1905
+ * PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
1783
1906
  * inside the SQL query. The 0th element of the +params+ array is bound
1784
1907
  * to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
1785
1908
  *
@@ -1827,6 +1950,7 @@ pgconn_send_query_params(int argc, VALUE *argv, VALUE self)
1827
1950
  rb_iv_set(error, "@connection", self);
1828
1951
  rb_exc_raise(error);
1829
1952
  }
1953
+ pgconn_wait_for_flush( self );
1830
1954
  return Qnil;
1831
1955
  }
1832
1956
 
@@ -1847,7 +1971,7 @@ pgconn_send_query_params(int argc, VALUE *argv, VALUE self)
1847
1971
  *
1848
1972
  * For example: "SELECT $1::int"
1849
1973
  *
1850
- * PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
1974
+ * PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
1851
1975
  * inside the SQL query.
1852
1976
  */
1853
1977
  static VALUE
@@ -1890,6 +2014,7 @@ pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
1890
2014
  rb_iv_set(error, "@connection", self);
1891
2015
  rb_exc_raise(error);
1892
2016
  }
2017
+ pgconn_wait_for_flush( self );
1893
2018
  return Qnil;
1894
2019
  }
1895
2020
 
@@ -1911,7 +2036,7 @@ pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
1911
2036
  * or, it may be a String. If it is a string, that is equivalent to the hash:
1912
2037
  * { :value => <string value>, :format => 0 }
1913
2038
  *
1914
- * PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
2039
+ * PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
1915
2040
  * inside the SQL query. The 0th element of the +params+ array is bound
1916
2041
  * to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
1917
2042
  *
@@ -1941,7 +2066,6 @@ pgconn_send_query_prepared(int argc, VALUE *argv, VALUE self)
1941
2066
 
1942
2067
  if(NIL_P(paramsData.params)) {
1943
2068
  paramsData.params = rb_ary_new2(0);
1944
- resultFormat = 0;
1945
2069
  }
1946
2070
  pgconn_query_assign_typemap( self, &paramsData );
1947
2071
 
@@ -1959,6 +2083,7 @@ pgconn_send_query_prepared(int argc, VALUE *argv, VALUE self)
1959
2083
  rb_iv_set(error, "@connection", self);
1960
2084
  rb_exc_raise(error);
1961
2085
  }
2086
+ pgconn_wait_for_flush( self );
1962
2087
  return Qnil;
1963
2088
  }
1964
2089
 
@@ -1980,6 +2105,7 @@ pgconn_send_describe_prepared(VALUE self, VALUE stmt_name)
1980
2105
  rb_iv_set(error, "@connection", self);
1981
2106
  rb_exc_raise(error);
1982
2107
  }
2108
+ pgconn_wait_for_flush( self );
1983
2109
  return Qnil;
1984
2110
  }
1985
2111
 
@@ -2002,6 +2128,7 @@ pgconn_send_describe_portal(VALUE self, VALUE portal)
2002
2128
  rb_iv_set(error, "@connection", self);
2003
2129
  rb_exc_raise(error);
2004
2130
  }
2131
+ pgconn_wait_for_flush( self );
2005
2132
  return Qnil;
2006
2133
  }
2007
2134
 
@@ -2141,8 +2268,7 @@ pgconn_isnonblocking(self)
2141
2268
  * Raises PG::Error if some other failure occurred.
2142
2269
  */
2143
2270
  static VALUE
2144
- pgconn_flush(self)
2145
- VALUE self;
2271
+ pgconn_sync_flush(VALUE self)
2146
2272
  {
2147
2273
  PGconn *conn = pg_get_pgconn(self);
2148
2274
  int ret;
@@ -2161,7 +2287,7 @@ pgconn_flush(self)
2161
2287
  * conn.cancel() -> String
2162
2288
  *
2163
2289
  * Requests cancellation of the command currently being
2164
- * processed. (Only implemented in PostgreSQL >= 8.0)
2290
+ * processed.
2165
2291
  *
2166
2292
  * Returns +nil+ on success, or a string containing the
2167
2293
  * error message if a failure occurs.
@@ -2178,7 +2304,7 @@ pgconn_cancel(VALUE self)
2178
2304
  if(cancel == NULL)
2179
2305
  rb_raise(rb_ePGerror,"Invalid connection!");
2180
2306
 
2181
- ret = gvl_PQcancel(cancel, errbuf, 256);
2307
+ ret = gvl_PQcancel(cancel, errbuf, sizeof(errbuf));
2182
2308
  if(ret == 1)
2183
2309
  retval = Qnil;
2184
2310
  else
@@ -2229,103 +2355,44 @@ pgconn_notifies(VALUE self)
2229
2355
  return hash;
2230
2356
  }
2231
2357
 
2232
- /* Win32 + Ruby 1.9+ */
2233
- #if defined( _WIN32 )
2234
- /*
2235
- * On Windows, use platform-specific strategies to wait for the socket
2236
- * instead of rb_wait_for_single_fd().
2237
- */
2238
-
2239
- int rb_w32_wait_events( HANDLE *events, int num, DWORD timeout );
2240
-
2241
- static void *
2242
- wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readable)(PGconn *) )
2243
- {
2244
- int sd = PQsocket( conn );
2245
- void *retval;
2246
- struct timeval aborttime={0,0}, currtime, waittime;
2247
- DWORD timeout_milisec = INFINITE;
2248
- DWORD wait_ret;
2249
- WSAEVENT hEvent;
2250
-
2251
- if ( sd < 0 )
2252
- rb_raise(rb_eConnectionBad, "PQsocket() can't get socket descriptor");
2253
2358
 
2254
- hEvent = WSACreateEvent();
2359
+ #if !defined(HAVE_RB_IO_WAIT)
2360
+ /* For compat with ruby < 3.0 */
2255
2361
 
2256
- /* Check for connection errors (PQisBusy is true on connection errors) */
2257
- if( PQconsumeInput(conn) == 0 ) {
2258
- WSACloseEvent( hEvent );
2259
- rb_raise( rb_eConnectionBad, "PQconsumeInput() %s", PQerrorMessage(conn) );
2260
- }
2362
+ typedef enum {
2363
+ RUBY_IO_READABLE = RB_WAITFD_IN,
2364
+ RUBY_IO_WRITABLE = RB_WAITFD_OUT,
2365
+ RUBY_IO_PRIORITY = RB_WAITFD_PRI,
2366
+ } rb_io_event_t;
2261
2367
 
2262
- if ( ptimeout ) {
2263
- gettimeofday(&currtime, NULL);
2264
- timeradd(&currtime, ptimeout, &aborttime);
2265
- }
2266
-
2267
- while ( !(retval=is_readable(conn)) ) {
2268
- if ( WSAEventSelect(sd, hEvent, FD_READ|FD_CLOSE) == SOCKET_ERROR ) {
2269
- WSACloseEvent( hEvent );
2270
- rb_raise( rb_eConnectionBad, "WSAEventSelect socket error: %d", WSAGetLastError() );
2271
- }
2272
-
2273
- if ( ptimeout ) {
2274
- gettimeofday(&currtime, NULL);
2275
- timersub(&aborttime, &currtime, &waittime);
2276
- timeout_milisec = (DWORD)( waittime.tv_sec * 1e3 + waittime.tv_usec / 1e3 );
2277
- }
2278
-
2279
- /* Is the given timeout valid? */
2280
- if( !ptimeout || (waittime.tv_sec >= 0 && waittime.tv_usec >= 0) ){
2281
- /* Wait for the socket to become readable before checking again */
2282
- wait_ret = rb_w32_wait_events( &hEvent, 1, timeout_milisec );
2283
- } else {
2284
- wait_ret = WAIT_TIMEOUT;
2285
- }
2286
-
2287
- if ( wait_ret == WAIT_TIMEOUT ) {
2288
- WSACloseEvent( hEvent );
2289
- return NULL;
2290
- } else if ( wait_ret == WAIT_OBJECT_0 ) {
2291
- /* The event we were waiting for. */
2292
- } else if ( wait_ret == WAIT_OBJECT_0 + 1) {
2293
- /* This indicates interruption from timer thread, GC, exception
2294
- * from other threads etc... */
2295
- rb_thread_check_ints();
2296
- } else if ( wait_ret == WAIT_FAILED ) {
2297
- WSACloseEvent( hEvent );
2298
- rb_raise( rb_eConnectionBad, "Wait on socket error (WaitForMultipleObjects): %lu", GetLastError() );
2299
- } else {
2300
- WSACloseEvent( hEvent );
2301
- rb_raise( rb_eConnectionBad, "Wait on socket abandoned (WaitForMultipleObjects)" );
2302
- }
2303
-
2304
- /* Check for connection errors (PQisBusy is true on connection errors) */
2305
- if ( PQconsumeInput(conn) == 0 ) {
2306
- WSACloseEvent( hEvent );
2307
- rb_raise( rb_eConnectionBad, "PQconsumeInput() %s", PQerrorMessage(conn) );
2308
- }
2368
+ static VALUE
2369
+ rb_io_wait(VALUE io, VALUE events, VALUE timeout) {
2370
+ rb_io_t *fptr;
2371
+ struct timeval waittime;
2372
+ int res;
2373
+
2374
+ GetOpenFile((io), fptr);
2375
+ if( !NIL_P(timeout) ){
2376
+ waittime.tv_sec = (time_t)(NUM2DBL(timeout));
2377
+ waittime.tv_usec = (time_t)(NUM2DBL(timeout) - (double)waittime.tv_sec);
2309
2378
  }
2379
+ res = rb_wait_for_single_fd(fptr->fd, NUM2UINT(events), NIL_P(timeout) ? NULL : &waittime);
2310
2380
 
2311
- WSACloseEvent( hEvent );
2312
- return retval;
2381
+ return UINT2NUM(res);
2313
2382
  }
2314
-
2315
- #else
2316
-
2317
- /* non Win32 */
2383
+ #endif
2318
2384
 
2319
2385
  static void *
2320
- wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readable)(PGconn *))
2386
+ wait_socket_readable( VALUE self, struct timeval *ptimeout, void *(*is_readable)(PGconn *))
2321
2387
  {
2322
- int sd = PQsocket( conn );
2323
- int ret;
2388
+ VALUE socket_io;
2389
+ VALUE ret;
2324
2390
  void *retval;
2325
2391
  struct timeval aborttime={0,0}, currtime, waittime;
2392
+ VALUE wait_timeout = Qnil;
2393
+ PGconn *conn = pg_get_pgconn(self);
2326
2394
 
2327
- if ( sd < 0 )
2328
- rb_raise(rb_eConnectionBad, "PQsocket() can't get socket descriptor");
2395
+ socket_io = pgconn_socket_io(self);
2329
2396
 
2330
2397
  /* Check for connection errors (PQisBusy is true on connection errors) */
2331
2398
  if ( PQconsumeInput(conn) == 0 )
@@ -2340,22 +2407,19 @@ wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readabl
2340
2407
  if ( ptimeout ) {
2341
2408
  gettimeofday(&currtime, NULL);
2342
2409
  timersub(&aborttime, &currtime, &waittime);
2410
+ wait_timeout = DBL2NUM((double)(waittime.tv_sec) + (double)(waittime.tv_usec) / 1000000.0);
2343
2411
  }
2344
2412
 
2345
2413
  /* Is the given timeout valid? */
2346
2414
  if( !ptimeout || (waittime.tv_sec >= 0 && waittime.tv_usec >= 0) ){
2347
2415
  /* Wait for the socket to become readable before checking again */
2348
- ret = rb_wait_for_single_fd( sd, RB_WAITFD_IN, ptimeout ? &waittime : NULL );
2416
+ ret = rb_io_wait(socket_io, RB_INT2NUM(RUBY_IO_READABLE), wait_timeout);
2349
2417
  } else {
2350
- ret = 0;
2351
- }
2352
-
2353
- if ( ret < 0 ){
2354
- rb_sys_fail( "rb_wait_for_single_fd()" );
2418
+ ret = Qfalse;
2355
2419
  }
2356
2420
 
2357
2421
  /* Return false if the select() timed out */
2358
- if ( ret == 0 ){
2422
+ if ( ret == Qfalse ){
2359
2423
  return NULL;
2360
2424
  }
2361
2425
 
@@ -2368,8 +2432,35 @@ wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readabl
2368
2432
  return retval;
2369
2433
  }
2370
2434
 
2435
+ static VALUE
2436
+ pgconn_async_flush(VALUE self)
2437
+ {
2438
+ while( pgconn_sync_flush(self) == Qfalse ){
2439
+ /* wait for the socket to become read- or write-ready */
2440
+ int events;
2441
+ VALUE socket_io = pgconn_socket_io(self);
2442
+ events = RB_NUM2INT(rb_io_wait(socket_io, RB_INT2NUM(RUBY_IO_READABLE | RUBY_IO_WRITABLE), Qnil));
2371
2443
 
2372
- #endif
2444
+ if (events & RUBY_IO_READABLE)
2445
+ pgconn_consume_input(self);
2446
+ }
2447
+ return Qtrue;
2448
+ }
2449
+
2450
+ static VALUE
2451
+ pgconn_wait_for_flush( VALUE self ){
2452
+ if( !pg_get_connection_safe(self)->flush_data )
2453
+ return Qnil;
2454
+
2455
+ return pgconn_async_flush(self);
2456
+ }
2457
+
2458
+ static VALUE
2459
+ pgconn_flush_data_set( VALUE self, VALUE enabled ){
2460
+ t_pg_connection *conn = pg_get_connection(self);
2461
+ conn->flush_data = RTEST(enabled);
2462
+ return enabled;
2463
+ }
2373
2464
 
2374
2465
  static void *
2375
2466
  notify_readable(PGconn *conn)
@@ -2408,7 +2499,7 @@ pgconn_wait_for_notify(int argc, VALUE *argv, VALUE self)
2408
2499
  ptimeout = &timeout;
2409
2500
  }
2410
2501
 
2411
- pnotification = (PGnotify*) wait_socket_readable( this->pgconn, ptimeout, notify_readable);
2502
+ pnotification = (PGnotify*) wait_socket_readable( self, ptimeout, notify_readable);
2412
2503
 
2413
2504
  /* Return nil if the select timed out */
2414
2505
  if ( !pnotification ) return Qnil;
@@ -2467,13 +2558,11 @@ pgconn_put_copy_data(int argc, VALUE *argv, VALUE self)
2467
2558
  if( NIL_P(this->encoder_for_put_copy_data) ){
2468
2559
  buffer = value;
2469
2560
  } else {
2470
- p_coder = DATA_PTR( this->encoder_for_put_copy_data );
2561
+ p_coder = RTYPEDDATA_DATA( this->encoder_for_put_copy_data );
2471
2562
  }
2472
- } else if( rb_obj_is_kind_of(encoder, rb_cPG_Coder) ) {
2473
- Data_Get_Struct( encoder, t_pg_coder, p_coder );
2474
2563
  } else {
2475
- rb_raise( rb_eTypeError, "wrong encoder type %s (expected some kind of PG::Coder)",
2476
- rb_obj_classname( encoder ) );
2564
+ /* Check argument type and use argument encoder */
2565
+ TypedData_Get_Struct(encoder, t_pg_coder, &pg_coder_type, p_coder);
2477
2566
  }
2478
2567
 
2479
2568
  if( p_coder ){
@@ -2517,8 +2606,8 @@ pgconn_put_copy_data(int argc, VALUE *argv, VALUE self)
2517
2606
  * forces the COPY command to fail with the string
2518
2607
  * _error_message_.
2519
2608
  *
2520
- * Returns true if the end-of-data was sent, false if it was
2521
- * not sent (false is only possible if the connection
2609
+ * Returns true if the end-of-data was sent, *false* if it was
2610
+ * not sent (*false* is only possible if the connection
2522
2611
  * is in nonblocking mode, and this command would block).
2523
2612
  */
2524
2613
  static VALUE
@@ -2546,11 +2635,11 @@ pgconn_put_copy_end(int argc, VALUE *argv, VALUE self)
2546
2635
 
2547
2636
  /*
2548
2637
  * call-seq:
2549
- * conn.get_copy_data( [ async = false [, decoder = nil ]] ) -> Object
2638
+ * conn.get_copy_data( [ nonblock = false [, decoder = nil ]] ) -> Object
2550
2639
  *
2551
2640
  * Return one row of data, +nil+
2552
2641
  * if the copy is done, or +false+ if the call would
2553
- * block (only possible if _async_ is true).
2642
+ * block (only possible if _nonblock_ is true).
2554
2643
  *
2555
2644
  * If _decoder_ is not set or +nil+, data is returned as binary string.
2556
2645
  *
@@ -2579,13 +2668,11 @@ pgconn_get_copy_data(int argc, VALUE *argv, VALUE self )
2579
2668
 
2580
2669
  if( NIL_P(decoder) ){
2581
2670
  if( !NIL_P(this->decoder_for_get_copy_data) ){
2582
- p_coder = DATA_PTR( this->decoder_for_get_copy_data );
2671
+ p_coder = RTYPEDDATA_DATA( this->decoder_for_get_copy_data );
2583
2672
  }
2584
- } else if( rb_obj_is_kind_of(decoder, rb_cPG_Coder) ) {
2585
- Data_Get_Struct( decoder, t_pg_coder, p_coder );
2586
2673
  } else {
2587
- rb_raise( rb_eTypeError, "wrong decoder type %s (expected some kind of PG::Coder)",
2588
- rb_obj_classname( decoder ) );
2674
+ /* Check argument type and use argument decoder */
2675
+ TypedData_Get_Struct(decoder, t_pg_coder, &pg_coder_type, p_coder);
2589
2676
  }
2590
2677
 
2591
2678
  ret = gvl_PQgetCopyData(this->pgconn, &buffer, RTEST(async_in));
@@ -2830,7 +2917,7 @@ notice_processor_proxy(void *arg, const char *message)
2830
2917
  * call-seq:
2831
2918
  * conn.set_notice_processor {|message| ... } -> Proc
2832
2919
  *
2833
- * See #set_notice_receiver for the desription of what this and the
2920
+ * See #set_notice_receiver for the description of what this and the
2834
2921
  * notice_processor methods do.
2835
2922
  *
2836
2923
  * This function takes a new block to act as the notice processor and returns
@@ -2884,9 +2971,11 @@ pgconn_get_client_encoding(VALUE self)
2884
2971
 
2885
2972
  /*
2886
2973
  * call-seq:
2887
- * conn.set_client_encoding( encoding )
2974
+ * conn.sync_set_client_encoding( encoding )
2888
2975
  *
2889
- * Sets the client encoding to the _encoding_ String.
2976
+ * This function has the same behavior as #async_set_client_encoding, but is implemented using the synchronous command processing API of libpq.
2977
+ * See #async_exec for the differences between the two API variants.
2978
+ * It's not recommended to use explicit sync or async variants but #set_client_encoding instead, unless you have a good reason to do so.
2890
2979
  */
2891
2980
  static VALUE
2892
2981
  pgconn_set_client_encoding(VALUE self, VALUE str)
@@ -2903,49 +2992,6 @@ pgconn_set_client_encoding(VALUE self, VALUE str)
2903
2992
  return Qnil;
2904
2993
  }
2905
2994
 
2906
- /*
2907
- * call-seq:
2908
- * conn.transaction { |conn| ... } -> result of the block
2909
- *
2910
- * Executes a +BEGIN+ at the start of the block,
2911
- * and a +COMMIT+ at the end of the block, or
2912
- * +ROLLBACK+ if any exception occurs.
2913
- */
2914
- static VALUE
2915
- pgconn_transaction(VALUE self)
2916
- {
2917
- PGconn *conn = pg_get_pgconn(self);
2918
- PGresult *result;
2919
- VALUE rb_pgresult;
2920
- VALUE block_result = Qnil;
2921
- int status;
2922
-
2923
- if (rb_block_given_p()) {
2924
- result = gvl_PQexec(conn, "BEGIN");
2925
- rb_pgresult = pg_new_result(result, self);
2926
- pg_result_check(rb_pgresult);
2927
- block_result = rb_protect(rb_yield, self, &status);
2928
- if(status == 0) {
2929
- result = gvl_PQexec(conn, "COMMIT");
2930
- rb_pgresult = pg_new_result(result, self);
2931
- pg_result_check(rb_pgresult);
2932
- }
2933
- else {
2934
- /* exception occurred, ROLLBACK and re-raise */
2935
- result = gvl_PQexec(conn, "ROLLBACK");
2936
- rb_pgresult = pg_new_result(result, self);
2937
- pg_result_check(rb_pgresult);
2938
- rb_jump_tag(status);
2939
- }
2940
-
2941
- }
2942
- else {
2943
- /* no block supplied? */
2944
- rb_raise(rb_eArgError, "Must supply block for PG::Connection#transaction");
2945
- }
2946
- return block_result;
2947
- }
2948
-
2949
2995
 
2950
2996
  /*
2951
2997
  * call-seq:
@@ -3022,8 +3068,6 @@ get_result_readable(PGconn *conn)
3022
3068
  */
3023
3069
  static VALUE
3024
3070
  pgconn_block( int argc, VALUE *argv, VALUE self ) {
3025
- PGconn *conn = pg_get_pgconn( self );
3026
-
3027
3071
  struct timeval timeout;
3028
3072
  struct timeval *ptimeout = NULL;
3029
3073
  VALUE timeout_in;
@@ -3037,7 +3081,7 @@ pgconn_block( int argc, VALUE *argv, VALUE self ) {
3037
3081
  ptimeout = &timeout;
3038
3082
  }
3039
3083
 
3040
- ret = wait_socket_readable( conn, ptimeout, get_result_readable);
3084
+ ret = wait_socket_readable( self, ptimeout, get_result_readable);
3041
3085
 
3042
3086
  if( !ret )
3043
3087
  return Qfalse;
@@ -3046,6 +3090,42 @@ pgconn_block( int argc, VALUE *argv, VALUE self ) {
3046
3090
  }
3047
3091
 
3048
3092
 
3093
+ /*
3094
+ * call-seq:
3095
+ * conn.sync_get_last_result( ) -> PG::Result
3096
+ *
3097
+ * This function has the same behavior as #async_get_last_result, but is implemented using the synchronous command processing API of libpq.
3098
+ * See #async_exec for the differences between the two API variants.
3099
+ * It's not recommended to use explicit sync or async variants but #get_last_result instead, unless you have a good reason to do so.
3100
+ */
3101
+ static VALUE
3102
+ pgconn_get_last_result(VALUE self)
3103
+ {
3104
+ PGconn *conn = pg_get_pgconn(self);
3105
+ VALUE rb_pgresult = Qnil;
3106
+ PGresult *cur, *prev;
3107
+
3108
+
3109
+ cur = prev = NULL;
3110
+ while ((cur = gvl_PQgetResult(conn)) != NULL) {
3111
+ int status;
3112
+
3113
+ if (prev) PQclear(prev);
3114
+ prev = cur;
3115
+
3116
+ status = PQresultStatus(cur);
3117
+ if (status == PGRES_COPY_OUT || status == PGRES_COPY_IN || status == PGRES_COPY_BOTH)
3118
+ break;
3119
+ }
3120
+
3121
+ if (prev) {
3122
+ rb_pgresult = pg_new_result( prev, self );
3123
+ pg_result_check(rb_pgresult);
3124
+ }
3125
+
3126
+ return rb_pgresult;
3127
+ }
3128
+
3049
3129
  /*
3050
3130
  * call-seq:
3051
3131
  * conn.get_last_result( ) -> PG::Result
@@ -3056,27 +3136,35 @@ pgconn_block( int argc, VALUE *argv, VALUE self ) {
3056
3136
  * returns the last non-NULL result, or +nil+ if no
3057
3137
  * results are available.
3058
3138
  *
3139
+ * If the last result contains a bad result_status, an
3140
+ * appropriate exception is raised.
3141
+ *
3059
3142
  * This function is similar to #get_result
3060
3143
  * except that it is designed to get one and only
3061
- * one result.
3144
+ * one result and that it checks the result state.
3062
3145
  */
3063
3146
  static VALUE
3064
- pgconn_get_last_result(VALUE self)
3147
+ pgconn_async_get_last_result(VALUE self)
3065
3148
  {
3066
3149
  PGconn *conn = pg_get_pgconn(self);
3067
3150
  VALUE rb_pgresult = Qnil;
3068
3151
  PGresult *cur, *prev;
3069
3152
 
3070
-
3071
- cur = prev = NULL;
3072
- while ((cur = gvl_PQgetResult(conn)) != NULL) {
3153
+ cur = prev = NULL;
3154
+ for(;;) {
3073
3155
  int status;
3074
3156
 
3157
+ pgconn_block( 0, NULL, self ); /* wait for input (without blocking) before reading the last result */
3158
+
3159
+ cur = gvl_PQgetResult(conn);
3160
+ if (cur == NULL)
3161
+ break;
3162
+
3075
3163
  if (prev) PQclear(prev);
3076
3164
  prev = cur;
3077
3165
 
3078
3166
  status = PQresultStatus(cur);
3079
- if (status == PGRES_COPY_OUT || status == PGRES_COPY_IN)
3167
+ if (status == PGRES_COPY_OUT || status == PGRES_COPY_IN || status == PGRES_COPY_BOTH)
3080
3168
  break;
3081
3169
  }
3082
3170
 
@@ -3100,22 +3188,56 @@ static VALUE
3100
3188
  pgconn_discard_results(VALUE self)
3101
3189
  {
3102
3190
  PGconn *conn = pg_get_pgconn(self);
3191
+ VALUE socket_io;
3103
3192
 
3104
- PGresult *cur;
3105
- while ((cur = gvl_PQgetResult(conn)) != NULL) {
3106
- int status = PQresultStatus(cur);
3193
+ if( PQtransactionStatus(conn) == PQTRANS_IDLE ) {
3194
+ return Qnil;
3195
+ }
3196
+
3197
+ socket_io = pgconn_socket_io(self);
3198
+
3199
+ for(;;) {
3200
+ PGresult *cur;
3201
+ int status;
3202
+
3203
+ /* pgconn_block() raises an exception in case of errors.
3204
+ * To avoid this call rb_io_wait() and PQconsumeInput() without rb_raise().
3205
+ */
3206
+ while( gvl_PQisBusy(conn) ){
3207
+ rb_io_wait(socket_io, RB_INT2NUM(RUBY_IO_READABLE), Qnil);
3208
+ if ( PQconsumeInput(conn) == 0 )
3209
+ return Qfalse;
3210
+ }
3211
+
3212
+ cur = gvl_PQgetResult(conn);
3213
+ if( cur == NULL) break;
3214
+
3215
+ status = PQresultStatus(cur);
3107
3216
  PQclear(cur);
3108
3217
  if (status == PGRES_COPY_IN){
3109
3218
  gvl_PQputCopyEnd(conn, "COPY terminated by new PQexec");
3110
3219
  }
3111
3220
  if (status == PGRES_COPY_OUT){
3112
- char *buffer = NULL;
3113
- while( gvl_PQgetCopyData(conn, &buffer, 0) > 0)
3114
- PQfreemem(buffer);
3221
+ for(;;) {
3222
+ char *buffer = NULL;
3223
+ int st = gvl_PQgetCopyData(conn, &buffer, 1);
3224
+ if( st == 0 ) {
3225
+ /* would block -> wait for readable data */
3226
+ rb_io_wait(socket_io, RB_INT2NUM(RUBY_IO_READABLE), Qnil);
3227
+ if ( PQconsumeInput(conn) == 0 )
3228
+ return Qfalse;
3229
+ } else if( st > 0 ) {
3230
+ /* some data retrieved -> discard it */
3231
+ PQfreemem(buffer);
3232
+ } else {
3233
+ /* no more data */
3234
+ break;
3235
+ }
3236
+ }
3115
3237
  }
3116
3238
  }
3117
3239
 
3118
- return Qnil;
3240
+ return Qtrue;
3119
3241
  }
3120
3242
 
3121
3243
  /*
@@ -3152,8 +3274,7 @@ pgconn_async_exec(int argc, VALUE *argv, VALUE self)
3152
3274
 
3153
3275
  pgconn_discard_results( self );
3154
3276
  pgconn_send_query( argc, argv, self );
3155
- pgconn_block( 0, NULL, self ); /* wait for input (without blocking) before reading the last result */
3156
- rb_pgresult = pgconn_get_last_result( self );
3277
+ rb_pgresult = pgconn_async_get_last_result( self );
3157
3278
 
3158
3279
  if ( rb_block_given_p() ) {
3159
3280
  return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
@@ -3182,7 +3303,7 @@ pgconn_async_exec(int argc, VALUE *argv, VALUE self)
3182
3303
  * or, it may be a String. If it is a string, that is equivalent to the hash:
3183
3304
  * { :value => <string value>, :type => 0, :format => 0 }
3184
3305
  *
3185
- * PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
3306
+ * PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
3186
3307
  * inside the SQL query. The 0th element of the +params+ array is bound
3187
3308
  * to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
3188
3309
  *
@@ -3225,8 +3346,7 @@ pgconn_async_exec_params(int argc, VALUE *argv, VALUE self)
3225
3346
  } else {
3226
3347
  pgconn_send_query_params( argc, argv, self );
3227
3348
  }
3228
- pgconn_block( 0, NULL, self ); /* wait for input (without blocking) before reading the last result */
3229
- rb_pgresult = pgconn_get_last_result( self );
3349
+ rb_pgresult = pgconn_async_get_last_result( self );
3230
3350
 
3231
3351
  if ( rb_block_given_p() ) {
3232
3352
  return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
@@ -3252,7 +3372,7 @@ pgconn_async_exec_params(int argc, VALUE *argv, VALUE self)
3252
3372
  *
3253
3373
  * For example: "SELECT $1::int"
3254
3374
  *
3255
- * PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
3375
+ * PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
3256
3376
  * inside the SQL query.
3257
3377
  *
3258
3378
  * See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQPREPARE].
@@ -3264,8 +3384,7 @@ pgconn_async_prepare(int argc, VALUE *argv, VALUE self)
3264
3384
 
3265
3385
  pgconn_discard_results( self );
3266
3386
  pgconn_send_prepare( argc, argv, self );
3267
- pgconn_block( 0, NULL, self ); /* wait for input (without blocking) before reading the last result */
3268
- rb_pgresult = pgconn_get_last_result( self );
3387
+ rb_pgresult = pgconn_async_get_last_result( self );
3269
3388
 
3270
3389
  if ( rb_block_given_p() ) {
3271
3390
  return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
@@ -3292,7 +3411,7 @@ pgconn_async_prepare(int argc, VALUE *argv, VALUE self)
3292
3411
  * or, it may be a String. If it is a string, that is equivalent to the hash:
3293
3412
  * { :value => <string value>, :format => 0 }
3294
3413
  *
3295
- * PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
3414
+ * PostgreSQL bind parameters are represented as $1, $2, $3, etc.,
3296
3415
  * inside the SQL query. The 0th element of the +params+ array is bound
3297
3416
  * to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
3298
3417
  *
@@ -3318,8 +3437,7 @@ pgconn_async_exec_prepared(int argc, VALUE *argv, VALUE self)
3318
3437
 
3319
3438
  pgconn_discard_results( self );
3320
3439
  pgconn_send_query_prepared( argc, argv, self );
3321
- pgconn_block( 0, NULL, self ); /* wait for input (without blocking) before reading the last result */
3322
- rb_pgresult = pgconn_get_last_result( self );
3440
+ rb_pgresult = pgconn_async_get_last_result( self );
3323
3441
 
3324
3442
  if ( rb_block_given_p() ) {
3325
3443
  return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
@@ -3343,8 +3461,7 @@ pgconn_async_describe_portal(VALUE self, VALUE portal)
3343
3461
 
3344
3462
  pgconn_discard_results( self );
3345
3463
  pgconn_send_describe_portal( self, portal );
3346
- pgconn_block( 0, NULL, self ); /* wait for input (without blocking) before reading the last result */
3347
- rb_pgresult = pgconn_get_last_result( self );
3464
+ rb_pgresult = pgconn_async_get_last_result( self );
3348
3465
 
3349
3466
  if ( rb_block_given_p() ) {
3350
3467
  return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
@@ -3368,8 +3485,7 @@ pgconn_async_describe_prepared(VALUE self, VALUE stmt_name)
3368
3485
 
3369
3486
  pgconn_discard_results( self );
3370
3487
  pgconn_send_describe_prepared( self, stmt_name );
3371
- pgconn_block( 0, NULL, self ); /* wait for input (without blocking) before reading the last result */
3372
- rb_pgresult = pgconn_get_last_result( self );
3488
+ rb_pgresult = pgconn_async_get_last_result( self );
3373
3489
 
3374
3490
  if ( rb_block_given_p() ) {
3375
3491
  return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
@@ -3457,6 +3573,126 @@ pgconn_ssl_attribute_names(VALUE self)
3457
3573
  #endif
3458
3574
 
3459
3575
 
3576
+ #ifdef HAVE_PQENTERPIPELINEMODE
3577
+ /*
3578
+ * call-seq:
3579
+ * conn.pipeline_status -> Integer
3580
+ *
3581
+ * Returns the current pipeline mode status of the libpq connection.
3582
+ *
3583
+ * PQpipelineStatus can return one of the following values:
3584
+ *
3585
+ * * PQ_PIPELINE_ON - The libpq connection is in pipeline mode.
3586
+ * * PQ_PIPELINE_OFF - The libpq connection is not in pipeline mode.
3587
+ * * PQ_PIPELINE_ABORTED - The libpq connection is in pipeline mode and an error occurred while processing the current pipeline.
3588
+ * The aborted flag is cleared when PQgetResult returns a result of type PGRES_PIPELINE_SYNC.
3589
+ *
3590
+ * Available since PostgreSQL-14
3591
+ */
3592
+ static VALUE
3593
+ pgconn_pipeline_status(VALUE self)
3594
+ {
3595
+ int res = PQpipelineStatus(pg_get_pgconn(self));
3596
+ return INT2FIX(res);
3597
+ }
3598
+
3599
+
3600
+ /*
3601
+ * call-seq:
3602
+ * conn.enter_pipeline_mode -> nil
3603
+ *
3604
+ * Causes a connection to enter pipeline mode if it is currently idle or already in pipeline mode.
3605
+ *
3606
+ * 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.
3607
+ * This function does not actually send anything to the server, it just changes the libpq connection state.
3608
+ *
3609
+ * Available since PostgreSQL-14
3610
+ */
3611
+ static VALUE
3612
+ pgconn_enter_pipeline_mode(VALUE self)
3613
+ {
3614
+ PGconn *conn = pg_get_pgconn(self);
3615
+ int res = PQenterPipelineMode(conn);
3616
+ if( res == 1 ) {
3617
+ return Qnil;
3618
+ } else {
3619
+ rb_raise(rb_ePGerror, "%s", PQerrorMessage(conn));
3620
+ }
3621
+ }
3622
+
3623
+ /*
3624
+ * call-seq:
3625
+ * conn.exit_pipeline_mode -> nil
3626
+ *
3627
+ * Causes a connection to exit pipeline mode if it is currently in pipeline mode with an empty queue and no pending results.
3628
+ *
3629
+ * Takes no action if not in pipeline mode.
3630
+ * Raises PG::Error if the current statement isn't finished processing, or PQgetResult has not been called to collect results from all previously sent query.
3631
+ *
3632
+ * Available since PostgreSQL-14
3633
+ */
3634
+ static VALUE
3635
+ pgconn_exit_pipeline_mode(VALUE self)
3636
+ {
3637
+ PGconn *conn = pg_get_pgconn(self);
3638
+ int res = PQexitPipelineMode(conn);
3639
+ if( res == 1 ) {
3640
+ return Qnil;
3641
+ } else {
3642
+ rb_raise(rb_ePGerror, "%s", PQerrorMessage(conn));
3643
+ }
3644
+ }
3645
+
3646
+
3647
+ /*
3648
+ * call-seq:
3649
+ * conn.pipeline_sync -> nil
3650
+ *
3651
+ * Marks a synchronization point in a pipeline by sending a sync message and flushing the send buffer.
3652
+ * This serves as the delimiter of an implicit transaction and an error recovery point; see Section 34.5.1.3 of the PostgreSQL documentation.
3653
+ *
3654
+ * Raises PG::Error if the connection is not in pipeline mode or sending a sync message failed.
3655
+ *
3656
+ * Available since PostgreSQL-14
3657
+ */
3658
+ static VALUE
3659
+ pgconn_pipeline_sync(VALUE self)
3660
+ {
3661
+ PGconn *conn = pg_get_pgconn(self);
3662
+ int res = PQpipelineSync(conn);
3663
+ if( res == 1 ) {
3664
+ return Qnil;
3665
+ } else {
3666
+ rb_raise(rb_ePGerror, "%s", PQerrorMessage(conn));
3667
+ }
3668
+ }
3669
+
3670
+ /*
3671
+ * call-seq:
3672
+ * conn.pipeline_sync -> nil
3673
+ *
3674
+ * Sends a request for the server to flush its output buffer.
3675
+ *
3676
+ * The server flushes its output buffer automatically as a result of Connection#pipeline_sync being called, or on any request when not in pipeline mode.
3677
+ * This function is useful to cause the server to flush its output buffer in pipeline mode without establishing a synchronization point.
3678
+ * Note that the request is not itself flushed to the server automatically; use Connection#flush if necessary.
3679
+ *
3680
+ * Available since PostgreSQL-14
3681
+ */
3682
+ static VALUE
3683
+ pgconn_send_flush_request(VALUE self)
3684
+ {
3685
+ PGconn *conn = pg_get_pgconn(self);
3686
+ int res = PQsendFlushRequest(conn);
3687
+ if( res == 1 ) {
3688
+ return Qnil;
3689
+ } else {
3690
+ rb_raise(rb_ePGerror, "%s", PQerrorMessage(conn));
3691
+ }
3692
+ }
3693
+
3694
+ #endif
3695
+
3460
3696
  /**************************************************************************
3461
3697
  * LARGE OBJECT SUPPORT
3462
3698
  **************************************************************************/
@@ -3843,16 +4079,33 @@ pgconn_external_encoding(VALUE self)
3843
4079
  return rb_enc_from_encoding( enc );
3844
4080
  }
3845
4081
 
4082
+ /*
4083
+ * call-seq:
4084
+ * conn.set_client_encoding( encoding )
4085
+ *
4086
+ * Sets the client encoding to the _encoding_ String.
4087
+ */
4088
+ static VALUE
4089
+ pgconn_async_set_client_encoding(VALUE self, VALUE encname)
4090
+ {
4091
+ VALUE query_format, query;
4092
+
4093
+ Check_Type(encname, T_STRING);
4094
+ query_format = rb_str_new_cstr("set client_encoding to '%s'");
4095
+ query = rb_funcall(query_format, rb_intern("%"), 1, encname);
4096
+
4097
+ pgconn_async_exec(1, &query, self);
4098
+ pgconn_set_internal_encoding_index( self );
4099
+
4100
+ return Qnil;
4101
+ }
3846
4102
 
3847
4103
  static VALUE
3848
4104
  pgconn_set_client_encoding_async1( VALUE args )
3849
4105
  {
3850
4106
  VALUE self = ((VALUE*)args)[0];
3851
4107
  VALUE encname = ((VALUE*)args)[1];
3852
- VALUE query_format = rb_str_new_cstr("set client_encoding to '%s'");
3853
- VALUE query = rb_funcall(query_format, rb_intern("%"), 1, encname);
3854
-
3855
- pgconn_async_exec(1, &query, self);
4108
+ pgconn_async_set_client_encoding(self, encname);
3856
4109
  return 0;
3857
4110
  }
3858
4111
 
@@ -3867,9 +4120,9 @@ pgconn_set_client_encoding_async2( VALUE arg, VALUE ex )
3867
4120
 
3868
4121
 
3869
4122
  static VALUE
3870
- pgconn_set_client_encoding_async( VALUE self, const char *encname )
4123
+ pgconn_set_client_encoding_async( VALUE self, VALUE encname )
3871
4124
  {
3872
- VALUE args[] = { self, rb_str_new_cstr(encname) };
4125
+ VALUE args[] = { self, encname };
3873
4126
  return rb_rescue(pgconn_set_client_encoding_async1, (VALUE)&args, pgconn_set_client_encoding_async2, Qnil);
3874
4127
  }
3875
4128
 
@@ -3891,10 +4144,9 @@ pgconn_set_default_encoding( VALUE self )
3891
4144
 
3892
4145
  if (( enc = rb_default_internal_encoding() )) {
3893
4146
  encname = pg_get_rb_encoding_as_pg_encoding( enc );
3894
- if ( pgconn_set_client_encoding_async(self, encname) != 0 )
4147
+ if ( pgconn_set_client_encoding_async(self, rb_str_new_cstr(encname)) != 0 )
3895
4148
  rb_warning( "Failed to set the default_internal encoding to %s: '%s'",
3896
4149
  encname, PQerrorMessage(conn) );
3897
- pgconn_set_internal_encoding_index( self );
3898
4150
  return rb_enc_from_encoding( enc );
3899
4151
  } else {
3900
4152
  pgconn_set_internal_encoding_index( self );
@@ -3916,12 +4168,12 @@ static VALUE
3916
4168
  pgconn_type_map_for_queries_set(VALUE self, VALUE typemap)
3917
4169
  {
3918
4170
  t_pg_connection *this = pg_get_connection( self );
4171
+ t_typemap *tm;
4172
+ UNUSED(tm);
4173
+
4174
+ /* Check type of method param */
4175
+ TypedData_Get_Struct(typemap, t_typemap, &pg_typemap_type, tm);
3919
4176
 
3920
- if ( !rb_obj_is_kind_of(typemap, rb_cTypeMap) ) {
3921
- rb_raise( rb_eTypeError, "wrong argument type %s (expected kind of PG::TypeMap)",
3922
- rb_obj_classname( typemap ) );
3923
- }
3924
- Check_Type(typemap, T_DATA);
3925
4177
  this->type_map_for_queries = typemap;
3926
4178
 
3927
4179
  return typemap;
@@ -3956,12 +4208,10 @@ static VALUE
3956
4208
  pgconn_type_map_for_results_set(VALUE self, VALUE typemap)
3957
4209
  {
3958
4210
  t_pg_connection *this = pg_get_connection( self );
4211
+ t_typemap *tm;
4212
+ UNUSED(tm);
3959
4213
 
3960
- if ( !rb_obj_is_kind_of(typemap, rb_cTypeMap) ) {
3961
- rb_raise( rb_eTypeError, "wrong argument type %s (expected kind of PG::TypeMap)",
3962
- rb_obj_classname( typemap ) );
3963
- }
3964
- Check_Type(typemap, T_DATA);
4214
+ TypedData_Get_Struct(typemap, t_typemap, &pg_typemap_type, tm);
3965
4215
  this->type_map_for_results = typemap;
3966
4216
 
3967
4217
  return typemap;
@@ -3996,20 +4246,19 @@ pgconn_type_map_for_results_get(VALUE self)
3996
4246
  *
3997
4247
  */
3998
4248
  static VALUE
3999
- pgconn_encoder_for_put_copy_data_set(VALUE self, VALUE typemap)
4249
+ pgconn_encoder_for_put_copy_data_set(VALUE self, VALUE encoder)
4000
4250
  {
4001
4251
  t_pg_connection *this = pg_get_connection( self );
4002
4252
 
4003
- if( typemap != Qnil ){
4004
- if ( !rb_obj_is_kind_of(typemap, rb_cPG_Coder) ) {
4005
- rb_raise( rb_eTypeError, "wrong argument type %s (expected kind of PG::Coder)",
4006
- rb_obj_classname( typemap ) );
4007
- }
4008
- Check_Type(typemap, T_DATA);
4253
+ if( encoder != Qnil ){
4254
+ t_pg_coder *co;
4255
+ UNUSED(co);
4256
+ /* Check argument type */
4257
+ TypedData_Get_Struct(encoder, t_pg_coder, &pg_coder_type, co);
4009
4258
  }
4010
- this->encoder_for_put_copy_data = typemap;
4259
+ this->encoder_for_put_copy_data = encoder;
4011
4260
 
4012
- return typemap;
4261
+ return encoder;
4013
4262
  }
4014
4263
 
4015
4264
  /*
@@ -4045,20 +4294,19 @@ pgconn_encoder_for_put_copy_data_get(VALUE self)
4045
4294
  *
4046
4295
  */
4047
4296
  static VALUE
4048
- pgconn_decoder_for_get_copy_data_set(VALUE self, VALUE typemap)
4297
+ pgconn_decoder_for_get_copy_data_set(VALUE self, VALUE decoder)
4049
4298
  {
4050
4299
  t_pg_connection *this = pg_get_connection( self );
4051
4300
 
4052
- if( typemap != Qnil ){
4053
- if ( !rb_obj_is_kind_of(typemap, rb_cPG_Coder) ) {
4054
- rb_raise( rb_eTypeError, "wrong argument type %s (expected kind of PG::Coder)",
4055
- rb_obj_classname( typemap ) );
4056
- }
4057
- Check_Type(typemap, T_DATA);
4301
+ if( decoder != Qnil ){
4302
+ t_pg_coder *co;
4303
+ UNUSED(co);
4304
+ /* Check argument type */
4305
+ TypedData_Get_Struct(decoder, t_pg_coder, &pg_coder_type, co);
4058
4306
  }
4059
- this->decoder_for_get_copy_data = typemap;
4307
+ this->decoder_for_get_copy_data = decoder;
4060
4308
 
4061
- return typemap;
4309
+ return decoder;
4062
4310
  }
4063
4311
 
4064
4312
  /*
@@ -4141,6 +4389,7 @@ void
4141
4389
  init_pg_connection()
4142
4390
  {
4143
4391
  s_id_encode = rb_intern("encode");
4392
+ s_id_autoclose_set = rb_intern("autoclose=");
4144
4393
  sym_type = ID2SYM(rb_intern("type"));
4145
4394
  sym_format = ID2SYM(rb_intern("format"));
4146
4395
  sym_value = ID2SYM(rb_intern("value"));
@@ -4187,9 +4436,7 @@ init_pg_connection()
4187
4436
  rb_define_method(rb_cPGconn, "host", pgconn_host, 0);
4188
4437
  rb_define_method(rb_cPGconn, "port", pgconn_port, 0);
4189
4438
  rb_define_method(rb_cPGconn, "tty", pgconn_tty, 0);
4190
- #ifdef HAVE_PQCONNINFO
4191
4439
  rb_define_method(rb_cPGconn, "conninfo", pgconn_conninfo, 0);
4192
- #endif
4193
4440
  rb_define_method(rb_cPGconn, "options", pgconn_options, 0);
4194
4441
  rb_define_method(rb_cPGconn, "status", pgconn_status, 0);
4195
4442
  rb_define_method(rb_cPGconn, "transaction_status", pgconn_transaction_status, 0);
@@ -4200,6 +4447,7 @@ init_pg_connection()
4200
4447
  rb_define_method(rb_cPGconn, "socket", pgconn_socket, 0);
4201
4448
  rb_define_method(rb_cPGconn, "socket_io", pgconn_socket_io, 0);
4202
4449
  rb_define_method(rb_cPGconn, "backend_pid", pgconn_backend_pid, 0);
4450
+ rb_define_method(rb_cPGconn, "backend_key", pgconn_backend_key, 0);
4203
4451
  rb_define_method(rb_cPGconn, "connection_needs_password", pgconn_connection_needs_password, 0);
4204
4452
  rb_define_method(rb_cPGconn, "connection_used_password", pgconn_connection_used_password, 0);
4205
4453
  /* rb_define_method(rb_cPGconn, "getssl", pgconn_getssl, 0); */
@@ -4249,7 +4497,8 @@ init_pg_connection()
4249
4497
  rb_define_method(rb_cPGconn, "setnonblocking", pgconn_setnonblocking, 1);
4250
4498
  rb_define_method(rb_cPGconn, "isnonblocking", pgconn_isnonblocking, 0);
4251
4499
  rb_define_alias(rb_cPGconn, "nonblocking?", "isnonblocking");
4252
- rb_define_method(rb_cPGconn, "flush", pgconn_flush, 0);
4500
+ rb_define_method(rb_cPGconn, "sync_flush", pgconn_sync_flush, 0);
4501
+ rb_define_method(rb_cPGconn, "async_flush", pgconn_async_flush, 0);
4253
4502
  rb_define_method(rb_cPGconn, "discard_results", pgconn_discard_results, 0);
4254
4503
 
4255
4504
  /****** PG::Connection INSTANCE METHODS: Cancelling Queries in Progress ******/
@@ -4277,14 +4526,16 @@ init_pg_connection()
4277
4526
 
4278
4527
  /****** PG::Connection INSTANCE METHODS: Other ******/
4279
4528
  rb_define_method(rb_cPGconn, "get_client_encoding", pgconn_get_client_encoding, 0);
4280
- rb_define_method(rb_cPGconn, "set_client_encoding", pgconn_set_client_encoding, 1);
4281
- rb_define_alias(rb_cPGconn, "client_encoding=", "set_client_encoding");
4282
- rb_define_method(rb_cPGconn, "transaction", pgconn_transaction, 0);
4529
+ rb_define_method(rb_cPGconn, "sync_set_client_encoding", pgconn_set_client_encoding, 1);
4530
+ rb_define_method(rb_cPGconn, "async_set_client_encoding", pgconn_async_set_client_encoding, 1);
4531
+ rb_define_alias(rb_cPGconn, "async_client_encoding=", "async_set_client_encoding");
4283
4532
  rb_define_method(rb_cPGconn, "block", pgconn_block, -1);
4533
+ rb_define_private_method(rb_cPGconn, "flush_data=", pgconn_flush_data_set, 1);
4284
4534
  rb_define_method(rb_cPGconn, "wait_for_notify", pgconn_wait_for_notify, -1);
4285
4535
  rb_define_alias(rb_cPGconn, "notifies_wait", "wait_for_notify");
4286
4536
  rb_define_method(rb_cPGconn, "quote_ident", pgconn_s_quote_ident, 1);
4287
- rb_define_method(rb_cPGconn, "get_last_result", pgconn_get_last_result, 0);
4537
+ rb_define_method(rb_cPGconn, "sync_get_last_result", pgconn_get_last_result, 0);
4538
+ rb_define_method(rb_cPGconn, "async_get_last_result", pgconn_async_get_last_result, 0);
4288
4539
  #ifdef HAVE_PQENCRYPTPASSWORDCONN
4289
4540
  rb_define_method(rb_cPGconn, "encrypt_password", pgconn_encrypt_password, -1);
4290
4541
  #endif
@@ -4295,6 +4546,14 @@ init_pg_connection()
4295
4546
  rb_define_method(rb_cPGconn, "ssl_attribute_names", pgconn_ssl_attribute_names, 0);
4296
4547
  #endif
4297
4548
 
4549
+ #ifdef HAVE_PQENTERPIPELINEMODE
4550
+ rb_define_method(rb_cPGconn, "pipeline_status", pgconn_pipeline_status, 0);
4551
+ rb_define_method(rb_cPGconn, "enter_pipeline_mode", pgconn_enter_pipeline_mode, 0);
4552
+ rb_define_method(rb_cPGconn, "exit_pipeline_mode", pgconn_exit_pipeline_mode, 0);
4553
+ rb_define_method(rb_cPGconn, "pipeline_sync", pgconn_pipeline_sync, 0);
4554
+ rb_define_method(rb_cPGconn, "send_flush_request", pgconn_send_flush_request, 0);
4555
+ #endif
4556
+
4298
4557
  /****** PG::Connection INSTANCE METHODS: Large Object Support ******/
4299
4558
  rb_define_method(rb_cPGconn, "lo_creat", pgconn_locreat, -1);
4300
4559
  rb_define_alias(rb_cPGconn, "locreat", "lo_creat");