pgsql 1.6 → 1.9.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5906425e386ca8404df02a1d14dec2ec92e730cabd03c8192f624112d537c3d2
4
- data.tar.gz: 5bc40a7923bc2076aef6cdd8a2af71b679f01bee63fed44bbc475bf8e3a12dbb
3
+ metadata.gz: d735e83feb39d55f95efc1a196d433800c523fd0e73538b2c6415edd098f405c
4
+ data.tar.gz: e8e6e0b0526a73de32bf227effe13337ef125ea9f69d05099401aae4455c4288
5
5
  SHA512:
6
- metadata.gz: a32d74928d3a5c2d04dd30d4453e11a346ce7f4bb24db40665d375776b6caa89dabed59fa87774ab52fdb1d09a9d37e3e8eca13118e04a35572c33c8e827856c
7
- data.tar.gz: c405985704ae2c8a1bb52d957965a9b6ad4811bec41fe9785b3c56dba79c463fe1569ab27426a5853bfb1c5dfea4b10ae85505f7944bf5f6cdb6a0595174b895
6
+ metadata.gz: bbccf68542f27fc341ed1b517109655d5dd96b9d8cb21ac94e9d874f54d40eec9b3f50652967bb592cf04da68804c1351e01598ab8e4f3487ecc50b706dee65a
7
+ data.tar.gz: 388001a630086ddb47acb19672291ebe1cbd95f0349038e97189ff676e246047c4ce055bc726d065a9aea399cfdf1ff8d1e62d293178ebc6b8c131b10e4b951a
data/lib/Rakefile CHANGED
@@ -17,7 +17,7 @@ DLs = {
17
17
  }
18
18
 
19
19
  DLs.each { |k,v|
20
- task k => v do |t|
20
+ file k => v do |t|
21
21
  l.cc t.name, t.prerequisites
22
22
  end
23
23
  }
data/lib/conn.c CHANGED
@@ -26,11 +26,11 @@ extern VALUE pgconn_mkstring( struct pgconn_data *ptr, const char *str);
26
26
  extern VALUE pgconn_mkstringn( struct pgconn_data *ptr, const char *str, int len);
27
27
  static VALUE pgconn_alloc( VALUE cls);
28
28
  static VALUE pgconn_s_connect( int argc, VALUE *argv, VALUE cls);
29
- static VALUE pgconn_s_parse( VALUE cls, VALUE str);
30
29
  static VALUE pgconn_init( int argc, VALUE *argv, VALUE self);
31
30
  static int set_connect_params( st_data_t key, st_data_t val, st_data_t args);
32
- static void connstr_to_hash( VALUE params, VALUE str);
33
- static void connstr_passwd( VALUE self, VALUE params);
31
+ static VALUE connstr_sym_dbname( void);
32
+ static VALUE connstr_sym_password( void);
33
+ static void connstr_passwd( VALUE self, VALUE orig_params, VALUE *params);
34
34
  static VALUE connstr_getparam( RB_BLOCK_CALL_FUNC_ARGLIST( yielded, params));
35
35
 
36
36
  static VALUE pgconn_close( VALUE self);
@@ -71,6 +71,10 @@ VALUE rb_cPgConn;
71
71
  static VALUE rb_ePgConnFailed;
72
72
  static VALUE rb_ePgConnInvalid;
73
73
 
74
+ static VALUE sym_dbname = Qundef;
75
+ static VALUE sym_password = Qundef;
76
+
77
+ static ID id_to_s;
74
78
 
75
79
 
76
80
  void
@@ -221,24 +225,6 @@ pgconn_s_connect( int argc, VALUE *argv, VALUE cls)
221
225
  rb_ensure( rb_yield, pgconn, pgconn_close, pgconn) : pgconn;
222
226
  }
223
227
 
224
- /*
225
- * call-seq:
226
- * Pg::Conn.parse( str) -> hash
227
- *
228
- * Parse a connection string and return a hash with keys <code>:dbname</code>,
229
- * <code>:user</code>, <code>:host</code>, etc.
230
- *
231
- */
232
- VALUE
233
- pgconn_s_parse( VALUE cls, VALUE str)
234
- {
235
- VALUE params;
236
-
237
- params = rb_hash_new();
238
- connstr_to_hash( params, str);
239
- return params;
240
- }
241
-
242
228
 
243
229
  /*
244
230
  * Document-method: Pg::Conn.new
@@ -252,23 +238,39 @@ pgconn_s_parse( VALUE cls, VALUE str)
252
238
  *
253
239
  * c = Pg::Conn.new :dbname => "movies", :host => "jupiter", ...
254
240
  *
255
- * The most common parameters may be given in a URL-like
256
- * connection string:
241
+ * If the +str+ argument is given but no further parameters,
242
+ * the PQconnectdb() (not PQconnectdbParams()) function will be called.
243
+ * If further arguments are present, the +str+ argument will be made into
244
+ * the "dbname" parameter, but without overwriting an existing one.
245
+ *
246
+ * The "dbname" parameter may be a +conninfo+ string as described in the
247
+ * PostgreSQL documentation:
257
248
  *
258
- * "user:password@host:port/dbname"
249
+ * c = Pg::Conn.new "postgresql://user:password@host:port/dbname"
250
+ * c = Pg::Conn.new "postgres://user:password@host:port/dbname"
251
+ * c = Pg::Conn.new "dbname=... host=... user=..."
259
252
  *
260
- * Any of these parts may be omitted. If there is no slash, the part after the
261
- * @ sign will be read as database name.
253
+ * The password may be specified as an extra parameter:
254
+ *
255
+ * c = Pg::Conn.new "postgresql://user@host/dbname", password: "verysecret"
262
256
  *
263
257
  * If the password is the empty string, and there is either an instance method
264
258
  * or a class method <code>password?</code>, that method will be asked. This
265
259
  * method may ask <code>yield :user</code> or <code>yield :dbname</code> and so
266
260
  * on to get the connection parameters.
267
261
  *
262
+ * class Pg::Conn
263
+ * def password?
264
+ * "tercesyrev".reverse
265
+ * end
266
+ * end
267
+ * c = Pg::Conn.new "postgresql://user@host/dbname", password: ""
268
+ *
268
269
  * See the PostgreSQL documentation for a full list:
269
270
  * [http://www.postgresql.org/docs/current/interactive/libpq-connect.html#LIBPQ-PQCONNECTDBPARAMS]
270
271
  *
271
272
  * On failure, a +Pg::Error+ exception will be raised.
273
+ *
272
274
  */
