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 +4 -4
- data/lib/Rakefile +1 -1
- data/lib/conn.c +83 -87
- data/lib/conn_exec.c +191 -75
- data/lib/conn_quote.c +7 -7
- data/lib/module.c +1 -1
- data/lib/result.c +2 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d735e83feb39d55f95efc1a196d433800c523fd0e73538b2c6415edd098f405c
|
4
|
+
data.tar.gz: e8e6e0b0526a73de32bf227effe13337ef125ea9f69d05099401aae4455c4288
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bbccf68542f27fc341ed1b517109655d5dd96b9d8cb21ac94e9d874f54d40eec9b3f50652967bb592cf04da68804c1351e01598ab8e4f3487ecc50b706dee65a
|
7
|
+
data.tar.gz: 388001a630086ddb47acb19672291ebe1cbd95f0349038e97189ff676e246047c4ce055bc726d065a9aea399cfdf1ff8d1e62d293178ebc6b8c131b10e4b951a
|
data/lib/Rakefile
CHANGED
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
|
33
|
-
static
|
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
|
-
*
|
256
|
-
*
|
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
|
-
*
|
261
|
-
*
|
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, ¶ms) < 2)
|
283
|
-
if (TYPE( str)
|
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
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
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, ¶ms);
|
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
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
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
|
-
|
348
|
-
|
349
|
-
{
|
350
|
-
|
351
|
-
|
352
|
-
|
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
|
-
|
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
|
-
|
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
|
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
|
38
|
+
static VALUE rollback_transaction( VALUE conn, VALUE err);
|
34
39
|
static VALUE commit_transaction( VALUE self);
|
35
|
-
static VALUE yield_transaction( VALUE
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
*
|
203
|
-
*
|
204
|
-
*
|
205
|
-
*
|
206
|
-
*
|
207
|
-
*
|
208
|
-
*
|
209
|
-
*
|
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()
|
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
|
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
|
-
|
240
|
-
|
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)
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
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
|
-
|
251
|
-
|
252
|
-
{
|
253
|
-
|
254
|
-
|
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
|
322
|
+
clear_resultqueue( VALUE conn)
|
259
323
|
{
|
260
324
|
struct pgconn_data *c;
|
261
325
|
PGresult *result;
|
326
|
+
int cancelled;
|
262
327
|
|
263
|
-
|
264
|
-
|
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.
|
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
|
-
|
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
|
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
|
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
|
-
|
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
|
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( "
|
546
|
+
cmd = rb_str_buf_new2( "BEGIN");
|
434
547
|
p = 0;
|
435
548
|
if (!NIL_P( ser)) {
|
436
|
-
rb_str_buf_cat2( cmd, "
|
437
|
-
rb_str_buf_cat2( cmd, RTEST(ser) ? "
|
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, "
|
443
|
-
rb_str_buf_cat2( cmd, (RTEST(ro) ? "
|
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
|
-
|
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(
|
452
|
-
return rb_ensure( yield_transaction,
|
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
|
569
|
+
yield_transaction( VALUE conn)
|
457
570
|
{
|
458
|
-
return rb_rescue( rb_yield,
|
571
|
+
return rb_rescue( rb_yield, conn, rollback_transaction, conn);
|
459
572
|
}
|
460
573
|
|
461
574
|
VALUE
|
462
|
-
rollback_transaction( VALUE
|
575
|
+
rollback_transaction( VALUE conn, VALUE err)
|
463
576
|
{
|
464
|
-
pgresult_clear( pg_statement_exec(
|
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
|
583
|
+
commit_transaction( VALUE conn)
|
471
584
|
{
|
472
585
|
struct pgconn_data *c;
|
473
586
|
|
474
|
-
|
587
|
+
c = get_pgconn( conn);
|
475
588
|
if (PQtransactionStatus( c->conn) > PQTRANS_IDLE)
|
476
|
-
pgresult_clear( pg_statement_exec(
|
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
|
-
|
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( "
|
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( "
|
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( "
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
860
|
-
|
861
|
-
|
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,
|
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, "
|
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
|
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 "
|
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 = "
|
520
|
+
type = "TIMESTAMPTZ";
|
521
521
|
} else if (co == rb_cDate) {
|
522
522
|
res = rb_obj_as_string( obj);
|
523
|
-
type = "
|
523
|
+
type = "DATE";
|
524
524
|
} else if (co == rb_cDateTime) {
|
525
525
|
res = rb_obj_as_string( obj);
|
526
|
-
type = "
|
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 = "
|
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 = "
|
538
|
+
type = "UNKNOWN";
|
539
539
|
}
|
540
540
|
res = quote_string( self, res);
|
541
541
|
if (type != NULL) {
|
data/lib/module.c
CHANGED
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:
|
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:
|
11
|
+
date: 2021-09-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: autorake
|