Commit 0f2fbbba authored by Tom Lane's avatar Tom Lane

Try to make array_in's behavior a tad less bizarre. Leading whitespace

before a data item is now always skipped, rather than only sometimes.
Backslashes not within double-quoted text are treated reasonably, as
are multiple sequences of quoted text in a single data item.  But it
still seems rather prone to misbehavior if the input is not completely
syntactically correct --- in particular, garbage following a right brace
will be ignored.
parent 134fe5ec
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/arrayfuncs.c,v 1.75 2002/03/02 00:34:24 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/utils/adt/arrayfuncs.c,v 1.76 2002/03/16 22:47:13 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -51,7 +51,7 @@ ...@@ -51,7 +51,7 @@
#define RETURN_NULL(type) do { *isNull = true; return (type) 0; } while (0) #define RETURN_NULL(type) do { *isNull = true; return (type) 0; } while (0)
static int ArrayCount(char *str, int *dim, int typdelim); static int ArrayCount(char *str, int *dim, char typdelim);
static Datum *ReadArrayStr(char *arrayStr, int nitems, int ndim, int *dim, static Datum *ReadArrayStr(char *arrayStr, int nitems, int ndim, int *dim,
FmgrInfo *inputproc, Oid typelem, int32 typmod, FmgrInfo *inputproc, Oid typelem, int32 typmod,
char typdelim, int typlen, bool typbyval, char typdelim, int typlen, bool typbyval,
...@@ -245,7 +245,7 @@ array_in(PG_FUNCTION_ARGS) ...@@ -245,7 +245,7 @@ array_in(PG_FUNCTION_ARGS)
*----------------------------------------------------------------------------- *-----------------------------------------------------------------------------
*/ */
static int static int
ArrayCount(char *str, int *dim, int typdelim) ArrayCount(char *str, int *dim, char typdelim)
{ {
int nest_level = 0, int nest_level = 0,
i; i;
...@@ -253,7 +253,7 @@ ArrayCount(char *str, int *dim, int typdelim) ...@@ -253,7 +253,7 @@ ArrayCount(char *str, int *dim, int typdelim)
temp[MAXDIM]; temp[MAXDIM];
bool scanning_string = false; bool scanning_string = false;
bool eoArray = false; bool eoArray = false;
char *q; char *ptr;
for (i = 0; i < MAXDIM; ++i) for (i = 0; i < MAXDIM; ++i)
temp[i] = dim[i] = 0; temp[i] = dim[i] = 0;
...@@ -261,26 +261,24 @@ ArrayCount(char *str, int *dim, int typdelim) ...@@ -261,26 +261,24 @@ ArrayCount(char *str, int *dim, int typdelim)
if (strncmp(str, "{}", 2) == 0) if (strncmp(str, "{}", 2) == 0)
return 0; return 0;
q = str; ptr = str;
while (eoArray != true) while (!eoArray)
{ {
bool done = false; bool itemdone = false;
while (!done) while (!itemdone)
{ {
switch (*q) switch (*ptr)
{ {
case '\\':
/* skip escaped characters (\ and ") inside strings */
if (scanning_string && *(q + 1))
q++;
break;
case '\0': case '\0':
/* Signal a premature end of the string */
/* elog(ERROR, "malformed array constant: %s", str);
* Signal a premature end of the string. DZ - break;
* 2-9-1996 case '\\':
*/ /* skip the escaped character */
if (*(ptr + 1))
ptr++;
else
elog(ERROR, "malformed array constant: %s", str); elog(ERROR, "malformed array constant: %s", str);
break; break;
case '\"': case '\"':
...@@ -289,37 +287,42 @@ ArrayCount(char *str, int *dim, int typdelim) ...@@ -289,37 +287,42 @@ ArrayCount(char *str, int *dim, int typdelim)
case '{': case '{':
if (!scanning_string) if (!scanning_string)
{ {
if (nest_level >= MAXDIM)
elog(ERROR, "array_in: illformed array constant");
temp[nest_level] = 0; temp[nest_level] = 0;
nest_level++; nest_level++;
if (ndim < nest_level)
ndim = nest_level;
} }
break; break;
case '}': case '}':
if (!scanning_string) if (!scanning_string)
{ {
if (!ndim) if (nest_level == 0)
ndim = nest_level; elog(ERROR, "array_in: illformed array constant");
nest_level--; nest_level--;
if (nest_level)
temp[nest_level - 1]++;
if (nest_level == 0) if (nest_level == 0)
eoArray = done = true; eoArray = itemdone = true;
else
{
/*
* We don't set itemdone here; see comments in
* ReadArrayStr
*/
temp[nest_level - 1]++;
}
} }
break; break;
default: default:
if (!ndim) if (*ptr == typdelim && !scanning_string)
ndim = nest_level; itemdone = true;
if (*q == typdelim && !scanning_string)
done = true;
break; break;
} }
if (!done) if (!itemdone)
q++; ptr++;
} }
temp[ndim - 1]++; temp[ndim - 1]++;
q++; ptr++;
if (!eoArray)
while (isspace((unsigned char) *q))
q++;
} }
for (i = 0; i < ndim; ++i) for (i = 0; i < ndim; ++i)
dim[i] = temp[i]; dim[i] = temp[i];
...@@ -359,103 +362,119 @@ ReadArrayStr(char *arrayStr, ...@@ -359,103 +362,119 @@ ReadArrayStr(char *arrayStr,
int i, int i,
nest_level = 0; nest_level = 0;
Datum *values; Datum *values;
char *p, char *ptr;
*q,
*r;
bool scanning_string = false; bool scanning_string = false;
bool eoArray = false;
int indx[MAXDIM], int indx[MAXDIM],
prod[MAXDIM]; prod[MAXDIM];
bool eoArray = false;
mda_get_prod(ndim, dim, prod); mda_get_prod(ndim, dim, prod);
values = (Datum *) palloc(nitems * sizeof(Datum)); values = (Datum *) palloc(nitems * sizeof(Datum));
MemSet(values, 0, nitems * sizeof(Datum)); MemSet(values, 0, nitems * sizeof(Datum));
MemSet(indx, 0, sizeof(indx)); MemSet(indx, 0, sizeof(indx));
q = p = arrayStr;
/* read array enclosed within {} */ /* read array enclosed within {} */
ptr = arrayStr;
while (!eoArray) while (!eoArray)
{ {
bool done = false; bool itemdone = false;
int i = -1; int i = -1;
char *itemstart;
while (!done) /* skip leading whitespace */
while (isspace((unsigned char) *ptr))
ptr++;
itemstart = ptr;
while (!itemdone)
{ {
switch (*q) switch (*ptr)
{ {
case '\0':
/* Signal a premature end of the string */
elog(ERROR, "malformed array constant: %s", arrayStr);
break;
case '\\': case '\\':
{
char *cptr;
/* Crunch the string on top of the backslash. */ /* Crunch the string on top of the backslash. */
for (r = q; *r != '\0'; r++) for (cptr = ptr; *cptr != '\0'; cptr++)
*r = *(r + 1); *cptr = *(cptr + 1);
if (*ptr == '\0')
elog(ERROR, "malformed array constant: %s", arrayStr);
break; break;
}
case '\"': case '\"':
if (!scanning_string)
{ {
while (p != q) char *cptr;
p++;
p++; /* get p past first doublequote */
}
else
*q = '\0';
scanning_string = !scanning_string; scanning_string = !scanning_string;
/* Crunch the string on top of the quote. */
for (cptr = ptr; *cptr != '\0'; cptr++)
*cptr = *(cptr + 1);
/* Back up to not miss following character. */
ptr--;
break; break;
}
case '{': case '{':
if (!scanning_string) if (!scanning_string)
{ {
p++; if (nest_level >= ndim)
nest_level++;
if (nest_level > ndim)
elog(ERROR, "array_in: illformed array constant"); elog(ERROR, "array_in: illformed array constant");
nest_level++;
indx[nest_level - 1] = 0; indx[nest_level - 1] = 0;
indx[ndim - 1] = 0; /* skip leading whitespace */
while (isspace((unsigned char) *(ptr+1)))
ptr++;
itemstart = ptr+1;
} }
break; break;
case '}': case '}':
if (!scanning_string) if (!scanning_string)
{ {
if (nest_level == 0)
elog(ERROR, "array_in: illformed array constant");
if (i == -1) if (i == -1)
i = ArrayGetOffset0(ndim, indx, prod); i = ArrayGetOffset0(ndim, indx, prod);
indx[nest_level - 1] = 0;
nest_level--; nest_level--;
if (nest_level == 0) if (nest_level == 0)
eoArray = done = true; eoArray = itemdone = true;
else else
{ {
*q = '\0'; /*
* tricky coding: terminate item value string at
* first '}', but don't process it till we see
* a typdelim char or end of array. This handles
* case where several '}'s appear successively
* in a multidimensional array.
*/
*ptr = '\0';
indx[nest_level - 1]++; indx[nest_level - 1]++;
} }
} }
break; break;
default: default:
if (*q == typdelim && !scanning_string) if (*ptr == typdelim && !scanning_string)
{ {
if (i == -1) if (i == -1)
i = ArrayGetOffset0(ndim, indx, prod); i = ArrayGetOffset0(ndim, indx, prod);
done = true; itemdone = true;
indx[ndim - 1]++; indx[ndim - 1]++;
} }
break; break;
} }
if (!done) if (!itemdone)
q++; ptr++;
} }
*q = '\0'; *ptr++ = '\0';
if (i >= nitems) if (i < 0 || i >= nitems)
elog(ERROR, "array_in: illformed array constant"); elog(ERROR, "array_in: illformed array constant");
values[i] = FunctionCall3(inputproc, values[i] = FunctionCall3(inputproc,
CStringGetDatum(p), CStringGetDatum(itemstart),
ObjectIdGetDatum(typelem), ObjectIdGetDatum(typelem),
Int32GetDatum(typmod)); Int32GetDatum(typmod));
p = ++q;
/*
* if not at the end of the array skip white space
*/
if (!eoArray)
while (isspace((unsigned char) *q))
{
p++;
q++;
}
} }
/* /*
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment