postgres 0.7.9.2007.12.12 → 0.7.9.2007.12.22

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.
@@ -20,13 +20,13 @@ end
20
20
  dir_config('pgsql', config_value('include'), config_value('lib'))
21
21
 
22
22
  required_libraries = []
23
- desired_functions = %w(PQsetClientEncoding pg_encoding_to_char PQfreemem)
23
+ desired_functions = %w(PQsetClientEncoding pg_encoding_to_char PQfreemem PQserverVersion)
24
24
  compat_functions = %w(PQescapeString PQexecParams)
25
25
 
26
26
  if have_build_env
27
27
  required_libraries.each(&method(:have_library))
28
28
  desired_functions.each(&method(:have_func))
29
- $objs = ['postgres.o'] if compat_functions.all?(&method(:have_func))
29
+ $objs = ['postgres.o','libpq-compat.o'] if compat_functions.all?(&method(:have_func))
30
30
  $CFLAGS << ' -Wall '
31
31
  create_makefile("postgres")
32
32
  else
@@ -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
@@ -25,6 +25,22 @@
25
25
  #include <stdlib.h>
26
26
  #include <sys/types.h>
27
27
 
28
+ #ifndef HAVE_PQSERVERVERSION
29
+ static int
30
+ PQserverVersion(const PGconn *conn)
31
+ {
32
+ rb_raise(rb_eArgError,"this version of libpq doesn't support PQserverVersion");
33
+ }
34
+ #endif /* HAVE_PQSERVERVERSION */
35
+
36
+ #ifndef RSTRING_LEN
37
+ #define RSTRING_LEN(x) RSTRING((x))->len
38
+ #endif /* RSTRING_LEN */
39
+
40
+ #ifndef RSTRING_PTR
41
+ #define RSTRING_PTR(x) RSTRING((x))->ptr
42
+ #endif /* RSTRING_PTR */
43
+
28
44
  #ifndef HAVE_PG_ENCODING_TO_CHAR
29
45
  #define pg_encoding_to_char(x) "SQL_ASCII"
30
46
  #endif
@@ -175,9 +191,11 @@ pgconn_connect(argc, argv, self)
175
191
  rb_raise(rb_ePGError, StringValuePtr(message));
176
192
  }
177
193
 
194
+ #ifdef HAVE_PQSERVERVERSION
178
195
  if (PQserverVersion(conn) >= 80100) {
179
196
  rb_define_singleton_method(self, "lastval", pgconn_lastval, 0);
180
197
  }
198
+ #endif /* HAVE_PQSERVERVERSION */
181
199
 
182
200
  Data_Set_Struct(self, conn);
183
201
  return self;
