pgsql 1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/LICENSE +35 -0
- data/README +47 -0
- data/lib/Rakefile +31 -0
- data/lib/conn.c +902 -0
- data/lib/conn.h +42 -0
- data/lib/conn_exec.c +869 -0
- data/lib/conn_exec.h +14 -0
- data/lib/conn_quote.c +669 -0
- data/lib/conn_quote.h +27 -0
- data/lib/mkrf_conf +38 -0
- data/lib/module.c +47 -0
- data/lib/module.h +39 -0
- data/lib/result.c +891 -0
- data/lib/result.h +32 -0
- data/lib/undef.h +11 -0
- metadata +90 -0
data/lib/conn_exec.h
ADDED
data/lib/conn_quote.c
ADDED
@@ -0,0 +1,669 @@
|
|
1
|
+
/*
|
2
|
+
* conn_quote.c -- PostgreSQL connection, string handling
|
3
|
+
*/
|
4
|
+
|
5
|
+
|
6
|
+
#include "conn_quote.h"
|
7
|
+
|
8
|
+
|
9
|
+
extern VALUE pg_currency_class( void);
|
10
|
+
|
11
|
+
static VALUE pgconn_format( VALUE self, VALUE obj);
|
12
|
+
|
13
|
+
static VALUE pgconn_escape_bytea( VALUE self, VALUE str);
|
14
|
+
#ifdef RUBY_ENCODING
|
15
|
+
static VALUE pgconn_unescape_bytea( int argc, VALUE *argv, VALUE self);
|
16
|
+
#else
|
17
|
+
static VALUE pgconn_unescape_bytea( VALUE self, VALUE obj);
|
18
|
+
#endif
|
19
|
+
|
20
|
+
extern VALUE pgconn_stringize( VALUE self, VALUE obj);
|
21
|
+
extern VALUE pgconn_stringize_line( VALUE self, VALUE ary);
|
22
|
+
extern VALUE pgconn_for_copy( VALUE self, VALUE str);
|
23
|
+
static int needs_dquote_string( VALUE str);
|
24
|
+
static VALUE dquote_string( VALUE str);
|
25
|
+
static VALUE stringize_array( VALUE self, VALUE result, VALUE ary);
|
26
|
+
static VALUE gsub_escape_i( VALUE c, VALUE arg);
|
27
|
+
|
28
|
+
static VALUE pgconn_quote( VALUE self, VALUE obj);
|
29
|
+
static VALUE pgconn_quote_all( int argc, VALUE *argv, VALUE self);
|
30
|
+
static VALUE quote_string( VALUE conn, VALUE str);
|
31
|
+
static VALUE quote_array( VALUE self, VALUE result, VALUE ary);
|
32
|
+
static void quote_all( VALUE self, VALUE ary, VALUE res);
|
33
|
+
|
34
|
+
static VALUE pgconn_quote_identifier( VALUE self, VALUE value);
|
35
|
+
|
36
|
+
|
37
|
+
|
38
|
+
VALUE rb_cDate;
|
39
|
+
VALUE rb_cDateTime;
|
40
|
+
VALUE rb_cCurrency;
|
41
|
+
|
42
|
+
static ID id_format;
|
43
|
+
static ID id_iso8601;
|
44
|
+
static ID id_raw;
|
45
|
+
static ID id_to_postgres;
|
46
|
+
static ID id_gsub;
|
47
|
+
static ID id_currency;
|
48
|
+
|
49
|
+
static VALUE pg_string_null;
|
50
|
+
static VALUE pg_string_bsl_N;
|
51
|
+
static VALUE pg_escape_regex;
|
52
|
+
|
53
|
+
|
54
|
+
|
55
|
+
VALUE
|
56
|
+
pg_currency_class( void)
|
57
|
+
{
|
58
|
+
if (NIL_P( rb_cCurrency) && id_currency) {
|
59
|
+
if (rb_const_defined( rb_cObject, id_currency))
|
60
|
+
rb_cCurrency = rb_const_get( rb_cObject, id_currency);
|
61
|
+
id_currency = 0;
|
62
|
+
}
|
63
|
+
return rb_cCurrency;
|
64
|
+
}
|
65
|
+
|
66
|
+
|
67
|
+
|
68
|
+
/*
|
69
|
+
* call-seq:
|
70
|
+
* conn.format( obj) -> obj
|
71
|
+
*
|
72
|
+
* Format an object before it will be made a PostgreSQL type.
|
73
|
+
* By default this just returns the unmodified object but you may
|
74
|
+
* overwrite it fitting you own needs.
|
75
|
+
*
|
76
|
+
* The Object won't be replaced if this method returns +nil+.
|
77
|
+
*
|
78
|
+
* == Example
|
79
|
+
*
|
80
|
+
* class MyConn < Pg::Conn
|
81
|
+
* def format obj
|
82
|
+
* case obj
|
83
|
+
* when Currency then obj.to_s_by_locale
|
84
|
+
* else obj
|
85
|
+
* end
|
86
|
+
* end
|
87
|
+
* end
|
88
|
+
*/
|
89
|
+
VALUE
|
90
|
+
pgconn_format( VALUE self, VALUE obj)
|
91
|
+
{
|
92
|
+
return obj;
|
93
|
+
}
|
94
|
+
|
95
|
+
|
96
|
+
/*
|
97
|
+
* call-seq:
|
98
|
+
* conn.escape_bytea( str) -> str
|
99
|
+
*
|
100
|
+
* Converts a string of binary data into an escaped version.
|
101
|
+
*
|
102
|
+
* == Example
|
103
|
+
*
|
104
|
+
* conn.escape_bytea "abc" # => "\\x616263"
|
105
|
+
* # (One backslash, then an 'x'.)
|
106
|
+
*
|
107
|
+
* This is what you need, when you pass your object as a Conn#exec parameter,
|
108
|
+
* as a +COPY+ input line or as a subject to +Conn#quote+-ing.
|
109
|
+
*
|
110
|
+
* If you execute an +INSERT+ statement and mention your object in the statement
|
111
|
+
* string via "#{}" you should call Conn.quote() after this.
|
112
|
+
*
|
113
|
+
* Note that the encoding does not have any influence. The bytes will be written
|
114
|
+
* as if <code>String#each_byte</code> would have been called.
|
115
|
+
*
|
116
|
+
* See the PostgreSQL documentation on PQescapeByteaConn
|
117
|
+
* [http://www.postgresql.org/docs/current/interactive/libpq-exec.html#LIBPQ-PQESCAPEBYTEACONN]
|
118
|
+
* for more information.
|
119
|
+
*/
|
120
|
+
VALUE
|
121
|
+
pgconn_escape_bytea( VALUE self, VALUE str)
|
122
|
+
{
|
123
|
+
unsigned char *s;
|
124
|
+
int l;
|
125
|
+
VALUE ret;
|
126
|
+
|
127
|
+
if (NIL_P( str))
|
128
|
+
return Qnil;
|
129
|
+
StringValue( str);
|
130
|
+
s = PQescapeByteaConn( get_pgconn( self)->conn,
|
131
|
+
(unsigned char *) RSTRING_PTR( str), RSTRING_LEN( str), &l);
|
132
|
+
ret = rb_str_new( (char *) s, l - 1);
|
133
|
+
PQfreemem( s);
|
134
|
+
OBJ_INFECT( ret, str);
|
135
|
+
return ret;
|
136
|
+
}
|
137
|
+
|
138
|
+
/*
|
139
|
+
* call-seq:
|
140
|
+
* conn.unescape_bytea( str, enc = nil) -> str
|
141
|
+
* conn.unescape_bytea( str) -> str (Ruby 1.8)
|
142
|
+
*
|
143
|
+
* Converts an escaped string into binary data.
|
144
|
+
*
|
145
|
+
* == Example
|
146
|
+
*
|
147
|
+
* Pg::Conn.unescape_bytea "\\x616263" # => "abc"
|
148
|
+
*
|
149
|
+
* You will need this because Pg::Result will not convert a return value
|
150
|
+
* automatically if the field type was a +bytea+.
|
151
|
+
*
|
152
|
+
* If +enc+ is given, the result will be associated with this encoding.
|
153
|
+
* A conversion will not be tried. Probably, if dealing with encodings
|
154
|
+
* you should store the encoding in another column next to the data.
|
155
|
+
*
|
156
|
+
* See the PostgreSQL documentation on PQunescapeBytea
|
157
|
+
* [http://www.postgresql.org/docs/current/interactive/libpq-exec.html#LIBPQ-PQUNESCAPEBYTEA]
|
158
|
+
* for more information.
|
159
|
+
*/
|
160
|
+
#ifdef RUBY_ENCODING
|
161
|
+
VALUE
|
162
|
+
pgconn_unescape_bytea( int argc, VALUE *argv, VALUE self)
|
163
|
+
#else
|
164
|
+
VALUE
|
165
|
+
pgconn_unescape_bytea( VALUE self, VALUE obj)
|
166
|
+
#endif
|
167
|
+
{
|
168
|
+
#ifdef RUBY_ENCODING
|
169
|
+
VALUE obj, enc;
|
170
|
+
#endif
|
171
|
+
unsigned char *s;
|
172
|
+
size_t l;
|
173
|
+
VALUE ret;
|
174
|
+
|
175
|
+
if (NIL_P( obj))
|
176
|
+
return Qnil;
|
177
|
+
#ifdef RUBY_ENCODING
|
178
|
+
rb_scan_args( argc, argv, "11", &obj, &enc);
|
179
|
+
#endif
|
180
|
+
StringValue( obj);
|
181
|
+
|
182
|
+
s = PQunescapeBytea( (unsigned char *) RSTRING_PTR( obj), &l);
|
183
|
+
ret = rb_str_new( (char *) s, l);
|
184
|
+
PQfreemem( s);
|
185
|
+
|
186
|
+
#ifdef RUBY_ENCODING
|
187
|
+
if (!NIL_P( enc))
|
188
|
+
rb_enc_associate( ret, rb_to_encoding( enc));
|
189
|
+
#endif
|
190
|
+
|
191
|
+
OBJ_INFECT( ret, obj);
|
192
|
+
return ret;
|
193
|
+
}
|
194
|
+
|
195
|
+
|
196
|
+
/*
|
197
|
+
* call-seq:
|
198
|
+
* conn.stringize( obj) -> str
|
199
|
+
*
|
200
|
+
* This methods makes a string out of everything. Numbers, booleans, +nil+,
|
201
|
+
* date and time values, and even arrays will be written as string the way
|
202
|
+
* PostgreSQL accepts constants. You may pass the result as a field after a
|
203
|
+
* +COPY+ statement. This will be called internally for the parameters to
|
204
|
+
* +exec+, +query+ etc.
|
205
|
+
*
|
206
|
+
* Any other objects will be checked whether they have a method named
|
207
|
+
* +to_postgres+. If that doesn't exist the object will be converted by
|
208
|
+
* +to_s+.
|
209
|
+
*
|
210
|
+
* If you are quoting into a SQL statement please don't do something like
|
211
|
+
* <code>"insert into ... (E'#{conn.stringize obj}', ...);"</code>. Use
|
212
|
+
* +Conn.quote+ instead that will put the appropriate quoting characters around
|
213
|
+
* its strings.
|
214
|
+
*
|
215
|
+
* If you like to pass a +bytea+ you have to escape the string yourself.
|
216
|
+
* This library cannot decide itself whether a String object is meant as a
|
217
|
+
* string or as a +bytea+. See the Pg::Conn#escape_bytea method.
|
218
|
+
*/
|
219
|
+
VALUE
|
220
|
+
pgconn_stringize( VALUE self, VALUE obj)
|
221
|
+
{
|
222
|
+
VALUE o, result;
|
223
|
+
|
224
|
+
o = rb_funcall( self, id_format, 1, obj);
|
225
|
+
if (!NIL_P( o))
|
226
|
+
obj = o;
|
227
|
+
switch (TYPE( obj)) {
|
228
|
+
case T_STRING:
|
229
|
+
result = obj;
|
230
|
+
break;
|
231
|
+
|
232
|
+
case T_NIL:
|
233
|
+
result = pg_string_null;
|
234
|
+
break;
|
235
|
+
|
236
|
+
case T_TRUE:
|
237
|
+
case T_FALSE:
|
238
|
+
result = rb_obj_as_string( obj);
|
239
|
+
break;
|
240
|
+
|
241
|
+
case T_BIGNUM:
|
242
|
+
case T_FLOAT:
|
243
|
+
case T_FIXNUM:
|
244
|
+
result = rb_obj_as_string( obj);
|
245
|
+
break;
|
246
|
+
|
247
|
+
case T_ARRAY:
|
248
|
+
result = rb_str_buf_new2( "{");
|
249
|
+
stringize_array( self, result, obj);
|
250
|
+
rb_str_buf_cat2( result, "}");
|
251
|
+
break;
|
252
|
+
|
253
|
+
default:
|
254
|
+
if (rb_obj_is_kind_of( obj, rb_cNumeric))
|
255
|
+
result = rb_obj_as_string( obj);
|
256
|
+
else {
|
257
|
+
VALUE co;
|
258
|
+
|
259
|
+
co = CLASS_OF( obj);
|
260
|
+
if (co == rb_cTime) {
|
261
|
+
result = rb_funcall( obj, id_iso8601, 0);
|
262
|
+
OBJ_INFECT( result, obj);
|
263
|
+
} else if (co == rb_cDate)
|
264
|
+
result = rb_obj_as_string( obj);
|
265
|
+
else if (co == rb_cDateTime)
|
266
|
+
result = rb_obj_as_string( obj);
|
267
|
+
else if (co == pg_currency_class() &&
|
268
|
+
rb_respond_to( obj, id_raw))
|
269
|
+
result = rb_funcall( obj, id_raw, 0);
|
270
|
+
else if (rb_respond_to( obj, id_to_postgres)) {
|
271
|
+
result = rb_funcall( obj, id_to_postgres, 0);
|
272
|
+
StringValue( result);
|
273
|
+
OBJ_INFECT( result, obj);
|
274
|
+
} else
|
275
|
+
result = rb_obj_as_string( obj);
|
276
|
+
}
|
277
|
+
break;
|
278
|
+
}
|
279
|
+
return result;
|
280
|
+
}
|
281
|
+
|
282
|
+
/*
|
283
|
+
* call-seq:
|
284
|
+
* conn.stringize_line( ary) -> str
|
285
|
+
*
|
286
|
+
* Quote a line the standard way that +COPY+ expects. Tabs, newlines, and
|
287
|
+
* backslashes will be escaped, +nil+ will become "\\N".
|
288
|
+
*/
|
289
|
+
VALUE
|
290
|
+
pgconn_stringize_line( VALUE self, VALUE ary)
|
291
|
+
{
|
292
|
+
VALUE a;
|
293
|
+
VALUE *p;
|
294
|
+
int l;
|
295
|
+
VALUE ret, s;
|
296
|
+
|
297
|
+
a = rb_check_convert_type( ary, T_ARRAY, "Array", "to_ary");
|
298
|
+
if (NIL_P(a))
|
299
|
+
rb_raise( rb_eArgError, "Give me an array.");
|
300
|
+
ret = rb_str_new( NULL, 0);
|
301
|
+
for (l = RARRAY_LEN( a), p = RARRAY_PTR( a); l; ++p) {
|
302
|
+
rb_str_concat( ret, pgconn_for_copy( self, *p));
|
303
|
+
rb_str_cat( ret, (--l > 0 ? "\t" : "\n"), 1);
|
304
|
+
}
|
305
|
+
return ret;
|
306
|
+
}
|
307
|
+
|
308
|
+
/*
|
309
|
+
* call-seq:
|
310
|
+
* conn.for_copy( obj) -> str
|
311
|
+
*
|
312
|
+
* Quote for +COPY+ expects. +nil+ will become "\\N".
|
313
|
+
*
|
314
|
+
* Then, tabs, newlines, and backslashes will be escaped.
|
315
|
+
*/
|
316
|
+
VALUE
|
317
|
+
pgconn_for_copy( VALUE self, VALUE obj)
|
318
|
+
{
|
319
|
+
VALUE ret;
|
320
|
+
|
321
|
+
if (NIL_P( obj))
|
322
|
+
ret = pg_string_bsl_N;
|
323
|
+
else {
|
324
|
+
ret = pgconn_stringize( self, obj);
|
325
|
+
if (NIL_P( pg_escape_regex)) {
|
326
|
+
pg_escape_regex = rb_reg_new( "([\\b\\f\\n\\r\\t\\v\\\\])", 18, 0);
|
327
|
+
rb_global_variable( &pg_escape_regex);
|
328
|
+
}
|
329
|
+
if (RTEST( rb_reg_match( pg_escape_regex, ret)))
|
330
|
+
ret = rb_block_call( ret, id_gsub, 1, &pg_escape_regex, gsub_escape_i, Qnil);
|
331
|
+
}
|
332
|
+
return ret;
|
333
|
+
}
|
334
|
+
|
335
|
+
|
336
|
+
int
|
337
|
+
needs_dquote_string( VALUE str)
|
338
|
+
{
|
339
|
+
char *p;
|
340
|
+
long l;
|
341
|
+
|
342
|
+
if (rb_str_cmp( str, pg_string_null) == 0)
|
343
|
+
return 1;
|
344
|
+
l = RSTRING_LEN( str);
|
345
|
+
if (l == 0)
|
346
|
+
return 1;
|
347
|
+
for (p = RSTRING_PTR( str); l; ++p, --l)
|
348
|
+
if (*p == ',' || *p == ' ' || *p == '\\' || *p == '"')
|
349
|
+
break;
|
350
|
+
return l > 0;
|
351
|
+
}
|
352
|
+
|
353
|
+
VALUE
|
354
|
+
dquote_string( VALUE str)
|
355
|
+
{
|
356
|
+
VALUE ret;
|
357
|
+
|
358
|
+
ret = str;
|
359
|
+
if (needs_dquote_string( str)) {
|
360
|
+
char *p, *q;
|
361
|
+
long l, m;
|
362
|
+
|
363
|
+
ret = rb_str_buf_new2( "\"");
|
364
|
+
p = RSTRING_PTR( str);
|
365
|
+
l = RSTRING_LEN( str);
|
366
|
+
while (l) {
|
367
|
+
q = p, m = l;
|
368
|
+
for (; m && (*q != '"' && *q != '\\'); --m, ++q)
|
369
|
+
;
|
370
|
+
rb_str_buf_cat( ret, p, l - m);
|
371
|
+
if (m) {
|
372
|
+
rb_str_buf_cat2( ret, "\\");
|
373
|
+
rb_str_buf_cat( ret, q, 1);
|
374
|
+
--m, ++q;
|
375
|
+
}
|
376
|
+
p = q, l = m;
|
377
|
+
}
|
378
|
+
rb_str_buf_cat2( ret, "\"");
|
379
|
+
rb_enc_associate( ret, rb_enc_get( str));
|
380
|
+
}
|
381
|
+
return ret;
|
382
|
+
}
|
383
|
+
|
384
|
+
VALUE
|
385
|
+
stringize_array( VALUE self, VALUE result, VALUE ary)
|
386
|
+
{
|
387
|
+
long i, j;
|
388
|
+
VALUE *o;
|
389
|
+
VALUE cf, co;
|
390
|
+
VALUE r;
|
391
|
+
|
392
|
+
cf = Qundef;
|
393
|
+
for (o = RARRAY_PTR( ary), j = RARRAY_LEN( ary); j; ++o, --j) {
|
394
|
+
co = CLASS_OF( *o);
|
395
|
+
if (cf == Qundef)
|
396
|
+
cf = co;
|
397
|
+
else {
|
398
|
+
if (co != cf)
|
399
|
+
rb_raise( rb_ePgError, "Array members of different type.");
|
400
|
+
rb_str_buf_cat2( result, ",");
|
401
|
+
}
|
402
|
+
r = pgconn_stringize( self, *o);
|
403
|
+
if (!NIL_P( *o)) {
|
404
|
+
r = dquote_string( r);
|
405
|
+
OBJ_INFECT( result, *o);
|
406
|
+
}
|
407
|
+
rb_str_buf_append( result, r);
|
408
|
+
}
|
409
|
+
return result;
|
410
|
+
}
|
411
|
+
|
412
|
+
|
413
|
+
VALUE
|
414
|
+
gsub_escape_i( VALUE c, VALUE arg)
|
415
|
+
{
|
416
|
+
const char *r;
|
417
|
+
|
418
|
+
r = NULL;
|
419
|
+
switch (*RSTRING_PTR( c)) {
|
420
|
+
case '\b': r = "\\b"; break;
|
421
|
+
case '\f': r = "\\f"; break;
|
422
|
+
case '\n': r = "\\n"; break;
|
423
|
+
case '\r': r = "\\r"; break;
|
424
|
+
case '\t': r = "\\t"; break;
|
425
|
+
case '\v': r = "\\v"; break;
|
426
|
+
case '\\': r = "\\\\"; break;
|
427
|
+
default: break;
|
428
|
+
}
|
429
|
+
return rb_str_new2( r);
|
430
|
+
}
|
431
|
+
|
432
|
+
|
433
|
+
|
434
|
+
|
435
|
+
/*
|
436
|
+
* call-seq: conn.quote( obj) -> str
|
437
|
+
*
|
438
|
+
* This methods makes a PostgreSQL constant out of everything. You may mention
|
439
|
+
* any result in a statement passed to Conn#exec via "#{}".
|
440
|
+
*
|
441
|
+
* If you prefer to pass your objects as a parameter to +exec+, +query+ etc. or
|
442
|
+
* as a field after a +COPY+ statement you should call conn#stringize.
|
443
|
+
*
|
444
|
+
* This method is to prevent you from saying something like <code>"insert into
|
445
|
+
* ... (E'#{conn.stringize obj}', ...);"</code>. It is more efficient to say
|
446
|
+
*
|
447
|
+
* conn.exec "insert into ... (#{conn.quote obj}, ...);"
|
448
|
+
*
|
449
|
+
* Your self-defined classes will be checked whether they have a method named
|
450
|
+
* +to_postgres+. If that doesn't exist the object will be converted by
|
451
|
+
* +to_s+.
|
452
|
+
*
|
453
|
+
* Call Pg::Conn#escape_bytea first if you want to tell your string is a byte
|
454
|
+
* array and the quote that result.
|
455
|
+
*/
|
456
|
+
VALUE pgconn_quote( VALUE self, VALUE obj) { VALUE o, res;
|
457
|
+
|
458
|
+
o = rb_funcall( self, id_format, 1, obj);
|
459
|
+
if (!NIL_P( o))
|
460
|
+
obj = o;
|
461
|
+
switch (TYPE( obj)) {
|
462
|
+
case T_STRING:
|
463
|
+
return quote_string( self, obj);
|
464
|
+
case T_NIL:
|
465
|
+
return pg_string_null;
|
466
|
+
case T_TRUE:
|
467
|
+
case T_FALSE:
|
468
|
+
case T_FIXNUM:
|
469
|
+
return rb_obj_as_string( obj);
|
470
|
+
case T_BIGNUM:
|
471
|
+
case T_FLOAT:
|
472
|
+
return rb_obj_as_string( obj);
|
473
|
+
|
474
|
+
case T_ARRAY:
|
475
|
+
res = rb_str_buf_new2( "ARRAY[");
|
476
|
+
quote_array( self, res, obj);
|
477
|
+
rb_str_buf_cat2( res, "]");
|
478
|
+
break;
|
479
|
+
|
480
|
+
default:
|
481
|
+
if (rb_obj_is_kind_of( obj, rb_cNumeric))
|
482
|
+
res = rb_obj_as_string( obj);
|
483
|
+
else {
|
484
|
+
VALUE co;
|
485
|
+
char *type;
|
486
|
+
|
487
|
+
co = CLASS_OF( obj);
|
488
|
+
if (co == rb_cTime) {
|
489
|
+
res = rb_funcall( obj, id_iso8601, 0);
|
490
|
+
type = "timestamptz";
|
491
|
+
} else if (co == rb_cDate) {
|
492
|
+
res = rb_obj_as_string( obj);
|
493
|
+
type = "date";
|
494
|
+
} else if (co == rb_cDateTime) {
|
495
|
+
res = rb_obj_as_string( obj);
|
496
|
+
type = "timestamptz";
|
497
|
+
} else if (co == pg_currency_class() &&
|
498
|
+
rb_respond_to( obj, id_raw)) {
|
499
|
+
res = rb_funcall( obj, id_raw, 0);
|
500
|
+
StringValue( res);
|
501
|
+
type = "money";
|
502
|
+
} else if (rb_respond_to( obj, id_to_postgres)) {
|
503
|
+
res = rb_funcall( obj, id_to_postgres, 0);
|
504
|
+
StringValue( res);
|
505
|
+
type = NULL;
|
506
|
+
} else {
|
507
|
+
res = rb_obj_as_string( obj);
|
508
|
+
type = "unknown";
|
509
|
+
}
|
510
|
+
res = quote_string( self, res);
|
511
|
+
if (type != NULL) {
|
512
|
+
rb_str_buf_cat2( res, "::");
|
513
|
+
rb_str_buf_cat2( res, type);
|
514
|
+
}
|
515
|
+
OBJ_INFECT( res, obj);
|
516
|
+
}
|
517
|
+
break;
|
518
|
+
}
|
519
|
+
return res;
|
520
|
+
}
|
521
|
+
|
522
|
+
/*
|
523
|
+
* call-seq:
|
524
|
+
* conn.quote_all( *args) -> str
|
525
|
+
*
|
526
|
+
* Does a #quote for every argument and pastes the results
|
527
|
+
* together with comma.
|
528
|
+
*/
|
529
|
+
VALUE
|
530
|
+
pgconn_quote_all( int argc, VALUE *argv, VALUE self)
|
531
|
+
{
|
532
|
+
VALUE res;
|
533
|
+
VALUE args;
|
534
|
+
|
535
|
+
res = rb_str_new( NULL, 0);
|
536
|
+
rb_scan_args( argc, argv, "0*", &args);
|
537
|
+
quote_all( self, args, res);
|
538
|
+
return res;
|
539
|
+
}
|
540
|
+
|
541
|
+
VALUE
|
542
|
+
quote_string( VALUE conn, VALUE str)
|
543
|
+
{
|
544
|
+
char *p;
|
545
|
+
VALUE res;
|
546
|
+
|
547
|
+
p = PQescapeLiteral( get_pgconn( conn)->conn, RSTRING_PTR( str), RSTRING_LEN( str));
|
548
|
+
res = rb_str_new2( p);
|
549
|
+
PQfreemem( p);
|
550
|
+
rb_enc_associate( res, rb_enc_get( str));
|
551
|
+
OBJ_INFECT( res, str);
|
552
|
+
return res;
|
553
|
+
}
|
554
|
+
|
555
|
+
VALUE
|
556
|
+
quote_array( VALUE self, VALUE result, VALUE ary)
|
557
|
+
{
|
558
|
+
long i, j;
|
559
|
+
VALUE *o;
|
560
|
+
VALUE cf, co;
|
561
|
+
|
562
|
+
cf = Qundef;
|
563
|
+
for (o = RARRAY_PTR( ary), j = RARRAY_LEN( ary); j; ++o, --j) {
|
564
|
+
co = CLASS_OF( *o);
|
565
|
+
if (cf == Qundef)
|
566
|
+
cf = co;
|
567
|
+
else {
|
568
|
+
if (co != cf)
|
569
|
+
rb_raise( rb_ePgError, "Array members of different type.");
|
570
|
+
rb_str_buf_cat2( result, ",");
|
571
|
+
}
|
572
|
+
rb_str_buf_append( result, pgconn_quote( self, *o));
|
573
|
+
}
|
574
|
+
return result;
|
575
|
+
}
|
576
|
+
|
577
|
+
void
|
578
|
+
quote_all( VALUE self, VALUE ary, VALUE res)
|
579
|
+
{
|
580
|
+
VALUE *p;
|
581
|
+
long len;
|
582
|
+
|
583
|
+
for (p = RARRAY_PTR( ary), len = RARRAY_LEN( ary); len; len--, p++) {
|
584
|
+
if (TYPE( *p) == T_ARRAY)
|
585
|
+
quote_all( self, *p, res);
|
586
|
+
else {
|
587
|
+
if (RSTRING_LEN( res) > 0)
|
588
|
+
rb_str_buf_cat2( res, ",");
|
589
|
+
rb_str_buf_append( res, pgconn_quote( self, *p));
|
590
|
+
}
|
591
|
+
}
|
592
|
+
}
|
593
|
+
|
594
|
+
|
595
|
+
|
596
|
+
/*
|
597
|
+
* call-seq:
|
598
|
+
* conn.quote_identifier() -> str
|
599
|
+
*
|
600
|
+
* Put double quotes around an identifier containing non-letters
|
601
|
+
* or upper case.
|
602
|
+
*/
|
603
|
+
VALUE
|
604
|
+
pgconn_quote_identifier( VALUE self, VALUE str)
|
605
|
+
{
|
606
|
+
char *p;
|
607
|
+
VALUE res;
|
608
|
+
|
609
|
+
if (NIL_P( str))
|
610
|
+
return Qnil;
|
611
|
+
StringValue( str);
|
612
|
+
p = PQescapeIdentifier( get_pgconn( self)->conn, RSTRING_PTR( str), RSTRING_LEN( str));
|
613
|
+
res = rb_str_new2( p);
|
614
|
+
PQfreemem( p);
|
615
|
+
rb_enc_associate( res, rb_enc_get( str));
|
616
|
+
OBJ_INFECT( res, str);
|
617
|
+
return res;
|
618
|
+
}
|
619
|
+
|
620
|
+
|
621
|
+
|
622
|
+
void
|
623
|
+
Init_pgsql_conn_quote( void)
|
624
|
+
{
|
625
|
+
rb_require( "date");
|
626
|
+
rb_require( "time");
|
627
|
+
rb_cDate = rb_const_get( rb_cObject, rb_intern( "Date"));
|
628
|
+
rb_cDateTime = rb_const_get( rb_cObject, rb_intern( "DateTime"));
|
629
|
+
rb_cCurrency = Qnil;
|
630
|
+
|
631
|
+
#ifdef RDOC_NEEDS_THIS
|
632
|
+
rb_cPgConn = rb_define_class_under( rb_mPg, "Conn", rb_cObject);
|
633
|
+
#endif
|
634
|
+
|
635
|
+
rb_define_method( rb_cPgConn, "format", &pgconn_format, 1);
|
636
|
+
|
637
|
+
rb_define_method( rb_cPgConn, "escape_bytea", &pgconn_escape_bytea, 1);
|
638
|
+
#ifdef RUBY_ENCODING
|
639
|
+
rb_define_method( rb_cPgConn, "unescape_bytea", &pgconn_unescape_bytea, -1);
|
640
|
+
rb_define_singleton_method( rb_cPgConn, "unescape_bytea", &pgconn_unescape_bytea, -1);
|
641
|
+
#else
|
642
|
+
rb_define_method( rb_cPgConn, "unescape_bytea", &pgconn_unescape_bytea, 1);
|
643
|
+
rb_define_singleton_method( rb_cPgConn, "unescape_bytea", &pgconn_unescape_bytea, 1);
|
644
|
+
#endif
|
645
|
+
|
646
|
+
rb_define_method( rb_cPgConn, "stringize", &pgconn_stringize, 1);
|
647
|
+
rb_define_method( rb_cPgConn, "stringize_line", &pgconn_stringize_line, 1);
|
648
|
+
rb_define_method( rb_cPgConn, "for_copy", &pgconn_for_copy, 1);
|
649
|
+
|
650
|
+
rb_define_method( rb_cPgConn, "quote", &pgconn_quote, 1);
|
651
|
+
rb_define_method( rb_cPgConn, "quote_all", &pgconn_quote_all, -1);
|
652
|
+
rb_define_alias( rb_cPgConn, "q", "quote_all");
|
653
|
+
|
654
|
+
rb_define_method( rb_cPgConn, "quote_identifier", &pgconn_quote_identifier, 1);
|
655
|
+
rb_define_alias( rb_cPgConn, "quote_ident", "quote_identifier");
|
656
|
+
|
657
|
+
id_format = rb_intern( "format");
|
658
|
+
id_iso8601 = rb_intern( "iso8601");
|
659
|
+
id_raw = rb_intern( "raw");
|
660
|
+
id_to_postgres = rb_intern( "to_postgres");
|
661
|
+
id_gsub = rb_intern( "gsub");
|
662
|
+
|
663
|
+
id_currency = rb_intern( "Currency");
|
664
|
+
|
665
|
+
pg_string_null = rb_str_new2( "NULL"); rb_global_variable( &pg_string_null); rb_str_freeze( pg_string_null);
|
666
|
+
pg_string_bsl_N = rb_str_new2( "\\N"); rb_global_variable( &pg_string_bsl_N); rb_str_freeze( pg_string_bsl_N);
|
667
|
+
pg_escape_regex = Qnil;
|
668
|
+
}
|
669
|
+
|