pg 1.2.0-x86-mingw32 → 1.3.0.rc1-x86-mingw32

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 (112) 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 +98 -7
  16. data/Manifest.txt +0 -1
  17. data/README.rdoc +9 -8
  18. data/Rakefile +31 -140
  19. data/Rakefile.cross +54 -56
  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 -0
  28. data/ext/pg_coder.c +90 -24
  29. data/ext/pg_connection.c +538 -279
  30. data/ext/pg_copy_coder.c +45 -15
  31. data/ext/pg_record_coder.c +38 -9
  32. data/ext/pg_result.c +70 -34
  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 +50 -21
  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/2.5/pg_ext.so +0 -0
  45. data/lib/2.6/pg_ext.so +0 -0
  46. data/lib/2.7/pg_ext.so +0 -0
  47. data/lib/3.0/pg_ext.so +0 -0
  48. data/lib/pg/basic_type_map_based_on_result.rb +47 -0
  49. data/lib/pg/basic_type_map_for_queries.rb +193 -0
  50. data/lib/pg/basic_type_map_for_results.rb +81 -0
  51. data/lib/pg/basic_type_registry.rb +296 -0
  52. data/lib/pg/coder.rb +1 -1
  53. data/lib/pg/connection.rb +369 -56
  54. data/lib/pg/version.rb +4 -0
  55. data/lib/pg.rb +38 -24
  56. data/lib/x86-mingw32/libpq.dll +0 -0
  57. data/misc/openssl-pg-segfault.rb +31 -0
  58. data/misc/postgres/History.txt +9 -0
  59. data/misc/postgres/Manifest.txt +5 -0
  60. data/misc/postgres/README.txt +21 -0
  61. data/misc/postgres/Rakefile +21 -0
  62. data/misc/postgres/lib/postgres.rb +16 -0
  63. data/misc/ruby-pg/History.txt +9 -0
  64. data/misc/ruby-pg/Manifest.txt +5 -0
  65. data/misc/ruby-pg/README.txt +21 -0
  66. data/misc/ruby-pg/Rakefile +21 -0
  67. data/misc/ruby-pg/lib/ruby/pg.rb +16 -0
  68. data/pg.gemspec +32 -0
  69. data/sample/array_insert.rb +20 -0
  70. data/sample/async_api.rb +106 -0
  71. data/sample/async_copyto.rb +39 -0
  72. data/sample/async_mixed.rb +56 -0
  73. data/sample/check_conn.rb +21 -0
  74. data/sample/copydata.rb +71 -0
  75. data/sample/copyfrom.rb +81 -0
  76. data/sample/copyto.rb +19 -0
  77. data/sample/cursor.rb +21 -0
  78. data/sample/disk_usage_report.rb +177 -0
  79. data/sample/issue-119.rb +94 -0
  80. data/sample/losample.rb +69 -0
  81. data/sample/minimal-testcase.rb +17 -0
  82. data/sample/notify_wait.rb +72 -0
  83. data/sample/pg_statistics.rb +285 -0
  84. data/sample/replication_monitor.rb +222 -0
  85. data/sample/test_binary_values.rb +33 -0
  86. data/sample/wal_shipper.rb +434 -0
  87. data/sample/warehouse_partitions.rb +311 -0
  88. data.tar.gz.sig +0 -0
  89. metadata +83 -232
  90. metadata.gz.sig +0 -0
  91. data/ChangeLog +0 -0
  92. data/lib/2.2/pg_ext.so +0 -0
  93. data/lib/2.3/pg_ext.so +0 -0
  94. data/lib/2.4/pg_ext.so +0 -0
  95. data/lib/libpq.dll +0 -0
  96. data/lib/pg/basic_type_mapping.rb +0 -522
  97. data/spec/data/expected_trace.out +0 -26
  98. data/spec/data/random_binary_data +0 -0
  99. data/spec/helpers.rb +0 -382
  100. data/spec/pg/basic_type_mapping_spec.rb +0 -645
  101. data/spec/pg/connection_spec.rb +0 -1911
  102. data/spec/pg/connection_sync_spec.rb +0 -41
  103. data/spec/pg/result_spec.rb +0 -681
  104. data/spec/pg/tuple_spec.rb +0 -333
  105. data/spec/pg/type_map_by_class_spec.rb +0 -138
  106. data/spec/pg/type_map_by_column_spec.rb +0 -226
  107. data/spec/pg/type_map_by_mri_type_spec.rb +0 -136
  108. data/spec/pg/type_map_by_oid_spec.rb +0 -149
  109. data/spec/pg/type_map_in_ruby_spec.rb +0 -164
  110. data/spec/pg/type_map_spec.rb +0 -22
  111. data/spec/pg/type_spec.rb +0 -1123
  112. 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");