@@ -259,8 +277,8 @@ pgconn_s_quote(self, obj)
259
277
  if (TYPE(obj) == T_STRING) {
260
278
  /* length * 2 because every char could require escaping */
261
279
  /* + 2 for the quotes, + 1 for the null terminator */
262
- quoted = ALLOCA_N(char, RSTRING(obj)->len * 2 + 2 + 1);
263
- size = PQescapeString(quoted + 1, RSTRING(obj)->ptr, RSTRING(obj)->len);
280
+ quoted = ALLOCA_N(char, RSTRING_LEN(obj) * 2 + 2 + 1);
281
+ size = PQescapeString(quoted + 1, RSTRING_PTR(obj), RSTRING_LEN(obj));
264
282
  *quoted = *(quoted + size + 1) = SINGLE_QUOTE;
265
283
  result = rb_str_new(quoted, size + 2);
266
284
  OBJ_INFECT(result, obj);
@@ -299,8 +317,9 @@ pgconn_quote(self, obj)
299
317
  if (TYPE(obj) == T_STRING) {
300
318
  /* length * 2 because every char could require escaping */
301
319
  /* + 2 for the quotes, + 1 for the null terminator */
302
- quoted = ALLOCA_N(char, RSTRING(obj)->len * 2 + 2 + 1);
303
- size = PQescapeStringConn(get_pgconn(self),quoted + 1, RSTRING(obj)->ptr, RSTRING(obj)->len, &error);
320
+ quoted = ALLOCA_N(char, RSTRING_LEN(obj) * 2 + 2 + 1);
321
+ size = PQescapeStringConn(get_pgconn(self),quoted + 1,
322
+ RSTRING_PTR(obj), RSTRING_LEN(obj), &error);
304
323
  *quoted = *(quoted + size + 1) = SINGLE_QUOTE;
305
324
  result = rb_str_new(quoted, size + 2);
306
325
  OBJ_INFECT(result, obj);
@@ -321,8 +340,8 @@ pgconn_s_quote_connstr(string)
321
340
 
322
341
  Check_Type(string, T_STRING);
323
342
 
324
- ptr = RSTRING(string)->ptr;
325
- len = RSTRING(string)->len;
343
+ ptr = RSTRING_PTR(string);
344
+ len = RSTRING_LEN(string);
326
345
  str = ALLOCA_N(char, len * 2 + 2 + 1);
327
346
  str[j++] = '\'';
328
347
  for(i = 0; i < len; i++) {
@@ -366,8 +385,8 @@ pgconn_s_quote_ident(self, string)
366
385
 
367
386
  Check_Type(string, T_STRING);
368
387
 
369
- ptr = RSTRING(string)->ptr;
370
- len = RSTRING(string)->len;
388
+ ptr = RSTRING_PTR(string);
389
+ len = RSTRING_LEN(string);
371
390
  str = ALLOCA_N(char, len * 2 + 2 + 1);
372
391
  str[j++] = '"';
373
392
  for(i = 0; i < len; i++) {
@@ -397,8 +416,8 @@ pgconn_s_escape(self, string)
397
416
 
398
417
  Check_Type(string, T_STRING);
399
418
 
400
- escaped = ALLOCA_N(char, RSTRING(string)->len * 2 + 1);
401
- size = PQescapeString(escaped, RSTRING(string)->ptr, RSTRING(string)->len);
419
+ escaped = ALLOCA_N(char, RSTRING_LEN(string) * 2 + 1);
420
+ size = PQescapeString(escaped, RSTRING_PTR(string), RSTRING_LEN(string));
402
421
  result = rb_str_new(escaped, size);
403
422
  OBJ_INFECT(result, string);
404
423
  return result;
@@ -418,8 +437,9 @@ pgconn_escape(self, string)
418
437
 
419
438
  Check_Type(string, T_STRING);
420
439
 
421
- escaped = ALLOCA_N(char, RSTRING(string)->len * 2 + 1);
422
- size = PQescapeStringConn(get_pgconn(self),escaped, RSTRING(string)->ptr, RSTRING(string)->len, &error);
440
+ escaped = ALLOCA_N(char, RSTRING_LEN(string) * 2 + 1);
441
+ size = PQescapeStringConn(get_pgconn(self),escaped, RSTRING_PTR(string),
442
+ RSTRING_LEN(string), &error);
423
443
  result = rb_str_new(escaped, size);
424
444
  OBJ_INFECT(result, string);
425
445
  return result;
@@ -450,8 +470,8 @@ pgconn_s_escape_bytea(self, obj)
450
470
  VALUE ret;
451
471
 
452
472
  Check_Type(obj, T_STRING);
453
- from = RSTRING(obj)->ptr;
454
- from_len = RSTRING(obj)->len;
473
+ from = RSTRING_PTR(obj);
474
+ from_len = RSTRING_LEN(obj);
455
475
 
456
476
  to = (char *)PQescapeBytea(from, from_len, &to_len);
457
477
 
@@ -488,8 +508,8 @@ pgconn_escape_bytea(self, obj)
488
508
  VALUE ret;
489
509
 
490
510
  Check_Type(obj, T_STRING);
491
- from = RSTRING(obj)->ptr;
492
- from_len = RSTRING(obj)->len;
511
+ from = RSTRING_PTR(obj);
512
+ from_len = RSTRING_LEN(obj);
493
513
 
494
514
  to = (char *)PQescapeByteaConn(get_pgconn(self),from, from_len, &to_len);
495
515
 
@@ -653,13 +673,13 @@ translate_to_pg(VALUE value, char const** result, int* length, int* format)
653
673
  return;
654
674
  case T_STRING:
655
675
  *result = StringValuePtr(value);
656
- *length = RSTRING(value)->len;
676
+ *length = RSTRING_LEN(value);
657
677
  *format = BINARY_FORMAT;
658
678
  return;
659
679
  default: {
660
680
  VALUE formatted = pgconn_s_format(rb_cPGconn, value);
661
681
  *result = StringValuePtr(formatted);
662
- *length = RSTRING(formatted)->len;
682
+ *length = RSTRING_LEN(formatted);
663
683
  *format = TEXT_FORMAT;
664
684
  }
665
685
  }
@@ -735,7 +755,7 @@ pgconn_exec(argc, argv, obj)
735
755
  case PGRES_BAD_RESPONSE:
736
756
  case PGRES_FATAL_ERROR:
737
757
  case PGRES_NONFATAL_ERROR:
738
- msg = RSTRING(rb_str_new2(PQresultErrorMessage(result)))->ptr;
758
+ msg = RSTRING_PTR(rb_str_new2(PQresultErrorMessage(result)));
739
759
  break;
740
760
  default:
741
761
  msg = "internal error : unknown result status.";
@@ -771,7 +791,7 @@ pgconn_async_exec(obj, str)
771
791
  PQclear(result);
772
792
  }
773
793
 
774
- if (!PQsendQuery(conn, RSTRING(str)->ptr)) {
794
+ if (!PQsendQuery(conn, RSTRING_PTR(str))) {
775
795
  rb_raise(rb_ePGError, PQerrorMessage(conn));
776
796
  }
777
797
 
@@ -814,7 +834,7 @@ pgconn_async_exec(obj, str)
814
834
  case PGRES_BAD_RESPONSE:
815
835
  case PGRES_FATAL_ERROR:
816
836
  case PGRES_NONFATAL_ERROR:
817
- msg = RSTRING(rb_str_new2(PQresultErrorMessage(result)))->ptr;
837
+ msg = RSTRING_PTR(rb_str_new2(PQresultErrorMessage(result)));
818
838
  break;
819
839
  default:
820
840
  msg = "internal error : unknown result status.";
@@ -925,9 +945,9 @@ pgconn_insert_table(obj, table, values)
925
945
  }
926
946
  }
927
947
 
928
- buffer = rb_str_new(0, RSTRING(table)->len + 17 + 1);
948
+ buffer = rb_str_new(0, RSTRING_LEN(table) + 17 + 1);
929
949
  /* starts query */
930
- snprintf(RSTRING(buffer)->ptr, RSTRING(buffer)->len, "copy %s from stdin ", StringValuePtr(table));
950
+ snprintf(RSTRING_PTR(buffer), RSTRING_LEN(buffer), "copy %s from stdin ", StringValuePtr(table));
931
951
 
932
952
  result = PQexec(conn, StringValuePtr(buffer));
933
953
  if (!result){
@@ -945,7 +965,7 @@ pgconn_insert_table(obj, table, values)
945
965
  } else {
946
966
  s = rb_obj_as_string(row->ptr[j]);
947
967
  rb_funcall(s,pg_gsub_bang_id,2,pg_escape_regex,pg_escape_str);
948
- rb_str_cat(buffer, StringValuePtr(s), RSTRING(s)->len);
968
+ rb_str_cat(buffer, StringValuePtr(s), RSTRING_LEN(s));
949
969
  }
950
970
  }
