pg 0.7.9.2008.01.28

Sign up to get free protection for your applications and to get access to all the features.
Files changed (12) 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/compat.c +529 -0
  8. data/ext/compat.h +176 -0
  9. data/ext/extconf.rb +80 -0
  10. data/ext/pg.c +3251 -0
  11. data/ext/pg.h +34 -0
  12. metadata +59 -0
@@ -0,0 +1,529 @@
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 <ctype.h>
16
+ #include "compat.h"
17
+
18
+ #ifdef PG_BEFORE_080300
19
+ int
20
+ PQconnectionNeedsPassword(PGconn *conn)
21
+ {
22
+ rb_raise(rb_eStandardError,
23
+ "PQconnectionNeedsPassword not supported by this client version.");
24
+ }
25
+
26
+ int
27
+ PQconnectionUsedPassword(PGconn *conn)
28
+ {
29
+ rb_raise(rb_eStandardError,
30
+ "PQconnectionUsedPassword not supported by this client version.");
31
+ }
32
+
33
+ int
34
+ lo_truncate(PGconn *conn, int fd, size_t len)
35
+ {
36
+ rb_raise(rb_eStandardError, "lo_truncate not supported by this client version.");
37
+ }
38
+ #endif /* PG_BEFORE_080300 */
39
+
40
+ #ifdef PG_BEFORE_080200
41
+ int
42
+ PQisthreadsafe()
43
+ {
44
+ return Qfalse;
45
+ }
46
+
47
+ int
48
+ PQnparams(const PGresult *res)
49
+ {
50
+ rb_raise(rb_eStandardError, "PQnparams not supported by this client version.");
51
+ }
52
+
53
+ Oid
54
+ PQparamtype(const PGresult *res, int param_number)
55
+ {
56
+ rb_raise(rb_eStandardError, "PQparamtype not supported by this client version.");
57
+ }
58
+
59
+ PGresult *
60
+ PQdescribePrepared(PGconn *conn, const char *stmtName)
61
+ {
62
+ rb_raise(rb_eStandardError, "PQdescribePrepared not supported by this client version.");
63
+ }
64
+
65
+ PGresult *
66
+ PQdescribePortal(PGconn *conn, const char *portalName)
67
+ {
68
+ rb_raise(rb_eStandardError, "PQdescribePortal not supported by this client version.");
69
+ }
70
+
71
+ int
72
+ PQsendDescribePrepared(PGconn *conn, const char *stmtName)
73
+ {
74
+ rb_raise(rb_eStandardError, "PQsendDescribePrepared not supported by this client version.");
75
+ }
76
+
77
+ int
78
+ PQsendDescribePortal(PGconn *conn, const char *portalName)
79
+ {
80
+ rb_raise(rb_eStandardError, "PQsendDescribePortal not supported by this client version.");
81
+ }
82
+
83
+ char *
84
+ PQencryptPassword(const char *passwd, const char *user)
85
+ {
86
+ rb_raise(rb_eStandardError, "PQencryptPassword not supported by this client version.");
87
+ }
88
+ #endif /* PG_BEFORE_080200 */
89
+
90
+ #ifdef PG_BEFORE_080100
91
+ Oid
92
+ lo_create(PGconn *conn, Oid lobjId)
93
+ {
94
+ rb_raise(rb_eStandardError, "lo_create not supported by this client version.");
95
+ }
96
+ #endif /* PG_BEFORE_080100 */
97
+
98
+ #ifdef PG_BEFORE_080000
99
+ PGresult *
100
+ PQprepare(PGconn *conn, const char *stmtName, const char *query,
101
+ int nParams, const Oid *paramTypes)
102
+ {
103
+ rb_raise(rb_eStandardError, "PQprepare not supported by this client version.");
104
+ }
105
+
106
+ int
107
+ PQsendPrepare(PGconn *conn, const char *stmtName, const char *query,
108
+ int nParams, const Oid *paramTypes)
109
+ {
110
+ rb_raise(rb_eStandardError, "PQsendPrepare not supported by this client version.");
111
+ }
112
+
113
+ int
114
+ PQserverVersion(const PGconn* conn)
115
+ {
116
+ rb_raise(rb_eStandardError, "PQserverVersion not supported by this client version.");
117
+ }
118
+ #endif /* PG_BEFORE_080000 */
119
+
120
+ #ifdef PG_BEFORE_070400
121
+ PGresult *
122
+ PQexecParams(PGconn *conn, const char *command, int nParams,
123
+ const Oid *paramTypes, const char * const * paramValues, const int *paramLengths,
124
+ const int *paramFormats, int resultFormat)
125
+ {
126
+ rb_raise(rb_eStandardError, "PQexecParams not supported by this client version.");
127
+ }
128
+
129
+ PGTransactionStatusType
130
+ PQtransactionStatus(const PGconn *conn)
131
+ {
132
+ rb_raise(rb_eStandardError, "PQtransactionStatus not supported by this client version.");
133
+ }
134
+
135
+ char *
136
+ PQparameterStatus(const PGconn *conn, const char *paramName)
137
+ {
138
+ rb_raise(rb_eStandardError, "PQparameterStatus not supported by this client version.");
139
+ }
140
+
141
+ int
142
+ PQprotocolVersion(const PGconn *conn)
143
+ {
144
+ rb_raise(rb_eStandardError, "PQprotocolVersion not supported by this client version.");
145
+ }
146
+
147
+ PGresult
148
+ *PQexecPrepared(PGconn *conn, const char *stmtName, int nParams,
149
+ const char * const *ParamValues, const int *paramLengths, const int *paramFormats,
150
+ int resultFormat)
151
+ {
152
+ rb_raise(rb_eStandardError, "PQexecPrepared not supported by this client version.");
153
+ }
154
+
155
+ int
156
+ PQsendQueryParams(PGconn *conn, const char *command, int nParams,
157
+ const Oid *paramTypes, const char * const * paramValues, const int *paramLengths,
158
+ const int *paramFormats, int resultFormat)
159
+ {
160
+ rb_raise(rb_eStandardError, "PQsendQueryParams not supported by this client version.");
161
+ }
162
+
163
+ int
164
+ PQsendQueryPrepared(PGconn *conn, const char *stmtName, int nParams,
165
+ const char * const *ParamValues, const int *paramLengths, const int *paramFormats,
166
+ int resultFormat)
167
+ {
168
+ rb_raise(rb_eStandardError, "PQsendQueryPrepared not supported by this client version.");
169
+ }
170
+
171
+ int
172
+ PQputCopyData(PGconn *conn, const char *buffer, int nbytes)
173
+ {
174
+ rb_raise(rb_eStandardError, "PQputCopyData not supported by this client version.");
175
+ }
176
+
177
+ int
178
+ PQputCopyEnd(PGconn *conn, const char *errormsg)
179
+ {
180
+ rb_raise(rb_eStandardError, "PQputCopyEnd not supported by this client version.");
181
+ }
182
+
183
+ int
184
+ PQgetCopyData(PGconn *conn, char **buffer, int async)
185
+ {
186
+ rb_raise(rb_eStandardError, "PQgetCopyData not supported by this client version.");
187
+ }
188
+
189
+ PGVerbosity
190
+ PQsetErrorVerbosity(PGconn *conn, PGVerbosity verbosity)
191
+ {
192
+ rb_raise(rb_eStandardError, "PQsetErrorVerbosity not supported by this client version.");
193
+ }
194
+
195
+ Oid
196
+ PQftable(const PGresult *res, int column_number)
197
+ {
198
+ rb_raise(rb_eStandardError, "PQftable not supported by this client version.");
199
+ }
200
+
201
+ int
202
+ PQftablecol(const PGresult *res, int column_number)
203
+ {
204
+ rb_raise(rb_eStandardError, "PQftablecol not supported by this client version.");
205
+ }
206
+
207
+ int
208
+ PQfformat(const PGresult *res, int column_number)
209
+ {
210
+ rb_raise(rb_eStandardError, "PQfformat not supported by this client version.");
211
+ }
212
+ #endif /* PG_BEFORE_070400 */
213
+
214
+ #ifdef PG_BEFORE_070300
215
+ size_t
216
+ PQescapeStringConn(PGconn *conn, char *to, const char *from,
217
+ size_t length, int *error)
218
+ {
219
+ return PQescapeString(to,from,length);
220
+ }
221
+
222
+ unsigned char *
223
+ PQescapeByteaConn(PGconn *conn, const unsigned char *from,
224
+ size_t from_length, size_t *to_length)
225
+ {
226
+ return PQescapeBytea(from, from_length, to_length);
227
+ }
228
+ #endif /* PG_BEFORE_070300 */
229
+
230
+
231
+ /**************************************************************************
232
+
233
+ IF ANY CODE IS COPIED FROM POSTGRESQL, PLACE IT AFTER THIS COMMENT.
234
+
235
+ ***************************************************************************
236
+
237
+ Portions of code after this point were copied from the PostgreSQL source
238
+ distribution, available at http://www.postgresql.org
239
+
240
+ ***************************************************************************
241
+
242
+ Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
243
+
244
+ Portions Copyright (c) 1994, The Regents of the University of California
245
+
246
+ Permission to use, copy, modify, and distribute this software and its
247
+ documentation for any purpose, without fee, and without a written agreement
248
+ is hereby granted, provided that the above copyright notice and this
249
+ paragraph and the following two paragraphs appear in all copies.
250
+
251
+ IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
252
+ DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING
253
+ LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
254
+ DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE
255
+ POSSIBILITY OF SUCH DAMAGE.
256
+
257
+ THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
258
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
259
+ AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
260
+ ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS TO
261
+ PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
262
+
263
+ **************************************************************************/
264
+
265
+ #ifndef HAVE_PQSETCLIENTENCODING
266
+ int
267
+ PQsetClientEncoding(PGconn *conn, const char *encoding)
268
+ {
269
+ char qbuf[128];
270
+ static const char query[] = "set client_encoding to '%s'";
271
+ PGresult *res;
272
+ int status;
273
+
274
+ if (!conn || conn->status != CONNECTION_OK)
275
+ return -1;
276
+
277
+ if (!encoding)
278
+ return -1;
279
+
280
+ /* check query buffer overflow */
281
+ if (sizeof(qbuf) < (sizeof(query) + strlen(encoding)))
282
+ return -1;
283
+
284
+ /* ok, now send a query */
285
+ sprintf(qbuf, query, encoding);
286
+ res = PQexec(conn, qbuf);
287
+
288
+ if (res == NULL)
289
+ return -1;
290
+ if (res->resultStatus != PGRES_COMMAND_OK)
291
+ status = -1;
292
+ else
293
+ {
294
+ /*
295
+ * In protocol 2 we have to assume the setting will stick, and adjust
296
+ * our state immediately. In protocol 3 and up we can rely on the
297
+ * backend to report the parameter value, and we'll change state at
298
+ * that time.
299
+ */
300
+ if (PG_PROTOCOL_MAJOR(conn->pversion) < 3)
301
+ pqSaveParameterStatus(conn, "client_encoding", encoding);
302
+ status = 0; /* everything is ok */
303
+ }
304
+ PQclear(res);
305
+ return status;
306
+ }
307
+ #endif /* HAVE_PQSETCLIENTENCODING */
308
+
309
+ #ifndef HAVE_PQESCAPESTRING
310
+ /*
311
+ * Escaping arbitrary strings to get valid SQL literal strings.
312
+ *
313
+ * Replaces "\\" with "\\\\" and "'" with "''".
314
+ *
315
+ * length is the length of the source string. (Note: if a terminating NUL
316
+ * is encountered sooner, PQescapeString stops short of "length"; the behavior
317
+ * is thus rather like strncpy.)
318
+ *
319
+ * For safety the buffer at "to" must be at least 2*length + 1 bytes long.
320
+ * A terminating NUL character is added to the output string, whether the
321
+ * input is NUL-terminated or not.
322
+ *
323
+ * Returns the actual length of the output (not counting the terminating NUL).
324
+ */
325
+ size_t
326
+ PQescapeString(char *to, const char *from, size_t length)
327
+ {
328
+ const char *source = from;
329
+ char *target = to;
330
+ size_t remaining = length;
331
+
332
+ while (remaining > 0 && *source != '\0')
333
+ {
334
+ switch (*source)
335
+ {
336
+ case '\\':
337
+ *target++ = '\\';
338
+ *target++ = '\\';
339
+ break;
340
+
341
+ case '\'':
342
+ *target++ = '\'';
343
+ *target++ = '\'';
344
+ break;
345
+
346
+ default:
347
+ *target++ = *source;
348
+ break;
349
+ }
350
+ source++;
351
+ remaining--;
352
+ }
353
+
354
+ /* Write the terminating NUL character. */
355
+ *target = '\0';
356
+
357
+ return target - to;
358
+ }
359
+
360
+ /*
361
+ * PQescapeBytea - converts from binary string to the
362
+ * minimal encoding necessary to include the string in an SQL
363
+ * INSERT statement with a bytea type column as the target.
364
+ *
365
+ * The following transformations are applied
366
+ * '\0' == ASCII 0 == \\000
367
+ * '\'' == ASCII 39 == \'
368
+ * '\\' == ASCII 92 == \\\\
369
+ * anything < 0x20, or > 0x7e ---> \\ooo
370
+ * (where ooo is an octal expression)
371
+ */
372
+ unsigned char *
373
+ PQescapeBytea(const unsigned char *bintext, size_t binlen, size_t *bytealen)
374
+ {
375
+ const unsigned char *vp;
376
+ unsigned char *rp;
377
+ unsigned char *result;
378
+ size_t i;
379
+ size_t len;
380
+
381
+ /*
382
+ * empty string has 1 char ('\0')
383
+ */
384
+ len = 1;
385
+
386
+ vp = bintext;
387
+ for (i = binlen; i > 0; i--, vp++)
388
+ {
389
+ if (*vp < 0x20 || *vp > 0x7e)
390
+ len += 5; /* '5' is for '\\ooo' */
391
+ else if (*vp == '\'')
392
+ len += 2;
393
+ else if (*vp == '\\')
394
+ len += 4;
395
+ else
396
+ len++;
397
+ }
398
+
399
+ rp = result = (unsigned char *) malloc(len);
400
+ if (rp == NULL)
401
+ return NULL;
402
+
403
+ vp = bintext;
404
+ *bytealen = len;
405
+
406
+ for (i = binlen; i > 0; i--, vp++)
407
+ {
408
+ if (*vp < 0x20 || *vp > 0x7e)
409
+ {
410
+ (void) sprintf(rp, "\\\\%03o", *vp);
411
+ rp += 5;
412
+ }
413
+ else if (*vp == '\'')
414
+ {
415
+ rp[0] = '\\';
416
+ rp[1] = '\'';
417
+ rp += 2;
418
+ }
419
+ else if (*vp == '\\')
420
+ {
421
+ rp[0] = '\\';
422
+ rp[1] = '\\';
423
+ rp[2] = '\\';
424
+ rp[3] = '\\';
425
+ rp += 4;
426
+ }
427
+ else
428
+ *rp++ = *vp;
429
+ }
430
+ *rp = '\0';
431
+
432
+ return result;
433
+ }
434
+
435
+ #define ISFIRSTOCTDIGIT(CH) ((CH) >= '0' && (CH) <= '3')
436
+ #define ISOCTDIGIT(CH) ((CH) >= '0' && (CH) <= '7')
437
+ #define OCTVAL(CH) ((CH) - '0')
438
+
439
+ /*
440
+ * PQunescapeBytea - converts the null terminated string representation
441
+ * of a bytea, strtext, into binary, filling a buffer. It returns a
442
+ * pointer to the buffer (or NULL on error), and the size of the
443
+ * buffer in retbuflen. The pointer may subsequently be used as an
444
+ * argument to the function free(3). It is the reverse of PQescapeBytea.
445
+ *
446
+ * The following transformations are made:
447
+ * \\ == ASCII 92 == \
448
+ * \ooo == a byte whose value = ooo (ooo is an octal number)
449
+ * \x == x (x is any character not matched by the above transformations)
450
+ */
451
+ unsigned char *
452
+ PQunescapeBytea(const unsigned char *strtext, size_t *retbuflen)
453
+ {
454
+ size_t strtextlen,
455
+ buflen;
456
+ unsigned char *buffer,
457
+ *tmpbuf;
458
+ size_t i,
459
+ j;
460
+
461
+ if (strtext == NULL)
462
+ return NULL;
463
+
464
+ strtextlen = strlen(strtext);
465
+
466
+ /*
467
+ * Length of input is max length of output, but add one to avoid
468
+ * unportable malloc(0) if input is zero-length.
469
+ */
470
+ buffer = (unsigned char *) malloc(strtextlen + 1);
471
+ if (buffer == NULL)
472
+ return NULL;
473
+
474
+ for (i = j = 0; i < strtextlen;)
475
+ {
476
+ switch (strtext[i])
477
+ {
478
+ case '\\':
479
+ i++;
480
+ if (strtext[i] == '\\')
481
+ buffer[j++] = strtext[i++];
482
+ else
483
+ {
484
+ if ((ISFIRSTOCTDIGIT(strtext[i])) &&
485
+ (ISOCTDIGIT(strtext[i + 1])) &&
486
+ (ISOCTDIGIT(strtext[i + 2])))
487
+ {
488
+ int byte;
489
+
490
+ byte = OCTVAL(strtext[i++]);
491
+ byte = (byte << 3) + OCTVAL(strtext[i++]);
492
+ byte = (byte << 3) + OCTVAL(strtext[i++]);
493
+ buffer[j++] = byte;
494
+ }
495
+ }
496
+
497
+ /*
498
+ * Note: if we see '\' followed by something that isn't a
499
+ * recognized escape sequence, we loop around having done
500
+ * nothing except advance i. Therefore the something will
501
+ * be emitted as ordinary data on the next cycle. Corner
502
+ * case: '\' at end of string will just be discarded.
503
+ */
504
+ break;
505
+
506
+ default:
507
+ buffer[j++] = strtext[i++];
508
+ break;
509
+ }
510
+ }
511
+ buflen = j; /* buflen is the length of the dequoted
512
+ * data */
513
+
514
+ /* Shrink the buffer to be no larger than necessary */
515
+ /* +1 avoids unportable behavior when buflen==0 */
516
+ tmpbuf = realloc(buffer, buflen + 1);
517
+
518
+ /* It would only be a very brain-dead realloc that could fail, but... */
519
+ if (!tmpbuf)
520
+ {
521
+ free(buffer);
522
+ return NULL;
523
+ }
524
+
525
+ *retbuflen = buflen;
526
+ return tmpbuf;
527
+ }
528
+ #endif
529
+