pg 1.4.5 → 1.4.6

Sign up to get free protection for your applications and to get access to all the features.
data/ext/pg_connection.c CHANGED
@@ -2446,8 +2446,9 @@ pgconn_async_flush(VALUE self)
2446
2446
  VALUE socket_io = pgconn_socket_io(self);
2447
2447
  events = RB_NUM2INT(pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE | PG_RUBY_IO_WRITABLE), Qnil));
2448
2448
 
2449
- if (events & PG_RUBY_IO_READABLE)
2449
+ if (events & PG_RUBY_IO_READABLE){
2450
2450
  pgconn_consume_input(self);
2451
+ }
2451
2452
  }
2452
2453
  return Qtrue;
2453
2454
  }
@@ -3126,8 +3127,14 @@ pgconn_async_get_last_result(VALUE self)
3126
3127
  * conn.discard_results()
3127
3128
  *
3128
3129
  * Silently discard any prior query result that application didn't eat.
3129
- * This is done prior of Connection#exec and sibling methods and can
3130
- * be called explicitly when using the async API.
3130
+ * This is internally used prior to Connection#exec and sibling methods.
3131
+ * It doesn't raise an exception on connection errors, but returns +false+ instead.
3132
+ *
3133
+ * Returns:
3134
+ * * +nil+ when the connection is already idle
3135
+ * * +true+ when some results have been discarded
3136
+ * * +false+ when a failure occured and the connection was closed
3137
+ *
3131
3138
  */
3132
3139
  static VALUE
3133
3140
  pgconn_discard_results(VALUE self)
@@ -3135,8 +3142,12 @@ pgconn_discard_results(VALUE self)
3135
3142
  PGconn *conn = pg_get_pgconn(self);
3136
3143
  VALUE socket_io;
3137
3144
 
3138
- if( PQtransactionStatus(conn) == PQTRANS_IDLE ) {
3139
- return Qnil;
3145
+ switch( PQtransactionStatus(conn) ) {
3146
+ case PQTRANS_IDLE:
3147
+ case PQTRANS_INTRANS:
3148
+ case PQTRANS_INERROR:
3149
+ return Qnil;
3150
+ default:;
3140
3151
  }
3141
3152
 
3142
3153
  socket_io = pgconn_socket_io(self);
@@ -3149,10 +3160,21 @@ pgconn_discard_results(VALUE self)
3149
3160
  * To avoid this call pg_rb_io_wait() and PQconsumeInput() without rb_raise().
3150
3161
  */
3151
3162
  while( gvl_PQisBusy(conn) ){
3152
- pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE), Qnil);
3153
- if ( PQconsumeInput(conn) == 0 ) {
3154
- pgconn_close_socket_io(self);
3155
- return Qfalse;
3163
+ int events;
3164
+
3165
+ switch( PQflush(conn) ) {
3166
+ case 1:
3167
+ events = RB_NUM2INT(pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE | PG_RUBY_IO_WRITABLE), Qnil));
3168
+ if (events & PG_RUBY_IO_READABLE){
3169
+ if ( PQconsumeInput(conn) == 0 ) goto error;
3170
+ }
3171
+ break;
3172
+ case 0:
3173
+ pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE), Qnil);
3174
+ if ( PQconsumeInput(conn) == 0 ) goto error;
3175
+ break;
3176
+ default:
3177
+ goto error;
3156
3178
  }
3157
3179
  }
3158
3180
 
@@ -3162,7 +3184,9 @@ pgconn_discard_results(VALUE self)
3162
3184
  status = PQresultStatus(cur);
3163
3185
  PQclear(cur);
3164
3186
  if (status == PGRES_COPY_IN){
3165
- gvl_PQputCopyEnd(conn, "COPY terminated by new PQexec");
3187
+ while( gvl_PQputCopyEnd(conn, "COPY terminated by new query or discard_results") == 0 ){
3188
+ pgconn_async_flush(self);
3189
+ }
3166
3190
  }
3167
3191
  if (status == PGRES_COPY_OUT){
3168
3192
  for(;;) {
@@ -3171,10 +3195,7 @@ pgconn_discard_results(VALUE self)
3171
3195
  if( st == 0 ) {
3172
3196
  /* would block -> wait for readable data */
3173
3197
  pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE), Qnil);
3174
- if ( PQconsumeInput(conn) == 0 ) {
3175
- pgconn_close_socket_io(self);
3176
- return Qfalse;
3177
- }
3198
+ if ( PQconsumeInput(conn) == 0 ) goto error;
3178
3199
  } else if( st > 0 ) {
3179
3200
  /* some data retrieved -> discard it */
3180
3201
  PQfreemem(buffer);
@@ -3187,6 +3208,10 @@ pgconn_discard_results(VALUE self)
3187
3208
  }
3188
3209
 