951
971
  rb_str_cat(buffer, "\n\0", 2);
@@ -996,7 +1016,7 @@ pgconn_getline(obj)
996
1016
  str = rb_tainted_str_new(0, size);
997
1017
 
998
1018
  for (;;) {
999
- ret = PQgetline(conn, RSTRING(str)->ptr + bytes, size - bytes);
1019
+ ret = PQgetline(conn, RSTRING_PTR(str) + bytes, size - bytes);
1000
1020
  switch (ret) {
1001
1021
  case EOF:
1002
1022
  return Qnil;
@@ -1182,7 +1202,7 @@ pgconn_error(obj)
1182
1202
  return rb_tainted_str_new2(error);
1183
1203
  }
1184
1204
 
1185
- /*
1205
+ /*TODO broken for ruby 1.9
1186
1206
  * call-seq:
1187
1207
  * conn.trace( port )
1188
1208
  *
@@ -1194,12 +1214,12 @@ static VALUE
1194
1214
  pgconn_trace(obj, port)
1195
1215
  VALUE obj, port;
1196
1216
  {
1197
- OpenFile* fp;
1217
+ //OpenFile* fp;
1198
1218
 
1199
1219
  Check_Type(port, T_FILE);
1200
- GetOpenFile(port, fp);
1220
+ //GetOpenFile(port, fp);
1201
1221
 
1202
- PQtrace(get_pgconn(obj), fp->f2?fp->f2:fp->f);
1222
+ //PQtrace(get_pgconn(obj), fp->f2?fp->f2:fp->f);
1203
1223
 
1204
1224
  return obj;
1205
1225
  }
@@ -2287,7 +2307,7 @@ loread_all(obj)
2287
2307
 
2288
2308
  str = rb_tainted_str_new(0,siz);
2289
2309
  for (;;) {
2290
- n = lo_read(pglarge->pgconn, pglarge->lo_fd, RSTRING(str)->ptr + bytes,siz - bytes);
2310
+ n = lo_read(pglarge->pgconn, pglarge->lo_fd, RSTRING_PTR(str) + bytes,siz - bytes);
2291
2311
  if (n == 0 && bytes == 0) return Qnil;
2292
2312
  bytes += n;
2293
2313
  if (bytes < siz ) break;
@@ -2332,7 +2352,7 @@ pglarge_read(argc, argv, obj)
2332
2352
  rb_raise(rb_ePGError, "error while reading");
2333
2353
  }
2334
2354
  if (len == 0) return Qnil;
2335
- RSTRING(str)->len = len;
2355
+ RSTRING_LEN(str) = len;
2336
2356
  return str;
2337
2357
  }
2338
2358
 
@@ -2352,10 +2372,11 @@ pglarge_write(obj, buffer)
2352
2372
 
2353
2373
  Check_Type(buffer, T_STRING);
2354
2374
 
2355
- if( RSTRING(buffer)->len < 0) {
2375
+ if( RSTRING_LEN(buffer) < 0) {
2356
2376
  rb_raise(rb_ePGError, "write buffer zero string");
2357
2377
  }
2358
- if((n = lo_write(pglarge->pgconn, pglarge->lo_fd, StringValuePtr(buffer), RSTRING(buffer)->len)) == -1) {
2378
+ if((n = lo_write(pglarge->pgconn, pglarge->lo_fd, StringValuePtr(buffer),
2379
+ RSTRING_LEN(buffer))) == -1) {
2359
2380
  rb_raise(rb_ePGError, "buffer truncated during write");
2360
2381
  }
2361
2382