273
275
  VALUE
274
276
  pgconn_init( int argc, VALUE *argv, VALUE self)
@@ -280,32 +282,43 @@ pgconn_init( int argc, VALUE *argv, VALUE self)
280
282
  struct pgconn_data *c;
281
283
 
282
284
  if (rb_scan_args( argc, argv, "02", &str, &params) < 2)
283
- if (TYPE( str) != T_STRING) {
285
+ if (TYPE( str) == T_HASH) {
284
286
  params = str;
285
287
  str = Qnil;
286
288
  }
287
- if (NIL_P( params))
288
- params = rb_hash_new();
289
- else if (TYPE( params) != T_HASH)
290
- params = rb_convert_type( params, T_HASH, "Hash", "to_hash");
291
- else
292
- params = rb_obj_dup( params);
293
- if (!NIL_P( str))
294
- connstr_to_hash( params, str);
295
- connstr_passwd( self, params);
296
289
 
297
290
  Data_Get_Struct( self, struct pgconn_data, c);
298
291
 
299
- l = RHASH_SIZE( params) + 1;
300
- keywords = (const char **) ALLOCA_N( char *, l);
301
- values = (const char **) ALLOCA_N( char *, l);
302
- ptrs[ 0] = keywords;
303
- ptrs[ 1] = values;
304
- ptrs[ 2] = (const char **) c;
305
- st_foreach( RHASH_TBL( params), &set_connect_params, (st_data_t) ptrs);
306
- *(ptrs[ 0]) = *(ptrs[ 1]) = NULL;
307
-
308
- c->conn = PQconnectdbParams( keywords, values, 1);
292
+ if (NIL_P( params)) {
293
+ c->conn = PQconnectdb( RSTRING_PTR( rb_funcall( str, id_to_s, 0)));
294
+ } else {
295
+ int expand_dbname;
296
+ VALUE orig_params = params;
297
+
298
+ if (TYPE( params) != T_HASH)
299
+ params = rb_convert_type( params, T_HASH, "Hash", "to_hash");
300
+
301
+ if (!NIL_P( str) && NIL_P( rb_hash_aref( params, connstr_sym_dbname()))) {
302
+ if (params == orig_params)
303
+ params = rb_obj_dup( params);
304
+ rb_hash_aset( params, sym_dbname, str);
305
+ expand_dbname = 1;
306
+ } else
307
+ expand_dbname = 0;
308
+
309
+ connstr_passwd( self, orig_params, &params);
310
+
311
+ l = RHASH_SIZE( params) + 1;
312
+ keywords = (const char **) ALLOCA_N( char *, l);
313
+ values = (const char **) ALLOCA_N( char *, l);
314
+ ptrs[ 0] = keywords;
315
+ ptrs[ 1] = values;
316
+ ptrs[ 2] = (const char **) c;
317
+ st_foreach( RHASH_TBL( params), &set_connect_params, (st_data_t) ptrs);
318
+ *(ptrs[ 0]) = *(ptrs[ 1]) = NULL;
319
+
320
+ c->conn = PQconnectdbParams( keywords, values, expand_dbname);
321
+ }
309
322
  if (PQstatus( c->conn) == CONNECTION_BAD)
310
323
  rb_exc_raise( pgconnfailederror_new( c, params));
311
324
 
@@ -331,50 +344,29 @@ set_connect_params( st_data_t key, st_data_t val, st_data_t args)
331
344
  return ST_CONTINUE;
332
345
  }
333
346
 
334
- static const char re_connstr[] =
335
- "\\A"
336
- "(?:(.*?)(?::(.*))?@)?" /* user:passwd@ */
337
- "(?:(.*?)(?::(\\d+))?/)?(?:(.+))?" /* host:port/dbname */
338
- "\\z"
339
- ;
340
-
341
- #define KEY_USER "user"
342
- #define KEY_PASSWORD "password"
343
- #define KEY_HOST "host"
344
- #define KEY_PORT "port"
345
- #define KEY_DBNAME "dbname"
347
+ VALUE
348
+ connstr_sym_dbname( void)
349
+ {
350
+ if (sym_dbname == Qundef)
351
+ sym_dbname = ID2SYM( rb_intern( "dbname"));
352
+ return sym_dbname;
353
+ }
346
354
 