3189
3210
  return Qtrue;
3211
+
3212
+ error:
3213
+ pgconn_close_socket_io(self);
3214
+ return Qfalse;
3190
3215
  }
3191
3216
 
3192
3217
  /*
@@ -3643,6 +3668,14 @@ pgconn_send_flush_request(VALUE self)
3643
3668
  * LARGE OBJECT SUPPORT
3644
3669
  **************************************************************************/
3645
3670
 
3671
+ #define BLOCKING_BEGIN(conn) do { \
3672
+ int old_nonblocking = PQisnonblocking(conn); \
3673
+ PQsetnonblocking(conn, 0);
3674
+
3675
+ #define BLOCKING_END(th) \
3676
+ PQsetnonblocking(conn, old_nonblocking); \
3677
+ } while(0);
3678
+
3646
3679
  /*
3647
3680
  * call-seq:
3648
3681
  * conn.lo_creat( [mode] ) -> Integer
@@ -3663,7 +3696,10 @@ pgconn_locreat(int argc, VALUE *argv, VALUE self)
3663
3696
  else
3664
3697
  mode = NUM2INT(nmode);
3665
3698
 
3666
- lo_oid = lo_creat(conn, mode);
3699
+ BLOCKING_BEGIN(conn)
3700
+ lo_oid = lo_creat(conn, mode);
3701
+ BLOCKING_END(conn)
3702
+
3667
3703
  if (lo_oid == 0)
3668
3704
  pg_raise_conn_error( rb_ePGerror, self, "lo_creat failed");
3669
3705
 
@@ -3708,7 +3744,10 @@ pgconn_loimport(VALUE self, VALUE filename)
3708
3744
 
3709
3745
  Check_Type(filename, T_STRING);
3710
3746
 
3711
- lo_oid = lo_import(conn, StringValueCStr(filename));
3747
+ BLOCKING_BEGIN(conn)
3748
+ lo_oid = lo_import(conn, StringValueCStr(filename));
3749
+ BLOCKING_END(conn)
3750
+
3712
3751
  if (lo_oid == 0) {
3713
3752
  pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
3714
3753
  }
@@ -3726,11 +3765,16 @@ pgconn_loexport(VALUE self, VALUE lo_oid, VALUE filename)
3726
3765
  {
3727
3766
  PGconn *conn = pg_get_pgconn(self);
3728
3767
  Oid oid;
3768
+ int ret;
3729
3769
  Check_Type(filename, T_STRING);
3730
3770
 
3731
3771
  oid = NUM2UINT(lo_oid);
3732
3772
 
3733
- if (lo_export(conn, oid, StringValueCStr(filename)) < 0) {
3773
+ BLOCKING_BEGIN(conn)
3774
+ ret = lo_export(conn, oid, StringValueCStr(filename));
3775
+ BLOCKING_END(conn)
3776
+
3777
+ if (ret < 0) {
3734
3778
  pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
3735
3779
  }
3736
3780
  return Qnil;
@@ -3761,7 +3805,11 @@ pgconn_loopen(int argc, VALUE *argv, VALUE self)
3761
3805
  else
3762
3806
  mode = NUM2INT(nmode);
3763
3807
 
3764
- if((fd = lo_open(conn, lo_oid, mode)) < 0) {
3808
+ BLOCKING_BEGIN(conn)
3809
+ fd = lo_open(conn, lo_oid, mode);
3810
+ BLOCKING_END(conn)
3811
+
3812
+ if(fd < 0) {
3765
3813
  pg_raise_conn_error( rb_ePGerror, self, "can't open large object: %s", PQerrorMessage(conn));
3766
3814
  }
3767
3815
  return INT2FIX(fd);
@@ -3786,8 +3834,12 @@ pgconn_lowrite(VALUE self, VALUE in_lo_desc, VALUE buffer)
3786
3834
  if( RSTRING_LEN(buffer) < 0) {
3787
3835
  pg_raise_conn_error( rb_ePGerror, self, "write buffer zero string");
3788
3836
  }
3789
- if((n = lo_write(conn, fd, StringValuePtr(buffer),
3790
- RSTRING_LEN(buffer))) < 0) {
3837
+ BLOCKING_BEGIN(conn)
3838
+ n = lo_write(conn, fd, StringValuePtr(buffer),
3839
+ RSTRING_LEN(buffer));
3840
+ BLOCKING_END(conn)
3841
+
3842
+ if(n < 0) {
3791
3843
  pg_raise_conn_error( rb_ePGerror, self, "lo_write failed: %s", PQerrorMessage(conn));
3792
3844
  }
3793
3845
 
@@ -3815,7 +3867,12 @@ pgconn_loread(VALUE self, VALUE in_lo_desc, VALUE in_len)
3815
3867
  pg_raise_conn_error( rb_ePGerror, self, "negative length %d given", len);
3816
3868
 
3817
3869
  buffer = ALLOC_N(char, len);
3818
- if((ret = lo_read(conn, lo_desc, buffer, len)) < 0)
3870
+
3871
+ BLOCKING_BEGIN(conn)
3872
+ ret = lo_read(conn, lo_desc, buffer, len);
3873
+ BLOCKING_END(conn)
3874
+
3875
+ if(ret < 0)
3819
3876
  pg_raise_conn_error( rb_ePGerror, self, "lo_read failed");
3820
3877
 
3821
3878
  if(ret == 0) {
@@ -3845,7 +3902,11 @@ pgconn_lolseek(VALUE self, VALUE in_lo_desc, VALUE offset, VALUE whence)
3845
3902
  int lo_desc = NUM2INT(in_lo_desc);
3846
3903
  int ret;
3847
3904
 
3848
- if((ret = lo_lseek(conn, lo_desc, NUM2INT(offset), NUM2INT(whence))) < 0) {
3905
+ BLOCKING_BEGIN(conn)
3906
+ ret = lo_lseek(conn, lo_desc, NUM2INT(offset), NUM2INT(whence));
3907
+ BLOCKING_END(conn)
3908
+
3909
+ if(ret < 0) {
3849
3910
  pg_raise_conn_error( rb_ePGerror, self, "lo_lseek failed");
3850
3911
  }
3851
3912
 
@@ -3865,7 +3926,11 @@ pgconn_lotell(VALUE self, VALUE in_lo_desc)
3865
3926
  PGconn *conn = pg_get_pgconn(self);
3866
3927
  int lo_desc = NUM2INT(in_lo_desc);
3867
3928
 
3868
- if((position = lo_tell(conn, lo_desc)) < 0)
3929
+ BLOCKING_BEGIN(conn)
3930
+ position = lo_tell(conn, lo_desc);
3931
+ BLOCKING_END(conn)
3932
+
3933
+ if(position < 0)
3869
3934
  pg_raise_conn_error( rb_ePGerror, self, "lo_tell failed");
3870
3935
 
3871
3936
  return INT2FIX(position);
@@ -3883,8 +3948,13 @@ pgconn_lotruncate(VALUE self, VALUE in_lo_desc, VALUE in_len)
3883
3948
  PGconn *conn = pg_get_pgconn(self);
3884
3949
  int lo_desc = NUM2INT(in_lo_desc);
3885
3950
  size_t len = NUM2INT(in_len);
3951
+ int ret;
3952
+
3953
+ BLOCKING_BEGIN(conn)
3954
+ ret = lo_truncate(conn,lo_desc,len);
3955
+ BLOCKING_END(conn)
3886
3956
 
3887
- if(lo_truncate(conn,lo_desc,len) < 0)
3957
+ if(ret < 0)
3888
3958
  pg_raise_conn_error( rb_ePGerror, self, "lo_truncate failed");
3889
3959
 
3890
3960
  return Qnil;
@@ -3901,8 +3971,13 @@ pgconn_loclose(VALUE self, VALUE in_lo_desc)
3901
3971
  {
3902
3972
  PGconn *conn = pg_get_pgconn(self);
3903
3973
  int lo_desc = NUM2INT(in_lo_desc);
3974
+ int ret;
3975
+
3976
+ BLOCKING_BEGIN(conn)
3977
+ ret = lo_close(conn,lo_desc);
3978
+ BLOCKING_END(conn)
3904
3979
 
3905
- if(lo_close(conn,lo_desc) < 0)
3980
+ if(ret < 0)
3906
3981
  pg_raise_conn_error( rb_ePGerror, self, "lo_close failed");
3907
3982
 
3908
3983
  return Qnil;
@@ -3919,8 +3994,13 @@ pgconn_lounlink(VALUE self, VALUE in_oid)
3919
3994
  {
3920
3995
  PGconn *conn = pg_get_pgconn(self);
3921
3996
  Oid oid = NUM2UINT(in_oid);
3997
+ int ret;
3998
+
3999
+ BLOCKING_BEGIN(conn)
4000
+ ret = lo_unlink(conn,oid);
4001
+ BLOCKING_END(conn)
3922
4002
 
3923
- if(lo_unlink(conn,oid) < 0)
4003
+ if(ret < 0)
3924
4004
  pg_raise_conn_error( rb_ePGerror, self, "lo_unlink failed");
3925
4005
 
3926
4006
  return Qnil;
data/lib/pg/connection.rb CHANGED
@@ -196,11 +196,19 @@ class PG::Connection
196
196
  yield res
197
197
  rescue Exception => err
198
198
  errmsg = "%s while copy data: %s" % [ err.class.name, err.message ]
199
- put_copy_end( errmsg )
200
- get_result
201
- raise
199
+ begin
200
+ put_copy_end( errmsg )
201
+ rescue PG::Error
202
+ # Ignore error in cleanup to avoid losing original exception
203
+ end
204
+ discard_results
205
+ raise err
202
206
  else
203
- put_copy_end
207
+ begin
208
+ put_copy_end
209
+ rescue PG::Error => err
210
+ raise PG::LostCopyState.new("#{err} (probably by executing another SQL query while running a COPY command)", connection: self)
211
+ end
204
212
  get_last_result
205
213
  ensure
206
214
  self.encoder_for_put_copy_data = old_coder if coder
@@ -213,24 +221,17 @@ class PG::Connection
213
221
  self.decoder_for_get_copy_data = coder
214
222
  end
215
223
  yield res
216
- rescue Exception => err
224
+ rescue Exception
217
225
  cancel
218
- begin
219
- while get_copy_data
220
- end
221
- rescue PG::Error
222
- # Ignore error in cleanup to avoid losing original exception
223
- end
224
- while get_result
225
- end
226
- raise err
226
+ discard_results
227
+ raise
227
228
  else
228
229
  res = get_last_result
229
- if !res || res.result_status != PGRES_COMMAND_OK
230
- while get_copy_data
231
- end
232
- while get_result
233
- end
230
+ if !res
231
+ discard_results
232
+ raise PG::LostCopyState.new("Lost COPY state (probably by executing another SQL query while running a COPY command)", connection: self)
233
+ elsif res.result_status != PGRES_COMMAND_OK
234
+ discard_results
234
235
  raise PG::NotAllCopyDataRetrieved.new("Not all COPY data retrieved", connection: self)
235
236
  end
236
237
  res
data/lib/pg/exceptions.rb CHANGED
@@ -14,5 +14,12 @@ module PG
14
14
  end
15
15
  end
16
16
 
17
+ class NotAllCopyDataRetrieved < PG::Error
18
+ end
19
+ class LostCopyState < PG::Error
20
+ end
21
+ class NotInBlockingMode < PG::Error
22
+ end
23
+
17
24
  end # module PG
18
25
 
data/lib/pg/version.rb CHANGED
@@ -1,4 +1,4 @@
1
1
  module PG
2
2
  # Library version
3
- VERSION = '1.4.5'
3
+ VERSION = '1.4.6'
4
4
  end
data/lib/pg.rb CHANGED
@@ -50,12 +50,6 @@ module PG
50
50
  end
51
51
  end
52
52
 
53
-
54
- class NotAllCopyDataRetrieved < PG::Error
55
- end
56
- class NotInBlockingMode < PG::Error
57
- end
58
-
59
53
  # Get the PG library version.
60
54
  #
61
55
  # +include_buildnum+ is no longer used and any value passed will be ignored.
data/pg.gemspec CHANGED
@@ -17,7 +17,7 @@ Gem::Specification.new do |spec|
17
17
 
18
18
  spec.metadata["homepage_uri"] = spec.homepage
19
19
  spec.metadata["source_code_uri"] = "https://github.com/ged/ruby-pg"
20
- spec.metadata["changelog_uri"] = "https://github.com/ged/ruby-pg/blob/master/History.rdoc"
20
+ spec.metadata["changelog_uri"] = "https://github.com/ged/ruby-pg/blob/master/History.md"
21
21
  spec.metadata["documentation_uri"] = "http://deveiate.org/code/pg"
22
22
 
23
23
  # Specify which files should be added to the gem when it is released.
@@ -28,5 +28,7 @@ Gem::Specification.new do |spec|
28
28
  spec.extensions = ["ext/extconf.rb"]
29
29
  spec.require_paths = ["lib"]
30
30
  spec.cert_chain = ["certs/ged.pem"]
31
- spec.rdoc_options = ["--main", "README.rdoc"]
31
+ spec.rdoc_options = ["--main", "README.md",
32
+ "--title", "PG: The Ruby PostgreSQL Driver"]
33
+ spec.extra_rdoc_files = `git ls-files -z *.rdoc *.md lib/*.rb lib/*/*.rb ext/*.c ext/*.h`.split("\x0")
32
34
  end
@@ -9,7 +9,7 @@ module TaskExtension
9
9
  def file(name, *args, &block)
10
10
  task_once(name, block) do
11
11
  super(name, *args) do |ta|
12
- block.call(ta).tap do
12
+ block&.call(ta).tap do
13
13
  raise "file #{ta.name} is missing after task executed" unless File.exist?(ta.name)
14
14
  end
15
15
  end
@@ -0,0 +1,7 @@
1
+ po4a version 0.69.
2
+ Written by Martin Quinson and Denis Barbier.
3
+
4
+ Copyright © 2002-2022 Software in the Public Interest, Inc.
5
+ This is free software; see source code for copying
6
+ conditions. There is NO warranty; not even for
7
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.