📄 arrayfuncs.c
字号:
if (ndim < nest_level) ndim = nest_level; } break; case '}': if (!in_quotes) { /* * A right brace can occur after an element start, an * element completion, a quoted element completion, or * a level completion. */ if (parse_state != ARRAY_ELEM_STARTED && parse_state != ARRAY_ELEM_COMPLETED && parse_state != ARRAY_QUOTED_ELEM_COMPLETED && parse_state != ARRAY_LEVEL_COMPLETED && !(nest_level == 1 && parse_state == ARRAY_LEVEL_STARTED)) ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("malformed array literal: \"%s\"", str))); parse_state = ARRAY_LEVEL_COMPLETED; if (nest_level == 0) ereport(ERROR, (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 { /* * We don't set itemdone here; see comments in * ReadArrayStr */ temp[nest_level - 1]++; } } break; default: if (!in_quotes) { if (*ptr == typdelim) { /* * Delimiters can occur after an element start, an * element completion, a quoted element * completion, or a level completion. */ if (parse_state != ARRAY_ELEM_STARTED && parse_state != ARRAY_ELEM_COMPLETED && parse_state != ARRAY_QUOTED_ELEM_COMPLETED && parse_state != ARRAY_LEVEL_COMPLETED) ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("malformed array literal: \"%s\"", str))); if (parse_state == ARRAY_LEVEL_COMPLETED) parse_state = ARRAY_LEVEL_DELIMITED; else parse_state = ARRAY_ELEM_DELIMITED; itemdone = true; nelems[nest_level - 1]++; } else if (!isspace((unsigned char) *ptr)) { /* * Other non-space characters must be after a * level start, after an element start, or after * an element delimiter. In any case we now must * be past an element start. */ if (parse_state != ARRAY_LEVEL_STARTED && parse_state != ARRAY_ELEM_STARTED && parse_state != ARRAY_ELEM_DELIMITED) ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("malformed array literal: \"%s\"", str))); parse_state = ARRAY_ELEM_STARTED; } } break; } if (!itemdone) ptr++; } temp[ndim - 1]++; ptr++; } /* only whitespace is allowed after the closing brace */ while (*ptr) { if (!isspace((unsigned char) *ptr++)) ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("malformed array literal: \"%s\"", str))); } /* special case for an empty array */ if (empty_array) return 0; for (i = 0; i < ndim; ++i) dim[i] = temp[i]; return ndim;}/*--------------------------------------------------------------------------- * ReadArrayStr : * parses the array string pointed by "arrayStr" and converts it to * internal format. The external format expected is like C array * declaration. Unspecified elements are initialized to zero for fixed length * base types and to empty varlena structures for variable length base * types. (This is pretty bogus; NULL would be much safer.) * * result : * returns a palloc'd array of Datum representations of the array elements. * If element type is pass-by-ref, the Datums point to palloc'd values. * *nbytes is set to the amount of data space needed for the array, * including alignment padding but not including array header overhead. * * CAUTION: the contents of "arrayStr" will be modified! *--------------------------------------------------------------------------- */static Datum *ReadArrayStr(char *arrayStr, const char *origStr, int nitems, int ndim, int *dim, FmgrInfo *inputproc, Oid typioparam, int32 typmod, char typdelim, int typlen, bool typbyval, char typalign, int *nbytes){ int i, nest_level = 0; Datum *values; char *srcptr; bool in_quotes = false; bool eoArray = false; int totbytes; int indx[MAXDIM], prod[MAXDIM]; mda_get_prod(ndim, dim, prod); values = (Datum *) palloc0(nitems * sizeof(Datum)); MemSet(indx, 0, sizeof(indx)); /* * We have to remove " and \ characters to create a clean item value to * pass to the datatype input routine. We overwrite each item value * in-place within arrayStr to do this. srcptr is the current scan point, * and dstptr is where we are copying to. * * We also want to suppress leading and trailing unquoted whitespace. We * use the leadingspace flag to suppress leading space. Trailing space is * tracked by using dstendptr to point to the last significant output * character. * * The error checking in this routine is mostly pro-forma, since we expect * that ArrayCount() already validated the string. */ srcptr = arrayStr; while (!eoArray) { bool itemdone = false; bool leadingspace = true; char *itemstart; char *dstptr; char *dstendptr; i = -1; itemstart = dstptr = dstendptr = srcptr; while (!itemdone) { switch (*srcptr) { case '\0': /* Signal a premature end of the string */ ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("malformed array literal: \"%s\"", origStr))); break; case '\\': /* Skip backslash, copy next character as-is. */ srcptr++; if (*srcptr == '\0') ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("malformed array literal: \"%s\"", origStr))); *dstptr++ = *srcptr++; /* Treat the escaped character as non-whitespace */ leadingspace = false; dstendptr = dstptr; break; case '\"': in_quotes = !in_quotes; if (in_quotes) leadingspace = false; else { /* * Advance dstendptr when we exit in_quotes; this * saves having to do it in all the other in_quotes * cases. */ dstendptr = dstptr; } srcptr++; break; case '{': if (!in_quotes) { if (nest_level >= ndim) ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("malformed array literal: \"%s\"", origStr))); nest_level++; indx[nest_level - 1] = 0; srcptr++; } else *dstptr++ = *srcptr++; break; case '}': if (!in_quotes) { if (nest_level == 0) ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("malformed array literal: \"%s\"", origStr))); if (i == -1) i = ArrayGetOffset0(ndim, indx, prod); indx[nest_level - 1] = 0; nest_level--; if (nest_level == 0) eoArray = itemdone = true; else indx[nest_level - 1]++; srcptr++; } else *dstptr++ = *srcptr++; break; default: if (in_quotes) *dstptr++ = *srcptr++; else if (*srcptr == typdelim) { if (i == -1) i = ArrayGetOffset0(ndim, indx, prod); itemdone = true; indx[ndim - 1]++; srcptr++; } else if (isspace((unsigned char) *srcptr)) { /* * If leading space, drop it immediately. Else, copy * but don't advance dstendptr. */ if (leadingspace) srcptr++; else *dstptr++ = *srcptr++; } else { *dstptr++ = *srcptr++; leadingspace = false; dstendptr = dstptr; } break; } } Assert(dstptr < srcptr); *dstendptr = '\0'; if (i < 0 || i >= nitems) ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("malformed array literal: \"%s\"", origStr))); values[i] = FunctionCall3(inputproc, CStringGetDatum(itemstart), ObjectIdGetDatum(typioparam), Int32GetDatum(typmod)); } /* * Initialize any unset items and compute total data space needed */ if (typlen > 0) { totbytes = nitems * att_align(typlen, typalign); if (!typbyval) for (i = 0; i < nitems; i++) if (values[i] == (Datum) 0) values[i] = PointerGetDatum(palloc0(typlen)); } else { Assert(!typbyval); totbytes = 0; for (i = 0; i < nitems; i++) { if (values[i] != (Datum) 0) { /* let's just make sure data is not toasted */ if (typlen == -1) values[i] = PointerGetDatum(PG_DETOAST_DATUM(values[i])); totbytes = att_addlength(totbytes, typlen, values[i]); totbytes = att_align(totbytes, typalign); } else if (typlen == -1) { /* dummy varlena value (XXX bogus, see notes above) */ values[i] = PointerGetDatum(palloc(sizeof(int32))); VARATT_SIZEP(DatumGetPointer(values[i])) = sizeof(int32); totbytes += sizeof(int32); totbytes = att_align(totbytes, typalign); } else { /* dummy cstring value */ Assert(typlen == -2); values[i] = PointerGetDatum(palloc(1)); *((char *) DatumGetPointer(values[i])) = '\0'; totbytes += 1; totbytes = att_align(totbytes, typalign); } } } *nbytes = totbytes; return values;}/*---------- * Copy data into an array object from a temporary array of Datums. * * p: pointer to start of array data area * values: array of Datums to be copied * nitems: number of Datums to be copied * typbyval, typlen, typalign: info about element datatype * freedata: if TRUE and element type is pass-by-ref, pfree data values * referenced by Datums after copying them. * * If the input data is of varlena type, the caller must have ensured that * the values are not toasted. (Doing it here doesn't work since the * caller has already allocated space for the array...) *---------- */static voidCopyArrayEls(char *p, Datum *values, int nitems, int typlen, bool typbyval, char typalign, bool freedata){ int i; if (typbyval) freedata = false; for (i = 0; i < nitems; i++) { p += ArrayCastAndSet(values[i], typlen, typbyval, typalign, p); if (freedata) pfree(DatumGetPointer(values[i])); }}/*------------------------------------------------------------------------- * array_out : * takes the internal representation of an array and returns a string * containing the array in its external format. *------------------------------------------------------------------------- */Datumarray_out(PG_FUNCTION_ARGS){ ArrayType *v = PG_GETARG_ARRAYTYPE_P(0); Oid element_type; int typlen; bool typbyval; char typalign; char typdelim; char *p, *tmp, *retval, **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, j, k, indx[MAXDIM]; int ndim, *dims, *lb; ArrayMetaState *my_extra; element_type = ARR_ELEMTYPE(v); /* * We arrange to look up info about element type, including its output * conversion proc, only once per series of calls, assuming the element * type doesn't change underneath us. */ my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra; if (my_extra == NULL) { fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt, sizeof(ArrayMetaState)); my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra; my_extra->element_type = InvalidOid; } if (my_extra->element_type != element_type) { /* * Get info about element type, including its output conversion proc */ get_type_io_data(element_type, IOFunc_output, &my_extra->typlen, &my_extra->typbyval, &my_extra->typalign, &my_extra->typdelim, &my_extra->typioparam, &my_extra->typiofunc); fmgr_info_cxt(my_extra->typiofunc, &my_extra->proc, fcinfo->flinfo->fn_mcxt); my_extra->element_type = element_type; } typlen = my_extra->typlen; typbyval = my_extra->typbyval; typalign = my_extra->typalign; typdelim = my_extra->typdelim; ndim = ARR_NDIM(v); dims = ARR_DIMS(v); lb = ARR_LBOUND(v);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -