postgres 0.7.9.2007.12.12 → 0.7.9.2007.12.22

Sign up to get free protection for your applications and to get access to all the features.
@@ -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