mirror of
https://github.com/postgres/postgres.git
synced 2025-07-28 23:42:10 +03:00
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.
This commit is contained in:
@ -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 @@
|
|||||||
#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)
|
|||||||
*-----------------------------------------------------------------------------
|
*-----------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
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)
|
|||||||
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,65 +261,68 @@ 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 */
|
||||||
/*
|
|
||||||
* Signal a premature end of the string. DZ -
|
|
||||||
* 2-9-1996
|
|
||||||
*/
|
|
||||||
elog(ERROR, "malformed array constant: %s", str);
|
elog(ERROR, "malformed array constant: %s", str);
|
||||||
break;
|
break;
|
||||||
|
case '\\':
|
||||||
|
/* skip the escaped character */
|
||||||
|
if (*(ptr + 1))
|
||||||
|
ptr++;
|
||||||
|
else
|
||||||
|
elog(ERROR, "malformed array constant: %s", str);
|
||||||
|
break;
|
||||||
case '\"':
|
case '\"':
|
||||||
scanning_string = !scanning_string;
|
scanning_string = !scanning_string;
|
||||||
break;
|
break;
|
||||||
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)
|
|
||||||
ndim = nest_level;
|
|
||||||
nest_level--;
|
|
||||||
if (nest_level)
|
|
||||||
temp[nest_level - 1]++;
|
|
||||||
if (nest_level == 0)
|
if (nest_level == 0)
|
||||||
eoArray = done = true;
|
elog(ERROR, "array_in: illformed array constant");
|
||||||
|
nest_level--;
|
||||||
|
if (nest_level == 0)
|
||||||
|
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,
|
|||||||
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)
|
{
|
||||||
{
|
char *cptr;
|
||||||
while (p != q)
|
|
||||||
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++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
Reference in New Issue
Block a user