Skip to content

Commit 0f2fbbb

Browse files
committed
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.
1 parent 134fe5e commit 0f2fbbb

File tree

1 file changed

+95
-76
lines changed

1 file changed

+95
-76
lines changed

src/backend/utils/adt/arrayfuncs.c

Lines changed: 95 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/utils/adt/arrayfuncs.c,v 1.75 2002/03/02 00:34:24 tgl Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/utils/adt/arrayfuncs.c,v 1.76 2002/03/16 22:47:13 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -51,7 +51,7 @@
5151
#define RETURN_NULL(type) do { *isNull = true; return (type) 0; } while (0)
5252

5353

54-
static int ArrayCount(char *str, int *dim, int typdelim);
54+
static int ArrayCount(char *str, int *dim, char typdelim);
5555
static Datum *ReadArrayStr(char *arrayStr, int nitems, int ndim, int *dim,
5656
FmgrInfo *inputproc, Oid typelem, int32 typmod,
5757
char typdelim, int typlen, bool typbyval,
@@ -245,81 +245,84 @@ array_in(PG_FUNCTION_ARGS)
245245
*-----------------------------------------------------------------------------
246246
*/
247247
static int
248-
ArrayCount(char *str, int *dim, int typdelim)
248+
ArrayCount(char *str, int *dim, char typdelim)
249249
{
250250
int nest_level = 0,
251251
i;
252252
int ndim = 0,
253253
temp[MAXDIM];
254254
bool scanning_string = false;
255255
bool eoArray = false;
256-
char *q;
256+
char *ptr;
257257

258258
for (i = 0; i < MAXDIM; ++i)
259259
temp[i] = dim[i] = 0;
260260

261261
if (strncmp(str, "{}", 2) == 0)
262262
return 0;
263263

264-
q = str;
265-
while (eoArray != true)
264+
ptr = str;
265+
while (!eoArray)
266266
{
267-
bool done = false;
267+
bool itemdone = false;
268268

269-
while (!done)
269+
while (!itemdone)
270270
{
271-
switch (*q)
271+
switch (*ptr)
272272
{
273-
case '\\':
274-
/* skip escaped characters (\ and ") inside strings */
275-
if (scanning_string && *(q + 1))
276-
q++;
277-
break;
278273
case '\0':
279-
280-
/*
281-
* Signal a premature end of the string. DZ -
282-
* 2-9-1996
283-
*/
274+
/* Signal a premature end of the string */
284275
elog(ERROR, "malformed array constant: %s", str);
285276
break;
277+
case '\\':
278+
/* skip the escaped character */
279+
if (*(ptr + 1))
280+
ptr++;
281+
else
282+
elog(ERROR, "malformed array constant: %s", str);
283+
break;
286284
case '\"':
287285
scanning_string = !scanning_string;
288286
break;
289287
case '{':
290288
if (!scanning_string)
291289
{
290+
if (nest_level >= MAXDIM)
291+
elog(ERROR, "array_in: illformed array constant");
292292
temp[nest_level] = 0;
293293
nest_level++;
294+
if (ndim < nest_level)
295+
ndim = nest_level;
294296
}
295297
break;
296298
case '}':
297299
if (!scanning_string)
298300
{
299-
if (!ndim)
300-
ndim = nest_level;
301+
if (nest_level == 0)
302+
elog(ERROR, "array_in: illformed array constant");
301303
nest_level--;
302-
if (nest_level)
303-
temp[nest_level - 1]++;
304304
if (nest_level == 0)
305-
eoArray = done = true;
305+
eoArray = itemdone = true;
306+
else
307+
{
308+
/*
309+
* We don't set itemdone here; see comments in
310+
* ReadArrayStr
311+
*/
312+
temp[nest_level - 1]++;
313+
}
306314
}
307315
break;
308316
default:
309-
if (!ndim)
310-
ndim = nest_level;
311-
if (*q == typdelim && !scanning_string)
312-
done = true;
317+
if (*ptr == typdelim && !scanning_string)
318+
itemdone = true;
313319
break;
314320
}
315-
if (!done)
316-
q++;
321+
if (!itemdone)
322+
ptr++;
317323
}
318324
temp[ndim - 1]++;
319-
q++;
320-
if (!eoArray)
321-
while (isspace((unsigned char) *q))
322-
q++;
325+
ptr++;
323326
}
324327
for (i = 0; i < ndim; ++i)
325328
dim[i] = temp[i];
@@ -359,103 +362,119 @@ ReadArrayStr(char *arrayStr,
359362
int i,
360363
nest_level = 0;
361364
Datum *values;
362-
char *p,
363-
*q,
364-
*r;
365+
char *ptr;
365366
bool scanning_string = false;
367+
bool eoArray = false;
366368
int indx[MAXDIM],
367369
prod[MAXDIM];
368-
bool eoArray = false;
369370

370371
mda_get_prod(ndim, dim, prod);
371372
values = (Datum *) palloc(nitems * sizeof(Datum));
372373
MemSet(values, 0, nitems * sizeof(Datum));
373374
MemSet(indx, 0, sizeof(indx));
374-
q = p = arrayStr;
375375

376376
/* read array enclosed within {} */
377+
ptr = arrayStr;
377378
while (!eoArray)
378379
{
379-
bool done = false;
380+
bool itemdone = false;
380381
int i = -1;
382+
char *itemstart;
383+
384+
/* skip leading whitespace */
385+
while (isspace((unsigned char) *ptr))
386+
ptr++;
387+
itemstart = ptr;
381388

382-
while (!done)
389+
while (!itemdone)
383390
{
384-
switch (*q)
391+
switch (*ptr)
385392
{
393+
case '\0':
394+
/* Signal a premature end of the string */
395+
elog(ERROR, "malformed array constant: %s", arrayStr);
396+
break;
386397
case '\\':
398+
{
399+
char *cptr;
400+
387401
/* Crunch the string on top of the backslash. */
388-
for (r = q; *r != '\0'; r++)
389-
*r = *(r + 1);
402+
for (cptr = ptr; *cptr != '\0'; cptr++)
403+
*cptr = *(cptr + 1);
404+
if (*ptr == '\0')
405+
elog(ERROR, "malformed array constant: %s", arrayStr);
390406
break;
407+
}
391408
case '\"':
392-
if (!scanning_string)
393-
{
394-
while (p != q)
395-
p++;
396-
p++; /* get p past first doublequote */
397-
}
398-
else
399-
*q = '\0';
409+
{
410+
char *cptr;
411+
400412
scanning_string = !scanning_string;
413+
/* Crunch the string on top of the quote. */
414+
for (cptr = ptr; *cptr != '\0'; cptr++)
415+
*cptr = *(cptr + 1);
416+
/* Back up to not miss following character. */
417+
ptr--;
401418
break;
419+
}
402420
case '{':
403421
if (!scanning_string)
404422
{
405-
p++;
406-
nest_level++;
407-
if (nest_level > ndim)
423+
if (nest_level >= ndim)
408424
elog(ERROR, "array_in: illformed array constant");
425+
nest_level++;
409426
indx[nest_level - 1] = 0;
410-
indx[ndim - 1] = 0;
427+
/* skip leading whitespace */
428+
while (isspace((unsigned char) *(ptr+1)))
429+
ptr++;
430+
itemstart = ptr+1;
411431
}
412432
break;
413433
case '}':
414434
if (!scanning_string)
415435
{
436+
if (nest_level == 0)
437+
elog(ERROR, "array_in: illformed array constant");
416438
if (i == -1)
417439
i = ArrayGetOffset0(ndim, indx, prod);
440+
indx[nest_level - 1] = 0;
418441
nest_level--;
419442
if (nest_level == 0)
420-
eoArray = done = true;
443+
eoArray = itemdone = true;
421444
else
422445
{
423-
*q = '\0';
446+
/*
447+
* tricky coding: terminate item value string at
448+
* first '}', but don't process it till we see
449+
* a typdelim char or end of array. This handles
450+
* case where several '}'s appear successively
451+
* in a multidimensional array.
452+
*/
453+
*ptr = '\0';
424454
indx[nest_level - 1]++;
425455
}
426456
}
427457
break;
428458
default:
429-
if (*q == typdelim && !scanning_string)
459+
if (*ptr == typdelim && !scanning_string)
430460
{
431461
if (i == -1)
432462
i = ArrayGetOffset0(ndim, indx, prod);
433-
done = true;
463+
itemdone = true;
434464
indx[ndim - 1]++;
435465
}
436466
break;
437467
}
438-
if (!done)
439-
q++;
468+
if (!itemdone)
469+
ptr++;
440470
}
441-
*q = '\0';
442-
if (i >= nitems)
471+
*ptr++ = '\0';
472+
if (i < 0 || i >= nitems)
443473
elog(ERROR, "array_in: illformed array constant");
444474
values[i] = FunctionCall3(inputproc,
445-
CStringGetDatum(p),
475+
CStringGetDatum(itemstart),
446476
ObjectIdGetDatum(typelem),
447477
Int32GetDatum(typmod));
448-
p = ++q;
449-
450-
/*
451-
* if not at the end of the array skip white space
452-
*/
453-
if (!eoArray)
454-
while (isspace((unsigned char) *q))
455-
{
456-
p++;
457-
q++;
458-
}
459478
}
460479

461480
/*

0 commit comments

Comments
 (0)