postgres 0.7.1 → 0.7.9.2007.12.12
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/COPYING +340 -0
- data/COPYING.txt +340 -0
- data/Contributors +28 -0
- data/GPL +340 -0
- data/LICENSE +58 -0
- data/README +31 -31
- data/compat-ruby-postgres/extconf.rb +34 -0
- data/compat-ruby-postgres/postgres.c +2811 -0
- data/compat-ruby-postgres/type-oids.h +65 -0
- data/ext/compat.c +461 -0
- data/ext/compat.h +106 -0
- data/ext/extconf.rb +48 -0
- data/ext/pg.c +2730 -0
- data/ext/pg.h +14 -0
- metadata +43 -35
- data/ChangeLog +0 -230
- data/MANIFEST +0 -14
- data/README.ja +0 -183
- data/doc/postgres.html +0 -257
- data/doc/postgres.jp.html +0 -239
- data/extconf.rb +0 -47
- data/postgres-ruby.gemspec +0 -22
- data/postgres.c +0 -1513
- data/sample/losample.rb +0 -47
- data/sample/psql.rb +0 -1181
- data/sample/psqlHelp.rb +0 -158
- data/sample/test1.rb +0 -63
- data/sample/test2.rb +0 -44
- data/sample/test4.rb +0 -71
@@ -0,0 +1,65 @@
|
|
1
|
+
#define BOOLOID 16
|
2
|
+
#define BYTEAOID 17
|
3
|
+
#define CHAROID 18
|
4
|
+
#define NAMEOID 19
|
5
|
+
#define INT8OID 20
|
6
|
+
#define INT2OID 21
|
7
|
+
#define INT2VECTOROID 22
|
8
|
+
#define INT4OID 23
|
9
|
+
#define REGPROCOID 24
|
10
|
+
#define TEXTOID 25
|
11
|
+
#define OIDOID 26
|
12
|
+
#define TIDOID 27
|
13
|
+
#define XIDOID 28
|
14
|
+
#define CIDOID 29
|
15
|
+
#define OIDVECTOROID 30
|
16
|
+
#define PG_TYPE_RELTYPE_OID 71
|
17
|
+
#define PG_ATTRIBUTE_RELTYPE_OID 75
|
18
|
+
#define PG_PROC_RELTYPE_OID 81
|
19
|
+
#define PG_CLASS_RELTYPE_OID 83
|
20
|
+
#define POINTOID 600
|
21
|
+
#define LSEGOID 601
|
22
|
+
#define PATHOID 602
|
23
|
+
#define BOXOID 603
|
24
|
+
#define POLYGONOID 604
|
25
|
+
#define LINEOID 628
|
26
|
+
#define FLOAT4OID 700
|
27
|
+
#define FLOAT8OID 701
|
28
|
+
#define ABSTIMEOID 702
|
29
|
+
#define RELTIMEOID 703
|
30
|
+
#define TINTERVALOID 704
|
31
|
+
#define UNKNOWNOID 705
|
32
|
+
#define CIRCLEOID 718
|
33
|
+
#define CASHOID 790
|
34
|
+
#define MACADDROID 829
|
35
|
+
#define INETOID 869
|
36
|
+
#define CIDROID 650
|
37
|
+
#define INT4ARRAYOID 1007
|
38
|
+
#define ACLITEMOID 1033
|
39
|
+
#define BPCHAROID 1042
|
40
|
+
#define VARCHAROID 1043
|
41
|
+
#define DATEOID 1082
|
42
|
+
#define TIMEOID 1083
|
43
|
+
#define TIMESTAMPOID 1114
|
44
|
+
#define TIMESTAMPTZOID 1184
|
45
|
+
#define INTERVALOID 1186
|
46
|
+
#define TIMETZOID 1266
|
47
|
+
#define BITOID 1560
|
48
|
+
#define VARBITOID 1562
|
49
|
+
#define NUMERICOID 1700
|
50
|
+
#define REFCURSOROID 1790
|
51
|
+
#define REGPROCEDUREOID 2202
|
52
|
+
#define REGOPEROID 2203
|
53
|
+
#define REGOPERATOROID 2204
|
54
|
+
#define REGCLASSOID 2205
|
55
|
+
#define REGTYPEOID 2206
|
56
|
+
#define RECORDOID 2249
|
57
|
+
#define CSTRINGOID 2275
|
58
|
+
#define ANYOID 2276
|
59
|
+
#define ANYARRAYOID 2277
|
60
|
+
#define VOIDOID 2278
|
61
|
+
#define TRIGGEROID 2279
|
62
|
+
#define LANGUAGE_HANDLEROID 2280
|
63
|
+
#define INTERNALOID 2281
|
64
|
+
#define OPAQUEOID 2282
|
65
|
+
#define ANYELEMENTOID 2283
|
data/ext/compat.c
ADDED
@@ -0,0 +1,461 @@
|
|
1
|
+
/************************************************
|
2
|
+
|
3
|
+
compat.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-04 14:25:44 -0800 (Tue, 04 Dec 2007) $
|
13
|
+
************************************************/
|
14
|
+
|
15
|
+
#include "compat.h"
|
16
|
+
|
17
|
+
|
18
|
+
#ifndef HAVE_PQESCAPESTRINGCONN
|
19
|
+
size_t
|
20
|
+
PQescapeStringConn(PGconn *conn, char *to, const char *from,
|
21
|
+
size_t length, int *error)
|
22
|
+
{
|
23
|
+
return PQescapeString(to,from,length);
|
24
|
+
}
|
25
|
+
|
26
|
+
unsigned char *
|
27
|
+
PQescapeByteaConn(PGconn *conn, const unsigned char *from,
|
28
|
+
size_t from_length, size_t *to_length)
|
29
|
+
{
|
30
|
+
return PQescapeBytea(from, from_length, to_length);
|
31
|
+
}
|
32
|
+
#endif /* HAVE_PQESCAPESTRINGCONN */
|
33
|
+
|
34
|
+
#ifndef HAVE_PQPREPARE
|
35
|
+
PGresult *
|
36
|
+
PQprepare(PGconn *conn, const char *stmtName, const char *query,
|
37
|
+
int nParams, const Oid *paramTypes)
|
38
|
+
{
|
39
|
+
rb_raise(rb_eStandardError, "PQprepare not supported by this client version.");
|
40
|
+
}
|
41
|
+
#endif /* HAVE_PQPREPARE */
|
42
|
+
|
43
|
+
#ifndef HAVE_PQCONNECTIONUSEDPASSWORD
|
44
|
+
int
|
45
|
+
PQconnectionUsedPassword(PGconn *conn)
|
46
|
+
{
|
47
|
+
rb_raise(rb_eStandardError,
|
48
|
+
"PQconnectionUsedPassword not supported by this client version.");
|
49
|
+
}
|
50
|
+
#endif /* HAVE_PQCONNECTIONUSEDPASSWORD */
|
51
|
+
|
52
|
+
#ifndef HAVE_PQISTHREADSAFE
|
53
|
+
int
|
54
|
+
PQisthreadsafe()
|
55
|
+
{
|
56
|
+
return Qfalse;
|
57
|
+
}
|
58
|
+
#endif /* HAVE_PQISTHREADSAFE */
|
59
|
+
|
60
|
+
#ifndef HAVE_LO_TRUNCATE
|
61
|
+
int
|
62
|
+
lo_truncate(PGconn *conn, int fd, size_t len)
|
63
|
+
{
|
64
|
+
rb_raise(rb_eStandardError, "lo_truncate not supported by this client version.");
|
65
|
+
}
|
66
|
+
#endif /* HAVE_LO_TRUNCATE */
|
67
|
+
|
68
|
+
#ifndef HAVE_LO_CREATE
|
69
|
+
Oid
|
70
|
+
lo_create(PGconn *conn, Oid lobjId)
|
71
|
+
{
|
72
|
+
rb_raise(rb_eStandardError, "lo_create not supported by this client version.");
|
73
|
+
}
|
74
|
+
#endif /* HAVE_LO_CREATE */
|
75
|
+
|
76
|
+
#ifndef HAVE_PQNPARAMS
|
77
|
+
int
|
78
|
+
PQnparams(const PGresult *res)
|
79
|
+
{
|
80
|
+
rb_raise(rb_eStandardError, "PQnparams not supported by this client version.");
|
81
|
+
}
|
82
|
+
#endif /* HAVE_PQNPARAMS */
|
83
|
+
|
84
|
+
#ifndef HAVE_PQPARAMTYPE
|
85
|
+
Oid
|
86
|
+
PQparamtype(const PGresult *res, int param_number)
|
87
|
+
{
|
88
|
+
rb_raise(rb_eStandardError, "PQparamtype not supported by this client version.");
|
89
|
+
}
|
90
|
+
#endif /* HAVE_PQPARAMTYPE */
|
91
|
+
|
92
|
+
#ifndef HAVE_PQSERVERVERSION
|
93
|
+
int
|
94
|
+
PQserverVersion(const PGconn* conn)
|
95
|
+
{
|
96
|
+
rb_raise(rb_eStandardError, "PQserverVersion not supported by this client version.");
|
97
|
+
}
|
98
|
+
#endif /* HAVE_PQSERVERVERSION */
|
99
|
+
|
100
|
+
#ifndef HAVE_PQSENDDESCRIBEPREPARED
|
101
|
+
int
|
102
|
+
PQsendDescribePrepared(PGconn *conn, const char *stmtName)
|
103
|
+
{
|
104
|
+
rb_raise(rb_eStandardError, "PQsendDescribePrepared not supported by this client version.");
|
105
|
+
}
|
106
|
+
#endif /* HAVE_PQSENDDESCRIBEPREPARED */
|
107
|
+
|
108
|
+
#ifndef HAVE_PQSENDDESCRIBEPORTAL
|
109
|
+
int
|
110
|
+
PQsendDescribePortal(PGconn *conn, const char *portalName)
|
111
|
+
{
|
112
|
+
rb_raise(rb_eStandardError, "PQsendDescribePortal not supported by this client version.");
|
113
|
+
}
|
114
|
+
#endif /* HAVE_PQSENDDESCRIBEPORTAL */
|
115
|
+
|
116
|
+
#ifndef HAVE_PQENCRYPTPASSWORD
|
117
|
+
char *
|
118
|
+
PQencryptPassword(const char *passwd, const char *user)
|
119
|
+
{
|
120
|
+
rb_raise(rb_eStandardError, "PQencryptPassword not supported by this client version.");
|
121
|
+
}
|
122
|
+
#endif /* HAVE_PQENCRYPTPASSWORD */
|
123
|
+
|
124
|
+
#ifndef HAVE_PQEXECPARAMS
|
125
|
+
PGresult *
|
126
|
+
PQexecParams(PGconn *conn, const char *command, int nParams,
|
127
|
+
const Oid *paramTypes, const char * const * paramValues, const int *paramLengths,
|
128
|
+
const int *paramFormats, int resultFormat)
|
129
|
+
{
|
130
|
+
rb_raise(rb_eStandardError, "PQexecParams not supported by this client version.");
|
131
|
+
}
|
132
|
+
|
133
|
+
#define BIND_PARAM_PATTERN "\\$(\\d+)"
|
134
|
+
#include <ruby.h>
|
135
|
+
#include <re.h>
|
136
|
+
PGresult *
|
137
|
+
PQexecParams_compat(PGconn *conn, VALUE command, VALUE values)
|
138
|
+
{
|
139
|
+
VALUE bind_param_re = rb_reg_new(BIND_PARAM_PATTERN, 7, 0);
|
140
|
+
VALUE result = rb_str_buf_new(RSTRING(command)->len);
|
141
|
+
char* ptr = RSTRING(command)->ptr;
|
142
|
+
int scan = 0;
|
143
|
+
while ((scan = rb_reg_search(bind_param_re, command, scan, 0)) > 0) {
|
144
|
+
VALUE match = rb_backref_get();
|
145
|
+
int pos = BindParamNumber(match);
|
146
|
+
if (pos < RARRAY(values)->len) {
|
147
|
+
rb_str_buf_cat(result, ptr, scan - (ptr - RSTRING(command)->ptr));
|
148
|
+
ptr = RSTRING(command)->ptr + scan;
|
149
|
+
rb_str_buf_append(result, RARRAY(values)->ptr[pos]);
|
150
|
+
}
|
151
|
+
scan += RSTRING(rb_reg_nth_match(0, match))->len;
|
152
|
+
ptr += RSTRING(rb_reg_nth_match(0, match))->len;
|
153
|
+
}
|
154
|
+
rb_str_buf_cat(result, ptr, RSTRING(command)->len - (ptr - RSTRING(command)->ptr));
|
155
|
+
|
156
|
+
return PQexec(conn, StringValuePtr(result));
|
157
|
+
}
|
158
|
+
#endif /* HAVE_PQEXECPARAMS */
|
159
|
+
|
160
|
+
|
161
|
+
/**************************************************************************
|
162
|
+
|
163
|
+
IF ANY CODE IS COPIED FROM POSTGRESQL, PLACE IT AFTER THIS COMMENT.
|
164
|
+
THE BSD LICENSE REQUIRES THAT YOU MAINTAIN THIS COPYRIGHT NOTICE.
|
165
|
+
|
166
|
+
***************************************************************************
|
167
|
+
|
168
|
+
Portions of code after this point were copied from the PostgreSQL source
|
169
|
+
distribution, available at http://www.postgresql.org
|
170
|
+
|
171
|
+
***************************************************************************
|
172
|
+
|
173
|
+
Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
174
|
+
|
175
|
+
Portions Copyright (c) 1994, The Regents of the University of California
|
176
|
+
|
177
|
+
Permission to use, copy, modify, and distribute this software and its
|
178
|
+
documentation for any purpose, without fee, and without a written agreement
|
179
|
+
is hereby granted, provided that the above copyright notice and this
|
180
|
+
paragraph and the following two paragraphs appear in all copies.
|
181
|
+
|
182
|
+
IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
|
183
|
+
DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING
|
184
|
+
LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
|
185
|
+
DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE
|
186
|
+
POSSIBILITY OF SUCH DAMAGE.
|
187
|
+
|
188
|
+
THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
|
189
|
+
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
190
|
+
AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
191
|
+
ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS TO
|
192
|
+
PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
193
|
+
|
194
|
+
**************************************************************************/
|
195
|
+
|
196
|
+
#ifndef HAVE_PQSETCLIENTENCODING
|
197
|
+
|
198
|
+
int
|
199
|
+
PQsetClientEncoding(PGconn *conn, const char *encoding)
|
200
|
+
{
|
201
|
+
char qbuf[128];
|
202
|
+
static const char query[] = "set client_encoding to '%s'";
|
203
|
+
PGresult *res;
|
204
|
+
int status;
|
205
|
+
|
206
|
+
if (!conn || conn->status != CONNECTION_OK)
|
207
|
+
return -1;
|
208
|
+
|
209
|
+
if (!encoding)
|
210
|
+
return -1;
|
211
|
+
|
212
|
+
/* check query buffer overflow */
|
213
|
+
if (sizeof(qbuf) < (sizeof(query) + strlen(encoding)))
|
214
|
+
return -1;
|
215
|
+
|
216
|
+
/* ok, now send a query */
|
217
|
+
sprintf(qbuf, query, encoding);
|
218
|
+
res = PQexec(conn, qbuf);
|
219
|
+
|
220
|
+
if (res == NULL)
|
221
|
+
return -1;
|
222
|
+
if (res->resultStatus != PGRES_COMMAND_OK)
|
223
|
+
status = -1;
|
224
|
+
else
|
225
|
+
{
|
226
|
+
/*
|
227
|
+
* In protocol 2 we have to assume the setting will stick, and adjust
|
228
|
+
* our state immediately. In protocol 3 and up we can rely on the
|
229
|
+
* backend to report the parameter value, and we'll change state at
|
230
|
+
* that time.
|
231
|
+
*/
|
232
|
+
if (PG_PROTOCOL_MAJOR(conn->pversion) < 3)
|
233
|
+
pqSaveParameterStatus(conn, "client_encoding", encoding);
|
234
|
+
status = 0; /* everything is ok */
|
235
|
+
}
|
236
|
+
PQclear(res);
|
237
|
+
return status;
|
238
|
+
}
|
239
|
+
#endif /* HAVE_PQSETCLIENTENCODING */
|
240
|
+
|
241
|
+
#ifndef HAVE_PQESCAPESTRING
|
242
|
+
/*
|
243
|
+
* Escaping arbitrary strings to get valid SQL literal strings.
|
244
|
+
*
|
245
|
+
* Replaces "\\" with "\\\\" and "'" with "''".
|
246
|
+
*
|
247
|
+
* length is the length of the source string. (Note: if a terminating NUL
|
248
|
+
* is encountered sooner, PQescapeString stops short of "length"; the behavior
|
249
|
+
* is thus rather like strncpy.)
|
250
|
+
*
|
251
|
+
* For safety the buffer at "to" must be at least 2*length + 1 bytes long.
|
252
|
+
* A terminating NUL character is added to the output string, whether the
|
253
|
+
* input is NUL-terminated or not.
|
254
|
+
*
|
255
|
+
* Returns the actual length of the output (not counting the terminating NUL).
|
256
|
+
*/
|
257
|
+
size_t
|
258
|
+
PQescapeString(char *to, const char *from, size_t length)
|
259
|
+
{
|
260
|
+
const char *source = from;
|
261
|
+
char *target = to;
|
262
|
+
size_t remaining = length;
|
263
|
+
|
264
|
+
while (remaining > 0 && *source != '\0')
|
265
|
+
{
|
266
|
+
switch (*source)
|
267
|
+
{
|
268
|
+
case '\\':
|
269
|
+
*target++ = '\\';
|
270
|
+
*target++ = '\\';
|
271
|
+
break;
|
272
|
+
|
273
|
+
case '\'':
|
274
|
+
*target++ = '\'';
|
275
|
+
*target++ = '\'';
|
276
|
+
break;
|
277
|
+
|
278
|
+
default:
|
279
|
+
*target++ = *source;
|
280
|
+
break;
|
281
|
+
}
|
282
|
+
source++;
|
283
|
+
remaining--;
|
284
|
+
}
|
285
|
+
|
286
|
+
/* Write the terminating NUL character. */
|
287
|
+
*target = '\0';
|
288
|
+
|
289
|
+
return target - to;
|
290
|
+
}
|
291
|
+
|
292
|
+
/*
|
293
|
+
* PQescapeBytea - converts from binary string to the
|
294
|
+
* minimal encoding necessary to include the string in an SQL
|
295
|
+
* INSERT statement with a bytea type column as the target.
|
296
|
+
*
|
297
|
+
* The following transformations are applied
|
298
|
+
* '\0' == ASCII 0 == \\000
|
299
|
+
* '\'' == ASCII 39 == \'
|
300
|
+
* '\\' == ASCII 92 == \\\\
|
301
|
+
* anything < 0x20, or > 0x7e ---> \\ooo
|
302
|
+
* (where ooo is an octal expression)
|
303
|
+
*/
|
304
|
+
unsigned char *
|
305
|
+
PQescapeBytea(const unsigned char *bintext, size_t binlen, size_t *bytealen)
|
306
|
+
{
|
307
|
+
const unsigned char *vp;
|
308
|
+
unsigned char *rp;
|
309
|
+
unsigned char *result;
|
310
|
+
size_t i;
|
311
|
+
size_t len;
|
312
|
+
|
313
|
+
/*
|
314
|
+
* empty string has 1 char ('\0')
|
315
|
+
*/
|
316
|
+
len = 1;
|
317
|
+
|
318
|
+
vp = bintext;
|
319
|
+
for (i = binlen; i > 0; i--, vp++)
|
320
|
+
{
|
321
|
+
if (*vp < 0x20 || *vp > 0x7e)
|
322
|
+
len += 5; /* '5' is for '\\ooo' */
|
323
|
+
else if (*vp == '\'')
|
324
|
+
len += 2;
|
325
|
+
else if (*vp == '\\')
|
326
|
+
len += 4;
|
327
|
+
else
|
328
|
+
len++;
|
329
|
+
}
|
330
|
+
|
331
|
+
rp = result = (unsigned char *) malloc(len);
|
332
|
+
if (rp == NULL)
|
333
|
+
return NULL;
|
334
|
+
|
335
|
+
vp = bintext;
|
336
|
+
*bytealen = len;
|
337
|
+
|
338
|
+
for (i = binlen; i > 0; i--, vp++)
|
339
|
+
{
|
340
|
+
if (*vp < 0x20 || *vp > 0x7e)
|
341
|
+
{
|
342
|
+
(void) sprintf(rp, "\\\\%03o", *vp);
|
343
|
+
rp += 5;
|
344
|
+
}
|
345
|
+
else if (*vp == '\'')
|
346
|
+
{
|
347
|
+
rp[0] = '\\';
|
348
|
+
rp[1] = '\'';
|
349
|
+
rp += 2;
|
350
|
+
}
|
351
|
+
else if (*vp == '\\')
|
352
|
+
{
|
353
|
+
rp[0] = '\\';
|
354
|
+
rp[1] = '\\';
|
355
|
+
rp[2] = '\\';
|
356
|
+
rp[3] = '\\';
|
357
|
+
rp += 4;
|
358
|
+
}
|
359
|
+
else
|
360
|
+
*rp++ = *vp;
|
361
|
+
}
|
362
|
+
*rp = '\0';
|
363
|
+
|
364
|
+
return result;
|
365
|
+
}
|
366
|
+
|
367
|
+
#define ISFIRSTOCTDIGIT(CH) ((CH) >= '0' && (CH) <= '3')
|
368
|
+
#define ISOCTDIGIT(CH) ((CH) >= '0' && (CH) <= '7')
|
369
|
+
#define OCTVAL(CH) ((CH) - '0')
|
370
|
+
|
371
|
+
/*
|
372
|
+
* PQunescapeBytea - converts the null terminated string representation
|
373
|
+
* of a bytea, strtext, into binary, filling a buffer. It returns a
|
374
|
+
* pointer to the buffer (or NULL on error), and the size of the
|
375
|
+
* buffer in retbuflen. The pointer may subsequently be used as an
|
376
|
+
* argument to the function free(3). It is the reverse of PQescapeBytea.
|
377
|
+
*
|
378
|
+
* The following transformations are made:
|
379
|
+
* \\ == ASCII 92 == \
|
380
|
+
* \ooo == a byte whose value = ooo (ooo is an octal number)
|
381
|
+
* \x == x (x is any character not matched by the above transformations)
|
382
|
+
*/
|
383
|
+
unsigned char *
|
384
|
+
PQunescapeBytea(const unsigned char *strtext, size_t *retbuflen)
|
385
|
+
{
|
386
|
+
size_t strtextlen,
|
387
|
+
buflen;
|
388
|
+
unsigned char *buffer,
|
389
|
+
*tmpbuf;
|
390
|
+
size_t i,
|
391
|
+
j;
|
392
|
+
|
393
|
+
if (strtext == NULL)
|
394
|
+
return NULL;
|
395
|
+
|
396
|
+
strtextlen = strlen(strtext);
|
397
|
+
|
398
|
+
/*
|
399
|
+
* Length of input is max length of output, but add one to avoid
|
400
|
+
* unportable malloc(0) if input is zero-length.
|
401
|
+
*/
|
402
|
+
buffer = (unsigned char *) malloc(strtextlen + 1);
|
403
|
+
if (buffer == NULL)
|
404
|
+
return NULL;
|
405
|
+
|
406
|
+
for (i = j = 0; i < strtextlen;)
|
407
|
+
{
|
408
|
+
switch (strtext[i])
|
409
|
+
{
|
410
|
+
case '\\':
|
411
|
+
i++;
|
412
|
+
if (strtext[i] == '\\')
|
413
|
+
buffer[j++] = strtext[i++];
|
414
|
+
else
|
415
|
+
{
|
416
|
+
if ((ISFIRSTOCTDIGIT(strtext[i])) &&
|
417
|
+
(ISOCTDIGIT(strtext[i + 1])) &&
|
418
|
+
(ISOCTDIGIT(strtext[i + 2])))
|
419
|
+
{
|
420
|
+
int byte;
|
421
|
+
|
422
|
+
byte = OCTVAL(strtext[i++]);
|
423
|
+
byte = (byte << 3) + OCTVAL(strtext[i++]);
|
424
|
+
byte = (byte << 3) + OCTVAL(strtext[i++]);
|
425
|
+
buffer[j++] = byte;
|
426
|
+
}
|
427
|
+
}
|
428
|
+
|
429
|
+
/*
|
430
|
+
* Note: if we see '\' followed by something that isn't a
|
431
|
+
* recognized escape sequence, we loop around having done
|
432
|
+
* nothing except advance i. Therefore the something will
|
433
|
+
* be emitted as ordinary data on the next cycle. Corner
|
434
|
+
* case: '\' at end of string will just be discarded.
|
435
|
+
*/
|
436
|
+
break;
|
437
|
+
|
438
|
+
default:
|
439
|
+
buffer[j++] = strtext[i++];
|
440
|
+
break;
|
441
|
+
}
|
442
|
+
}
|
443
|
+
buflen = j; /* buflen is the length of the dequoted
|
444
|
+
* data */
|
445
|
+
|
446
|
+
/* Shrink the buffer to be no larger than necessary */
|
447
|
+
/* +1 avoids unportable behavior when buflen==0 */
|
448
|
+
tmpbuf = realloc(buffer, buflen + 1);
|
449
|
+
|
450
|
+
/* It would only be a very brain-dead realloc that could fail, but... */
|
451
|
+
if (!tmpbuf)
|
452
|
+
{
|
453
|
+
free(buffer);
|
454
|
+
return NULL;
|
455
|
+
}
|
456
|
+
|
457
|
+
*retbuflen = buflen;
|
458
|
+
return tmpbuf;
|
459
|
+
}
|
460
|
+
#endif
|
461
|
+
|
data/ext/compat.h
ADDED
@@ -0,0 +1,106 @@
|
|
1
|
+
|
2
|
+
#ifndef __compat_h
|
3
|
+
#define __compat_h
|
4
|
+
|
5
|
+
#include <stdlib.h>
|
6
|
+
|
7
|
+
#include "ruby.h"
|
8
|
+
#include "rubyio.h"
|
9
|
+
#include "st.h"
|
10
|
+
#include "libpq-fe.h"
|
11
|
+
#include "libpq/libpq-fs.h" /* large-object interface */
|
12
|
+
|
13
|
+
#if RUBY_VERSION_CODE < 180
|
14
|
+
#define rb_check_string_type(x) rb_check_convert_type(x, T_STRING, "String", "to_str")
|
15
|
+
#endif /* RUBY_VERSION_CODE < 180 */
|
16
|
+
|
17
|
+
#ifndef StringValuePtr
|
18
|
+
#define StringValuePtr(x) STR2CSTR(x)
|
19
|
+
#endif /* StringValuePtr */
|
20
|
+
|
21
|
+
#ifndef HAVE_PG_ENCODING_TO_CHAR
|
22
|
+
#define pg_encoding_to_char(x) "SQL_ASCII"
|
23
|
+
#endif /* HAVE_PG_ENCODING_TO_CHAR */
|
24
|
+
|
25
|
+
#ifndef PG_DIAG_INTERNAL_POSITION
|
26
|
+
#define PG_DIAG_INTERNAL_POSITION 'p'
|
27
|
+
#endif /* PG_DIAG_INTERNAL_POSITION */
|
28
|
+
|
29
|
+
#ifndef PG_DIAG_INTERNAL_QUERY
|
30
|
+
#define PG_DIAG_INTERNAL_QUERY 'q'
|
31
|
+
#endif /* PG_DIAG_INTERNAL_QUERY */
|
32
|
+
|
33
|
+
#ifndef HAVE_PQFREEMEM
|
34
|
+
#define PQfreemem(ptr) free(ptr)
|
35
|
+
#endif /* HAVE_PQFREEMEM */
|
36
|
+
|
37
|
+
#ifndef HAVE_PQSETCLIENTENCODING
|
38
|
+
int PQsetClientEncoding(PGconn *conn, const char *encoding)
|
39
|
+
#endif /* HAVE_PQSETCLIENTENCODING */
|
40
|
+
|
41
|
+
#ifndef HAVE_PQESCAPESTRING
|
42
|
+
size_t PQescapeString(char *to, const char *from, size_t length);
|
43
|
+
unsigned char * PQescapeBytea(const unsigned char *bintext, size_t binlen, size_t *bytealen);
|
44
|
+
unsigned char * PQunescapeBytea(const unsigned char *strtext, size_t *retbuflen);
|
45
|
+
#endif /* HAVE_PQESCAPESTRING */
|
46
|
+
|
47
|
+
#ifndef HAVE_PQESCAPESTRINGCONN
|
48
|
+
size_t PQescapeStringConn(PGconn *conn, char *to, const char *from,
|
49
|
+
size_t length, int *error);
|
50
|
+
unsigned char *PQescapeByteaConn(PGconn *conn, const unsigned char *from,
|
51
|
+
size_t from_length, size_t *to_length);
|
52
|
+
#endif /* HAVE_PQESCAPESTRINGCONN */
|
53
|
+
|
54
|
+
#ifndef HAVE_PQPREPARE
|
55
|
+
PGresult *PQprepare(PGconn *conn, const char *stmtName, const char *query,
|
56
|
+
int nParams, const Oid *paramTypes);
|
57
|
+
#endif /* HAVE_PQPREPARE */
|
58
|
+
|
59
|
+
#ifndef HAVE_PQCONNECTIONUSEDPASSWORD
|
60
|
+
int PQconnectionUsedPassword(PGconn *conn);
|
61
|
+
#endif /* HAVE_PQCONNECTIONUSEDPASSWORD */
|
62
|
+
|
63
|
+
#ifndef HAVE_PQISTHREADSAFE
|
64
|
+
int PQisthreadsafe(void);
|
65
|
+
#endif /* HAVE_PQISTHREADSAFE */
|
66
|
+
|
67
|
+
#ifndef HAVE_LO_TRUNCATE
|
68
|
+
int lo_truncate(PGconn *conn, int fd, size_t len);
|
69
|
+
#endif /* HAVE_LO_TRUNCATE */
|
70
|
+
|
71
|
+
#ifndef HAVE_LO_CREATE
|
72
|
+
Oid lo_create(PGconn *conn, Oid lobjId);
|
73
|
+
#endif /* HAVE_LO_CREATE */
|
74
|
+
|
75
|
+
#ifndef HAVE_PQNPARAMS
|
76
|
+
int PQnparams(const PGresult *res);
|
77
|
+
#endif /* HAVE_PQNPARAMS */
|
78
|
+
|
79
|
+
#ifndef HAVE_PQPARAMTYPE
|
80
|
+
Oid PQparamtype(const PGresult *res, int param_number);
|
81
|
+
#endif /* HAVE_PQPARAMTYPE */
|
82
|
+
|
83
|
+
#ifndef HAVE_PQSERVERVERSION
|
84
|
+
int PQserverVersion(const PGconn* conn);
|
85
|
+
#endif /* HAVE_PQSERVERVERSION */
|
86
|
+
|
87
|
+
#ifndef HAVE_PQEXECPARAMS
|
88
|
+
PGresult *PQexecParams(PGconn *conn, const char *command, int nParams,
|
89
|
+
const Oid *paramTypes, const char * const * paramValues, const int *paramLengths,
|
90
|
+
const int *paramFormats, int resultFormat);
|
91
|
+
PGresult *PQexecParams_compat(PGconn *conn, VALUE command, VALUE values);
|
92
|
+
#endif /* HAVE_PQEXECPARAMS */
|
93
|
+
|
94
|
+
#ifndef HAVE_PQSENDDESCRIBEPREPARED
|
95
|
+
int PQsendDescribePrepared(PGconn *conn, const char *stmtName);
|
96
|
+
#endif /* HAVE_PQSENDDESCRIBEPREPARED */
|
97
|
+
|
98
|
+
#ifndef HAVE_PQSENDDESCRIBEPORTAL
|
99
|
+
int PQsendDescribePortal(PGconn *conn, const char *portalName);
|
100
|
+
#endif /* HAVE_PQSENDDESCRIBEPORTAL */
|
101
|
+
|
102
|
+
#ifndef HAVE_PQENCRYPTPASSWORD
|
103
|
+
char *PQencryptPassword(const char *passwd, const char *user);
|
104
|
+
#endif /* HAVE_PQENCRYPTPASSWORD */
|
105
|
+
|
106
|
+
#endif /* __compat_h */
|
data/ext/extconf.rb
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
if RUBY_VERSION < '1.3'
|
2
|
+
puts 'This library is for ruby-1.3 or higher.'
|
3
|
+
exit 1
|
4
|
+
end
|
5
|
+
|
6
|
+
require 'mkmf'
|
7
|
+
|
8
|
+
def config_value(type)
|
9
|
+
ENV["POSTGRES_#{type.upcase}"] || pg_config(type)
|
10
|
+
end
|
11
|
+
|
12
|
+
def pg_config(type)
|
13
|
+
IO.popen("pg_config --#{type}dir").readline.chomp rescue nil
|
14
|
+
end
|
15
|
+
|
16
|
+
def have_build_env
|
17
|
+
have_library('pq') && have_header('libpq-fe.h') && have_header('libpq/libpq-fs.h')
|
18
|
+
end
|
19
|
+
|
20
|
+
dir_config('pgsql', config_value('include'), config_value('lib'))
|
21
|
+
|
22
|
+
desired_functions = %w(
|
23
|
+
PQsetClientEncoding
|
24
|
+
PQfreemem
|
25
|
+
PQescapeStringConn
|
26
|
+
PQprepare
|
27
|
+
PQescapeString
|
28
|
+
PQexecParams
|
29
|
+
PQconnectionUsedPassword
|
30
|
+
PQisthreadsafe
|
31
|
+
PQnparams
|
32
|
+
PQparamtype
|
33
|
+
PQsendDescribePrepared
|
34
|
+
PQsendDescribePortal
|
35
|
+
PQencryptPassword
|
36
|
+
lo_create
|
37
|
+
lo_truncate
|
38
|
+
pg_encoding_to_char
|
39
|
+
)
|
40
|
+
|
41
|
+
if have_build_env
|
42
|
+
desired_functions.each(&method(:have_func))
|
43
|
+
$OBJS = ['pg.o','compat.o']
|
44
|
+
$CFLAGS << ' -Wall -Wmissing-prototypes'
|
45
|
+
create_makefile("pg")
|
46
|
+
else
|
47
|
+
puts 'Could not find PostgreSQL build environment (libraries & headers): Makefile not created'
|
48
|
+
end
|