ruby-postgres 0.7.1.2005.11.24-mswin32
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.
- data/ChangeLog +261 -0
- data/Contributors +26 -0
- data/MANIFEST +14 -0
- data/Makefile +139 -0
- data/README +171 -0
- data/README.ja +183 -0
- data/doc/postgres.html +278 -0
- data/doc/postgres.jp.html +256 -0
- data/extconf.rb +33 -0
- data/libpq-compat.c +253 -0
- data/mkmf.log +154 -0
- data/postgres.c +2454 -0
- data/postgres.o +0 -0
- data/postgres.so +0 -0
- data/ruby-postgres.gemspec +35 -0
- data/sample/losample.rb +47 -0
- data/sample/psql.rb +1181 -0
- data/sample/psqlHelp.rb +158 -0
- data/sample/test1.rb +63 -0
- data/sample/test2.rb +44 -0
- data/sample/test4.rb +71 -0
- data/type-oids.h +65 -0
- metadata +61 -0
data/postgres.c
ADDED
@@ -0,0 +1,2454 @@
|
|
1
|
+
/************************************************
|
2
|
+
|
3
|
+
postgres.c -
|
4
|
+
|
5
|
+
Author: matz
|
6
|
+
created at: Tue May 13 20:07:35 JST 1997
|
7
|
+
|
8
|
+
Author: ematsu
|
9
|
+
modified at: Wed Jan 20 16:41:51 1999
|
10
|
+
|
11
|
+
$Author: noboru $
|
12
|
+
$Date: 2003/01/06 01:38:20 $
|
13
|
+
************************************************/
|
14
|
+
|
15
|
+
#include "ruby.h"
|
16
|
+
#include "rubyio.h"
|
17
|
+
#include "st.h"
|
18
|
+
#include "intern.h"
|
19
|
+
|
20
|
+
/* grep '^#define' $(pg_config --includedir)/server/catalog/pg_type.h | grep OID */
|
21
|
+
#include "type-oids.h"
|
22
|
+
#include <libpq-fe.h>
|
23
|
+
#include <libpq/libpq-fs.h> /* large-object interface */
|
24
|
+
#include <stdio.h>
|
25
|
+
#include <stdlib.h>
|
26
|
+
#include <sys/types.h>
|
27
|
+
|
28
|
+
#ifndef HAVE_PG_ENCODING_TO_CHAR
|
29
|
+
#define pg_encoding_to_char(x) "SQL_ASCII"
|
30
|
+
#else
|
31
|
+
extern char* pg_encoding_to_char(int);
|
32
|
+
#endif
|
33
|
+
|
34
|
+
#ifndef HAVE_PQFREEMEM
|
35
|
+
#define PQfreemem(ptr) free(ptr)
|
36
|
+
#endif
|
37
|
+
|
38
|
+
#ifndef StringValuePtr
|
39
|
+
#define StringValuePtr(x) STR2CSTR(x)
|
40
|
+
#endif
|
41
|
+
|
42
|
+
#define AssignCheckedStringValue(cstring, rstring) do { \
|
43
|
+
if (!NIL_P(temp = rstring)) { \
|
44
|
+
Check_Type(temp, T_STRING); \
|
45
|
+
cstring = StringValuePtr(temp); \
|
46
|
+
} \
|
47
|
+
} while (0)
|
48
|
+
|
49
|
+
#if RUBY_VERSION_CODE < 180
|
50
|
+
#define rb_check_string_type(x) rb_check_convert_type(x, T_STRING, "String", "to_str")
|
51
|
+
#endif
|
52
|
+
|
53
|
+
#define rb_check_hash_type(x) rb_check_convert_type(x, T_HASH, "Hash", "to_hash")
|
54
|
+
|
55
|
+
#define Data_Set_Struct(obj,ptr) do { \
|
56
|
+
Check_Type(obj, T_DATA); \
|
57
|
+
DATA_PTR(obj) = ptr; \
|
58
|
+
} while (0)
|
59
|
+
|
60
|
+
#define RUBY_CLASS(name) rb_const_get(rb_cObject, rb_intern(name))
|
61
|
+
|
62
|
+
#define SINGLE_QUOTE '\''
|
63
|
+
|
64
|
+
EXTERN VALUE rb_mEnumerable;
|
65
|
+
EXTERN VALUE rb_mKernel;
|
66
|
+
EXTERN VALUE rb_cTime;
|
67
|
+
|
68
|
+
static VALUE rb_cDate;
|
69
|
+
static VALUE rb_cDateTime;
|
70
|
+
static VALUE rb_cBigDecimal;
|
71
|
+
|
72
|
+
static VALUE rb_cPGconn;
|
73
|
+
static VALUE rb_cPGresult;
|
74
|
+
static VALUE rb_ePGError;
|
75
|
+
static VALUE rb_cPGlarge;
|
76
|
+
static VALUE rb_cPGrow;
|
77
|
+
|
78
|
+
static VALUE pgresult_result_with_clear _((VALUE));
|
79
|
+
static VALUE pgresult_new _((PGresult*));
|
80
|
+
|
81
|
+
/* Large Object support */
|
82
|
+
typedef struct pglarge_object
|
83
|
+
{
|
84
|
+
PGconn *pgconn;
|
85
|
+
Oid lo_oid;
|
86
|
+
int lo_fd;
|
87
|
+
} PGlarge;
|
88
|
+
|
89
|
+
static VALUE pglarge_new _((PGconn*, Oid, int));
|
90
|
+
/* Large Object support */
|
91
|
+
|
92
|
+
static void free_pgconn(PGconn *);
|
93
|
+
|
94
|
+
static VALUE
|
95
|
+
pgconn_alloc(klass)
|
96
|
+
VALUE klass;
|
97
|
+
{
|
98
|
+
return Data_Wrap_Struct(klass, 0, free_pgconn, NULL);
|
99
|
+
}
|
100
|
+
|
101
|
+
static int build_key_value_string_i(VALUE key, VALUE value, VALUE result);
|
102
|
+
|
103
|
+
static PGconn *
|
104
|
+
try_connectdb(arg)
|
105
|
+
VALUE arg;
|
106
|
+
{
|
107
|
+
VALUE conninfo;
|
108
|
+
|
109
|
+
if (!NIL_P(conninfo = rb_check_string_type(arg))) {
|
110
|
+
/* do nothing */
|
111
|
+
}
|
112
|
+
else if (!NIL_P(conninfo = rb_check_hash_type(arg))) {
|
113
|
+
VALUE key_values = rb_ary_new2(RHASH(conninfo)->tbl->num_entries);
|
114
|
+
rb_hash_foreach(conninfo, build_key_value_string_i, key_values);
|
115
|
+
conninfo = rb_ary_join(key_values, rb_str_new2(" "));
|
116
|
+
}
|
117
|
+
else {
|
118
|
+
return NULL;
|
119
|
+
}
|
120
|
+
|
121
|
+
return PQconnectdb(StringValuePtr(conninfo));
|
122
|
+
}
|
123
|
+
|
124
|
+
static PGconn *
|
125
|
+
try_setdbLogin(args)
|
126
|
+
VALUE args;
|
127
|
+
{
|
128
|
+
VALUE temp;
|
129
|
+
char *host, *port, *opt, *tty, *dbname, *login, *pwd;
|
130
|
+
host=port=opt=tty=dbname=login=pwd=NULL;
|
131
|
+
|
132
|
+
rb_funcall(args, rb_intern("flatten!"), 0);
|
133
|
+
|
134
|
+
AssignCheckedStringValue(host, rb_ary_entry(args, 0));
|
135
|
+
if (!NIL_P(temp = rb_ary_entry(args, 1)) && NUM2INT(temp) != -1) {
|
136
|
+
temp = rb_obj_as_string(temp);
|
137
|
+
port = StringValuePtr(temp);
|
138
|
+
}
|
139
|
+
AssignCheckedStringValue(opt, rb_ary_entry(args, 2));
|
140
|
+
AssignCheckedStringValue(tty, rb_ary_entry(args, 3));
|
141
|
+
AssignCheckedStringValue(dbname, rb_ary_entry(args, 4));
|
142
|
+
AssignCheckedStringValue(login, rb_ary_entry(args, 5));
|
143
|
+
AssignCheckedStringValue(pwd, rb_ary_entry(args, 6));
|
144
|
+
|
145
|
+
return PQsetdbLogin(host, port, opt, tty, dbname, login, pwd);
|
146
|
+
}
|
147
|
+
|
148
|
+
static VALUE
|
149
|
+
pgconn_connect(argc, argv, self)
|
150
|
+
int argc;
|
151
|
+
VALUE *argv;
|
152
|
+
VALUE self;
|
153
|
+
{
|
154
|
+
VALUE args;
|
155
|
+
PGconn *conn = NULL;
|
156
|
+
|
157
|
+
rb_scan_args(argc, argv, "0*", &args);
|
158
|
+
if (RARRAY(args)->len == 1) {
|
159
|
+
conn = try_connectdb(rb_ary_entry(args, 0));
|
160
|
+
}
|
161
|
+
if (conn == NULL) {
|
162
|
+
conn = try_setdbLogin(args);
|
163
|
+
}
|
164
|
+
|
165
|
+
if (PQstatus(conn) == CONNECTION_BAD) {
|
166
|
+
VALUE message = rb_str_new2(PQerrorMessage(conn));
|
167
|
+
PQfinish(conn);
|
168
|
+
rb_raise(rb_ePGError, StringValuePtr(message));
|
169
|
+
}
|
170
|
+
|
171
|
+
Data_Set_Struct(self, conn);
|
172
|
+
return self;
|
173
|
+
}
|
174
|
+
|
175
|
+
/*
|
176
|
+
* See #new.
|
177
|
+
*/
|
178
|
+
static VALUE
|
179
|
+
pgconn_s_connect(argc, argv, klass)
|
180
|
+
int argc;
|
181
|
+
VALUE *argv;
|
182
|
+
VALUE klass;
|
183
|
+
{
|
184
|
+
return rb_class_new_instance(argc, argv, klass);
|
185
|
+
}
|
186
|
+
|
187
|
+
static VALUE format_array_element(VALUE obj);
|
188
|
+
|
189
|
+
static VALUE
|
190
|
+
pgconn_s_format(self, obj)
|
191
|
+
VALUE self;
|
192
|
+
VALUE obj;
|
193
|
+
{
|
194
|
+
VALUE result;
|
195
|
+
int tainted;
|
196
|
+
long i;
|
197
|
+
|
198
|
+
switch(TYPE(obj)) {
|
199
|
+
case T_STRING:
|
200
|
+
return obj;
|
201
|
+
|
202
|
+
case T_TRUE:
|
203
|
+
case T_FALSE:
|
204
|
+
case T_FIXNUM:
|
205
|
+
case T_BIGNUM:
|
206
|
+
case T_FLOAT:
|
207
|
+
return rb_obj_as_string(obj);
|
208
|
+
|
209
|
+
case T_NIL:
|
210
|
+
return rb_str_new2("NULL");
|
211
|
+
|
212
|
+
case T_ARRAY:
|
213
|
+
result = rb_str_buf_new2("{");
|
214
|
+
tainted = OBJ_TAINTED(obj);
|
215
|
+
for (i = 0; i < RARRAY(obj)->len; i++) {
|
216
|
+
VALUE element = format_array_element(RARRAY(obj)->ptr[i]);
|
217
|
+
if (OBJ_TAINTED(RARRAY(obj)->ptr[i])) tainted = Qtrue;
|
218
|
+
if (i > 0) rb_str_buf_cat2(result, ", ");
|
219
|
+
rb_str_buf_append(result, element);
|
220
|
+
}
|
221
|
+
rb_str_buf_cat2(result, "}");
|
222
|
+
if (tainted) OBJ_TAINT(result);
|
223
|
+
return result;
|
224
|
+
|
225
|
+
default:
|
226
|
+
if (rb_class_of(obj) == rb_cBigDecimal) {
|
227
|
+
return rb_funcall(obj, rb_intern("to_s"), 1, rb_str_new2("F"));
|
228
|
+
}
|
229
|
+
else if (rb_block_given_p()) {
|
230
|
+
return rb_yield(obj);
|
231
|
+
} else {
|
232
|
+
rb_raise(rb_ePGError, "can't format");
|
233
|
+
}
|
234
|
+
}
|
235
|
+
}
|
236
|
+
|
237
|
+
static VALUE
|
238
|
+
format_array_element(obj)
|
239
|
+
VALUE obj;
|
240
|
+
{
|
241
|
+
if (TYPE(obj) == T_STRING) {
|
242
|
+
obj = rb_funcall(obj, rb_intern("gsub"), 2, rb_reg_new("(?=[\\\\\"])", 9, 0), "\\");
|
243
|
+
return rb_funcall(obj, rb_intern("gsub!"), 2, rb_reg_new("^|$", 3, 0), "\"");
|
244
|
+
}
|
245
|
+
else {
|
246
|
+
return pgconn_s_format(NULL, obj);
|
247
|
+
}
|
248
|
+
}
|
249
|
+
|
250
|
+
/*
|
251
|
+
* call-seq:
|
252
|
+
* PGconn.quote( obj )
|
253
|
+
* PGconn.quote( obj ) { |obj| ... }
|
254
|
+
* PGconn.format( obj )
|
255
|
+
* PGconn.format( obj ) { |obj| ... }
|
256
|
+
*
|
257
|
+
* If _obj_ is a Number, String, Array, +nil+, +true+, or +false+ then
|
258
|
+
* #quote returns a String representation of that object safe for use in PostgreSQL.
|
259
|
+
*
|
260
|
+
* If _obj_ is not one of the above classes and a block is supplied to #quote,
|
261
|
+
* the block is invoked, passing along the object. The return value from the
|
262
|
+
* block is returned as a string.
|
263
|
+
*
|
264
|
+
* If _obj_ is not one of the recognized classes andno block is supplied,
|
265
|
+
* a PGError is raised.
|
266
|
+
*/
|
267
|
+
static VALUE
|
268
|
+
pgconn_s_quote(self, obj)
|
269
|
+
VALUE self;
|
270
|
+
VALUE obj;
|
271
|
+
{
|
272
|
+
char* quoted;
|
273
|
+
int size;
|
274
|
+
VALUE result;
|
275
|
+
|
276
|
+
if (TYPE(obj) == T_STRING) {
|
277
|
+
quoted = ALLOCA_N(char, RSTRING(obj)->len * 2 + 1 + 2);
|
278
|
+
size = PQescapeString(quoted + 1, RSTRING(obj)->ptr, RSTRING(obj)->len);
|
279
|
+
*quoted = *(quoted + size + 1) = SINGLE_QUOTE;
|
280
|
+
result = rb_str_new(quoted, size + 2);
|
281
|
+
OBJ_INFECT(result, obj);
|
282
|
+
return result;
|
283
|
+
}
|
284
|
+
else {
|
285
|
+
return pgconn_s_format(self, obj);
|
286
|
+
}
|
287
|
+
}
|
288
|
+
|
289
|
+
static int
|
290
|
+
build_key_value_string_i(key, value, result)
|
291
|
+
VALUE key, value, result;
|
292
|
+
{
|
293
|
+
VALUE key_value;
|
294
|
+
if (key == Qundef) return ST_CONTINUE;
|
295
|
+
key_value = rb_str_dup(key);
|
296
|
+
rb_str_cat(key_value, "=", 1);
|
297
|
+
rb_str_concat(key_value, pgconn_s_quote(NULL, value));
|
298
|
+
rb_ary_push(result, key_value);
|
299
|
+
return ST_CONTINUE;
|
300
|
+
}
|
301
|
+
|
302
|
+
/*
|
303
|
+
* call-seq:
|
304
|
+
* PGconn.escape( str )
|
305
|
+
*
|
306
|
+
* Returns a SQL-safe version of the String _str_. Unlike #quote, does not wrap the String in '...'.
|
307
|
+
*/
|
308
|
+
static VALUE
|
309
|
+
pgconn_s_escape(self, string)
|
310
|
+
VALUE self;
|
311
|
+
VALUE string;
|
312
|
+
{
|
313
|
+
char* escaped;
|
314
|
+
int size;
|
315
|
+
VALUE result;
|
316
|
+
|
317
|
+
Check_Type(string, T_STRING);
|
318
|
+
|
319
|
+
escaped = ALLOCA_N(char, RSTRING(string)->len * 2 + 1);
|
320
|
+
size = PQescapeString(escaped, RSTRING(string)->ptr, RSTRING(string)->len);
|
321
|
+
result = rb_str_new(escaped, size);
|
322
|
+
OBJ_INFECT(result, string);
|
323
|
+
return result;
|
324
|
+
}
|
325
|
+
|
326
|
+
/*
|
327
|
+
* call-seq:
|
328
|
+
* PGconn.escape_bytea( obj )
|
329
|
+
*
|
330
|
+
* Escapes binary data for use within an SQL command with the type +bytea+.
|
331
|
+
*
|
332
|
+
* Certain byte values must be escaped (but all byte values may be escaped)
|
333
|
+
* when used as part of a +bytea+ literal in an SQL statement. In general, to
|
334
|
+
* escape a byte, it is converted into the three digit octal number equal to
|
335
|
+
* the octet value, and preceded by two backslashes. The single quote (') and
|
336
|
+
* backslash (\) characters have special alternative escape sequences.
|
337
|
+
* #escape_bytea performs this operation, escaping only the minimally required bytes.
|
338
|
+
*
|
339
|
+
* See the PostgreSQL documentation on PQescapeBytea[http://www.postgresql.org/docs/current/interactive/libpq-exec.html#LIBPQ-EXEC-ESCAPE-BYTEA] for more information.
|
340
|
+
*/
|
341
|
+
static VALUE
|
342
|
+
pgconn_s_escape_bytea(self, obj)
|
343
|
+
VALUE self;
|
344
|
+
VALUE obj;
|
345
|
+
{
|
346
|
+
char *from, *to;
|
347
|
+
size_t from_len, to_len;
|
348
|
+
VALUE ret;
|
349
|
+
|
350
|
+
Check_Type(obj, T_STRING);
|
351
|
+
from = RSTRING(obj)->ptr;
|
352
|
+
from_len = RSTRING(obj)->len;
|
353
|
+
|
354
|
+
to = (char *)PQescapeBytea(from, from_len, &to_len);
|
355
|
+
|
356
|
+
ret = rb_str_new(to, to_len - 1);
|
357
|
+
OBJ_INFECT(ret, obj);
|
358
|
+
|
359
|
+
PQfreemem(to);
|
360
|
+
|
361
|
+
return ret;
|
362
|
+
}
|
363
|
+
|
364
|
+
/*
|
365
|
+
* call-seq:
|
366
|
+
* PGconn.unescape_bytea( obj )
|
367
|
+
*
|
368
|
+
* Converts an escaped string representation of binary data into binary data --- the
|
369
|
+
* reverse of #escape_bytea. This is needed when retrieving +bytea+ data in text format,
|
370
|
+
* but not when retrieving it in binary format.
|
371
|
+
*
|
372
|
+
* See the PostgreSQL documentation on PQunescapeBytea[http://www.postgresql.org/docs/current/interactive/libpq-exec.html#LIBPQ-EXEC-ESCAPE-BYTEA] for more information.
|
373
|
+
*/
|
374
|
+
static VALUE
|
375
|
+
pgconn_s_unescape_bytea(self, obj)
|
376
|
+
VALUE self;
|
377
|
+
VALUE obj;
|
378
|
+
{
|
379
|
+
char *from, *to;
|
380
|
+
size_t to_len;
|
381
|
+
VALUE ret;
|
382
|
+
|
383
|
+
Check_Type(obj, T_STRING);
|
384
|
+
from = StringValuePtr(obj);
|
385
|
+
|
386
|
+
to = (char *)PQunescapeBytea(from, &to_len);
|
387
|
+
|
388
|
+
ret = rb_str_new(to, to_len);
|
389
|
+
OBJ_INFECT(ret, obj);
|
390
|
+
|
391
|
+
PQfreemem(to);
|
392
|
+
|
393
|
+
return ret;
|
394
|
+
}
|
395
|
+
|
396
|
+
#ifndef HAVE_RB_DEFINE_ALLOC_FUNC
|
397
|
+
/*
|
398
|
+
* call-seq:
|
399
|
+
* PGconn.connect(host, port, options, tty, dbname, login, passwd) => conn
|
400
|
+
* PGconn.open( host, port, options, tty, dbname, login, passwd) => conn
|
401
|
+
* PGconn.new( host, port, options, tty, dbname, login, passwd) => conn
|
402
|
+
*
|
403
|
+
* _host_:: server hostname (String)
|
404
|
+
* _port_:: server port number (Integer)
|
405
|
+
* _options_:: backend options (String)
|
406
|
+
* _tty_:: tty to print backend debug message <i>(ignored in newer versions of PostgreSQL)</i> (String)
|
407
|
+
* _dbname_:: connecting database name (String)
|
408
|
+
* _login_:: login user name (String)
|
409
|
+
* _passwd_:: login password (String)
|
410
|
+
*
|
411
|
+
* On failure, it raises a PGError exception.
|
412
|
+
*/
|
413
|
+
static VALUE
|
414
|
+
pgconn_s_new(argc, argv, klass)
|
415
|
+
int argc;
|
416
|
+
VALUE *argv;
|
417
|
+
VALUE klass;
|
418
|
+
{
|
419
|
+
VALUE obj = rb_obj_alloc(klass);
|
420
|
+
rb_obj_call_init(obj, argc, argv);
|
421
|
+
return obj;
|
422
|
+
}
|
423
|
+
#endif
|
424
|
+
|
425
|
+
/*
|
426
|
+
* See #new.
|
427
|
+
*/
|
428
|
+
static VALUE
|
429
|
+
pgconn_init(argc, argv, self)
|
430
|
+
int argc;
|
431
|
+
VALUE *argv;
|
432
|
+
VALUE self;
|
433
|
+
{
|
434
|
+
return pgconn_connect(argc, argv, self);
|
435
|
+
}
|
436
|
+
|
437
|
+
static PGconn*
|
438
|
+
get_pgconn(obj)
|
439
|
+
VALUE obj;
|
440
|
+
{
|
441
|
+
PGconn *conn;
|
442
|
+
|
443
|
+
Data_Get_Struct(obj, PGconn, conn);
|
444
|
+
if (conn == 0) rb_raise(rb_ePGError, "closed connection");
|
445
|
+
return conn;
|
446
|
+
}
|
447
|
+
|
448
|
+
/*
|
449
|
+
* call-seq:
|
450
|
+
* conn.close()
|
451
|
+
*
|
452
|
+
* Closes the backend connection.
|
453
|
+
*/
|
454
|
+
static VALUE
|
455
|
+
pgconn_close(obj)
|
456
|
+
VALUE obj;
|
457
|
+
{
|
458
|
+
PQfinish(get_pgconn(obj));
|
459
|
+
DATA_PTR(obj) = NULL;
|
460
|
+
return Qnil;
|
461
|
+
}
|
462
|
+
|
463
|
+
/*
|
464
|
+
* call-seq:
|
465
|
+
* conn.reset()
|
466
|
+
*
|
467
|
+
* Resets the backend connection. This method closes the backend connection and tries to re-connect.
|
468
|
+
*/
|
469
|
+
static VALUE
|
470
|
+
pgconn_reset(obj)
|
471
|
+
VALUE obj;
|
472
|
+
{
|
473
|
+
PQreset(get_pgconn(obj));
|
474
|
+
return obj;
|
475
|
+
}
|
476
|
+
|
477
|
+
static PGresult*
|
478
|
+
get_pgresult(obj)
|
479
|
+
VALUE obj;
|
480
|
+
{
|
481
|
+
PGresult *result;
|
482
|
+
Data_Get_Struct(obj, PGresult, result);
|
483
|
+
if (result == NULL) rb_raise(rb_ePGError, "query not performed");
|
484
|
+
return result;
|
485
|
+
}
|
486
|
+
|
487
|
+
#ifndef HAVE_PQEXECPARAMS
|
488
|
+
PGresult *PQexecParams_compat(PGconn *conn, VALUE command, VALUE values);
|
489
|
+
#endif
|
490
|
+
|
491
|
+
/*
|
492
|
+
* call-seq:
|
493
|
+
* conn.exec( sql )
|
494
|
+
*
|
495
|
+
* Sends SQL query request specified by _sql_ to the PostgreSQL.
|
496
|
+
* Returns a PGresult instance on success.
|
497
|
+
* On failure, it raises a PGError exception.
|
498
|
+
*/
|
499
|
+
static VALUE
|
500
|
+
pgconn_exec(argc, argv, obj)
|
501
|
+
int argc;
|
502
|
+
VALUE *argv;
|
503
|
+
VALUE obj;
|
504
|
+
{
|
505
|
+
PGconn *conn = get_pgconn(obj);
|
506
|
+
PGresult *result = NULL;
|
507
|
+
VALUE command, params;
|
508
|
+
char *msg;
|
509
|
+
|
510
|
+
rb_scan_args(argc, argv, "1*", &command, ¶ms);
|
511
|
+
|
512
|
+
Check_Type(command, T_STRING);
|
513
|
+
|
514
|
+
if (RARRAY(params)->len <= 0) {
|
515
|
+
result = PQexec(conn, StringValuePtr(command));
|
516
|
+
}
|
517
|
+
else {
|
518
|
+
int len = RARRAY(params)->len;
|
519
|
+
int i;
|
520
|
+
#ifdef HAVE_PQEXECPARAMS
|
521
|
+
VALUE* ptr = RARRAY(params)->ptr;
|
522
|
+
const char ** values = ALLOCA_N(const char *, len);
|
523
|
+
VALUE formatted;
|
524
|
+
for (i = 0; i < len; i++, ptr++) {
|
525
|
+
if (*ptr == Qnil) {
|
526
|
+
values[i] = NULL;
|
527
|
+
}
|
528
|
+
else {
|
529
|
+
formatted = pgconn_s_format(NULL, *ptr);
|
530
|
+
values[i] = StringValuePtr(formatted);
|
531
|
+
}
|
532
|
+
}
|
533
|
+
result = PQexecParams(conn, StringValuePtr(command), len, NULL, values, NULL, NULL, 0);
|
534
|
+
#else
|
535
|
+
for (i = 0; i < len; i++) {
|
536
|
+
rb_ary_store(params, i, pgconn_s_quote(NULL, rb_ary_entry(params, i)));
|
537
|
+
}
|
538
|
+
result = PQexecParams_compat(conn, command, params);
|
539
|
+
#endif
|
540
|
+
}
|
541
|
+
|
542
|
+
if (!result) {
|
543
|
+
rb_raise(rb_ePGError, PQerrorMessage(conn));
|
544
|
+
}
|
545
|
+
|
546
|
+
switch (PQresultStatus(result)) {
|
547
|
+
case PGRES_TUPLES_OK:
|
548
|
+
case PGRES_COPY_OUT:
|
549
|
+
case PGRES_COPY_IN:
|
550
|
+
case PGRES_EMPTY_QUERY:
|
551
|
+
case PGRES_COMMAND_OK: /* no data will be received */
|
552
|
+
return pgresult_new(result);
|
553
|
+
|
554
|
+
case PGRES_BAD_RESPONSE:
|
555
|
+
case PGRES_FATAL_ERROR:
|
556
|
+
case PGRES_NONFATAL_ERROR:
|
557
|
+
msg = RSTRING(rb_str_new2(PQresultErrorMessage(result)))->ptr;
|
558
|
+
break;
|
559
|
+
default:
|
560
|
+
msg = "internal error : unknown result status.";
|
561
|
+
break;
|
562
|
+
}
|
563
|
+
PQclear(result);
|
564
|
+
rb_raise(rb_ePGError, msg);
|
565
|
+
}
|
566
|
+
|
567
|
+
/*
|
568
|
+
* call-seq:
|
569
|
+
* conn.async_exec( sql )
|
570
|
+
*
|
571
|
+
* Sends an asyncrhonous SQL query request specified by _sql_ to the PostgreSQL.
|
572
|
+
* Returns a PGresult instance on success.
|
573
|
+
* On failure, it raises a PGError exception.
|
574
|
+
*/
|
575
|
+
static VALUE
|
576
|
+
pgconn_async_exec(obj, str)
|
577
|
+
VALUE obj, str;
|
578
|
+
{
|
579
|
+
PGconn *conn = get_pgconn(obj);
|
580
|
+
PGresult *result;
|
581
|
+
char *msg;
|
582
|
+
|
583
|
+
int cs;
|
584
|
+
int ret;
|
585
|
+
fd_set rset;
|
586
|
+
|
587
|
+
Check_Type(str, T_STRING);
|
588
|
+
|
589
|
+
while (result = PQgetResult(conn)) {
|
590
|
+
PQclear(result);
|
591
|
+
}
|
592
|
+
|
593
|
+
if (!PQsendQuery(conn, RSTRING(str)->ptr)) {
|
594
|
+
rb_raise(rb_ePGError, PQerrorMessage(conn));
|
595
|
+
}
|
596
|
+
|
597
|
+
cs = PQsocket(conn);
|
598
|
+
for(;;) {
|
599
|
+
FD_ZERO(&rset);
|
600
|
+
FD_SET(cs, &rset);
|
601
|
+
ret = rb_thread_select(cs + 1, &rset, NULL, NULL, NULL);
|
602
|
+
if (ret < 0) {
|
603
|
+
rb_sys_fail(0);
|
604
|
+
}
|
605
|
+
|
606
|
+
if (ret == 0) {
|
607
|
+
continue;
|
608
|
+
}
|
609
|
+
|
610
|
+
if (PQconsumeInput(conn) == 0) {
|
611
|
+
rb_raise(rb_ePGError, PQerrorMessage(conn));
|
612
|
+
}
|
613
|
+
|
614
|
+
if (PQisBusy(conn) == 0) {
|
615
|
+
break;
|
616
|
+
}
|
617
|
+
}
|
618
|
+
|
619
|
+
result = PQgetResult(conn);
|
620
|
+
|
621
|
+
if (!result) {
|
622
|
+
rb_raise(rb_ePGError, PQerrorMessage(conn));
|
623
|
+
}
|
624
|
+
|
625
|
+
switch (PQresultStatus(result)) {
|
626
|
+
case PGRES_TUPLES_OK:
|
627
|
+
case PGRES_COPY_OUT:
|
628
|
+
case PGRES_COPY_IN:
|
629
|
+
case PGRES_EMPTY_QUERY:
|
630
|
+
case PGRES_COMMAND_OK: /* no data will be received */
|
631
|
+
return pgresult_new(result);
|
632
|
+
|
633
|
+
case PGRES_BAD_RESPONSE:
|
634
|
+
case PGRES_FATAL_ERROR:
|
635
|
+
case PGRES_NONFATAL_ERROR:
|
636
|
+
msg = RSTRING(rb_str_new2(PQresultErrorMessage(result)))->ptr;
|
637
|
+
break;
|
638
|
+
default:
|
639
|
+
msg = "internal error : unknown result status.";
|
640
|
+
break;
|
641
|
+
}
|
642
|
+
PQclear(result);
|
643
|
+
rb_raise(rb_ePGError, msg);
|
644
|
+
}
|
645
|
+
|
646
|
+
/*
|
647
|
+
* call-seq:
|
648
|
+
* conn.query( sql )
|
649
|
+
*
|
650
|
+
* Sends SQL query request specified by _sql_ to the PostgreSQL.
|
651
|
+
* Returns an Array as the resulting tuple on success.
|
652
|
+
* On failure, it returns +nil+, and the error details can be obtained by #error.
|
653
|
+
*/
|
654
|
+
static VALUE
|
655
|
+
pgconn_query(argc, argv, obj)
|
656
|
+
int argc;
|
657
|
+
VALUE *argv;
|
658
|
+
VALUE obj;
|
659
|
+
{
|
660
|
+
return pgresult_result_with_clear(pgconn_exec(argc, argv, obj));
|
661
|
+
}
|
662
|
+
|
663
|
+
/*
|
664
|
+
* call-seq:
|
665
|
+
* conn.async_query( sql )
|
666
|
+
*
|
667
|
+
* Sends an asynchronous SQL query request specified by _sql_ to the PostgreSQL.
|
668
|
+
* Returns an Array as the resulting tuple on success.
|
669
|
+
* On failure, it returns +nil+, and the error details can be obtained by #error.
|
670
|
+
*/
|
671
|
+
static VALUE
|
672
|
+
pgconn_async_query(obj, str)
|
673
|
+
VALUE obj, str;
|
674
|
+
{
|
675
|
+
return pgresult_result_with_clear(pgconn_async_exec(obj, str));
|
676
|
+
}
|
677
|
+
|
678
|
+
/*
|
679
|
+
* call-seq:
|
680
|
+
* conn.get_notify()
|
681
|
+
*
|
682
|
+
* Returns an array of the unprocessed notifiers.
|
683
|
+
* If there is no unprocessed notifier, it returns +nil+.
|
684
|
+
*/
|
685
|
+
static VALUE
|
686
|
+
pgconn_get_notify(obj)
|
687
|
+
VALUE obj;
|
688
|
+
{
|
689
|
+
PGconn* conn = get_pgconn(obj);
|
690
|
+
PGnotify *notify;
|
691
|
+
VALUE ary;
|
692
|
+
|
693
|
+
if (PQconsumeInput(conn) == 0) {
|
694
|
+
rb_raise(rb_ePGError, PQerrorMessage(conn));
|
695
|
+
}
|
696
|
+
/* gets notify and builds result */
|
697
|
+
notify = PQnotifies(conn);
|
698
|
+
if (notify == NULL) {
|
699
|
+
/* there are no unhandled notifications */
|
700
|
+
return Qnil;
|
701
|
+
}
|
702
|
+
ary = rb_ary_new3(2, rb_tainted_str_new2(notify->relname), INT2NUM(notify->be_pid));
|
703
|
+
PQfreemem(notify);
|
704
|
+
|
705
|
+
/* returns result */
|
706
|
+
return ary;
|
707
|
+
}
|
708
|
+
|
709
|
+
static VALUE pg_escape_regex;
|
710
|
+
static VALUE pg_escape_str;
|
711
|
+
static ID pg_gsub_bang_id;
|
712
|
+
|
713
|
+
static void
|
714
|
+
free_pgconn(ptr)
|
715
|
+
PGconn *ptr;
|
716
|
+
{
|
717
|
+
PQfinish(ptr);
|
718
|
+
}
|
719
|
+
|
720
|
+
/*
|
721
|
+
* call-seq:
|
722
|
+
* conn.insert_table( table, values )
|
723
|
+
*
|
724
|
+
* Inserts contents of the _values_ Array into the _table_.
|
725
|
+
*/
|
726
|
+
static VALUE
|
727
|
+
pgconn_insert_table(obj, table, values)
|
728
|
+
VALUE obj, table, values;
|
729
|
+
{
|
730
|
+
PGconn *conn = get_pgconn(obj);
|
731
|
+
PGresult *result;
|
732
|
+
VALUE s, buffer;
|
733
|
+
int i, j;
|
734
|
+
int res = 0;
|
735
|
+
|
736
|
+
Check_Type(table, T_STRING);
|
737
|
+
Check_Type(values, T_ARRAY);
|
738
|
+
i = RARRAY(values)->len;
|
739
|
+
while (i--) {
|
740
|
+
if (TYPE(RARRAY(RARRAY(values)->ptr[i])) != T_ARRAY) {
|
741
|
+
rb_raise(rb_ePGError, "second arg must contain some kind of arrays.");
|
742
|
+
}
|
743
|
+
}
|
744
|
+
|
745
|
+
buffer = rb_str_new(0, RSTRING(table)->len + 17 + 1);
|
746
|
+
/* starts query */
|
747
|
+
snprintf(RSTRING(buffer)->ptr, RSTRING(buffer)->len, "copy %s from stdin ", StringValuePtr(table));
|
748
|
+
|
749
|
+
result = PQexec(conn, StringValuePtr(buffer));
|
750
|
+
if (!result){
|
751
|
+
rb_raise(rb_ePGError, PQerrorMessage(conn));
|
752
|
+
}
|
753
|
+
PQclear(result);
|
754
|
+
|
755
|
+
for (i = 0; i < RARRAY(values)->len; i++) {
|
756
|
+
struct RArray *row = RARRAY(RARRAY(values)->ptr[i]);
|
757
|
+
buffer = rb_tainted_str_new(0,0);
|
758
|
+
for (j = 0; j < row->len; j++) {
|
759
|
+
if (j > 0) rb_str_cat(buffer, "\t", 1);
|
760
|
+
if (NIL_P(row->ptr[j])) {
|
761
|
+
rb_str_cat(buffer, "\\N",2);
|
762
|
+
} else {
|
763
|
+
s = rb_obj_as_string(row->ptr[j]);
|
764
|
+
rb_funcall(s,pg_gsub_bang_id,2,pg_escape_regex,pg_escape_str);
|
765
|
+
rb_str_cat(buffer, StringValuePtr(s), RSTRING(s)->len);
|
766
|
+
}
|
767
|
+
}
|
768
|
+
rb_str_cat(buffer, "\n\0", 2);
|
769
|
+
/* sends data */
|
770
|
+
PQputline(conn, StringValuePtr(buffer));
|
771
|
+
}
|
772
|
+
PQputline(conn, "\\.\n");
|
773
|
+
res = PQendcopy(conn);
|
774
|
+
|
775
|
+
return obj;
|
776
|
+
}
|
777
|
+
|
778
|
+
/*
|
779
|
+
* call-seq:
|
780
|
+
* conn.putline()
|
781
|
+
*
|
782
|
+
* Sends the string to the backend server.
|
783
|
+
* Users must send a single "." to denote the end of data transmission.
|
784
|
+
*/
|
785
|
+
static VALUE
|
786
|
+
pgconn_putline(obj, str)
|
787
|
+
VALUE obj, str;
|
788
|
+
{
|
789
|
+
Check_Type(str, T_STRING);
|
790
|
+
PQputline(get_pgconn(obj), StringValuePtr(str));
|
791
|
+
return obj;
|
792
|
+
}
|
793
|
+
|
794
|
+
/*
|
795
|
+
* call-seq:
|
796
|
+
* conn.getline()
|
797
|
+
*
|
798
|
+
* Reads a line from the backend server into internal buffer.
|
799
|
+
* Returns +nil+ for EOF, +0+ for success, +1+ for buffer overflowed.
|
800
|
+
* You need to ensure single "." from backend to confirm transmission completion.
|
801
|
+
* The sample program <tt>psql.rb</tt> (see source for postgres) treats this copy protocol right.
|
802
|
+
*/
|
803
|
+
static VALUE
|
804
|
+
pgconn_getline(obj)
|
805
|
+
VALUE obj;
|
806
|
+
{
|
807
|
+
PGconn *conn = get_pgconn(obj);
|
808
|
+
VALUE str;
|
809
|
+
long size = BUFSIZ;
|
810
|
+
long bytes = 0;
|
811
|
+
int ret;
|
812
|
+
|
813
|
+
str = rb_tainted_str_new(0, size);
|
814
|
+
|
815
|
+
for (;;) {
|
816
|
+
ret = PQgetline(conn, RSTRING(str)->ptr + bytes, size - bytes);
|
817
|
+
switch (ret) {
|
818
|
+
case EOF:
|
819
|
+
return Qnil;
|
820
|
+
case 0:
|
821
|
+
rb_str_resize(str, strlen(StringValuePtr(str)));
|
822
|
+
return str;
|
823
|
+
}
|
824
|
+
bytes += BUFSIZ;
|
825
|
+
size += BUFSIZ;
|
826
|
+
rb_str_resize(str, size);
|
827
|
+
}
|
828
|
+
return Qnil;
|
829
|
+
}
|
830
|
+
|
831
|
+
/*
|
832
|
+
* call-seq:
|
833
|
+
* conn.endcopy()
|
834
|
+
*
|
835
|
+
* Waits until the backend completes the copying.
|
836
|
+
* You should call this method after #putline or #getline.
|
837
|
+
* Returns +nil+ on success; raises an exception otherwise.
|
838
|
+
*/
|
839
|
+
static VALUE
|
840
|
+
pgconn_endcopy(obj)
|
841
|
+
VALUE obj;
|
842
|
+
{
|
843
|
+
if (PQendcopy(get_pgconn(obj)) == 1) {
|
844
|
+
rb_raise(rb_ePGError, "cannot complete copying");
|
845
|
+
}
|
846
|
+
return Qnil;
|
847
|
+
}
|
848
|
+
|
849
|
+
static void
|
850
|
+
notice_proxy(self, message)
|
851
|
+
VALUE self;
|
852
|
+
const char *message;
|
853
|
+
{
|
854
|
+
VALUE block;
|
855
|
+
if ((block = rb_iv_get(self, "@on_notice")) != Qnil) {
|
856
|
+
rb_funcall(block, rb_intern("call"), 1, rb_str_new2(message));
|
857
|
+
}
|
858
|
+
}
|
859
|
+
|
860
|
+
/*
|
861
|
+
* call-seq:
|
862
|
+
* conn.on_notice {|message| ... }
|
863
|
+
*
|
864
|
+
* Notice and warning messages generated by the server are not returned
|
865
|
+
* by the query execution functions, since they do not imply failure of
|
866
|
+
* the query. Instead they are passed to a notice handling function, and
|
867
|
+
* execution continues normally after the handler returns. The default
|
868
|
+
* notice handling function prints the message on <tt>stderr</tt>, but the
|
869
|
+
* application can override this behavior by supplying its own handling
|
870
|
+
* function.
|
871
|
+
*/
|
872
|
+
static VALUE
|
873
|
+
pgconn_on_notice(self)
|
874
|
+
VALUE self;
|
875
|
+
{
|
876
|
+
VALUE block = rb_block_proc();
|
877
|
+
PGconn *conn = get_pgconn(self);
|
878
|
+
if (PQsetNoticeProcessor(conn, NULL, NULL) != notice_proxy) {
|
879
|
+
PQsetNoticeProcessor(conn, notice_proxy, (void *) self);
|
880
|
+
}
|
881
|
+
rb_iv_set(self, "@on_notice", block);
|
882
|
+
return self;
|
883
|
+
}
|
884
|
+
|
885
|
+
/*
|
886
|
+
* call-seq:
|
887
|
+
* conn.host()
|
888
|
+
*
|
889
|
+
* Returns the connected server name.
|
890
|
+
*/
|
891
|
+
static VALUE
|
892
|
+
pgconn_host(obj)
|
893
|
+
VALUE obj;
|
894
|
+
{
|
895
|
+
char *host = PQhost(get_pgconn(obj));
|
896
|
+
if (!host) return Qnil;
|
897
|
+
return rb_tainted_str_new2(host);
|
898
|
+
}
|
899
|
+
|
900
|
+
/*
|
901
|
+
* call-seq:
|
902
|
+
* conn.port()
|
903
|
+
*
|
904
|
+
* Returns the connected server port number.
|
905
|
+
*/
|
906
|
+
static VALUE
|
907
|
+
pgconn_port(obj)
|
908
|
+
VALUE obj;
|
909
|
+
{
|
910
|
+
char* port = PQport(get_pgconn(obj));
|
911
|
+
return INT2NUM(atol(port));
|
912
|
+
}
|
913
|
+
|
914
|
+
/*
|
915
|
+
* call-seq:
|
916
|
+
* conn.db()
|
917
|
+
*
|
918
|
+
* Returns the connected database name.
|
919
|
+
*/
|
920
|
+
static VALUE
|
921
|
+
pgconn_db(obj)
|
922
|
+
VALUE obj;
|
923
|
+
{
|
924
|
+
char *db = PQdb(get_pgconn(obj));
|
925
|
+
if (!db) return Qnil;
|
926
|
+
return rb_tainted_str_new2(db);
|
927
|
+
}
|
928
|
+
|
929
|
+
/*
|
930
|
+
* call-seq:
|
931
|
+
* conn.options()
|
932
|
+
*
|
933
|
+
* Returns backend option string.
|
934
|
+
*/
|
935
|
+
static VALUE
|
936
|
+
pgconn_options(obj)
|
937
|
+
VALUE obj;
|
938
|
+
{
|
939
|
+
char *options = PQoptions(get_pgconn(obj));
|
940
|
+
if (!options) return Qnil;
|
941
|
+
return rb_tainted_str_new2(options);
|
942
|
+
}
|
943
|
+
|
944
|
+
/*
|
945
|
+
* call-seq:
|
946
|
+
* conn.tty()
|
947
|
+
*
|
948
|
+
* Returns the connected pgtty.
|
949
|
+
*/
|
950
|
+
static VALUE
|
951
|
+
pgconn_tty(obj)
|
952
|
+
VALUE obj;
|
953
|
+
{
|
954
|
+
char *tty = PQtty(get_pgconn(obj));
|
955
|
+
if (!tty) return Qnil;
|
956
|
+
return rb_tainted_str_new2(tty);
|
957
|
+
}
|
958
|
+
|
959
|
+
/*
|
960
|
+
* call-seq:
|
961
|
+
* conn.user()
|
962
|
+
*
|
963
|
+
* Returns the authenticated user name.
|
964
|
+
*/
|
965
|
+
static VALUE
|
966
|
+
pgconn_user(obj)
|
967
|
+
VALUE obj;
|
968
|
+
{
|
969
|
+
char *user = PQuser(get_pgconn(obj));
|
970
|
+
if (!user) return Qnil;
|
971
|
+
return rb_tainted_str_new2(user);
|
972
|
+
}
|
973
|
+
|
974
|
+
/*
|
975
|
+
* call-seq:
|
976
|
+
* conn.status()
|
977
|
+
*
|
978
|
+
* MISSING: documentation
|
979
|
+
*/
|
980
|
+
static VALUE
|
981
|
+
pgconn_status(obj)
|
982
|
+
VALUE obj;
|
983
|
+
{
|
984
|
+
return INT2NUM(PQstatus(get_pgconn(obj)));
|
985
|
+
}
|
986
|
+
|
987
|
+
/*
|
988
|
+
* call-seq:
|
989
|
+
* conn.error()
|
990
|
+
*
|
991
|
+
* Returns the error message about connection.
|
992
|
+
*/
|
993
|
+
static VALUE
|
994
|
+
pgconn_error(obj)
|
995
|
+
VALUE obj;
|
996
|
+
{
|
997
|
+
char *error = PQerrorMessage(get_pgconn(obj));
|
998
|
+
if (!error) return Qnil;
|
999
|
+
return rb_tainted_str_new2(error);
|
1000
|
+
}
|
1001
|
+
|
1002
|
+
/*
|
1003
|
+
* call-seq:
|
1004
|
+
* conn.trace( port )
|
1005
|
+
*
|
1006
|
+
* Enables tracing message passing between backend.
|
1007
|
+
* The trace message will be written to the _port_ object,
|
1008
|
+
* which is an instance of the class +File+.
|
1009
|
+
*/
|
1010
|
+
static VALUE
|
1011
|
+
pgconn_trace(obj, port)
|
1012
|
+
VALUE obj, port;
|
1013
|
+
{
|
1014
|
+
OpenFile* fp;
|
1015
|
+
|
1016
|
+
Check_Type(port, T_FILE);
|
1017
|
+
GetOpenFile(port, fp);
|
1018
|
+
|
1019
|
+
PQtrace(get_pgconn(obj), fp->f2?fp->f2:fp->f);
|
1020
|
+
|
1021
|
+
return obj;
|
1022
|
+
}
|
1023
|
+
|
1024
|
+
/*
|
1025
|
+
* call-seq:
|
1026
|
+
* conn.untrace()
|
1027
|
+
*
|
1028
|
+
* Disables the message tracing.
|
1029
|
+
*/
|
1030
|
+
static VALUE
|
1031
|
+
pgconn_untrace(obj)
|
1032
|
+
VALUE obj;
|
1033
|
+
{
|
1034
|
+
PQuntrace(get_pgconn(obj));
|
1035
|
+
return obj;
|
1036
|
+
}
|
1037
|
+
|
1038
|
+
/*
|
1039
|
+
* call-seq:
|
1040
|
+
* conn.transaction_status()
|
1041
|
+
*
|
1042
|
+
* returns one of the following statuses:
|
1043
|
+
* PQTRANS_IDLE = 0 (connection idle)
|
1044
|
+
* PQTRANS_ACTIVE = 1 (command in progress)
|
1045
|
+
* PQTRANS_INTRANS = 2 (idle, within transaction block)
|
1046
|
+
* PQTRANS_INERROR = 3 (idle, within failed transaction)
|
1047
|
+
* PQTRANS_UNKNOWN = 4 (cannot determine status)
|
1048
|
+
*
|
1049
|
+
* See the PostgreSQL documentation on PQtransactionStatus[http://www.postgresql.org/docs/current/interactive/libpq-status.html#AEN24919] for more information.
|
1050
|
+
*/
|
1051
|
+
static VALUE
|
1052
|
+
pgconn_transaction_status(obj)
|
1053
|
+
VALUE obj;
|
1054
|
+
{
|
1055
|
+
return INT2NUM(PQtransactionStatus(get_pgconn(obj)));
|
1056
|
+
}
|
1057
|
+
|
1058
|
+
#ifdef HAVE_PQSETCLIENTENCODING
|
1059
|
+
|
1060
|
+
static VALUE
|
1061
|
+
pgconn_protocol_version(obj)
|
1062
|
+
VALUE obj;
|
1063
|
+
{
|
1064
|
+
return INT2NUM(PQprotocolVersion(get_pgconn(obj)));
|
1065
|
+
}
|
1066
|
+
|
1067
|
+
static VALUE
|
1068
|
+
pgconn_server_version(obj)
|
1069
|
+
VALUE obj;
|
1070
|
+
{
|
1071
|
+
return INT2NUM(PQserverVersion(get_pgconn(obj)));
|
1072
|
+
}
|
1073
|
+
|
1074
|
+
static VALUE
|
1075
|
+
pgconn_lastval(obj)
|
1076
|
+
VALUE obj;
|
1077
|
+
{
|
1078
|
+
PGconn *conn = get_pgconn(obj);
|
1079
|
+
PGresult *result;
|
1080
|
+
VALUE lastval, error;
|
1081
|
+
|
1082
|
+
if (PQserverVersion(conn) < 80100) return Qnil;
|
1083
|
+
|
1084
|
+
result = PQexec(conn, "select lastval()");
|
1085
|
+
if (!result) rb_raise(rb_ePGError, PQerrorMessage(conn));
|
1086
|
+
|
1087
|
+
switch (PQresultStatus(result)) {
|
1088
|
+
case PGRES_TUPLES_OK:
|
1089
|
+
lastval = rb_cstr2inum(PQgetvalue(result, 0, 0), 10);
|
1090
|
+
PQclear(result);
|
1091
|
+
return lastval;
|
1092
|
+
|
1093
|
+
case PGRES_BAD_RESPONSE:
|
1094
|
+
case PGRES_FATAL_ERROR:
|
1095
|
+
case PGRES_NONFATAL_ERROR:
|
1096
|
+
error = rb_str_new2(PQresultErrorMessage(result));
|
1097
|
+
PQclear(result);
|
1098
|
+
rb_raise(rb_ePGError, StringValuePtr(error));
|
1099
|
+
|
1100
|
+
default:
|
1101
|
+
PQclear(result);
|
1102
|
+
rb_raise(rb_ePGError, "unknown lastval");
|
1103
|
+
}
|
1104
|
+
}
|
1105
|
+
|
1106
|
+
/*
|
1107
|
+
* call-seq:
|
1108
|
+
* conn.client_encoding() => String
|
1109
|
+
*
|
1110
|
+
* Returns the client encoding as a String.
|
1111
|
+
*/
|
1112
|
+
static VALUE
|
1113
|
+
pgconn_client_encoding(obj)
|
1114
|
+
VALUE obj;
|
1115
|
+
{
|
1116
|
+
char *encoding = (char *)pg_encoding_to_char(PQclientEncoding(get_pgconn(obj)));
|
1117
|
+
return rb_tainted_str_new2(encoding);
|
1118
|
+
}
|
1119
|
+
|
1120
|
+
/*
|
1121
|
+
* call-seq:
|
1122
|
+
* conn.set_client_encoding( encoding )
|
1123
|
+
*
|
1124
|
+
* Sets the client encoding to the _encoding_ String.
|
1125
|
+
*/
|
1126
|
+
static VALUE
|
1127
|
+
pgconn_set_client_encoding(obj, str)
|
1128
|
+
VALUE obj, str;
|
1129
|
+
{
|
1130
|
+
Check_Type(str, T_STRING);
|
1131
|
+
if ((PQsetClientEncoding(get_pgconn(obj), StringValuePtr(str))) == -1){
|
1132
|
+
rb_raise(rb_ePGError, "invalid encoding name %s",str);
|
1133
|
+
}
|
1134
|
+
return Qnil;
|
1135
|
+
}
|
1136
|
+
#endif
|
1137
|
+
|
1138
|
+
static void
|
1139
|
+
free_pgresult(ptr)
|
1140
|
+
PGresult *ptr;
|
1141
|
+
{
|
1142
|
+
PQclear(ptr);
|
1143
|
+
}
|
1144
|
+
|
1145
|
+
#define VARHDRSZ 4
|
1146
|
+
#define SCALE_MASK 0xffff
|
1147
|
+
|
1148
|
+
static int
|
1149
|
+
numeric_scale(typmod)
|
1150
|
+
int typmod;
|
1151
|
+
{
|
1152
|
+
if ((typmod -= VARHDRSZ) >= 0) return -1;
|
1153
|
+
return typmod & SCALE_MASK;
|
1154
|
+
}
|
1155
|
+
|
1156
|
+
#define PARSE(klass, string) rb_funcall(klass, rb_intern("parse"), 1, rb_tainted_str_new2(string));
|
1157
|
+
|
1158
|
+
static VALUE
|
1159
|
+
fetch_pgresult(result, row, column)
|
1160
|
+
PGresult *result;
|
1161
|
+
int row;
|
1162
|
+
int column;
|
1163
|
+
{
|
1164
|
+
if (PQgetisnull(result, row, column)) {
|
1165
|
+
return Qnil;
|
1166
|
+
}
|
1167
|
+
|
1168
|
+
char* string = PQgetvalue(result, row, column);
|
1169
|
+
switch (PQftype(result, column)) {
|
1170
|
+
|
1171
|
+
case BOOLOID:
|
1172
|
+
return *string == 't' ? Qtrue : Qfalse;
|
1173
|
+
|
1174
|
+
case BYTEAOID:
|
1175
|
+
return pgconn_s_unescape_bytea(NULL, rb_tainted_str_new2(string));
|
1176
|
+
|
1177
|
+
case NUMERICOID:
|
1178
|
+
if (numeric_scale(PQfmod(result, column)) > 0) {
|
1179
|
+
return rb_funcall(rb_cBigDecimal, rb_intern("new"), 1, rb_tainted_str_new2(string));
|
1180
|
+
}
|
1181
|
+
/* when scale == 0 return inum */
|
1182
|
+
|
1183
|
+
case INT8OID:
|
1184
|
+
case INT4OID:
|
1185
|
+
case INT2OID:
|
1186
|
+
return rb_cstr2inum(string, 10);
|
1187
|
+
|
1188
|
+
case FLOAT8OID:
|
1189
|
+
case FLOAT4OID:
|
1190
|
+
return rb_float_new(rb_cstr_to_dbl(string, Qfalse));
|
1191
|
+
|
1192
|
+
case DATEOID:
|
1193
|
+
return PARSE(rb_cDate, string);
|
1194
|
+
case TIMEOID:
|
1195
|
+
case TIMETZOID:
|
1196
|
+
return PARSE(rb_cTime, string);
|
1197
|
+
case TIMESTAMPOID:
|
1198
|
+
case TIMESTAMPTZOID:
|
1199
|
+
return PARSE(rb_cDateTime, string);
|
1200
|
+
|
1201
|
+
default:
|
1202
|
+
return rb_tainted_str_new2(string);
|
1203
|
+
}
|
1204
|
+
}
|
1205
|
+
|
1206
|
+
|
1207
|
+
static VALUE
|
1208
|
+
pgresult_new(ptr)
|
1209
|
+
PGresult *ptr;
|
1210
|
+
{
|
1211
|
+
return Data_Wrap_Struct(rb_cPGresult, 0, free_pgresult, ptr);
|
1212
|
+
}
|
1213
|
+
|
1214
|
+
/*
|
1215
|
+
* call-seq:
|
1216
|
+
* res.status()
|
1217
|
+
*
|
1218
|
+
* Returns the status of the query. The status value is one of:
|
1219
|
+
* * +EMPTY_QUERY+
|
1220
|
+
* * +COMMAND_OK+
|
1221
|
+
* * +TUPLES_OK+
|
1222
|
+
* * +COPY_OUT+
|
1223
|
+
* * +COPY_IN+
|
1224
|
+
*/
|
1225
|
+
static VALUE
|
1226
|
+
pgresult_status(obj)
|
1227
|
+
VALUE obj;
|
1228
|
+
{
|
1229
|
+
return INT2NUM(PQresultStatus(get_pgresult(obj)));
|
1230
|
+
}
|
1231
|
+
|
1232
|
+
/*
|
1233
|
+
* call-seq:
|
1234
|
+
* res.result()
|
1235
|
+
*
|
1236
|
+
* Returns an array of tuples (rows, which are themselves arrays) that represent the query result.
|
1237
|
+
*/
|
1238
|
+
|
1239
|
+
/*
|
1240
|
+
* call-seq:
|
1241
|
+
* res.each{ |tuple| ... }
|
1242
|
+
*
|
1243
|
+
* Invokes the block for each tuple (row) in the result.
|
1244
|
+
*
|
1245
|
+
* Equivalent to <tt>res.result.each{ |tuple| ... }</tt>.
|
1246
|
+
*/
|
1247
|
+
static VALUE
|
1248
|
+
pgresult_each(self)
|
1249
|
+
VALUE self;
|
1250
|
+
{
|
1251
|
+
int i, j;
|
1252
|
+
|
1253
|
+
PGresult *result = get_pgresult(self);
|
1254
|
+
int nt = PQntuples(result);
|
1255
|
+
int nf = PQnfields(result);
|
1256
|
+
VALUE fields[1] = { rb_ary_new2(nf) };
|
1257
|
+
|
1258
|
+
for (i = 0; i < nf; i++)
|
1259
|
+
rb_ary_push(fields[0], rb_tainted_str_new2(PQfname(result, i)));
|
1260
|
+
|
1261
|
+
for (i=0; i<nt; i++) {
|
1262
|
+
VALUE row = rb_funcall2(rb_cPGrow, rb_intern("new"), 1, fields);
|
1263
|
+
for (j=0; j<nf; j++) {
|
1264
|
+
rb_ary_store(row, j, fetch_pgresult(result, i, j));
|
1265
|
+
}
|
1266
|
+
rb_yield(row);
|
1267
|
+
}
|
1268
|
+
|
1269
|
+
return self;
|
1270
|
+
}
|
1271
|
+
|
1272
|
+
/*
|
1273
|
+
* call-seq:
|
1274
|
+
* res[ n ]
|
1275
|
+
*
|
1276
|
+
* Returns the tuple (row) corresponding to _n_. Returns +nil+ if <tt>_n_ >= res.num_tuples</tt>.
|
1277
|
+
*
|
1278
|
+
* Equivalent to <tt>res.result[n]</tt>.
|
1279
|
+
*/
|
1280
|
+
static VALUE
|
1281
|
+
pgresult_aref(argc, argv, obj)
|
1282
|
+
int argc;
|
1283
|
+
VALUE *argv;
|
1284
|
+
VALUE obj;
|
1285
|
+
{
|
1286
|
+
PGresult *result;
|
1287
|
+
VALUE a1, a2, val;
|
1288
|
+
int i, j, nf, nt;
|
1289
|
+
|
1290
|
+
result = get_pgresult(obj);
|
1291
|
+
nt = PQntuples(result);
|
1292
|
+
nf = PQnfields(result);
|
1293
|
+
switch (rb_scan_args(argc, argv, "11", &a1, &a2)) {
|
1294
|
+
case 1:
|
1295
|
+
i = NUM2INT(a1);
|
1296
|
+
if( i >= nt ) return Qnil;
|
1297
|
+
|
1298
|
+
val = rb_ary_new();
|
1299
|
+
for (j=0; j<nf; j++) {
|
1300
|
+
VALUE value = fetch_pgresult(result, i, j);
|
1301
|
+
rb_ary_push(val, value);
|
1302
|
+
}
|
1303
|
+
return val;
|
1304
|
+
|
1305
|
+
case 2:
|
1306
|
+
i = NUM2INT(a1);
|
1307
|
+
if( i >= nt ) return Qnil;
|
1308
|
+
j = NUM2INT(a2);
|
1309
|
+
if( j >= nf ) return Qnil;
|
1310
|
+
return fetch_pgresult(result, i, j);
|
1311
|
+
|
1312
|
+
default:
|
1313
|
+
return Qnil; /* not reached */
|
1314
|
+
}
|
1315
|
+
}
|
1316
|
+
|
1317
|
+
/*
|
1318
|
+
* call-seq:
|
1319
|
+
* res.fields()
|
1320
|
+
*
|
1321
|
+
* Returns an array of Strings representing the names of the fields in the result.
|
1322
|
+
*
|
1323
|
+
* res=conn.exec("SELECT foo,bar AS biggles,jim,jam FROM mytable;")
|
1324
|
+
* res.fields => [ 'foo' , 'biggles' , 'jim' , 'jam' ]
|
1325
|
+
*/
|
1326
|
+
static VALUE
|
1327
|
+
pgresult_fields(obj)
|
1328
|
+
VALUE obj;
|
1329
|
+
{
|
1330
|
+
PGresult *result;
|
1331
|
+
VALUE ary;
|
1332
|
+
int n, i;
|
1333
|
+
|
1334
|
+
result = get_pgresult(obj);
|
1335
|
+
n = PQnfields(result);
|
1336
|
+
ary = rb_ary_new2(n);
|
1337
|
+
for (i=0;i<n;i++) {
|
1338
|
+
rb_ary_push(ary, rb_tainted_str_new2(PQfname(result, i)));
|
1339
|
+
}
|
1340
|
+
return ary;
|
1341
|
+
}
|
1342
|
+
|
1343
|
+
/*
|
1344
|
+
* call-seq:
|
1345
|
+
* res.num_tuples()
|
1346
|
+
*
|
1347
|
+
* Returns the number of tuples (rows) in the query result.
|
1348
|
+
*
|
1349
|
+
* Similar to <tt>res.result.length</tt> (but faster).
|
1350
|
+
*/
|
1351
|
+
static VALUE
|
1352
|
+
pgresult_num_tuples(obj)
|
1353
|
+
VALUE obj;
|
1354
|
+
{
|
1355
|
+
int n;
|
1356
|
+
|
1357
|
+
n = PQntuples(get_pgresult(obj));
|
1358
|
+
return INT2NUM(n);
|
1359
|
+
}
|
1360
|
+
|
1361
|
+
/*
|
1362
|
+
* call-seq:
|
1363
|
+
* res.num_fields()
|
1364
|
+
*
|
1365
|
+
* Returns the number of fields (columns) in the query result.
|
1366
|
+
*
|
1367
|
+
* Similar to <tt>res.result[0].length</tt> (but faster).
|
1368
|
+
*/
|
1369
|
+
static VALUE
|
1370
|
+
pgresult_num_fields(obj)
|
1371
|
+
VALUE obj;
|
1372
|
+
{
|
1373
|
+
int n;
|
1374
|
+
|
1375
|
+
n = PQnfields(get_pgresult(obj));
|
1376
|
+
return INT2NUM(n);
|
1377
|
+
}
|
1378
|
+
|
1379
|
+
/*
|
1380
|
+
* call-seq:
|
1381
|
+
* res.fieldname( index )
|
1382
|
+
*
|
1383
|
+
* Returns the name of the field (column) corresponding to the index.
|
1384
|
+
*
|
1385
|
+
* res=conn.exec("SELECT foo,bar AS biggles,jim,jam FROM mytable;")
|
1386
|
+
* puts res.fieldname(2) => 'jim'
|
1387
|
+
* puts res.fieldname(1) => 'biggles'
|
1388
|
+
*
|
1389
|
+
* Equivalent to <tt>res.fields[_index_]</tt>.
|
1390
|
+
*/
|
1391
|
+
static VALUE
|
1392
|
+
pgresult_fieldname(obj, index)
|
1393
|
+
VALUE obj, index;
|
1394
|
+
{
|
1395
|
+
PGresult *result;
|
1396
|
+
int i = NUM2INT(index);
|
1397
|
+
char *name;
|
1398
|
+
|
1399
|
+
result = get_pgresult(obj);
|
1400
|
+
if (i < 0 || i >= PQnfields(result)) {
|
1401
|
+
rb_raise(rb_eArgError,"invalid field number %d", i);
|
1402
|
+
}
|
1403
|
+
name = PQfname(result, i);
|
1404
|
+
return rb_tainted_str_new2(name);
|
1405
|
+
}
|
1406
|
+
|
1407
|
+
/*
|
1408
|
+
* call-seq:
|
1409
|
+
* res.fieldnum( name )
|
1410
|
+
*
|
1411
|
+
* Returns the index of the field specified by the string _name_.
|
1412
|
+
*
|
1413
|
+
* res=conn.exec("SELECT foo,bar AS biggles,jim,jam FROM mytable;")
|
1414
|
+
* puts res.fieldnum('foo') => 0
|
1415
|
+
*
|
1416
|
+
* Raises an ArgumentError if the specified _name_ isn't one of the field names;
|
1417
|
+
* raises a TypeError if _name_ is not a String.
|
1418
|
+
*/
|
1419
|
+
static VALUE
|
1420
|
+
pgresult_fieldnum(obj, name)
|
1421
|
+
VALUE obj, name;
|
1422
|
+
{
|
1423
|
+
int n;
|
1424
|
+
|
1425
|
+
Check_Type(name, T_STRING);
|
1426
|
+
|
1427
|
+
n = PQfnumber(get_pgresult(obj), StringValuePtr(name));
|
1428
|
+
if (n == -1) {
|
1429
|
+
rb_raise(rb_eArgError,"Unknown field: %s", StringValuePtr(name));
|
1430
|
+
}
|
1431
|
+
return INT2NUM(n);
|
1432
|
+
}
|
1433
|
+
|
1434
|
+
/*
|
1435
|
+
* call-seq:
|
1436
|
+
* res.type( index )
|
1437
|
+
*
|
1438
|
+
* Returns the data type associated with the given column number.
|
1439
|
+
*
|
1440
|
+
* The integer returned is the internal +OID+ number (in PostgreSQL) of the type.
|
1441
|
+
* If you have the PostgreSQL source available, you can see the OIDs for every column type in the file <tt>src/include/catalog/pg_type.h</tt>.
|
1442
|
+
*/
|
1443
|
+
static VALUE
|
1444
|
+
pgresult_type(obj, index)
|
1445
|
+
VALUE obj, index;
|
1446
|
+
{
|
1447
|
+
PGresult* result = get_pgresult(obj);
|
1448
|
+
int i = NUM2INT(index);
|
1449
|
+
if (i < 0 || i >= PQnfields(result)) {
|
1450
|
+
rb_raise(rb_eArgError, "invalid field number %d", i);
|
1451
|
+
}
|
1452
|
+
return INT2NUM(PQftype(result, i));
|
1453
|
+
}
|
1454
|
+
|
1455
|
+
/*
|
1456
|
+
* call-seq:
|
1457
|
+
* res.size( index )
|
1458
|
+
*
|
1459
|
+
* Returns the size of the field type in bytes. Returns <tt>-1</tt> if the field is variable sized.
|
1460
|
+
*
|
1461
|
+
* res = conn.exec("SELECT myInt, myVarChar50 FROM foo;")
|
1462
|
+
* res.size(0) => 4
|
1463
|
+
* res.size(1) => -1
|
1464
|
+
*/
|
1465
|
+
static VALUE
|
1466
|
+
pgresult_size(obj, index)
|
1467
|
+
VALUE obj, index;
|
1468
|
+
{
|
1469
|
+
PGresult *result;
|
1470
|
+
int i = NUM2INT(index);
|
1471
|
+
int size;
|
1472
|
+
|
1473
|
+
result = get_pgresult(obj);
|
1474
|
+
if (i < 0 || i >= PQnfields(result)) {
|
1475
|
+
rb_raise(rb_eArgError,"invalid field number %d", i);
|
1476
|
+
}
|
1477
|
+
size = PQfsize(result, i);
|
1478
|
+
return INT2NUM(size);
|
1479
|
+
}
|
1480
|
+
|
1481
|
+
/*
|
1482
|
+
* call-seq:
|
1483
|
+
* res.value( tup_num, field_num )
|
1484
|
+
*
|
1485
|
+
* Returns the value in tuple number <i>tup_num</i>, field number <i>field_num</i>. (Row <i>tup_num</i>, column <i>field_num</i>.)
|
1486
|
+
*
|
1487
|
+
* Equivalent to <tt>res.result[<i>tup_num</i>][<i>field_num</i>]</tt> (but faster).
|
1488
|
+
*/
|
1489
|
+
static VALUE
|
1490
|
+
pgresult_getvalue(obj, tup_num, field_num)
|
1491
|
+
VALUE obj, tup_num, field_num;
|
1492
|
+
{
|
1493
|
+
PGresult *result;
|
1494
|
+
int i = NUM2INT(tup_num);
|
1495
|
+
int j = NUM2INT(field_num);
|
1496
|
+
|
1497
|
+
result = get_pgresult(obj);
|
1498
|
+
if (i < 0 || i >= PQntuples(result)) {
|
1499
|
+
rb_raise(rb_eArgError,"invalid tuple number %d", i);
|
1500
|
+
}
|
1501
|
+
if (j < 0 || j >= PQnfields(result)) {
|
1502
|
+
rb_raise(rb_eArgError,"invalid field number %d", j);
|
1503
|
+
}
|
1504
|
+
|
1505
|
+
return fetch_pgresult(result, i, j);
|
1506
|
+
}
|
1507
|
+
|
1508
|
+
|
1509
|
+
/*
|
1510
|
+
* call-seq:
|
1511
|
+
* res.value_byname( tup_num, field_name )
|
1512
|
+
*
|
1513
|
+
* Returns the value in tuple number <i>tup_num</i>, for the field named <i>field_name</i>.
|
1514
|
+
*
|
1515
|
+
* Equivalent to (but faster than) either of:
|
1516
|
+
* res.result[<i>tup_num</i>][ res.fieldnum(<i>field_name</i>) ]
|
1517
|
+
* res.value( <i>tup_num</i>, res.fieldnum(<i>field_name</i>) )
|
1518
|
+
*
|
1519
|
+
* <i>(This method internally calls #value as like the second example above; it is slower than using the field index directly.)</i>
|
1520
|
+
*/
|
1521
|
+
static VALUE
|
1522
|
+
pgresult_getvalue_byname(obj, tup_num, field_name)
|
1523
|
+
VALUE obj, tup_num, field_name;
|
1524
|
+
{
|
1525
|
+
return pgresult_getvalue(obj, tup_num, pgresult_fieldnum(obj, field_name));
|
1526
|
+
}
|
1527
|
+
|
1528
|
+
|
1529
|
+
/*
|
1530
|
+
* call-seq:
|
1531
|
+
* res.getlength( tup_num, field_num )
|
1532
|
+
*
|
1533
|
+
* Returns the (String) length of the field in bytes.
|
1534
|
+
*
|
1535
|
+
* Equivalent to <tt>res.value(<i>tup_num</i>,<i>field_num</i>).length</tt>.
|
1536
|
+
*/
|
1537
|
+
static VALUE
|
1538
|
+
pgresult_getlength(obj, tup_num, field_num)
|
1539
|
+
VALUE obj, tup_num, field_num;
|
1540
|
+
{
|
1541
|
+
PGresult *result;
|
1542
|
+
int i = NUM2INT(tup_num);
|
1543
|
+
int j = NUM2INT(field_num);
|
1544
|
+
|
1545
|
+
result = get_pgresult(obj);
|
1546
|
+
if (i < 0 || i >= PQntuples(result)) {
|
1547
|
+
rb_raise(rb_eArgError,"invalid tuple number %d", i);
|
1548
|
+
}
|
1549
|
+
if (j < 0 || j >= PQnfields(result)) {
|
1550
|
+
rb_raise(rb_eArgError,"invalid field number %d", j);
|
1551
|
+
}
|
1552
|
+
return INT2FIX(PQgetlength(result, i, j));
|
1553
|
+
}
|
1554
|
+
|
1555
|
+
/*
|
1556
|
+
* call-seq:
|
1557
|
+
* res.getisnull( tup_num, field_num ) => true or false
|
1558
|
+
*
|
1559
|
+
* Returns +true+ if the specified value is +nil+; +false+ otherwise.
|
1560
|
+
*
|
1561
|
+
* Equivalent to <tt>res.value(<i>tup_num</i>,<i>field_num</i>)==+nil+</tt>.
|
1562
|
+
*/
|
1563
|
+
static VALUE
|
1564
|
+
pgresult_getisnull(obj, tup_num, field_num)
|
1565
|
+
VALUE obj, tup_num, field_num;
|
1566
|
+
{
|
1567
|
+
PGresult *result;
|
1568
|
+
int i = NUM2INT(tup_num);
|
1569
|
+
int j = NUM2INT(field_num);
|
1570
|
+
|
1571
|
+
result = get_pgresult(obj);
|
1572
|
+
if (i < 0 || i >= PQntuples(result)) {
|
1573
|
+
rb_raise(rb_eArgError,"invalid tuple number %d", i);
|
1574
|
+
}
|
1575
|
+
if (j < 0 || j >= PQnfields(result)) {
|
1576
|
+
rb_raise(rb_eArgError,"invalid field number %d", j);
|
1577
|
+
}
|
1578
|
+
return PQgetisnull(result, i, j) ? Qtrue : Qfalse;
|
1579
|
+
}
|
1580
|
+
|
1581
|
+
/*
|
1582
|
+
* call-seq:
|
1583
|
+
* res.print( file, opt )
|
1584
|
+
*
|
1585
|
+
* MISSING: Documentation
|
1586
|
+
*/
|
1587
|
+
static VALUE
|
1588
|
+
pgresult_print(obj, file, opt)
|
1589
|
+
VALUE obj, file, opt;
|
1590
|
+
{
|
1591
|
+
VALUE value;
|
1592
|
+
ID mem;
|
1593
|
+
OpenFile* fp;
|
1594
|
+
PQprintOpt po;
|
1595
|
+
|
1596
|
+
Check_Type(file, T_FILE);
|
1597
|
+
Check_Type(opt, T_STRUCT);
|
1598
|
+
GetOpenFile(file, fp);
|
1599
|
+
|
1600
|
+
memset(&po, 0, sizeof(po));
|
1601
|
+
|
1602
|
+
mem = rb_intern("header");
|
1603
|
+
value = rb_struct_getmember(opt, mem);
|
1604
|
+
po.header = value == Qtrue ? 1 : 0;
|
1605
|
+
|
1606
|
+
mem = rb_intern("align");
|
1607
|
+
value = rb_struct_getmember(opt, mem);
|
1608
|
+
po.align = value == Qtrue ? 1 : 0;
|
1609
|
+
|
1610
|
+
mem = rb_intern("standard");
|
1611
|
+
value = rb_struct_getmember(opt, mem);
|
1612
|
+
po.standard = value == Qtrue ? 1 : 0;
|
1613
|
+
|
1614
|
+
mem = rb_intern("html3");
|
1615
|
+
value = rb_struct_getmember(opt, mem);
|
1616
|
+
po.html3 = value == Qtrue ? 1 : 0;
|
1617
|
+
|
1618
|
+
mem = rb_intern("expanded");
|
1619
|
+
value = rb_struct_getmember(opt, mem);
|
1620
|
+
po.expanded = value == Qtrue ? 1 : 0;
|
1621
|
+
|
1622
|
+
mem = rb_intern("pager");
|
1623
|
+
value = rb_struct_getmember(opt, mem);
|
1624
|
+
po.pager = value == Qtrue ? 1 : 0;
|
1625
|
+
|
1626
|
+
mem = rb_intern("fieldSep");
|
1627
|
+
value = rb_struct_getmember(opt, mem);
|
1628
|
+
if (!NIL_P(value)) {
|
1629
|
+
Check_Type(value, T_STRING);
|
1630
|
+
po.fieldSep = StringValuePtr(value);
|
1631
|
+
}
|
1632
|
+
|
1633
|
+
mem = rb_intern("tableOpt");
|
1634
|
+
value = rb_struct_getmember(opt, mem);
|
1635
|
+
if (!NIL_P(value)) {
|
1636
|
+
Check_Type(value, T_STRING);
|
1637
|
+
po.tableOpt = StringValuePtr(value);
|
1638
|
+
}
|
1639
|
+
|
1640
|
+
mem = rb_intern("caption");
|
1641
|
+
value = rb_struct_getmember(opt, mem);
|
1642
|
+
if (!NIL_P(value)) {
|
1643
|
+
Check_Type(value, T_STRING);
|
1644
|
+
po.caption = StringValuePtr(value);
|
1645
|
+
}
|
1646
|
+
|
1647
|
+
PQprint(fp->f2?fp->f2:fp->f, get_pgresult(obj), &po);
|
1648
|
+
return obj;
|
1649
|
+
}
|
1650
|
+
|
1651
|
+
/*
|
1652
|
+
* call-seq:
|
1653
|
+
* res.cmdtuples()
|
1654
|
+
*
|
1655
|
+
* Returns the number of tuples (rows) affected by the SQL command.
|
1656
|
+
*
|
1657
|
+
* If the SQL command that generated the PGresult was not one of +INSERT+, +UPDATE+, +DELETE+, +MOVE+, or +FETCH+, or if no tuples (rows) were affected, +0+ is returned.
|
1658
|
+
*/
|
1659
|
+
static VALUE
|
1660
|
+
pgresult_cmdtuples(obj)
|
1661
|
+
VALUE obj;
|
1662
|
+
{
|
1663
|
+
long n;
|
1664
|
+
n = strtol(PQcmdTuples(get_pgresult(obj)),NULL, 10);
|
1665
|
+
return INT2NUM(n);
|
1666
|
+
}
|
1667
|
+
/*
|
1668
|
+
* call-seq:
|
1669
|
+
* res.cmdstatus()
|
1670
|
+
*
|
1671
|
+
* Returns the status string of the last query command.
|
1672
|
+
*/
|
1673
|
+
static VALUE
|
1674
|
+
pgresult_cmdstatus(obj)
|
1675
|
+
VALUE obj;
|
1676
|
+
{
|
1677
|
+
return rb_tainted_str_new2(PQcmdStatus(get_pgresult(obj)));
|
1678
|
+
}
|
1679
|
+
|
1680
|
+
/*
|
1681
|
+
* call-seq:
|
1682
|
+
* res.oid()
|
1683
|
+
*
|
1684
|
+
* Returns the +oid+.
|
1685
|
+
*/
|
1686
|
+
static VALUE
|
1687
|
+
pgresult_oid(obj)
|
1688
|
+
VALUE obj;
|
1689
|
+
{
|
1690
|
+
Oid n = PQoidValue(get_pgresult(obj));
|
1691
|
+
if (n == InvalidOid)
|
1692
|
+
return Qnil;
|
1693
|
+
else
|
1694
|
+
return INT2NUM(n);
|
1695
|
+
}
|
1696
|
+
|
1697
|
+
/*
|
1698
|
+
* call-seq:
|
1699
|
+
* res.clear()
|
1700
|
+
*
|
1701
|
+
* Clears the PGresult object as the result of the query.
|
1702
|
+
*/
|
1703
|
+
static VALUE
|
1704
|
+
pgresult_clear(obj)
|
1705
|
+
VALUE obj;
|
1706
|
+
{
|
1707
|
+
PQclear(get_pgresult(obj));
|
1708
|
+
DATA_PTR(obj) = 0;
|
1709
|
+
|
1710
|
+
return Qnil;
|
1711
|
+
}
|
1712
|
+
|
1713
|
+
static VALUE
|
1714
|
+
pgresult_result_with_clear(self)
|
1715
|
+
VALUE self;
|
1716
|
+
{
|
1717
|
+
VALUE rows = rb_funcall(self, rb_intern("rows"), 0);
|
1718
|
+
pgresult_clear(self);
|
1719
|
+
return rows;
|
1720
|
+
}
|
1721
|
+
|
1722
|
+
/* Large Object support */
|
1723
|
+
static PGlarge*
|
1724
|
+
get_pglarge(obj)
|
1725
|
+
VALUE obj;
|
1726
|
+
{
|
1727
|
+
PGlarge *pglarge;
|
1728
|
+
Data_Get_Struct(obj, PGlarge, pglarge);
|
1729
|
+
if (pglarge == 0) rb_raise(rb_ePGError, "invalid large object");
|
1730
|
+
return pglarge;
|
1731
|
+
}
|
1732
|
+
|
1733
|
+
/*
|
1734
|
+
* call-seq:
|
1735
|
+
* conn.lo_import( file ) => pglarge
|
1736
|
+
*
|
1737
|
+
* Import a file to a large object. Returns a PGlarge instance on success. On failure, it raises a PGError exception.
|
1738
|
+
*/
|
1739
|
+
static VALUE
|
1740
|
+
pgconn_loimport(obj, filename)
|
1741
|
+
VALUE obj, filename;
|
1742
|
+
{
|
1743
|
+
Oid lo_oid;
|
1744
|
+
|
1745
|
+
PGconn *conn = get_pgconn(obj);
|
1746
|
+
|
1747
|
+
Check_Type(filename, T_STRING);
|
1748
|
+
|
1749
|
+
lo_oid = lo_import(conn, StringValuePtr(filename));
|
1750
|
+
if (lo_oid == 0) {
|
1751
|
+
rb_raise(rb_ePGError, PQerrorMessage(conn));
|
1752
|
+
}
|
1753
|
+
return pglarge_new(conn, lo_oid, -1);
|
1754
|
+
}
|
1755
|
+
|
1756
|
+
/*
|
1757
|
+
* call-seq:
|
1758
|
+
* conn.lo_export( oid, file )
|
1759
|
+
*
|
1760
|
+
* Saves a large object of _oid_ to a _file_.
|
1761
|
+
*/
|
1762
|
+
static VALUE
|
1763
|
+
pgconn_loexport(obj, lo_oid,filename)
|
1764
|
+
VALUE obj, lo_oid, filename;
|
1765
|
+
{
|
1766
|
+
PGconn *conn = get_pgconn(obj);
|
1767
|
+
int oid;
|
1768
|
+
Check_Type(filename, T_STRING);
|
1769
|
+
|
1770
|
+
oid = NUM2INT(lo_oid);
|
1771
|
+
if (oid < 0) {
|
1772
|
+
rb_raise(rb_ePGError, "invalid large object oid %d",oid);
|
1773
|
+
}
|
1774
|
+
|
1775
|
+
if (!lo_export(conn, oid, StringValuePtr(filename))) {
|
1776
|
+
rb_raise(rb_ePGError, PQerrorMessage(conn));
|
1777
|
+
}
|
1778
|
+
return Qnil;
|
1779
|
+
}
|
1780
|
+
|
1781
|
+
/*
|
1782
|
+
* call-seq:
|
1783
|
+
* conn.lo_create( [mode] ) => pglarge
|
1784
|
+
*
|
1785
|
+
* Returns a PGlarge instance on success. On failure, it raises PGError exception.
|
1786
|
+
* <i>(See #lo_open for information on _mode_.)</i>
|
1787
|
+
*/
|
1788
|
+
static VALUE
|
1789
|
+
pgconn_locreate(argc, argv, obj)
|
1790
|
+
int argc;
|
1791
|
+
VALUE *argv;
|
1792
|
+
VALUE obj;
|
1793
|
+
{
|
1794
|
+
Oid lo_oid;
|
1795
|
+
int mode;
|
1796
|
+
VALUE nmode;
|
1797
|
+
PGconn *conn;
|
1798
|
+
|
1799
|
+
if (rb_scan_args(argc, argv, "01", &nmode) == 0) {
|
1800
|
+
mode = INV_READ;
|
1801
|
+
}
|
1802
|
+
else {
|
1803
|
+
mode = FIX2INT(nmode);
|
1804
|
+
}
|
1805
|
+
|
1806
|
+
conn = get_pgconn(obj);
|
1807
|
+
lo_oid = lo_creat(conn, mode);
|
1808
|
+
if (lo_oid == 0){
|
1809
|
+
rb_raise(rb_ePGError, "can't creat large object");
|
1810
|
+
}
|
1811
|
+
|
1812
|
+
return pglarge_new(conn, lo_oid, -1);
|
1813
|
+
}
|
1814
|
+
|
1815
|
+
/*
|
1816
|
+
* call-seq:
|
1817
|
+
* conn.lo_open( oid, [mode] ) => pglarge
|
1818
|
+
*
|
1819
|
+
* Open a large object of _oid_. Returns a PGlarge instance on success.
|
1820
|
+
* The _mode_ argument specifies the mode for the opened large object,
|
1821
|
+
* which is either +INV_READ+, or +INV_WRITE+.
|
1822
|
+
* * If _mode_ On failure, it raises a PGError exception.
|
1823
|
+
* * If _mode_ is omitted, the default is +INV_READ+.
|
1824
|
+
*/
|
1825
|
+
static VALUE
|
1826
|
+
pgconn_loopen(argc, argv, obj)
|
1827
|
+
int argc;
|
1828
|
+
VALUE *argv;
|
1829
|
+
VALUE obj;
|
1830
|
+
{
|
1831
|
+
Oid lo_oid;
|
1832
|
+
int fd, mode;
|
1833
|
+
VALUE nmode, objid;
|
1834
|
+
PGconn *conn = get_pgconn(obj);
|
1835
|
+
|
1836
|
+
switch (rb_scan_args(argc, argv, "02", &objid, &nmode)) {
|
1837
|
+
case 1:
|
1838
|
+
lo_oid = NUM2INT(objid);
|
1839
|
+
mode = INV_READ;
|
1840
|
+
break;
|
1841
|
+
case 2:
|
1842
|
+
lo_oid = NUM2INT(objid);
|
1843
|
+
mode = FIX2INT(nmode);
|
1844
|
+
break;
|
1845
|
+
default:
|
1846
|
+
mode = INV_READ;
|
1847
|
+
lo_oid = lo_creat(conn, mode);
|
1848
|
+
if (lo_oid == 0){
|
1849
|
+
rb_raise(rb_ePGError, "can't creat large object");
|
1850
|
+
}
|
1851
|
+
}
|
1852
|
+
if((fd = lo_open(conn, lo_oid, mode)) < 0) {
|
1853
|
+
rb_raise(rb_ePGError, "can't open large object");
|
1854
|
+
}
|
1855
|
+
return pglarge_new(conn, lo_oid, fd);
|
1856
|
+
}
|
1857
|
+
|
1858
|
+
/*
|
1859
|
+
* call-seq:
|
1860
|
+
* conn.lo_unlink( oid )
|
1861
|
+
*
|
1862
|
+
* Unlinks (deletes) the postgres large object of _oid_.
|
1863
|
+
*/
|
1864
|
+
static VALUE
|
1865
|
+
pgconn_lounlink(obj, lo_oid)
|
1866
|
+
VALUE obj, lo_oid;
|
1867
|
+
{
|
1868
|
+
PGconn *conn;
|
1869
|
+
int oid = NUM2INT(lo_oid);
|
1870
|
+
int result;
|
1871
|
+
|
1872
|
+
if (oid < 0){
|
1873
|
+
rb_raise(rb_ePGError, "invalid oid %d",oid);
|
1874
|
+
}
|
1875
|
+
conn = get_pgconn(obj);
|
1876
|
+
result = lo_unlink(conn,oid);
|
1877
|
+
|
1878
|
+
return Qnil;
|
1879
|
+
}
|
1880
|
+
|
1881
|
+
static void
|
1882
|
+
free_pglarge(ptr)
|
1883
|
+
PGlarge *ptr;
|
1884
|
+
{
|
1885
|
+
if ((ptr->lo_fd) > 0) {
|
1886
|
+
lo_close(ptr->pgconn,ptr->lo_fd);
|
1887
|
+
}
|
1888
|
+
free(ptr);
|
1889
|
+
}
|
1890
|
+
|
1891
|
+
static VALUE
|
1892
|
+
pglarge_new(conn, lo_oid ,lo_fd)
|
1893
|
+
PGconn *conn;
|
1894
|
+
Oid lo_oid;
|
1895
|
+
int lo_fd;
|
1896
|
+
{
|
1897
|
+
VALUE obj;
|
1898
|
+
PGlarge *pglarge;
|
1899
|
+
|
1900
|
+
obj = Data_Make_Struct(rb_cPGlarge, PGlarge, 0, free_pglarge, pglarge);
|
1901
|
+
pglarge->pgconn = conn;
|
1902
|
+
pglarge->lo_oid = lo_oid;
|
1903
|
+
pglarge->lo_fd = lo_fd;
|
1904
|
+
|
1905
|
+
return obj;
|
1906
|
+
}
|
1907
|
+
|
1908
|
+
/*
|
1909
|
+
* call-seq:
|
1910
|
+
* lrg.oid()
|
1911
|
+
*
|
1912
|
+
* Returns the large object's +oid+.
|
1913
|
+
*/
|
1914
|
+
static VALUE
|
1915
|
+
pglarge_oid(obj)
|
1916
|
+
VALUE obj;
|
1917
|
+
{
|
1918
|
+
PGlarge *pglarge = get_pglarge(obj);
|
1919
|
+
|
1920
|
+
return INT2NUM(pglarge->lo_oid);
|
1921
|
+
}
|
1922
|
+
|
1923
|
+
/*
|
1924
|
+
* call-seq:
|
1925
|
+
* lrg.open( [mode] )
|
1926
|
+
*
|
1927
|
+
* Opens a large object.
|
1928
|
+
* The _mode_ argument specifies the mode for the opened large object,
|
1929
|
+
* which is either +INV_READ+ or +INV_WRITE+.
|
1930
|
+
*/
|
1931
|
+
static VALUE
|
1932
|
+
pglarge_open(argc, argv, obj)
|
1933
|
+
int argc;
|
1934
|
+
VALUE *argv;
|
1935
|
+
VALUE obj;
|
1936
|
+
{
|
1937
|
+
PGlarge *pglarge = get_pglarge(obj);
|
1938
|
+
VALUE nmode;
|
1939
|
+
int fd;
|
1940
|
+
int mode;
|
1941
|
+
|
1942
|
+
if (rb_scan_args(argc, argv, "01", &nmode) == 0) {
|
1943
|
+
mode = INV_READ;
|
1944
|
+
}
|
1945
|
+
else {
|
1946
|
+
mode = FIX2INT(nmode);
|
1947
|
+
}
|
1948
|
+
|
1949
|
+
if((fd = lo_open(pglarge->pgconn, pglarge->lo_oid, mode)) < 0) {
|
1950
|
+
rb_raise(rb_ePGError, "can't open large object");
|
1951
|
+
}
|
1952
|
+
pglarge->lo_fd = fd;
|
1953
|
+
|
1954
|
+
return INT2FIX(pglarge->lo_fd);
|
1955
|
+
}
|
1956
|
+
|
1957
|
+
/*
|
1958
|
+
* call-seq:
|
1959
|
+
* lrg.close()
|
1960
|
+
*
|
1961
|
+
* Closes a large object. Closed when they are garbage-collected.
|
1962
|
+
*/
|
1963
|
+
static VALUE
|
1964
|
+
pglarge_close(obj)
|
1965
|
+
VALUE obj;
|
1966
|
+
{
|
1967
|
+
PGlarge *pglarge = get_pglarge(obj);
|
1968
|
+
|
1969
|
+
if((lo_close(pglarge->pgconn, pglarge->lo_fd)) < 0) {
|
1970
|
+
rb_raise(rb_ePGError, "can't closed large object");
|
1971
|
+
}
|
1972
|
+
DATA_PTR(obj) = 0;
|
1973
|
+
|
1974
|
+
return Qnil;
|
1975
|
+
}
|
1976
|
+
|
1977
|
+
/*
|
1978
|
+
* call-seq:
|
1979
|
+
* lrg.tell()
|
1980
|
+
*
|
1981
|
+
* Returns the current position of the large object pointer.
|
1982
|
+
*/
|
1983
|
+
static VALUE
|
1984
|
+
pglarge_tell(obj)
|
1985
|
+
VALUE obj;
|
1986
|
+
{
|
1987
|
+
int start;
|
1988
|
+
PGlarge *pglarge = get_pglarge(obj);
|
1989
|
+
|
1990
|
+
if ((start = lo_tell(pglarge->pgconn,pglarge->lo_fd)) == -1) {
|
1991
|
+
rb_raise(rb_ePGError, "error while getting position");
|
1992
|
+
}
|
1993
|
+
return INT2NUM(start);
|
1994
|
+
}
|
1995
|
+
|
1996
|
+
static VALUE
|
1997
|
+
loread_all(obj)
|
1998
|
+
VALUE obj;
|
1999
|
+
{
|
2000
|
+
PGlarge *pglarge = get_pglarge(obj);
|
2001
|
+
VALUE str;
|
2002
|
+
long siz = BUFSIZ;
|
2003
|
+
long bytes = 0;
|
2004
|
+
int n;
|
2005
|
+
|
2006
|
+
str = rb_tainted_str_new(0,siz);
|
2007
|
+
for (;;) {
|
2008
|
+
n = lo_read(pglarge->pgconn, pglarge->lo_fd, RSTRING(str)->ptr + bytes,siz - bytes);
|
2009
|
+
if (n == 0 && bytes == 0) return Qnil;
|
2010
|
+
bytes += n;
|
2011
|
+
if (bytes < siz ) break;
|
2012
|
+
siz += BUFSIZ;
|
2013
|
+
rb_str_resize(str,siz);
|
2014
|
+
}
|
2015
|
+
if (bytes == 0) return rb_tainted_str_new(0,0);
|
2016
|
+
if (bytes != siz) rb_str_resize(str, bytes);
|
2017
|
+
return str;
|
2018
|
+
}
|
2019
|
+
|
2020
|
+
/*
|
2021
|
+
* call-seq:
|
2022
|
+
* lrg.read( [length] )
|
2023
|
+
*
|
2024
|
+
* Attempts to read _length_ bytes from large object.
|
2025
|
+
* If no _length_ is given, reads all data.
|
2026
|
+
*/
|
2027
|
+
static VALUE
|
2028
|
+
pglarge_read(argc, argv, obj)
|
2029
|
+
int argc;
|
2030
|
+
VALUE *argv;
|
2031
|
+
VALUE obj;
|
2032
|
+
{
|
2033
|
+
int len;
|
2034
|
+
PGlarge *pglarge = get_pglarge(obj);
|
2035
|
+
VALUE str;
|
2036
|
+
VALUE length;
|
2037
|
+
|
2038
|
+
rb_scan_args(argc, argv, "01", &length);
|
2039
|
+
if (NIL_P(length)) {
|
2040
|
+
return loread_all(obj);
|
2041
|
+
}
|
2042
|
+
|
2043
|
+
len = NUM2INT(length);
|
2044
|
+
if (len < 0){
|
2045
|
+
rb_raise(rb_ePGError,"nagative length %d given", len);
|
2046
|
+
}
|
2047
|
+
str = rb_tainted_str_new(0,len);
|
2048
|
+
|
2049
|
+
if((len = lo_read(pglarge->pgconn, pglarge->lo_fd, StringValuePtr(str), len)) < 0) {
|
2050
|
+
rb_raise(rb_ePGError, "error while reading");
|
2051
|
+
}
|
2052
|
+
if (len == 0) return Qnil;
|
2053
|
+
RSTRING(str)->len = len;
|
2054
|
+
return str;
|
2055
|
+
}
|
2056
|
+
|
2057
|
+
/*
|
2058
|
+
* call-seq:
|
2059
|
+
* lrg.write( str )
|
2060
|
+
*
|
2061
|
+
* Writes the string _str_ to the large object.
|
2062
|
+
* Returns the number of bytes written.
|
2063
|
+
*/
|
2064
|
+
static VALUE
|
2065
|
+
pglarge_write(obj, buffer)
|
2066
|
+
VALUE obj, buffer;
|
2067
|
+
{
|
2068
|
+
int n;
|
2069
|
+
PGlarge *pglarge = get_pglarge(obj);
|
2070
|
+
|
2071
|
+
Check_Type(buffer, T_STRING);
|
2072
|
+
|
2073
|
+
if( RSTRING(buffer)->len < 0) {
|
2074
|
+
rb_raise(rb_ePGError, "write buffer zero string");
|
2075
|
+
}
|
2076
|
+
if((n = lo_write(pglarge->pgconn, pglarge->lo_fd, StringValuePtr(buffer), RSTRING(buffer)->len)) == -1) {
|
2077
|
+
rb_raise(rb_ePGError, "buffer truncated during write");
|
2078
|
+
}
|
2079
|
+
|
2080
|
+
return INT2FIX(n);
|
2081
|
+
}
|
2082
|
+
|
2083
|
+
/*
|
2084
|
+
* call-seq:
|
2085
|
+
* lrg.seek( offset, whence )
|
2086
|
+
*
|
2087
|
+
* Move the large object pointer to the _offset_.
|
2088
|
+
* Valid values for _whence_ are +SEEK_SET+, +SEEK_CUR+, and +SEEK_END+.
|
2089
|
+
* (Or 0, 1, or 2.)
|
2090
|
+
*/
|
2091
|
+
static VALUE
|
2092
|
+
pglarge_seek(obj, offset, whence)
|
2093
|
+
VALUE obj, offset, whence;
|
2094
|
+
{
|
2095
|
+
PGlarge *pglarge = get_pglarge(obj);
|
2096
|
+
int ret;
|
2097
|
+
|
2098
|
+
if((ret = lo_lseek(pglarge->pgconn, pglarge->lo_fd, NUM2INT(offset), NUM2INT(whence))) == -1) {
|
2099
|
+
rb_raise(rb_ePGError, "error while moving cursor");
|
2100
|
+
}
|
2101
|
+
|
2102
|
+
return INT2NUM(ret);
|
2103
|
+
}
|
2104
|
+
|
2105
|
+
/*
|
2106
|
+
* call-seq:
|
2107
|
+
* lrg.size()
|
2108
|
+
*
|
2109
|
+
* Returns the size of the large object.
|
2110
|
+
*/
|
2111
|
+
static VALUE
|
2112
|
+
pglarge_size(obj)
|
2113
|
+
VALUE obj;
|
2114
|
+
{
|
2115
|
+
PGlarge *pglarge = get_pglarge(obj);
|
2116
|
+
int start, end;
|
2117
|
+
|
2118
|
+
if ((start = lo_tell(pglarge->pgconn,pglarge->lo_fd)) == -1) {
|
2119
|
+
rb_raise(rb_ePGError, "error while getting position");
|
2120
|
+
}
|
2121
|
+
|
2122
|
+
if ((end = lo_lseek(pglarge->pgconn, pglarge->lo_fd, 0, SEEK_END)) == -1) {
|
2123
|
+
rb_raise(rb_ePGError, "error while moving cursor");
|
2124
|
+
}
|
2125
|
+
|
2126
|
+
if ((start = lo_lseek(pglarge->pgconn, pglarge->lo_fd,start, SEEK_SET)) == -1) {
|
2127
|
+
rb_raise(rb_ePGError, "error while moving back to posiion");
|
2128
|
+
}
|
2129
|
+
|
2130
|
+
return INT2NUM(end);
|
2131
|
+
}
|
2132
|
+
|
2133
|
+
/*
|
2134
|
+
* call-seq:
|
2135
|
+
* lrg.export( file )
|
2136
|
+
*
|
2137
|
+
* Saves the large object to a file.
|
2138
|
+
*/
|
2139
|
+
static VALUE
|
2140
|
+
pglarge_export(obj, filename)
|
2141
|
+
VALUE obj, filename;
|
2142
|
+
{
|
2143
|
+
PGlarge *pglarge = get_pglarge(obj);
|
2144
|
+
|
2145
|
+
Check_Type(filename, T_STRING);
|
2146
|
+
|
2147
|
+
if (!lo_export(pglarge->pgconn, pglarge->lo_oid, StringValuePtr(filename))){
|
2148
|
+
rb_raise(rb_ePGError, PQerrorMessage(pglarge->pgconn));
|
2149
|
+
}
|
2150
|
+
|
2151
|
+
return Qnil;
|
2152
|
+
}
|
2153
|
+
|
2154
|
+
/*
|
2155
|
+
* call-seq:
|
2156
|
+
* lrg.unlink()
|
2157
|
+
*
|
2158
|
+
* Deletes the large object.
|
2159
|
+
*/
|
2160
|
+
static VALUE
|
2161
|
+
pglarge_unlink(obj)
|
2162
|
+
VALUE obj;
|
2163
|
+
{
|
2164
|
+
PGlarge *pglarge = get_pglarge(obj);
|
2165
|
+
|
2166
|
+
if (!lo_unlink(pglarge->pgconn,pglarge->lo_oid)) {
|
2167
|
+
rb_raise(rb_ePGError, PQerrorMessage(pglarge->pgconn));
|
2168
|
+
}
|
2169
|
+
DATA_PTR(obj) = 0;
|
2170
|
+
|
2171
|
+
return Qnil;
|
2172
|
+
}
|
2173
|
+
|
2174
|
+
static VALUE
|
2175
|
+
pgrow_init(self, keys)
|
2176
|
+
VALUE self, keys;
|
2177
|
+
{
|
2178
|
+
VALUE args[1] = { LONG2NUM(RARRAY(keys)->len) };
|
2179
|
+
rb_call_super(1, args);
|
2180
|
+
rb_iv_set(self, "@keys", keys);
|
2181
|
+
return self;
|
2182
|
+
}
|
2183
|
+
|
2184
|
+
static VALUE
|
2185
|
+
pgrow_keys(self)
|
2186
|
+
VALUE self;
|
2187
|
+
{
|
2188
|
+
return rb_iv_get(self, "@keys");
|
2189
|
+
}
|
2190
|
+
|
2191
|
+
static VALUE
|
2192
|
+
pgrow_values(self)
|
2193
|
+
VALUE self;
|
2194
|
+
{
|
2195
|
+
return self;
|
2196
|
+
}
|
2197
|
+
|
2198
|
+
static VALUE
|
2199
|
+
pgrow_aref(argc, argv, self)
|
2200
|
+
int argc;
|
2201
|
+
VALUE * argv;
|
2202
|
+
VALUE self;
|
2203
|
+
{
|
2204
|
+
if (TYPE(argv[0]) == T_STRING) {
|
2205
|
+
VALUE keys = pgrow_keys(self);
|
2206
|
+
int index = NUM2INT(rb_funcall(keys, rb_intern("index"), 1, argv[0]));
|
2207
|
+
return rb_ary_entry(self, index);
|
2208
|
+
}
|
2209
|
+
else {
|
2210
|
+
return rb_call_super(argc, argv);
|
2211
|
+
}
|
2212
|
+
}
|
2213
|
+
|
2214
|
+
static VALUE
|
2215
|
+
pgrow_each_value(self)
|
2216
|
+
VALUE self;
|
2217
|
+
{
|
2218
|
+
rb_ary_each(self);
|
2219
|
+
return self;
|
2220
|
+
}
|
2221
|
+
|
2222
|
+
static VALUE
|
2223
|
+
pgrow_each_pair(self)
|
2224
|
+
VALUE self;
|
2225
|
+
{
|
2226
|
+
VALUE keys = pgrow_keys(self);
|
2227
|
+
int i;
|
2228
|
+
for (i = 0; i < RARRAY(keys)->len; ++i) {
|
2229
|
+
rb_yield(rb_assoc_new(rb_ary_entry(keys, i), rb_ary_entry(self, i)));
|
2230
|
+
}
|
2231
|
+
return self;
|
2232
|
+
}
|
2233
|
+
|
2234
|
+
static VALUE
|
2235
|
+
pgrow_each(self)
|
2236
|
+
VALUE self;
|
2237
|
+
{
|
2238
|
+
int arity = NUM2INT(rb_funcall(rb_block_proc(), rb_intern("arity"), 0));
|
2239
|
+
if (arity == 2) {
|
2240
|
+
pgrow_each_pair(self);
|
2241
|
+
}
|
2242
|
+
else {
|
2243
|
+
pgrow_each_value(self);
|
2244
|
+
}
|
2245
|
+
return self;
|
2246
|
+
}
|
2247
|
+
|
2248
|
+
static VALUE
|
2249
|
+
pgrow_each_key(self)
|
2250
|
+
VALUE self;
|
2251
|
+
{
|
2252
|
+
rb_ary_each(pgrow_keys(self));
|
2253
|
+
return self;
|
2254
|
+
}
|
2255
|
+
|
2256
|
+
static VALUE
|
2257
|
+
pgrow_to_hash(self)
|
2258
|
+
VALUE self;
|
2259
|
+
{
|
2260
|
+
VALUE result = rb_hash_new();
|
2261
|
+
VALUE keys = pgrow_keys(self);
|
2262
|
+
int i;
|
2263
|
+
for (i = 0; i < RARRAY(self)->len; ++i) {
|
2264
|
+
rb_hash_aset(result, rb_ary_entry(keys, i), rb_ary_entry(self, i));
|
2265
|
+
}
|
2266
|
+
return result;
|
2267
|
+
}
|
2268
|
+
|
2269
|
+
/* Large Object support */
|
2270
|
+
|
2271
|
+
/********************************************************************
|
2272
|
+
*
|
2273
|
+
* Document-class: PGconn
|
2274
|
+
*
|
2275
|
+
* The class to access PostgreSQL database.
|
2276
|
+
* All other functionality of libpq save the large object to a file.
|
2277
|
+
*
|
2278
|
+
* For example, to send query to the database on the localhost:
|
2279
|
+
* require "postgres"
|
2280
|
+
* conn = PGconn.connect("localhost", 5432, "", "", "test1")
|
2281
|
+
* res = conn.exec("select * from a;")
|
2282
|
+
*
|
2283
|
+
* See the PGresult class for information on working with the results of a query.
|
2284
|
+
*/
|
2285
|
+
|
2286
|
+
|
2287
|
+
/********************************************************************
|
2288
|
+
*
|
2289
|
+
* Document-class: PGresult
|
2290
|
+
*
|
2291
|
+
* The class to represent the query result tuples (rows).
|
2292
|
+
* An instance of this class is created as the result of every query.
|
2293
|
+
* You may need to invoke the #clear method of the instance when finished with
|
2294
|
+
* the result for better memory performance.
|
2295
|
+
*/
|
2296
|
+
|
2297
|
+
|
2298
|
+
|
2299
|
+
/********************************************************************
|
2300
|
+
*
|
2301
|
+
* Document-class: PGlarge
|
2302
|
+
*
|
2303
|
+
* The class to access large objects.
|
2304
|
+
* An instance of this class is created as the result of
|
2305
|
+
* PGconn#lo_import, PGconn#lo_create, and PGconn#lo_open.
|
2306
|
+
*/
|
2307
|
+
|
2308
|
+
void
|
2309
|
+
Init_postgres()
|
2310
|
+
{
|
2311
|
+
pg_gsub_bang_id = rb_intern("gsub!");
|
2312
|
+
pg_escape_regex = rb_reg_new("([\\t\\n\\\\])", 10, 0);
|
2313
|
+
rb_global_variable(&pg_escape_regex);
|
2314
|
+
pg_escape_str = rb_str_new("\\\\\\1", 4);
|
2315
|
+
rb_global_variable(&pg_escape_str);
|
2316
|
+
|
2317
|
+
rb_require("bigdecimal");
|
2318
|
+
rb_require("date");
|
2319
|
+
rb_require("time");
|
2320
|
+
rb_cBigDecimal = RUBY_CLASS("BigDecimal");
|
2321
|
+
rb_cDate = RUBY_CLASS("Date");
|
2322
|
+
rb_cDateTime = RUBY_CLASS("DateTime");
|
2323
|
+
|
2324
|
+
rb_ePGError = rb_define_class("PGError", rb_eStandardError);
|
2325
|
+
|
2326
|
+
rb_cPGconn = rb_define_class("PGconn", rb_cObject);
|
2327
|
+
#ifdef HAVE_RB_DEFINE_ALLOC_FUNC
|
2328
|
+
rb_define_alloc_func(rb_cPGconn, pgconn_alloc);
|
2329
|
+
#else
|
2330
|
+
rb_define_singleton_method(rb_cPGconn, "new", pgconn_s_new, -1);
|
2331
|
+
#endif
|
2332
|
+
rb_define_singleton_method(rb_cPGconn, "connect", pgconn_s_connect, -1);
|
2333
|
+
rb_define_singleton_method(rb_cPGconn, "open", pgconn_s_connect, -1);
|
2334
|
+
rb_define_singleton_method(rb_cPGconn, "setdb", pgconn_s_connect, -1);
|
2335
|
+
rb_define_singleton_method(rb_cPGconn, "setdblogin", pgconn_s_connect, -1);
|
2336
|
+
rb_define_singleton_method(rb_cPGconn, "escape", pgconn_s_escape, 1);
|
2337
|
+
rb_define_singleton_method(rb_cPGconn, "quote", pgconn_s_quote, 1);
|
2338
|
+
rb_define_singleton_method(rb_cPGconn, "escape_bytea", pgconn_s_escape_bytea, 1);
|
2339
|
+
rb_define_singleton_method(rb_cPGconn, "unescape_bytea", pgconn_s_unescape_bytea, 1);
|
2340
|
+
|
2341
|
+
rb_define_const(rb_cPGconn, "CONNECTION_OK", INT2FIX(CONNECTION_OK));
|
2342
|
+
rb_define_const(rb_cPGconn, "CONNECTION_BAD", INT2FIX(CONNECTION_BAD));
|
2343
|
+
|
2344
|
+
rb_define_method(rb_cPGconn, "initialize", pgconn_init, -1);
|
2345
|
+
rb_define_method(rb_cPGconn, "db", pgconn_db, 0);
|
2346
|
+
rb_define_method(rb_cPGconn, "host", pgconn_host, 0);
|
2347
|
+
rb_define_method(rb_cPGconn, "options", pgconn_options, 0);
|
2348
|
+
rb_define_method(rb_cPGconn, "port", pgconn_port, 0);
|
2349
|
+
rb_define_method(rb_cPGconn, "tty", pgconn_tty, 0);
|
2350
|
+
rb_define_method(rb_cPGconn, "status", pgconn_status, 0);
|
2351
|
+
rb_define_method(rb_cPGconn, "error", pgconn_error, 0);
|
2352
|
+
rb_define_method(rb_cPGconn, "close", pgconn_close, 0);
|
2353
|
+
rb_define_alias(rb_cPGconn, "finish", "close");
|
2354
|
+
rb_define_method(rb_cPGconn, "reset", pgconn_reset, 0);
|
2355
|
+
rb_define_method(rb_cPGconn, "user", pgconn_user, 0);
|
2356
|
+
rb_define_method(rb_cPGconn, "trace", pgconn_trace, 1);
|
2357
|
+
rb_define_method(rb_cPGconn, "untrace", pgconn_untrace, 0);
|
2358
|
+
rb_define_method(rb_cPGconn, "exec", pgconn_exec, -1);
|
2359
|
+
rb_define_method(rb_cPGconn, "query", pgconn_query, -1);
|
2360
|
+
rb_define_method(rb_cPGconn, "async_exec", pgconn_async_exec, 1);
|
2361
|
+
rb_define_method(rb_cPGconn, "async_query", pgconn_async_query, 1);
|
2362
|
+
rb_define_method(rb_cPGconn, "get_notify", pgconn_get_notify, 0);
|
2363
|
+
rb_define_method(rb_cPGconn, "insert_table", pgconn_insert_table, 2);
|
2364
|
+
rb_define_method(rb_cPGconn, "putline", pgconn_putline, 1);
|
2365
|
+
rb_define_method(rb_cPGconn, "getline", pgconn_getline, 0);
|
2366
|
+
rb_define_method(rb_cPGconn, "endcopy", pgconn_endcopy, 0);
|
2367
|
+
rb_define_method(rb_cPGconn, "on_notice", pgconn_on_notice, 0);
|
2368
|
+
rb_define_method(rb_cPGconn, "transaction_status", pgconn_transaction_status, 0);
|
2369
|
+
rb_define_method(rb_cPGconn, "protocol_version", pgconn_protocol_version, 0);
|
2370
|
+
rb_define_method(rb_cPGconn, "server_version", pgconn_server_version, 0);
|
2371
|
+
rb_define_method(rb_cPGconn, "lastval", pgconn_lastval, 0);
|
2372
|
+
|
2373
|
+
#ifdef HAVE_PQSETCLIENTENCODING
|
2374
|
+
rb_define_method(rb_cPGconn, "client_encoding", pgconn_client_encoding, 0);
|
2375
|
+
rb_define_method(rb_cPGconn, "set_client_encoding", pgconn_set_client_encoding, 1);
|
2376
|
+
#endif
|
2377
|
+
|
2378
|
+
/* Large Object support */
|
2379
|
+
rb_define_method(rb_cPGconn, "lo_import", pgconn_loimport, 1);
|
2380
|
+
rb_define_alias(rb_cPGconn, "loimport", "lo_import");
|
2381
|
+
rb_define_method(rb_cPGconn, "lo_create", pgconn_locreate, -1);
|
2382
|
+
rb_define_alias(rb_cPGconn, "locreate", "lo_create");
|
2383
|
+
rb_define_method(rb_cPGconn, "lo_open", pgconn_loopen, -1);
|
2384
|
+
rb_define_alias(rb_cPGconn, "loopen", "lo_open");
|
2385
|
+
rb_define_method(rb_cPGconn, "lo_export", pgconn_loexport, 2);
|
2386
|
+
rb_define_alias(rb_cPGconn, "loexport", "lo_export");
|
2387
|
+
rb_define_method(rb_cPGconn, "lo_unlink", pgconn_lounlink, 1);
|
2388
|
+
rb_define_alias(rb_cPGconn, "lounlink", "lo_unlink");
|
2389
|
+
|
2390
|
+
rb_cPGlarge = rb_define_class("PGlarge", rb_cObject);
|
2391
|
+
rb_define_method(rb_cPGlarge, "oid",pglarge_oid, 0);
|
2392
|
+
rb_define_method(rb_cPGlarge, "open",pglarge_open, -1);
|
2393
|
+
rb_define_method(rb_cPGlarge, "close",pglarge_close, 0);
|
2394
|
+
rb_define_method(rb_cPGlarge, "read",pglarge_read, -1);
|
2395
|
+
rb_define_method(rb_cPGlarge, "write",pglarge_write, 1);
|
2396
|
+
rb_define_method(rb_cPGlarge, "seek",pglarge_seek, 2);
|
2397
|
+
rb_define_method(rb_cPGlarge, "tell",pglarge_tell, 0);
|
2398
|
+
rb_define_method(rb_cPGlarge, "size",pglarge_size, 0);
|
2399
|
+
rb_define_method(rb_cPGlarge, "export",pglarge_export, 1);
|
2400
|
+
rb_define_method(rb_cPGlarge, "unlink",pglarge_unlink, 0);
|
2401
|
+
|
2402
|
+
rb_define_const(rb_cPGlarge, "INV_WRITE", INT2FIX(INV_WRITE));
|
2403
|
+
rb_define_const(rb_cPGlarge, "INV_READ", INT2FIX(INV_READ));
|
2404
|
+
rb_define_const(rb_cPGlarge, "SEEK_SET", INT2FIX(SEEK_SET));
|
2405
|
+
rb_define_const(rb_cPGlarge, "SEEK_CUR", INT2FIX(SEEK_CUR));
|
2406
|
+
rb_define_const(rb_cPGlarge, "SEEK_END", INT2FIX(SEEK_END));
|
2407
|
+
/* Large Object support */
|
2408
|
+
|
2409
|
+
rb_cPGresult = rb_define_class("PGresult", rb_cObject);
|
2410
|
+
rb_include_module(rb_cPGresult, rb_mEnumerable);
|
2411
|
+
|
2412
|
+
rb_define_const(rb_cPGresult, "EMPTY_QUERY", INT2FIX(PGRES_EMPTY_QUERY));
|
2413
|
+
rb_define_const(rb_cPGresult, "COMMAND_OK", INT2FIX(PGRES_COMMAND_OK));
|
2414
|
+
rb_define_const(rb_cPGresult, "TUPLES_OK", INT2FIX(PGRES_TUPLES_OK));
|
2415
|
+
rb_define_const(rb_cPGresult, "COPY_OUT", INT2FIX(PGRES_COPY_OUT));
|
2416
|
+
rb_define_const(rb_cPGresult, "COPY_IN", INT2FIX(PGRES_COPY_IN));
|
2417
|
+
rb_define_const(rb_cPGresult, "BAD_RESPONSE", INT2FIX(PGRES_BAD_RESPONSE));
|
2418
|
+
rb_define_const(rb_cPGresult, "NONFATAL_ERROR",INT2FIX(PGRES_NONFATAL_ERROR));
|
2419
|
+
rb_define_const(rb_cPGresult, "FATAL_ERROR", INT2FIX(PGRES_FATAL_ERROR));
|
2420
|
+
|
2421
|
+
rb_define_method(rb_cPGresult, "status", pgresult_status, 0);
|
2422
|
+
rb_define_alias(rb_cPGresult, "result", "entries");
|
2423
|
+
rb_define_alias(rb_cPGresult, "rows", "entries");
|
2424
|
+
rb_define_method(rb_cPGresult, "each", pgresult_each, 0);
|
2425
|
+
rb_define_method(rb_cPGresult, "[]", pgresult_aref, -1);
|
2426
|
+
rb_define_method(rb_cPGresult, "fields", pgresult_fields, 0);
|
2427
|
+
rb_define_method(rb_cPGresult, "num_tuples", pgresult_num_tuples, 0);
|
2428
|
+
rb_define_method(rb_cPGresult, "num_fields", pgresult_num_fields, 0);
|
2429
|
+
rb_define_method(rb_cPGresult, "fieldname", pgresult_fieldname, 1);
|
2430
|
+
rb_define_method(rb_cPGresult, "fieldnum", pgresult_fieldnum, 1);
|
2431
|
+
rb_define_method(rb_cPGresult, "type", pgresult_type, 1);
|
2432
|
+
rb_define_method(rb_cPGresult, "size", pgresult_size, 1);
|
2433
|
+
rb_define_method(rb_cPGresult, "getvalue", pgresult_getvalue, 2);
|
2434
|
+
rb_define_method(rb_cPGresult, "getvalue_byname", pgresult_getvalue_byname, 2);
|
2435
|
+
rb_define_method(rb_cPGresult, "getlength", pgresult_getlength, 2);
|
2436
|
+
rb_define_method(rb_cPGresult, "getisnull", pgresult_getisnull, 2);
|
2437
|
+
rb_define_method(rb_cPGresult, "cmdtuples", pgresult_cmdtuples, 0);
|
2438
|
+
rb_define_method(rb_cPGresult, "cmdstatus", pgresult_cmdstatus, 0);
|
2439
|
+
rb_define_method(rb_cPGresult, "oid", pgresult_oid, 0);
|
2440
|
+
rb_define_method(rb_cPGresult, "print", pgresult_print, 2);
|
2441
|
+
rb_define_method(rb_cPGresult, "clear", pgresult_clear, 0);
|
2442
|
+
rb_define_alias(rb_cPGresult, "close", "clear");
|
2443
|
+
|
2444
|
+
rb_cPGrow = rb_define_class("PGrow", rb_cArray);
|
2445
|
+
rb_define_method(rb_cPGrow, "initialize", pgrow_init, 1);
|
2446
|
+
rb_define_method(rb_cPGrow, "[]", pgrow_aref, -1);
|
2447
|
+
rb_define_method(rb_cPGrow, "keys", pgrow_keys, 0);
|
2448
|
+
rb_define_method(rb_cPGrow, "values", pgrow_values, 0);
|
2449
|
+
rb_define_method(rb_cPGrow, "each", pgrow_each, 0);
|
2450
|
+
rb_define_method(rb_cPGrow, "each_pair", pgrow_each_pair, 0);
|
2451
|
+
rb_define_method(rb_cPGrow, "each_key", pgrow_each_key, 0);
|
2452
|
+
rb_define_method(rb_cPGrow, "each_value", pgrow_each_value, 0);
|
2453
|
+
rb_define_method(rb_cPGrow, "to_hash", pgrow_to_hash, 0);
|
2454
|
+
}
|