347
- void
348
- connstr_to_hash( VALUE params, VALUE str)
349
- {
350
- VALUE re, match, k, m;
351
-
352
- re = rb_reg_new( re_connstr, sizeof re_connstr - 1, 0);
353
- if (RTEST( rb_reg_match( re, str))) {
354
- match = rb_backref_get();
355
- #define ADD_TO_RES( key, n) \
356
- k = ID2SYM( rb_intern( key)); m = rb_reg_nth_match( n, match); \
357
- if (NIL_P( rb_hash_aref( params, k)) && !NIL_P(m)) \
358
- rb_hash_aset( params, k, m)
359
- ADD_TO_RES( KEY_USER, 1);
360
- ADD_TO_RES( KEY_PASSWORD, 2);
361
- ADD_TO_RES( KEY_HOST, 3);
362
- ADD_TO_RES( KEY_PORT, 4);
363
- ADD_TO_RES( KEY_DBNAME, 5);
364
- #undef ADD_TO_RES
365
- } else
366
- rb_raise( rb_eArgError, "Invalid connection: %s", RSTRING_PTR( str));
355
+ VALUE
356
+ connstr_sym_password( void)
357
+ {
358
+ if (sym_password == Qundef)
359
+ sym_password = ID2SYM( rb_intern( "password"));
360
+ return sym_password;
367
361
  }
368
362
 
363
+
369
364
  void
370
- connstr_passwd( VALUE self, VALUE params)
365
+ connstr_passwd( VALUE self, VALUE orig_params, VALUE *params)
371
366
  {
372
- static VALUE sym_password = Qundef;
373
367
  VALUE pw;
374
368
 
375
- if (sym_password == Qundef)
376
- sym_password = ID2SYM( rb_intern( KEY_PASSWORD));
377
- pw = rb_hash_aref( params, sym_password);
369
+ pw = rb_hash_aref( *params, connstr_sym_password());
378
370
  if (TYPE( pw) == T_STRING && RSTRING_LEN( pw) == 0) {
379
371
  static ID id_password_q = 0;
380
372
  VALUE pwobj;
@@ -386,10 +378,13 @@ connstr_passwd( VALUE self, VALUE params)
386
378
  pwobj = self;
387
379
  if (rb_respond_to( CLASS_OF( self), id_password_q))
388
380
  pwobj = CLASS_OF( self);
389
- if (pwobj != Qundef)
390
- rb_hash_aset( params, sym_password,
381
+ if (pwobj != Qundef) {
382
+ if (*params == orig_params)
383
+ *params = rb_obj_dup( *params);
384
+ rb_hash_aset( *params, sym_password,
391
385
  rb_block_call( pwobj, id_password_q, 0, NULL,
392
- &connstr_getparam, params));
386
+ &connstr_getparam, *params));
387
+ }
393
388
  }
394
389
  }
395
390
 
@@ -866,7 +861,6 @@ Init_pgsql_conn( void)
866
861
  rb_define_alloc_func( rb_cPgConn, pgconn_alloc);
867
862
  rb_define_singleton_method( rb_cPgConn, "connect", pgconn_s_connect, -1);
868
863
  rb_define_alias( rb_singleton_class( rb_cPgConn), "open", "connect");
869
- rb_define_singleton_method( rb_cPgConn, "parse", pgconn_s_parse, 1);
870
864
  rb_define_method( rb_cPgConn, "initialize", &pgconn_init, -1);
871
865
  rb_define_method( rb_cPgConn, "close", &pgconn_close, 0);
872
866
  rb_define_alias( rb_cPgConn, "finish", "close");
@@ -906,6 +900,8 @@ Init_pgsql_conn( void)
906
900
 
907
901
  rb_define_method( rb_cPgConn, "on_notice", &pgconn_on_notice, 0);
908
902
 
903
+ id_to_s = rb_intern( "to_s");
904
+
909
905
  Init_pgsql_conn_quote();
910
906
  Init_pgsql_conn_exec();
911
907
  }
data/lib/conn_exec.c CHANGED
@@ -8,6 +8,8 @@
8
8
  #include "conn_quote.h"
9
9
  #include "result.h"
10
10
 
11
+ #include <math.h>
12
+
11
13
 
12
14
  static void pg_raise_connexec( struct pgconn_data *c);
13
15
 
@@ -18,21 +20,24 @@ static void free_strings( char **strs, int len);
18
20
  static void pg_parse_parameters( int argc, VALUE *argv, VALUE *cmd, VALUE *par);
19
21
 
20
22
  static VALUE pgconn_exec( int argc, VALUE *argv, VALUE obj);
21
- static VALUE pgconn_send( int argc, VALUE *argv, VALUE obj);
22
- static VALUE pgconn_fetch( VALUE obj);
23
23
  static VALUE yield_or_return_result( VALUE res);
24
+ static VALUE pgconn_send( int argc, VALUE *argv, VALUE obj);
25
+ static VALUE pgconn_fetch( int argc, VALUE *argv, VALUE conn);
26
+ static void wait_for_pgsocket( PGconn *c, VALUE to);
24
27
  static VALUE clear_resultqueue( VALUE self);
28
+ static VALUE pgconn_fetch_rows( int argc, VALUE *argv, VALUE conn);
29
+ static VALUE fetch_result_each( RB_BLOCK_CALL_FUNC_ARGLIST( res, arg));
25
30
 
26
31
  static VALUE pgconn_query( int argc, VALUE *argv, VALUE self);
27
- static VALUE pgconn_select_one( int argc, VALUE *argv, VALUE self);
32
+ static VALUE pgconn_select_row( int argc, VALUE *argv, VALUE self);
28
33
  static VALUE pgconn_select_value( int argc, VALUE *argv, VALUE self);
29
34
  static VALUE pgconn_select_values( int argc, VALUE *argv, VALUE self);
30
35
  static VALUE pgconn_get_notify( VALUE self);
31
36
 
32
37
  static VALUE pgconn_transaction( int argc, VALUE *argv, VALUE self);
33
- static VALUE rollback_transaction( VALUE self, VALUE err);
38
+ static VALUE rollback_transaction( VALUE conn, VALUE err);
34
39
  static VALUE commit_transaction( VALUE self);
35
- static VALUE yield_transaction( VALUE self);
40
+ static VALUE yield_transaction( VALUE conn);
36
41
  static VALUE pgconn_subtransaction( int argc, VALUE *argv, VALUE self);
