arrayfuncs.c
来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 2,367 行 · 第 1/5 页
C
2,367 行
/*------------------------------------------------------------------------- * * arrayfuncs.c * Support functions for arrays. * * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION * $Header: /cvsroot/pgsql/src/backend/utils/adt/arrayfuncs.c,v 1.100.2.1 2004/06/08 20:28:29 tgl Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#include <ctype.h>#include "access/tupmacs.h"#include "catalog/catalog.h"#include "catalog/pg_type.h"#include "libpq/pqformat.h"#include "parser/parse_coerce.h"#include "parser/parse_oper.h"#include "utils/array.h"#include "utils/builtins.h"#include "utils/datum.h"#include "utils/memutils.h"#include "utils/lsyscache.h"#include "utils/syscache.h"#include "utils/typcache.h"/*---------- * A standard varlena array has the following internal structure: * <size> - total number of bytes (also, TOAST info flags) * <ndim> - number of dimensions of the array * <flags> - bit mask of flags * <elemtype> - element type OID * <dim> - size of each array axis (C array of int) * <dim_lower> - lower boundary of each dimension (C array of int) * <actual data> - whatever is the stored data * The actual data starts on a MAXALIGN boundary. Individual items in the * array are aligned as specified by the array element type. * * NOTE: it is important that array elements of toastable datatypes NOT be * toasted, since the tupletoaster won't know they are there. (We could * support compressed toasted items; only out-of-line items are dangerous. * However, it seems preferable to store such items uncompressed and allow * the toaster to compress the whole array as one input.) * * There is currently no support for NULL elements in arrays, either. * A reasonable (and backwards-compatible) way to add support would be to * add a nulls bitmap following the <dim_lower> array, which would be present * if needed; and its presence would be signaled by a bit in the flags word. * * * There are also some "fixed-length array" datatypes, such as NAME and * OIDVECTOR. These are simply a sequence of a fixed number of items each * of a fixed-length datatype, with no overhead; the item size must be * a multiple of its alignment requirement, because we do no padding. * We support subscripting on these types, but array_in() and array_out() * only work with varlena arrays. *---------- *//* ---------- * Local definitions * ---------- */#define ASSGN "="#define RETURN_NULL(type) do { *isNull = true; return (type) 0; } while (0)static int ArrayCount(char *str, int *dim, char typdelim);static Datum *ReadArrayStr(char *arrayStr, int nitems, int ndim, int *dim, FmgrInfo *inputproc, Oid typelem, int32 typmod, char typdelim, int typlen, bool typbyval, char typalign, int *nbytes);static Datum *ReadArrayBinary(StringInfo buf, int nitems, FmgrInfo *receiveproc, Oid typelem, int typlen, bool typbyval, char typalign, int *nbytes);static void CopyArrayEls(char *p, Datum *values, int nitems, int typlen, bool typbyval, char typalign, bool freedata);static Datum ArrayCast(char *value, bool byval, int len);static int ArrayCastAndSet(Datum src, int typlen, bool typbyval, char typalign, char *dest);static int array_nelems_size(char *ptr, int nitems, int typlen, bool typbyval, char typalign);static char *array_seek(char *ptr, int nitems, int typlen, bool typbyval, char typalign);static int array_copy(char *destptr, int nitems, char *srcptr, int typlen, bool typbyval, char typalign);static int array_slice_size(int ndim, int *dim, int *lb, char *arraydataptr, int *st, int *endp, int typlen, bool typbyval, char typalign);static void array_extract_slice(int ndim, int *dim, int *lb, char *arraydataptr, int *st, int *endp, char *destPtr, int typlen, bool typbyval, char typalign);static void array_insert_slice(int ndim, int *dim, int *lb, char *origPtr, int origdatasize, char *destPtr, int *st, int *endp, char *srcPtr, int typlen, bool typbyval, char typalign);static int array_cmp(FunctionCallInfo fcinfo);/*--------------------------------------------------------------------- * array_in : * converts an array from the external format in "string" to * its internal format. * return value : * the internal representation of the input array *-------------------------------------------------------------------- */Datumarray_in(PG_FUNCTION_ARGS){ char *string = PG_GETARG_CSTRING(0); /* external form */ Oid element_type = PG_GETARG_OID(1); /* type of an array * element */ int32 typmod = PG_GETARG_INT32(2); /* typmod for array * elements */ int typlen; bool typbyval; char typalign; char typdelim; Oid typelem; char *string_save, *p; int i, nitems; int32 nbytes; Datum *dataPtr; ArrayType *retval; int ndim, dim[MAXDIM], lBound[MAXDIM]; ArrayMetaState *my_extra; /* * We arrange to look up info about element type, including its input * 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 input conversion * proc */ get_type_io_data(element_type, IOFunc_input, &my_extra->typlen, &my_extra->typbyval, &my_extra->typalign, &my_extra->typdelim, &my_extra->typelem, &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; typelem = my_extra->typelem; /* Make a modifiable copy of the input */ /* XXX why are we allocating an extra 2 bytes here? */ string_save = (char *) palloc(strlen(string) + 3); strcpy(string_save, string); /* * If the input string starts with dimension info, read and use that. * Otherwise, we require the input to be in curly-brace style, and we * prescan the input to determine dimensions. * * Dimension info takes the form of one or more [n] or [m:n] items. The * outer loop iterates once per dimension item. */ p = string_save; ndim = 0; for (;;) { char *q; int ub; /* * Note: we currently allow whitespace between, but not within, * dimension items. */ while (isspace((unsigned char) *p)) p++; if (*p != '[') break; /* no more dimension items */ p++; if (ndim >= MAXDIM) ereport(ERROR, (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)", ndim, MAXDIM))); for (q = p; isdigit((unsigned char) *q); q++); if (q == p) /* no digits? */ ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("missing dimension value"))); if (*q == ':') { /* [m:n] format */ *q = '\0'; lBound[ndim] = atoi(p); p = q + 1; for (q = p; isdigit((unsigned char) *q); q++); if (q == p) /* no digits? */ ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("missing dimension value"))); } else { /* [n] format */ lBound[ndim] = 1; } if (*q != ']') ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("missing \"]\" in array dimensions"))); *q = '\0'; ub = atoi(p); p = q + 1; if (ub < lBound[ndim]) ereport(ERROR, (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), errmsg("upper bound cannot be less than lower bound"))); dim[ndim] = ub - lBound[ndim] + 1; ndim++; } if (ndim == 0) { /* No array dimensions, so intuit dimensions from brace structure */ if (*p != '{') ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("array value must start with \"{\" or dimension information"))); ndim = ArrayCount(p, dim, typdelim); for (i = 0; i < ndim; i++) lBound[i] = 1; } else { /* If array dimensions are given, expect '=' operator */ if (strncmp(p, ASSGN, strlen(ASSGN)) != 0) ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("missing assignment operator"))); p += strlen(ASSGN); while (isspace((unsigned char) *p)) p++; }#ifdef ARRAYDEBUG printf("array_in- ndim %d (", ndim); for (i = 0; i < ndim; i++) { printf(" %d", dim[i]); }; printf(") for %s\n", string);#endif nitems = ArrayGetNItems(ndim, dim); if (nitems == 0) { /* Return empty array */ retval = (ArrayType *) palloc0(sizeof(ArrayType)); retval->size = sizeof(ArrayType); retval->elemtype = element_type; PG_RETURN_ARRAYTYPE_P(retval); } if (*p != '{') ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("missing left brace"))); dataPtr = ReadArrayStr(p, nitems, ndim, dim, &my_extra->proc, typelem, typmod, typdelim, typlen, typbyval, typalign, &nbytes); nbytes += ARR_OVERHEAD(ndim); retval = (ArrayType *) palloc0(nbytes); retval->size = nbytes; retval->ndim = ndim; retval->elemtype = element_type; memcpy((char *) ARR_DIMS(retval), (char *) dim, ndim * sizeof(int)); memcpy((char *) ARR_LBOUND(retval), (char *) lBound, ndim * sizeof(int)); CopyArrayEls(ARR_DATA_PTR(retval), dataPtr, nitems, typlen, typbyval, typalign, true); pfree(dataPtr); pfree(string_save); PG_RETURN_ARRAYTYPE_P(retval);}/*----------------------------------------------------------------------------- * ArrayCount * Counts the number of dimensions and the *dim array for an array string. * The syntax for array input is C-like nested curly braces *----------------------------------------------------------------------------- */static intArrayCount(char *str, int *dim, char typdelim){ int nest_level = 0, i; int ndim = 1, temp[MAXDIM]; bool scanning_string = false; bool eoArray = false; char *ptr; for (i = 0; i < MAXDIM; ++i) temp[i] = dim[i] = 0; if (strncmp(str, "{}", 2) == 0) return 0; ptr = str; while (!eoArray) { bool itemdone = false; while (!itemdone) { switch (*ptr) { case '\0': /* Signal a premature end of the string */ ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("malformed array literal: \"%s\"", str))); break; case '\\': /* skip the escaped character */ if (*(ptr + 1)) ptr++; else ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("malformed array literal: \"%s\"", str))); break; case '\"': scanning_string = !scanning_string; break; case '{': if (!scanning_string) { if (nest_level >= MAXDIM) ereport(ERROR, (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)", nest_level, MAXDIM))); temp[nest_level] = 0; nest_level++; if (ndim < nest_level) ndim = nest_level; } break; case '}': if (!scanning_string) { if (nest_level == 0) ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("malformed array literal: \"%s\"", str))); nest_level--; 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 (*ptr == typdelim && !scanning_string) itemdone = true; break; } if (!itemdone) ptr++; } temp[ndim - 1]++; ptr++; } 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" may be modified! *--------------------------------------------------------------------------- */static Datum *ReadArrayStr(char *arrayStr, int nitems, int ndim, int *dim, FmgrInfo *inputproc, Oid typelem, int32 typmod, char typdelim, int typlen, bool typbyval, char typalign, int *nbytes){ int i, nest_level = 0; Datum *values; char *ptr; bool scanning_string = false; bool eoArray = false; int indx[MAXDIM], prod[MAXDIM]; mda_get_prod(ndim, dim, prod); values = (Datum *) palloc0(nitems * sizeof(Datum)); MemSet(indx, 0, sizeof(indx)); /* read array enclosed within {} */ ptr = arrayStr; while (!eoArray) { bool itemdone = false; int i = -1; char *itemstart; /* skip leading whitespace */ while (isspace((unsigned char) *ptr))
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?