|
8 | 8 | *
|
9 | 9 | *
|
10 | 10 | * 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 $ |
12 | 12 | *
|
13 | 13 | *-------------------------------------------------------------------------
|
14 | 14 | */
|
|
51 | 51 | #define RETURN_NULL(type) do { *isNull = true; return (type) 0; } while (0)
|
52 | 52 |
|
53 | 53 |
|
54 |
| -static int ArrayCount(char *str, int *dim, int typdelim); |
| 54 | +static int ArrayCount(char *str, int *dim, char typdelim); |
55 | 55 | static Datum *ReadArrayStr(char *arrayStr, int nitems, int ndim, int *dim,
|
56 | 56 | FmgrInfo *inputproc, Oid typelem, int32 typmod,
|
57 | 57 | char typdelim, int typlen, bool typbyval,
|
@@ -245,81 +245,84 @@ array_in(PG_FUNCTION_ARGS)
|
245 | 245 | *-----------------------------------------------------------------------------
|
246 | 246 | */
|
247 | 247 | static int
|
248 |
| -ArrayCount(char *str, int *dim, int typdelim) |
| 248 | +ArrayCount(char *str, int *dim, char typdelim) |
249 | 249 | {
|
250 | 250 | int nest_level = 0,
|
251 | 251 | i;
|
252 | 252 | int ndim = 0,
|
253 | 253 | temp[MAXDIM];
|
254 | 254 | bool scanning_string = false;
|
255 | 255 | bool eoArray = false;
|
256 |
| - char *q; |
| 256 | + char *ptr; |
257 | 257 |
|
258 | 258 | for (i = 0; i < MAXDIM; ++i)
|
259 | 259 | temp[i] = dim[i] = 0;
|
260 | 260 |
|
261 | 261 | if (strncmp(str, "{}", 2) == 0)
|
262 | 262 | return 0;
|
263 | 263 |
|
264 |
| - q = str; |
265 |
| - while (eoArray != true) |
| 264 | + ptr = str; |
| 265 | + while (!eoArray) |
266 | 266 | {
|
267 |
| - bool done = false; |
| 267 | + bool itemdone = false; |
268 | 268 |
|
269 |
| - while (!done) |
| 269 | + while (!itemdone) |
270 | 270 | {
|
271 |
| - switch (*q) |
| 271 | + switch (*ptr) |
272 | 272 | {
|
273 |
| - case '\\': |
274 |
| - /* skip escaped characters (\ and ") inside strings */ |
275 |
| - if (scanning_string && *(q + 1)) |
276 |
| - q++; |
277 |
| - break; |
278 | 273 | 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 */ |
284 | 275 | elog(ERROR, "malformed array constant: %s", str);
|
285 | 276 | 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; |
286 | 284 | case '\"':
|
287 | 285 | scanning_string = !scanning_string;
|
288 | 286 | break;
|
289 | 287 | case '{':
|
290 | 288 | if (!scanning_string)
|
291 | 289 | {
|
| 290 | + if (nest_level >= MAXDIM) |
| 291 | + elog(ERROR, "array_in: illformed array constant"); |
292 | 292 | temp[nest_level] = 0;
|
293 | 293 | nest_level++;
|
| 294 | + if (ndim < nest_level) |
| 295 | + ndim = nest_level; |
294 | 296 | }
|
295 | 297 | break;
|
296 | 298 | case '}':
|
297 | 299 | if (!scanning_string)
|
298 | 300 | {
|
299 |
| - if (!ndim) |
300 |
| - ndim = nest_level; |
| 301 | + if (nest_level == 0) |
| 302 | + elog(ERROR, "array_in: illformed array constant"); |
301 | 303 | nest_level--;
|
302 |
| - if (nest_level) |
303 |
| - temp[nest_level - 1]++; |
304 | 304 | 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 | + } |
306 | 314 | }
|
307 | 315 | break;
|
308 | 316 | 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; |
313 | 319 | break;
|
314 | 320 | }
|
315 |
| - if (!done) |
316 |
| - q++; |
| 321 | + if (!itemdone) |
| 322 | + ptr++; |
317 | 323 | }
|
318 | 324 | temp[ndim - 1]++;
|
319 |
| - q++; |
320 |
| - if (!eoArray) |
321 |
| - while (isspace((unsigned char) *q)) |
322 |
| - q++; |
| 325 | + ptr++; |
323 | 326 | }
|
324 | 327 | for (i = 0; i < ndim; ++i)
|
325 | 328 | dim[i] = temp[i];
|
@@ -359,103 +362,119 @@ ReadArrayStr(char *arrayStr,
|
359 | 362 | int i,
|
360 | 363 | nest_level = 0;
|
361 | 364 | Datum *values;
|
362 |
| - char *p, |
363 |
| - *q, |
364 |
| - *r; |
| 365 | + char *ptr; |
365 | 366 | bool scanning_string = false;
|
| 367 | + bool eoArray = false; |
366 | 368 | int indx[MAXDIM],
|
367 | 369 | prod[MAXDIM];
|
368 |
| - bool eoArray = false; |
369 | 370 |
|
370 | 371 | mda_get_prod(ndim, dim, prod);
|
371 | 372 | values = (Datum *) palloc(nitems * sizeof(Datum));
|
372 | 373 | MemSet(values, 0, nitems * sizeof(Datum));
|
373 | 374 | MemSet(indx, 0, sizeof(indx));
|
374 |
| - q = p = arrayStr; |
375 | 375 |
|
376 | 376 | /* read array enclosed within {} */
|
| 377 | + ptr = arrayStr; |
377 | 378 | while (!eoArray)
|
378 | 379 | {
|
379 |
| - bool done = false; |
| 380 | + bool itemdone = false; |
380 | 381 | int i = -1;
|
| 382 | + char *itemstart; |
| 383 | + |
| 384 | + /* skip leading whitespace */ |
| 385 | + while (isspace((unsigned char) *ptr)) |
| 386 | + ptr++; |
| 387 | + itemstart = ptr; |
381 | 388 |
|
382 |
| - while (!done) |
| 389 | + while (!itemdone) |
383 | 390 | {
|
384 |
| - switch (*q) |
| 391 | + switch (*ptr) |
385 | 392 | {
|
| 393 | + case '\0': |
| 394 | + /* Signal a premature end of the string */ |
| 395 | + elog(ERROR, "malformed array constant: %s", arrayStr); |
| 396 | + break; |
386 | 397 | case '\\':
|
| 398 | + { |
| 399 | + char *cptr; |
| 400 | + |
387 | 401 | /* 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); |
390 | 406 | break;
|
| 407 | + } |
391 | 408 | 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 | + |
400 | 412 | 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--; |
401 | 418 | break;
|
| 419 | + } |
402 | 420 | case '{':
|
403 | 421 | if (!scanning_string)
|
404 | 422 | {
|
405 |
| - p++; |
406 |
| - nest_level++; |
407 |
| - if (nest_level > ndim) |
| 423 | + if (nest_level >= ndim) |
408 | 424 | elog(ERROR, "array_in: illformed array constant");
|
| 425 | + nest_level++; |
409 | 426 | 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; |
411 | 431 | }
|
412 | 432 | break;
|
413 | 433 | case '}':
|
414 | 434 | if (!scanning_string)
|
415 | 435 | {
|
| 436 | + if (nest_level == 0) |
| 437 | + elog(ERROR, "array_in: illformed array constant"); |
416 | 438 | if (i == -1)
|
417 | 439 | i = ArrayGetOffset0(ndim, indx, prod);
|
| 440 | + indx[nest_level - 1] = 0; |
418 | 441 | nest_level--;
|
419 | 442 | if (nest_level == 0)
|
420 |
| - eoArray = done = true; |
| 443 | + eoArray = itemdone = true; |
421 | 444 | else
|
422 | 445 | {
|
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'; |
424 | 454 | indx[nest_level - 1]++;
|
425 | 455 | }
|
426 | 456 | }
|
427 | 457 | break;
|
428 | 458 | default:
|
429 |
| - if (*q == typdelim && !scanning_string) |
| 459 | + if (*ptr == typdelim && !scanning_string) |
430 | 460 | {
|
431 | 461 | if (i == -1)
|
432 | 462 | i = ArrayGetOffset0(ndim, indx, prod);
|
433 |
| - done = true; |
| 463 | + itemdone = true; |
434 | 464 | indx[ndim - 1]++;
|
435 | 465 | }
|
436 | 466 | break;
|
437 | 467 | }
|
438 |
| - if (!done) |
439 |
| - q++; |
| 468 | + if (!itemdone) |
| 469 | + ptr++; |
440 | 470 | }
|
441 |
| - *q = '\0'; |
442 |
| - if (i >= nitems) |
| 471 | + *ptr++ = '\0'; |
| 472 | + if (i < 0 || i >= nitems) |
443 | 473 | elog(ERROR, "array_in: illformed array constant");
|
444 | 474 | values[i] = FunctionCall3(inputproc,
|
445 |
| - CStringGetDatum(p), |
| 475 | + CStringGetDatum(itemstart), |
446 | 476 | ObjectIdGetDatum(typelem),
|
447 | 477 | 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 |
| - } |
459 | 478 | }
|
460 | 479 |
|
461 | 480 | /*
|
|
0 commit comments