37
42
  static VALUE rollback_subtransaction( VALUE ary, VALUE err);
38
43
  static VALUE release_subtransaction( VALUE ary);
@@ -53,10 +58,12 @@ static VALUE backup_end( VALUE conn);
53
58
 
54
59
 
55
60
  static VALUE rb_ePgConnExec;
61
+ static VALUE rb_ePgConnTimeout;
56
62
  static VALUE rb_ePgConnTrans;
57
63
  static VALUE rb_ePgConnCopy;
58
64
 
59
65
  static ID id_to_a;
66
+ static ID id_fetch;
60
67
 
61
68
 
62
69
  void
@@ -72,8 +79,7 @@ pg_statement_exec( VALUE conn, VALUE cmd, VALUE par)
72
79
  struct pgconn_data *c;
73
80
  PGresult *result;
74
81
 
75
- Data_Get_Struct( conn, struct pgconn_data, c);
76
- pg_check_conninvalid( c);
82
+ c = get_pgconn( conn);
77
83
  if (NIL_P( par))
78
84
  result = PQexec( c->conn, pgconn_destring( c, cmd, NULL));
79
85
  else {
@@ -97,8 +103,7 @@ pg_statement_send( VALUE conn, VALUE cmd, VALUE par)
97
103
  struct pgconn_data *c;
98
104
  int res;
99
105
 
100
- Data_Get_Struct( conn, struct pgconn_data, c);
101
- pg_check_conninvalid( c);
106
+ c = get_pgconn( conn);
102
107
  if (NIL_P( par))
103
108
  res = PQsendQuery( c->conn, pgconn_destring( c, cmd, NULL));
104
109
  else {
@@ -112,6 +117,7 @@ pg_statement_send( VALUE conn, VALUE cmd, VALUE par)
112
117
  }
113
118
  if (res <= 0)
114
119
  pg_raise_connexec( c);
120
+ PQsetSingleRowMode( c->conn);
115
121
  }
116
122
 
117
123
  char **
@@ -123,7 +129,7 @@ params_to_strings( VALUE conn, VALUE params, int *len)
123
129
  char **values, **v;
124
130
  char *a;
125
131
 
126
- Data_Get_Struct( conn, struct pgconn_data, c);
132
+ c = get_pgconn( conn);
127
133
  ptr = RARRAY_PTR( params);
128
134
  *len = l = RARRAY_LEN( params);
129
135
  values = ALLOC_N( char *, l);
@@ -187,6 +193,13 @@ pgconn_exec( int argc, VALUE *argv, VALUE self)
187
193
  return yield_or_return_result( res);
188
194
  }
189
195
 
196
+ VALUE
197
+ yield_or_return_result( VALUE result)
198
+ {
199
+ return rb_block_given_p() ?
200
+ rb_ensure( rb_yield, result, pgresult_clear, result) : result;
201
+ }
202
+
190
203
 
191
204
  /*
192
205
  * call-seq:
@@ -195,18 +208,28 @@ pgconn_exec( int argc, VALUE *argv, VALUE self)
195
208
  * Sends an asynchronous SQL query request specified by +sql+ to the
196
209
  * PostgreSQL server.
197
210
  *
211
+ * This sets the query into single row mode. You have to call +Pg::Conn#fetch+
212
+ * what will yield one-row results. You may cancel the delivery by breaking
213
+ * the loop.
214
+ *
198
215
  * Use Pg::Conn#fetch to fetch the results after you waited for data.
199
216
  *
200
217
  * Pg::Conn.connect do |conn|
201
218
  * conn.send "SELECT pg_sleep(3), * FROM t;" do
202
- * ins = [ conn.socket]
203
- * loop do
204
- * r = IO.select ins, nil, nil, 0.5
205
- * break if r
206
- * puts Time.now
207
- * end
208
- * res = conn.fetch
209
- * res.each { |w| puts w.inspect }
219
+ * conn.fetch { |res|
220
+ * puts res.first.inspect
221
+ * break if (rand 3) < 1
222
+ * }
223
+ * end
224
+ * end
225
+ *
226
+ * Multiple select statements will be separated by an empty result.
227
+ *
228
+ * Pg::Conn.connect do |conn|
229
+ * conn.send "SELECT 33; SELECT 'foo';" do
230
+ * conn.fetch { |res|
231
+ * puts res.first.inspect
232
+ * }
210
233
  * end
211
234
  * end
212
235
  */
@@ -222,51 +245,140 @@ pgconn_send( int argc, VALUE *argv, VALUE self)
222
245
 
223
246
  /*
224
247
  * call-seq:
225
- * conn.fetch() -> result or nil
226
- * conn.fetch() { |result| ... } -> obj
248
+ * conn.fetch( timeout = nil) { |result| ... } -> obj
227
249
  *
228
250
  * Fetches the results of the previous Pg::Conn#send call.
229
251
  * See there for an example.
230
252
  *
231
- * The result will be +nil+ if there are no more results.
232
253
  */
233
254
  VALUE
234
- pgconn_fetch( VALUE self)
255
+ pgconn_fetch( int argc, VALUE *argv, VALUE conn)
235
256
  {
236
257
  struct pgconn_data *c;
237
258
  PGresult *result;
259
+ VALUE to;
260
+
261
+ rb_scan_args( argc, argv, "01", &to);
238
262
 
239
- Data_Get_Struct( self, struct pgconn_data, c);
240
- pg_check_conninvalid( c);
263
+ c = get_pgconn( conn);
264
+ wait_for_pgsocket( c->conn, to);
241
265
  if (PQconsumeInput( c->conn) == 0)
242
266
  pg_raise_connexec( c);
243
- if (PQisBusy( c->conn) > 0)
244
- return Qnil;
245
- result = PQgetResult( c->conn);
246
- return result == NULL ? Qnil :
247
- yield_or_return_result( pgresult_new( result, c, Qnil, Qnil));
267
+ if (PQisBusy( c->conn) == 0)
268
+ while ((result = PQgetResult( c->conn)) != NULL) {
269
+ VALUE res;
270
+
271
+ res = pgresult_new( result, c, Qnil, Qnil);
272
+ rb_ensure( rb_yield, res, pgresult_clear, res);
273
+ }
274
+ return Qnil;
248
275
  }
