antage-postgres 0.7.9.2009.05.12

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