diff options
author | Joe Conway <mail@joeconway.com> | 2004-08-05 03:30:44 +0000 |
---|---|---|
committer | Joe Conway <mail@joeconway.com> | 2004-08-05 03:30:44 +0000 |
commit | 0e13d627bebad769498696b5fd0ac821bde5140d (patch) | |
tree | fa38c02b12546fa68889ec06c8375dc901de36c3 /src/backend/utils/adt/arrayfuncs.c | |
parent | 39ec59f30fde11fede88a33e17357f794689310e (diff) | |
download | postgresql-0e13d627bebad769498696b5fd0ac821bde5140d.tar.gz postgresql-0e13d627bebad769498696b5fd0ac821bde5140d.zip |
Require that array literals produce "rectangular" arrays, i.e. all the
subarrays of a given dimension have the same number of elements/subarrays.
Also repair a longstanding undocumented (as far as I can see) ability to
explicitly set array bounds in the array literal syntax. It now can
deal properly with negative array indicies. Modify array_out so that
arrays with non-standard lower bounds (i.e. not 1) are output with
the expicit dimension syntax. This fixes a longstanding issue whereby
arrays with non-default lower bounds had them changed to default
after a dump/reload cycle.
Modify regression tests and docs to suit, and add some minimal
documentation regarding the explicit dimension syntax.
Diffstat (limited to 'src/backend/utils/adt/arrayfuncs.c')
-rw-r--r-- | src/backend/utils/adt/arrayfuncs.c | 97 |
1 files changed, 88 insertions, 9 deletions
diff --git a/src/backend/utils/adt/arrayfuncs.c b/src/backend/utils/adt/arrayfuncs.c index e9951d839a3..a8b1b636e08 100644 --- a/src/backend/utils/adt/arrayfuncs.c +++ b/src/backend/utils/adt/arrayfuncs.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/adt/arrayfuncs.c,v 1.105 2004/06/16 01:26:47 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/arrayfuncs.c,v 1.106 2004/08/05 03:29:37 joe Exp $ * *------------------------------------------------------------------------- */ @@ -217,7 +217,7 @@ array_in(PG_FUNCTION_ARGS) errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)", ndim, MAXDIM))); - for (q = p; isdigit((unsigned char) *q); q++); + for (q = p; isdigit((unsigned char) *q) || (*q == '-') || (*q == '+'); q++); if (q == p) /* no digits? */ ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), @@ -229,7 +229,7 @@ array_in(PG_FUNCTION_ARGS) *q = '\0'; lBound[ndim] = atoi(p); p = q + 1; - for (q = p; isdigit((unsigned char) *q); q++); + for (q = p; isdigit((unsigned char) *q) || (*q == '-') || (*q == '+'); q++); if (q == p) /* no digits? */ ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), @@ -270,6 +270,9 @@ array_in(PG_FUNCTION_ARGS) } else { + int ndim_braces, + dim_braces[MAXDIM]; + /* If array dimensions are given, expect '=' operator */ if (strncmp(p, ASSGN, strlen(ASSGN)) != 0) ereport(ERROR, @@ -278,6 +281,27 @@ array_in(PG_FUNCTION_ARGS) p += strlen(ASSGN); while (isspace((unsigned char) *p)) p++; + + /* + * intuit dimensions from brace structure -- it better match what + * we were given + */ + if (*p != '{') + ereport(ERROR, + (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), + errmsg("array value must start with \"{\" or dimension information"))); + ndim_braces = ArrayCount(p, dim_braces, typdelim); + if (ndim_braces != ndim) + ereport(ERROR, + (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), + errmsg("array dimensions incompatible with array literal"))); + for (i = 0; i < ndim; ++i) + { + if (dim[i] != dim_braces[i]) + ereport(ERROR, + (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), + errmsg("array dimensions incompatible with array literal"))); + } } #ifdef ARRAYDEBUG @@ -303,7 +327,6 @@ array_in(PG_FUNCTION_ARGS) ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("missing left brace"))); - dataPtr = ReadArrayStr(p, nitems, ndim, dim, &my_extra->proc, typioparam, typmod, typdelim, typlen, typbyval, typalign, &nbytes); @@ -334,13 +357,18 @@ ArrayCount(char *str, int *dim, char typdelim) int nest_level = 0, i; int ndim = 1, - temp[MAXDIM]; + temp[MAXDIM], + nelems[MAXDIM], + nelems_last[MAXDIM]; bool scanning_string = false; bool eoArray = false; char *ptr; for (i = 0; i < MAXDIM; ++i) + { temp[i] = dim[i] = 0; + nelems_last[i] = nelems[i] = 1; + } if (strncmp(str, "{}", 2) == 0) return 0; @@ -394,6 +422,16 @@ ArrayCount(char *str, int *dim, char typdelim) (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("malformed array literal: \"%s\"", str))); nest_level--; + + if ((nelems_last[nest_level] != 1) && + (nelems[nest_level] != nelems_last[nest_level])) + ereport(ERROR, + (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), + errmsg("multidimensional arrays must have " + "array expressions with matching " + "dimensions"))); + nelems_last[nest_level] = nelems[nest_level]; + nelems[nest_level] = 1; if (nest_level == 0) eoArray = itemdone = true; else @@ -408,7 +446,10 @@ ArrayCount(char *str, int *dim, char typdelim) break; default: if (*ptr == typdelim && !scanning_string) + { itemdone = true; + nelems[nest_level - 1]++; + } break; } if (!itemdone) @@ -684,8 +725,15 @@ array_out(PG_FUNCTION_ARGS) char *p, *tmp, *retval, - **values; - bool *needquotes; + **values, + /* + * 33 per dim since we assume 15 digits per number + ':' +'[]' + * + * +2 allows for assignment operator + trailing null + */ + dims_str[(MAXDIM * 33) + 2]; + bool *needquotes, + needdims = false; int nitems, overall_length, i, @@ -693,7 +741,8 @@ array_out(PG_FUNCTION_ARGS) k, indx[MAXDIM]; int ndim, - *dim; + *dim, + *lb; ArrayMetaState *my_extra; element_type = ARR_ELEMTYPE(v); @@ -734,6 +783,7 @@ array_out(PG_FUNCTION_ARGS) ndim = ARR_NDIM(v); dim = ARR_DIMS(v); + lb = ARR_LBOUND(v); nitems = ArrayGetNItems(ndim, dim); if (nitems == 0) @@ -743,6 +793,19 @@ array_out(PG_FUNCTION_ARGS) } /* + * we will need to add explicit dimensions if any dimension + * has a lower bound other than one + */ + for (i = 0; i < ndim; i++) + { + if (lb[i] != 1) + { + needdims = true; + break; + } + } + + /* * Convert all values to string form, count total space needed * (including any overhead such as escaping backslashes), and detect * whether each item needs double quotes. @@ -798,12 +861,28 @@ array_out(PG_FUNCTION_ARGS) */ for (i = j = 0, k = 1; i < ndim; k *= dim[i++], j += k); - retval = (char *) palloc(overall_length + 2 * j); + /* add explicit dimensions if required */ + if (needdims) + { + char *ptr = dims_str; + + for (i = 0; i < ndim; i++) + { + sprintf(ptr, "[%d:%d]", lb[i], lb[i] + dim[i] - 1); + ptr += strlen(ptr); + } + *ptr++ = *ASSGN; + *ptr = '\0'; + } + + retval = (char *) palloc(strlen(dims_str) + overall_length + 2 * j); p = retval; #define APPENDSTR(str) (strcpy(p, (str)), p += strlen(p)) #define APPENDCHAR(ch) (*p++ = (ch), *p = '\0') + if (needdims) + APPENDSTR(dims_str); APPENDCHAR('{'); for (i = 0; i < ndim; indx[i++] = 0); j = 0; |