249
276
 
250
- VALUE
251
- yield_or_return_result( VALUE result)
252
- {
253
- return rb_block_given_p() ?
254
- rb_ensure( rb_yield, result, pgresult_clear, result) : result;
277
+ void
278
+ wait_for_pgsocket( PGconn *c, VALUE to)
279
+ {
280
+ int fd;
281
+ fd_set readset;
282
+ struct timeval tv, *ptv;
283
+
284
+ fd = PQsocket( c);
285
+
286
+ FD_ZERO(&readset);
287
+ FD_SET(fd, &readset);
288
+
289
+ ptv = NULL;
290
+ if (!NIL_P( to)) {
291
+ int type = TYPE( to);
292
+ if (type == T_FIXNUM) {
293
+ tv.tv_sec = FIX2LONG( to);
294
+ tv.tv_usec = 0;
295
+ } else {
296
+ double x;
297
+ switch (type) {
298
+ case T_FLOAT:
299
+ x = RFLOAT_VALUE( to);
300
+ break;
301
+ case T_BIGNUM:
302
+ x = rb_big2dbl( to);
303
+ break;
304
+ case T_RATIONAL:
305
+ x = rb_num2dbl( to);
306
+ break;
307
+ default:
308
+ x = RFLOAT_VALUE( rb_funcall( to, rb_intern( "to_f"), 0));
309
+ break;
310
+ }
311
+ tv.tv_sec = floor( x);
312
+ tv.tv_usec = round( (x-tv.tv_sec)*1000000);
313
+ }
314
+ ptv = &tv;
315
+ }
316
+
317
+ if (select( fd+1, &readset, NULL, NULL, ptv) < 0 || !FD_ISSET( fd, &readset))
318
+ rb_raise( rb_ePgConnTimeout, "Wait for data timed out.");
255
319
  }
256
320
 
257
321
  VALUE
258
- clear_resultqueue( VALUE self)
322
+ clear_resultqueue( VALUE conn)
259
323
  {
260
324
  struct pgconn_data *c;
261
325
  PGresult *result;
326
+ int cancelled;
262
327
 
263
- Data_Get_Struct( self, struct pgconn_data, c);
264
- while ((result = PQgetResult( c->conn)) != NULL)
328
+ c = get_pgconn( conn);
329
+ cancelled = 0;
330
+ while ((result = PQgetResult( c->conn)) != NULL) {
265
331
  PQclear( result);
332
+ if (!cancelled) {
333
+ char errbuf[ 256];
334
+ PGcancel *cancel;
335
+ int ret;
336
+
337
+ cancel = PQgetCancel( c->conn);
338
+ if (cancel == NULL)
339
+ rb_raise( rb_ePgConnTrans, "Could not get cancel object.");
340
+ ret = PQcancel( cancel, errbuf, sizeof errbuf);
341
+ PQfreeCancel( cancel);
342
+ if (ret == 0)
343
+ rb_raise( rb_ePgConnTrans, "Cancel of sent query failed: %s", errbuf);
344
+ cancelled = 1;
345
+ }
346
+ }
266
347
  return Qnil;
267
348
  }
268
349
 
269
350
 
351
+ /*
352
+ * call-seq:
353
+ * conn.fetch_rows( timeout = nil) { |row| ... } -> obj
354
+ *
355
+ * Fetches the results of the previous Pg::Conn#send call as an array.
356
+ *
357
+ * Multiple select statements will _not_ be separated by an empty array or
358
+ * something similar. Query twice or call +#fetch+ if you want to separate
359
+ * them.
360
+ *
361
+ * Pg::Conn.connect do |conn|
362
+ * conn.send "SELECT 33; SELECT 'foo';" do
363
+ * conn.fetch { |row|
364
+ * puts row.inspect
365
+ * }
366
+ * end
367
+ * end
368
+ */
369
+ VALUE
370
+ pgconn_fetch_rows( int argc, VALUE *argv, VALUE conn)
371
+ {
372
+ if (!id_fetch)
373
+ id_fetch = rb_intern( "fetch");
374
+ return rb_block_call( conn, id_fetch, argc, argv, fetch_result_each, Qnil);
375
+ }
376
+
377
+ VALUE
378
+ fetch_result_each( RB_BLOCK_CALL_FUNC_ARGLIST( res, arg))
379
+ {
380
+ return pgresult_each( res);
381
+ }
270
382
 
271
383
 
272
384
  /*
@@ -303,13 +415,13 @@ pgconn_query( int argc, VALUE *argv, VALUE self)
303
415
 
304
416
  /*
305
417
  * call-seq:
306
- * conn.select_one( query, *bind_values)
418
+ * conn.select_row( query, *bind_values)
307
419
  *
308
420
  * Return the first row of the query results.
309
421
  * Equivalent to <code>conn.query( query, *bind_values).first</code>.
310
422
  */
311
423
  VALUE
312
- pgconn_select_one( int argc, VALUE *argv, VALUE self)
424
+ pgconn_select_row( int argc, VALUE *argv, VALUE self)
313
425
  {
314
426
  VALUE cmd, par;
315
427
  VALUE res;
@@ -327,7 +439,7 @@ pgconn_select_one( int argc, VALUE *argv, VALUE self)
327
439
  * conn.select_value( query, *bind_values)
328
440
  *
329
441
  * Return the first value of the first row of the query results.
330
- * Equivalent to conn.query( query, *bind_values).first.first
442
+ * Equivalent to conn.query( query, *bind_values).first&.first
331
443
  */
332
444
  VALUE
333
445
  pgconn_select_value( int argc, VALUE *argv, VALUE self)
@@ -348,6 +460,7 @@ pgconn_select_value( int argc, VALUE *argv, VALUE self)
348
460
  * call-seq:
349
461
  * conn.select_values( query, *bind_values)
350
462
  *
463
+ * Return the all values over all rows as one array.
351
464
  * Equivalent to conn.query( query, *bind_values).flatten
352
465
  */
353
466
  VALUE
@@ -386,14 +499,14 @@ pgconn_select_values( int argc, VALUE *argv, VALUE self)
386
499
  * Returns a notifier. If there is no unprocessed notifier, it returns +nil+.
387
500
  */
388
501
  VALUE
389
- pgconn_get_notify( VALUE self)
502
+ pgconn_get_notify( VALUE conn)
390
503
  {
391
504
  struct pgconn_data *c;
392
505
  PGnotify *notify;
393
506
  VALUE rel, pid, ext;
394
507
  VALUE ret;
395
508
 
396
- Data_Get_Struct( self, struct pgconn_data, c);
509
+ c = get_pgconn( conn);
397
510
  if (PQconsumeInput( c->conn) == 0)
398
511
  pg_raise_connexec( c);
399
512
  notify = PQnotifies( c->conn);
@@ -422,7 +535,7 @@ pgconn_get_notify( VALUE self)
422
535
  *
423
536
  */
424
537
  VALUE
425
- pgconn_transaction( int argc, VALUE *argv, VALUE self)
538
+ pgconn_transaction( int argc, VALUE *argv, VALUE conn)
426
539
  {
427
540
  struct pgconn_data *c;
428
541
  VALUE ser, ro;
@@ -430,50 +543,50 @@ pgconn_transaction( int argc, VALUE *argv, VALUE self)
430
543
  int p;
431
544
 
432
545
  rb_scan_args( argc, argv, "02", &ser, &ro);
433
- cmd = rb_str_buf_new2( "begin");
546
+ cmd = rb_str_buf_new2( "BEGIN");
434
547
  p = 0;
435
548
  if (!NIL_P( ser)) {
436
- rb_str_buf_cat2( cmd, " isolation level ");
437
- rb_str_buf_cat2( cmd, RTEST(ser) ? "serializable" : "read committed");
549
+ rb_str_buf_cat2( cmd, " ISOLATION LEVEL ");
550
+ rb_str_buf_cat2( cmd, RTEST(ser) ? "SERIALIZABLE" : "READ COMMITTED");
438
551
  p++;
439
552
  }
440
553
  if (!NIL_P( ro)) {
441
554
  if (p) rb_str_buf_cat2( cmd, ",");
442
- rb_str_buf_cat2( cmd, " read ");
443
- rb_str_buf_cat2( cmd, (RTEST(ro) ? "only" : "write"));
555
+ rb_str_buf_cat2( cmd, " READ ");
556
+ rb_str_buf_cat2( cmd, (RTEST(ro) ? "ONLY" : "WRITE"));
444
557
  }
445
558
  rb_str_buf_cat2( cmd, ";");
446
559
 
447
- Data_Get_Struct( self, struct pgconn_data, c);
560
+ c = get_pgconn( conn);
448
561
  if (PQtransactionStatus( c->conn) > PQTRANS_IDLE)
449
562
  rb_raise( rb_ePgConnTrans,
450
563
  "Nested transaction block. Use Conn#subtransaction.");
451
- pgresult_clear( pg_statement_exec( self, cmd, Qnil));
452
- return rb_ensure( yield_transaction, self, commit_transaction, self);
564
+ pgresult_clear( pg_statement_exec( conn, cmd, Qnil));
565
+ return rb_ensure( yield_transaction, conn, commit_transaction, conn);
453
566
  }
454
567
 
455
568
  VALUE
456
- yield_transaction( VALUE self)
569
+ yield_transaction( VALUE conn)
457
570
  {
458
- return rb_rescue( rb_yield, self, rollback_transaction, self);
571
+ return rb_rescue( rb_yield, conn, rollback_transaction, conn);
459
572
  }
460
573
 
461
574
  VALUE
462
- rollback_transaction( VALUE self, VALUE err)
575
+ rollback_transaction( VALUE conn, VALUE err)
463
576
  {
464
- pgresult_clear( pg_statement_exec( self, rb_str_new2( "ROLLBACK;"), Qnil));
577
+ pgresult_clear( pg_statement_exec( conn, rb_str_new2( "ROLLBACK;"), Qnil));
465
578
  rb_exc_raise( err);
466
579
  return Qnil;
467
580
  }
468
581
 
469
582
  VALUE
470
- commit_transaction( VALUE self)
583
+ commit_transaction( VALUE conn)
471
584
  {
472
585
  struct pgconn_data *c;
473
586
 
474
- Data_Get_Struct( self, struct pgconn_data, c);
587
+ c = get_pgconn( conn);
475
588
  if (PQtransactionStatus( c->conn) > PQTRANS_IDLE)
476
- pgresult_clear( pg_statement_exec( self, rb_str_new2( "COMMIT;"), Qnil));
589
+ pgresult_clear( pg_statement_exec( conn, rb_str_new2( "COMMIT;"), Qnil));
477
590
  return Qnil;
478
591
  }
479
592
 
@@ -495,13 +608,13 @@ pgconn_subtransaction( int argc, VALUE *argv, VALUE self)
495
608
  char *p;
496
609
  int n;
497
610
 
498
- Data_Get_Struct( self, struct pgconn_data, c);
611
+ c = get_pgconn( self);
499
612
  a = rb_scan_args( argc, argv, "1*", &sp, &par);
500
613
  StringValue( sp);
501
614
  if (a > 1)
502
615
  sp = rb_str_format(RARRAY_LEN(par), RARRAY_PTR(par), sp);
503
616
 
504
- cmd = rb_str_buf_new2( "savepoint ");
617
+ cmd = rb_str_buf_new2( "SAVEPOINT ");
505
618
  q = pgconn_destring( c, sp, &n);
506
619
  p = PQescapeIdentifier( c->conn, q, n);
507
620
  rb_str_buf_cat2( cmd, p);
@@ -524,7 +637,7 @@ rollback_subtransaction( VALUE ary, VALUE err)
524
637
  {
525
638
  VALUE cmd;
526
639
 
527
- cmd = rb_str_buf_new2( "rollback to savepoint ");
640
+ cmd = rb_str_buf_new2( "ROLLBACK TO SAVEPOINT ");
528
641
  rb_str_buf_append( cmd, rb_ary_entry( ary, 1));
529
642
  rb_str_buf_cat2( cmd, ";");
530
643
  pgresult_clear( pg_statement_exec( rb_ary_entry( ary, 0), cmd, Qnil));
@@ -541,7 +654,7 @@ release_subtransaction( VALUE ary)
541
654
 
542
655
  n = rb_ary_entry( ary, 1);
543
656
  if (!NIL_P( n)) {
544
- cmd = rb_str_buf_new2( "release savepoint ");
657
+ cmd = rb_str_buf_new2( "RELEASE SAVEPOINT ");
545
658
  rb_str_buf_append( cmd, n);
546
659
  rb_str_buf_cat2( cmd, ";");
547
660
  pgresult_clear( pg_statement_exec( rb_ary_entry( ary, 0), cmd, Qnil));
@@ -569,7 +682,7 @@ pgconn_transaction_status( VALUE self)
569
682
  {
570
683
  struct pgconn_data *c;
571
684
 
572
- Data_Get_Struct( self, struct pgconn_data, c);
685
+ c = get_pgconn( self);
573
686
  return INT2FIX( PQtransactionStatus( c->conn));
574
687
  }
575
688
 
@@ -584,7 +697,7 @@ pgconn_transaction_status( VALUE self)
584
697
  *
585
698
  * conn.copy_stdin "COPY t FROM STDIN;" do
586
699
  * ary = ...
587
- * l = stringize_line ary
700
+ * l = conn.stringize_line ary
588
701
  * conn.put l
589
702
  * end
590
703
  *
@@ -609,7 +722,7 @@ put_end( VALUE self)
609
722
  int r;
610
723
  PGresult *res;
611
724
 
612
- Data_Get_Struct( self, struct pgconn_data, c);
725
+ c = get_pgconn( self);
613
726
  /*
614
727
  * I would like to hand over something like
615
728
  * RSTRING_PTR( rb_obj_as_string( rb_errinfo()))
@@ -669,7 +782,7 @@ pgconn_putline( VALUE self, VALUE arg)
669
782
  str = t;
670
783
  }
671
784
 
672
- Data_Get_Struct( self, struct pgconn_data, c);
785
+ c = get_pgconn( self);
673
786
  p = pgconn_destring( c, str, &l);
674
787
  r = PQputCopyData( c->conn, p, l);
675
788
  if (r < 0)
@@ -721,7 +834,7 @@ get_end( VALUE self)
721
834
  struct pgconn_data *c;
722
835
  PGresult *res;
723
836
 
724
- Data_Get_Struct( self, struct pgconn_data, c);
837
+ c = get_pgconn( self);
725
838
  if ((res = PQgetResult( c->conn)) != NULL)
726
839
  pgresult_new( res, c, Qnil, Qnil);
727
840
  return Qnil;
@@ -752,7 +865,7 @@ pgconn_getline( int argc, VALUE *argv, VALUE self)
752
865
 
753
866
  async = rb_scan_args( argc, argv, "01", &as) > 0 && !NIL_P( as) ? 1 : 0;
754
867
 
755
- Data_Get_Struct( self, struct pgconn_data, c);
868
+ c = get_pgconn( self);
756
869
  r = PQgetCopyData( c->conn, &b, async);
757
870
  if (r > 0) {
758
871
  VALUE ret;
@@ -786,7 +899,7 @@ pgconn_each_line( VALUE self)
786
899
  int r;
787
900
  VALUE s;
788
901
 
789
- Data_Get_Struct( self, struct pgconn_data, c);
902
+ c = get_pgconn( self);
790
903
  for (; (r = PQgetCopyData( c->conn, &b, 0)) > 0;) {
791
904
  s = pgconn_mkstringn( c, b, r);
792
905
  PQfreemem( b);
@@ -856,16 +969,18 @@ Init_pgsql_conn_exec( void)
856
969
  rb_cPgConn = rb_define_class_under( rb_mPg, "Conn", rb_cObject);
857
970
  #endif
858
971
 
859
- rb_ePgConnExec = rb_define_class_under( rb_cPgConn, "ExecError", rb_ePgError);
860
- rb_ePgConnTrans = rb_define_class_under( rb_cPgConn, "TransactionError", rb_ePgError);
861
- rb_ePgConnCopy = rb_define_class_under( rb_cPgConn, "CopyError", rb_ePgError);
972
+ rb_ePgConnExec = rb_define_class_under( rb_cPgConn, "ExecError", rb_ePgError);
973
+ rb_ePgConnTimeout = rb_define_class_under( rb_cPgConn, "Timeout", rb_ePgError);
974
+ rb_ePgConnTrans = rb_define_class_under( rb_cPgConn, "TransactionError", rb_ePgError);
975
+ rb_ePgConnCopy = rb_define_class_under( rb_cPgConn, "CopyError", rb_ePgError);
862
976
 
863
977
  rb_define_method( rb_cPgConn, "exec", &pgconn_exec, -1);
864
978
  rb_define_method( rb_cPgConn, "send", &pgconn_send, -1);
865
- rb_define_method( rb_cPgConn, "fetch", &pgconn_fetch, 0);
979
+ rb_define_method( rb_cPgConn, "fetch", &pgconn_fetch, -1);
980
+ rb_define_method( rb_cPgConn, "fetch_rows", &pgconn_fetch_rows, -1);
866
981
 
867
982
  rb_define_method( rb_cPgConn, "query", &pgconn_query, -1);
868
- rb_define_method( rb_cPgConn, "select_one", &pgconn_select_one, -1);
983
+ rb_define_method( rb_cPgConn, "select_row", &pgconn_select_row, -1);
869
984
  rb_define_method( rb_cPgConn, "select_value", &pgconn_select_value, -1);
870
985
  rb_define_method( rb_cPgConn, "select_values", &pgconn_select_values, -1);
871
986
  rb_define_method( rb_cPgConn, "get_notify", &pgconn_get_notify, 0);
@@ -895,6 +1010,7 @@ Init_pgsql_conn_exec( void)
895
1010
 
896
1011
  rb_define_method( rb_cPgConn, "backup", &pgconn_backup, 1);
897
1012
 
898
- id_to_a = 0;
1013
+ id_to_a = 0;
1014
+ id_fetch = 0;
899
1015
  }
900
1016
 
data/lib/conn_quote.c CHANGED
@@ -355,7 +355,7 @@ pgconn_for_copy( VALUE self, VALUE obj)
355
355
  rb_global_variable( &pg_escape_regex);
356
356
  }
357
357
  if (RTEST( rb_reg_match( pg_escape_regex, ret)))
358
- ret = rb_block_call( ret, id_gsub, 1, &pg_escape_regex, gsub_escape_i, Qnil);
358
+ ret = rb_block_call( ret, id_gsub, 1, &pg_escape_regex, &gsub_escape_i, Qnil);
359
359
  }
360
360
  return ret;
361
361
  }
@@ -472,7 +472,7 @@ gsub_escape_i( RB_BLOCK_CALL_FUNC_ARGLIST( c, arg))
472
472
  * This method is to prevent you from saying something like <code>"insert into
473
473
  * ... (E'#{conn.stringize obj}', ...);"</code>. It is more efficient to say
474
474
  *
475
- * conn.exec "insert into ... (#{conn.quote obj}, ...);"
475
+ * conn.exec "INSERT INTO ... (#{conn.quote obj}, ...);"
476
476
  *
477
477
  * Your self-defined classes will be checked whether they have a method named
478
478
  * +to_postgres+. If that doesn't exist the object will be converted by
@@ -517,25 +517,25 @@ VALUE pgconn_quote( VALUE self, VALUE obj)
517
517
  co = CLASS_OF( obj);
518
518
  if (co == rb_cTime) {
519
519
  res = rb_funcall( obj, id_iso8601, 0);
520
- type = "timestamptz";
520
+ type = "TIMESTAMPTZ";
521
521
  } else if (co == rb_cDate) {
522
522
  res = rb_obj_as_string( obj);
523
- type = "date";
523
+ type = "DATE";
524
524
  } else if (co == rb_cDateTime) {
525
525
  res = rb_obj_as_string( obj);
526
- type = "timestamptz";
526
+ type = "TIMESTAMPTZ";
527
527
  } else if (co == pg_monetary_class() &&
528
528
  rb_respond_to( obj, id_raw)) {
529
529
  res = rb_funcall( obj, id_raw, 0);
530
530
  StringValue( res);
531
- type = "money";
531
+ type = "MONEY";
532
532
  } else if (rb_respond_to( obj, id_to_postgres)) {
533
533
  res = rb_funcall( obj, id_to_postgres, 0);
534
534
  StringValue( res);
535
535
  type = NULL;
536
536
  } else {
537
537
  res = rb_obj_as_string( obj);
538
- type = "unknown";
538
+ type = "UNKNOWN";
539
539
  }
540
540
  res = quote_string( self, res);
541
541
  if (type != NULL) {
data/lib/module.c CHANGED
@@ -8,7 +8,7 @@
8
8
  #include "result.h"
9
9
 
10
10
 
11
- #define PGSQL_VERSION "1.6"
11
+ #define PGSQL_VERSION "1.9.1"
12
12
 
13
13
 
14
14
  VALUE rb_mPg;
data/lib/result.c CHANGED
@@ -241,6 +241,8 @@ pgresult_new( PGresult *result, struct pgconn_data *conn, VALUE cmd, VALUE par)
241
241
  case PGRES_TUPLES_OK:
242
242
  case PGRES_COPY_OUT:
243
243
  case PGRES_COPY_IN:
244
+ case PGRES_COPY_BOTH:
245
+ case PGRES_SINGLE_TUPLE:
244
246
  break;
245
247
  case PGRES_BAD_RESPONSE:
246
248
  case PGRES_NONFATAL_ERROR:
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pgsql
3
3
  version: !ruby/object:Gem::Version
4
- version: '1.6'
4
+ version: 1.9.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bertram Scharpf
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-12-04 00:00:00.000000000 Z
11
+ date: 2021-09-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: autorake