arrayfuncs.c
来自「postgresql8.3.4源码,开源数据库」· C语言 代码 · 共 2,484 行 · 第 1/5 页
C
2,484 行
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 to by "arrayStr" and converts the values * to internal format. Unspecified elements are initialized to nulls. * The array dimensions must already have been determined. * * Inputs: * arrayStr: the string to parse. * CAUTION: the contents of "arrayStr" will be modified! * origStr: the unmodified input string, used only in error messages. * nitems: total number of array elements, as already determined. * ndim: number of array dimensions * dim[]: array axis lengths * inputproc: type-specific input procedure for element datatype. * typioparam, typmod: auxiliary values to pass to inputproc. * typdelim: the value delimiter (type-specific). * typlen, typbyval, typalign: storage parameters of element datatype. * * Outputs: * values[]: filled with converted data values. * nulls[]: filled with is-null markers. * *hasnulls: set TRUE iff there are any null elements. * *nbytes: set to total size of data area needed (including alignment * padding but not including array header overhead). * * Note that values[] and nulls[] are allocated by the caller, and must have * nitems elements. */static voidReadArrayStr(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, Datum *values, bool *nulls, bool *hasnulls, int32 *nbytes){ int i, nest_level = 0; char *srcptr; bool in_quotes = false; bool eoArray = false; bool hasnull; int32 totbytes; int indx[MAXDIM], prod[MAXDIM]; mda_get_prod(ndim, dim, prod); MemSet(indx, 0, sizeof(indx)); /* Initialize is-null markers to true */ memset(nulls, true, nitems * sizeof(bool)); /* * 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; bool hasquoting = false; 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; hasquoting = true; /* can't be a NULL marker */ 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; } hasquoting = true; /* can't be a NULL marker */ 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))); if (Array_nulls && !hasquoting && pg_strcasecmp(itemstart, "NULL") == 0) { /* it's a NULL item */ values[i] = InputFunctionCall(inputproc, NULL, typioparam, typmod); nulls[i] = true; } else { values[i] = InputFunctionCall(inputproc, itemstart, typioparam, typmod); nulls[i] = false; } } /* * Check for nulls, compute total data space needed */ hasnull = false; totbytes = 0; for (i = 0; i < nitems; i++) { if (nulls[i]) hasnull = true; else { /* let's just make sure data is not toasted */ if (typlen == -1) values[i] = PointerGetDatum(PG_DETOAST_DATUM(values[i])); totbytes = att_addlength_datum(totbytes, typlen, values[i]); totbytes = att_align_nominal(totbytes, typalign); /* check for overflow of total request */ if (!AllocSizeIsValid(totbytes)) ereport(ERROR, (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), errmsg("array size exceeds the maximum allowed (%d)", (int) MaxAllocSize))); } } *hasnulls = hasnull; *nbytes = totbytes;}/* * Copy data into an array object from a temporary array of Datums. * * array: array object (with header fields already filled in) * values: array of Datums to be copied * nulls: array of is-null flags (can be NULL if no nulls) * 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(ArrayType *array, Datum *values, bool *nulls, int nitems, int typlen, bool typbyval, char typalign, bool freedata){ char *p = ARR_DATA_PTR(array); bits8 *bitmap = ARR_NULLBITMAP(array); int bitval = 0; int bitmask = 1; int i; if (typbyval) freedata = false; for (i = 0; i < nitems; i++) { if (nulls && nulls[i]) { if (!bitmap) /* shouldn't happen */ elog(ERROR, "null array element where not supported"); /* bitmap bit stays 0 */ } else { bitval |= bitmask; p += ArrayCastAndSet(values[i], typlen, typbyval, typalign, p); if (freedata) pfree(DatumGetPointer(values[i])); } if (bitmap) { bitmask <<= 1; if (bitmask == 0x100) { *bitmap++ = bitval; bitval = 0; bitmask = 1; } } } if (bitmap && bitmask != 1) *bitmap = bitval;}/* * 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 = ARR_ELEMTYPE(v); int typlen; bool typbyval; char typalign; char typdelim; char *p, *tmp, *retval, **values, dims_str[(MAXDIM * 33) + 2]; /* * 33 per dim since we assume 15 digits per number + ':' +'[]' * * +2 allows for assignment operator + trailing null */ bits8 *bitmap; int bitmask; bool *needquotes, needdims = false; int nitems, overall_length, i, j, k, indx[MAXDIM]; int ndim, *dims, *lb; ArrayMetaState *my_extra; /* * 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 = ~element_type; } 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); nitems = ArrayGetNItems(ndim, dims); if (nitems == 0) { retval = pstrdup("{}"); PG_RETURN_CSTRING(retval); } /* * 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. */ values = (char **) palloc(nitems * sizeof(char *)); needquotes = (bool *) palloc(nitems * sizeof(bool)); overall_length = 1; /* don't forget to count \0 at end. */ p = ARR_DATA_PTR(v); bitmap = ARR_NULLBITMAP(v);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?