pgsql 1.6 → 1.9.1
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.
- 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
|