Skip to content

Commit 24f0012

Browse files
committed
I have made some corrections to my previous patches for retrieving array
attributes as tcl arrays. The previous code had problems with some chars used as delimiter by Tcl. The new code should be more robust. By: Massimo Dal Zotto <dz@cs.unitn.it>
1 parent 33dccad commit 24f0012

File tree

1 file changed

+198
-1
lines changed

1 file changed

+198
-1
lines changed

src/interfaces/libpgtcl/pgtclCmds.c

Lines changed: 198 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
*
88
*
99
* IDENTIFICATION
10-
* $Header: /cvsroot/pgsql/src/interfaces/libpgtcl/Attic/pgtclCmds.c,v 1.2 1996/07/23 03:38:44 scrappy Exp $
10+
* $Header: /cvsroot/pgsql/src/interfaces/libpgtcl/Attic/pgtclCmds.c,v 1.3 1996/09/16 05:54:53 scrappy Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -23,6 +23,192 @@
2323
#include "pgtclCmds.h"
2424
#include "pgtclId.h"
2525

26+
#ifdef TCL_ARRAYS
27+
#define ISOCTAL(c) (((c) >= '0') && ((c) <= '7'))
28+
#define DIGIT(c) ((c) - '0')
29+
30+
/*
31+
* translate_escape() --
32+
*
33+
* This function performs in-place translation of a single C-style
34+
* escape sequence pointed by p. Curly braces { } and double-quote
35+
* are left escaped if they appear inside an array.
36+
* The value returned is the pointer to the last character (the one
37+
* just before the rest of the buffer).
38+
*/
39+
40+
static inline char*
41+
translate_escape(char *p, int isArray)
42+
{
43+
register char c, *q, *s;
44+
45+
#ifdef DEBUG_ESCAPE
46+
printf(" escape = '%s'\n", p);
47+
#endif
48+
/* Address of the first character after the escape sequence */
49+
s = p+2;
50+
switch (c = *(p+1)) {
51+
case '0':
52+
case '1':
53+
case '2':
54+
case '3':
55+
case '4':
56+
case '5':
57+
case '6':
58+
case '7':
59+
c = DIGIT(c);
60+
if (ISOCTAL(*s)) {
61+
c = (c<<3) + DIGIT(*s++);
62+
}
63+
if (ISOCTAL(*s)) {
64+
c = (c<<3) + DIGIT(*s++);
65+
}
66+
*p = c;
67+
break;
68+
case 'b':
69+
*p = '\b';
70+
break;
71+
case 'f':
72+
*p = '\f';
73+
break;
74+
case 'n':
75+
*p = '\n';
76+
break;
77+
case 'r':
78+
*p = '\r';
79+
break;
80+
case 't':
81+
*p = '\t';
82+
break;
83+
case 'v':
84+
*p = '\v';
85+
break;
86+
case '\\':
87+
case '{':
88+
case '}':
89+
case '"':
90+
/*
91+
* Backslahes, curly braces and double-quotes are left
92+
* escaped if they appear inside an array. They will be
93+
* unescaped by Tcl in Tcl_AppendElement.
94+
* The buffer position is advanced by 1 so that the this
95+
* character is not processed again by the caller.
96+
*/
97+
if (isArray) {
98+
return p+1;
99+
} else {
100+
*p = c;
101+
}
102+
break;
103+
case '\0':
104+
/*
105+
* This means a backslash at the end of the string.
106+
* It should never happen but in that case replace
107+
* the \ with a \0 but don't shift the rest of the
108+
* buffer so that the caller can see the end of the
109+
* string and terminate.
110+
*/
111+
*p = c;
112+
return p;
113+
break;
114+
default:
115+
/*
116+
* Default case, store the escaped character over the backslash
117+
* and shift the buffer over itself.
118+
*/
119+
*p = c;
120+
}
121+
/* Shift the rest of the buffer over itself after the current char */
122+
q = p+1;
123+
for ( ; *s ; ) {
124+
*q++ = *s++;
125+
}
126+
*q = '\0';
127+
#ifdef DEBUG_ESCAPE
128+
printf(" after = '%s'\n", p);
129+
#endif
130+
return p;
131+
}
132+
133+
/*
134+
* tcl_value() --
135+
*
136+
* This function does in-line conversion of a value returned by libpq
137+
* into a tcl string or into a tcl list if the value looks like the
138+
* representation of a postgres array.
139+
*/
140+
141+
static char *
142+
tcl_value (char *value)
143+
{
144+
int literal, last;
145+
register char c, *p, *q, *s;
146+
147+
if (!value) {
148+
return ((char *) NULL);
149+
}
150+
151+
#ifdef DEBUG
152+
printf("pq_value = '%s'\n", value);
153+
#endif
154+
last = strlen(value)-1;
155+
if ((last >= 1) && (value[0] == '{') && (value[last] == '}')) {
156+
/* Looks like an array, replace ',' with spaces */
157+
/* Remove the outer pair of { }, the last first! */
158+
value[last] = '\0';
159+
value++;
160+
literal = 0;
161+
for (p=value; *p; p++) {
162+
if (!literal) {
163+
/* We are at the list level, look for ',' and '"' */
164+
switch (*p) {
165+
case '"': /* beginning of literal */
166+
literal = 1;
167+
break;
168+
case ',': /* replace the ',' with space */
169+
*p = ' ';
170+
break;
171+
}
172+
} else {
173+
/* We are inside a C string */
174+
switch (*p) {
175+
case '"': /* end of literal */
176+
literal = 0;
177+
break;
178+
case '\\':
179+
/*
180+
* escape sequence, translate it
181+
*/
182+
p = translate_escape(p,1);
183+
break;
184+
}
185+
}
186+
if (!*p) {
187+
break;
188+
}
189+
}
190+
} else {
191+
/* Looks like a normal scalar value */
192+
for (p=value; *p; p++) {
193+
if (*p == '\\') {
194+
/*
195+
* escape sequence, translate it
196+
*/
197+
p = translate_escape(p,0);
198+
}
199+
if (!*p) {
200+
break;
201+
}
202+
}
203+
}
204+
#ifdef DEBUG
205+
printf("tcl_value = '%s'\n\n", value);
206+
#endif
207+
return (value);
208+
}
209+
210+
#endif
211+
26212
/**********************************
27213
* pg_connect
28214
make a connection to a backend.
@@ -264,7 +450,11 @@ Pg_result(ClientData cData, Tcl_Interp *interp, int argc, char* argv[])
264450
for (i=0;i<PQnfields(result);i++) {
265451
sprintf(arrayInd, "%d,%s", tupno, PQfname(result,i));
266452
Tcl_SetVar2(interp, arrVar, arrayInd,
453+
#ifdef TCL_ARRAYS
454+
tcl_value(PQgetvalue(result,tupno,i)),
455+
#else
267456
PQgetvalue(result,tupno,i),
457+
#endif
268458
TCL_LEAVE_ERR_MSG);
269459
}
270460
}
@@ -304,12 +494,19 @@ Pg_result(ClientData cData, Tcl_Interp *interp, int argc, char* argv[])
304494
return TCL_ERROR;
305495
}
306496

497+
#ifdef TCL_ARRAYS
498+
for (i=0; i<PQnfields(result); i++) {
499+
Tcl_AppendElement(interp, tcl_value(PQgetvalue(result,tupno,i)));
500+
}
501+
#else
307502
/* Tcl_AppendResult(interp, PQgetvalue(result,tupno,0),NULL); */
308503
Tcl_AppendElement(interp, PQgetvalue(result,tupno,0));
309504
for (i=1;i<PQnfields(result);i++) {
310505
/* Tcl_AppendResult(interp, " ", PQgetvalue(result,tupno,i),NULL);*/
311506
Tcl_AppendElement(interp, PQgetvalue(result,tupno,i));
312507
}
508+
#endif
509+
313510
return TCL_OK;
314511
}
315512
else if (strcmp(opt, "-attributes") == 0) {

0 commit comments

Comments
 (0)