arrayfuncs.c
来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 2,367 行 · 第 1/5 页
C
2,367 行
&my_extra->typlen, &my_extra->typbyval, &my_extra->typalign, &my_extra->typdelim, &my_extra->typelem, &my_extra->typiofunc); if (!OidIsValid(my_extra->typiofunc)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_FUNCTION), errmsg("no binary input function available for type %s", format_type_be(element_type)))); 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; typelem = my_extra->typelem; dataPtr = ReadArrayBinary(buf, nitems, &my_extra->proc, typelem, 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); PG_RETURN_ARRAYTYPE_P(retval);}/*--------------------------------------------------------------------------- * ReadArrayBinary: * collect the data elements of an array being read in binary style. * 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. *--------------------------------------------------------------------------- */static Datum *ReadArrayBinary(StringInfo buf, int nitems, FmgrInfo *receiveproc, Oid typelem, int typlen, bool typbyval, char typalign, int *nbytes){ Datum *values; int i; values = (Datum *) palloc(nitems * sizeof(Datum)); for (i = 0; i < nitems; i++) { int itemlen; StringInfoData elem_buf; char csave; /* Get and check the item length */ itemlen = pq_getmsgint(buf, 4); if (itemlen < 0 || itemlen > (buf->len - buf->cursor)) ereport(ERROR, (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION), errmsg("insufficient data left in message"))); /* * Rather than copying data around, we just set up a phony * StringInfo pointing to the correct portion of the input buffer. * We assume we can scribble on the input buffer so as to maintain * the convention that StringInfos have a trailing null. */ elem_buf.data = &buf->data[buf->cursor]; elem_buf.maxlen = itemlen + 1; elem_buf.len = itemlen; elem_buf.cursor = 0; buf->cursor += itemlen; csave = buf->data[buf->cursor]; buf->data[buf->cursor] = '\0'; /* Now call the element's receiveproc */ values[i] = FunctionCall2(receiveproc, PointerGetDatum(&elem_buf), ObjectIdGetDatum(typelem)); /* Trouble if it didn't eat the whole buffer */ if (elem_buf.cursor != itemlen) ereport(ERROR, (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION), errmsg("improper binary format in array element %d", i + 1))); buf->data[buf->cursor] = csave; } /* * Compute total data space needed */ if (typlen > 0) *nbytes = nitems * att_align(typlen, typalign); else { Assert(!typbyval); *nbytes = 0; for (i = 0; i < nitems; i++) { /* let's just make sure data is not toasted */ if (typlen == -1) values[i] = PointerGetDatum(PG_DETOAST_DATUM(values[i])); *nbytes = att_addlength(*nbytes, typlen, values[i]); *nbytes = att_align(*nbytes, typalign); } } return values;}/*------------------------------------------------------------------------- * array_send : * takes the internal representation of an array and returns a bytea * containing the array in its external binary format. *------------------------------------------------------------------------- */Datumarray_send(PG_FUNCTION_ARGS){ ArrayType *v = PG_GETARG_ARRAYTYPE_P(0); Oid element_type; int typlen; bool typbyval; char typalign; Oid typelem; char *p; int nitems, i; int ndim, *dim; StringInfoData buf; ArrayMetaState *my_extra; /* Get information about the element type and the array dimensions */ element_type = ARR_ELEMTYPE(v); /* * We arrange to look up info about element type, including its send * 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 send proc */ get_type_io_data(element_type, IOFunc_send, &my_extra->typlen, &my_extra->typbyval, &my_extra->typalign, &my_extra->typdelim, &my_extra->typelem, &my_extra->typiofunc); if (!OidIsValid(my_extra->typiofunc)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_FUNCTION), errmsg("no binary output function available for type %s", format_type_be(element_type)))); 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; typelem = my_extra->typelem; ndim = ARR_NDIM(v); dim = ARR_DIMS(v); nitems = ArrayGetNItems(ndim, dim); pq_begintypsend(&buf); /* Send the array header information */ pq_sendint(&buf, ndim, 4); pq_sendint(&buf, v->flags, 4); pq_sendint(&buf, element_type, sizeof(Oid)); for (i = 0; i < ndim; i++) { pq_sendint(&buf, ARR_DIMS(v)[i], 4); pq_sendint(&buf, ARR_LBOUND(v)[i], 4); } /* Send the array elements using the element's own sendproc */ p = ARR_DATA_PTR(v); for (i = 0; i < nitems; i++) { Datum itemvalue; bytea *outputbytes; itemvalue = fetch_att(p, typbyval, typlen); outputbytes = DatumGetByteaP(FunctionCall2(&my_extra->proc, itemvalue, ObjectIdGetDatum(typelem))); /* We assume the result will not have been toasted */ pq_sendint(&buf, VARSIZE(outputbytes) - VARHDRSZ, 4); pq_sendbytes(&buf, VARDATA(outputbytes), VARSIZE(outputbytes) - VARHDRSZ); pfree(outputbytes); p = att_addlength(p, typlen, PointerGetDatum(p)); p = (char *) att_align(p, typalign); } PG_RETURN_BYTEA_P(pq_endtypsend(&buf));}/*------------------------------------------------------------------------- * array_length_coerce : * Apply the element type's length-coercion routine to each element * of the given array. *------------------------------------------------------------------------- */Datumarray_length_coerce(PG_FUNCTION_ARGS){ ArrayType *v = PG_GETARG_ARRAYTYPE_P(0); int32 len = PG_GETARG_INT32(1); bool isExplicit = PG_GETARG_BOOL(2); FmgrInfo *fmgr_info = fcinfo->flinfo; typedef struct { Oid elemtype; FmgrInfo coerce_finfo; } alc_extra; alc_extra *my_extra; FunctionCallInfoData locfcinfo; /* If no typmod is provided, shortcircuit the whole thing */ if (len < 0) PG_RETURN_ARRAYTYPE_P(v); /* * We arrange to look up the element type's coercion function only * once per series of calls, assuming the element type doesn't change * underneath us. */ my_extra = (alc_extra *) fmgr_info->fn_extra; if (my_extra == NULL) { fmgr_info->fn_extra = MemoryContextAlloc(fmgr_info->fn_mcxt, sizeof(alc_extra)); my_extra = (alc_extra *) fmgr_info->fn_extra; my_extra->elemtype = InvalidOid; } if (my_extra->elemtype != ARR_ELEMTYPE(v)) { Oid funcId; int nargs; funcId = find_typmod_coercion_function(ARR_ELEMTYPE(v), &nargs); if (OidIsValid(funcId)) fmgr_info_cxt(funcId, &my_extra->coerce_finfo, fmgr_info->fn_mcxt); else my_extra->coerce_finfo.fn_oid = InvalidOid; my_extra->elemtype = ARR_ELEMTYPE(v); } /* * If we didn't find a coercion function, return the array unmodified * (this should not happen in the normal course of things, but might * happen if this function is called manually). */ if (my_extra->coerce_finfo.fn_oid == InvalidOid) PG_RETURN_ARRAYTYPE_P(v); /* * Use array_map to apply the function to each array element. * * Note: we pass isExplicit whether or not the function wants it ... */ MemSet(&locfcinfo, 0, sizeof(locfcinfo)); locfcinfo.flinfo = &my_extra->coerce_finfo; locfcinfo.nargs = 3; locfcinfo.arg[0] = PointerGetDatum(v); locfcinfo.arg[1] = Int32GetDatum(len); locfcinfo.arg[2] = BoolGetDatum(isExplicit); return array_map(&locfcinfo, ARR_ELEMTYPE(v), ARR_ELEMTYPE(v));}/*----------------------------------------------------------------------------- * array_dims : * returns the dimensions of the array pointed to by "v", as a "text" *---------------------------------------------------------------------------- */Datumarray_dims(PG_FUNCTION_ARGS){ ArrayType *v = PG_GETARG_ARRAYTYPE_P(0); text *result; char *p; int nbytes, i; int *dimv, *lb; /* Sanity check: does it look like an array at all? */ if (ARR_NDIM(v) <= 0 || ARR_NDIM(v) > MAXDIM) PG_RETURN_NULL(); nbytes = ARR_NDIM(v) * 33 + 1; /* * 33 since we assume 15 digits per number + ':' +'[]' * * +1 allows for temp trailing null */ result = (text *) palloc(nbytes + VARHDRSZ); p = VARDATA(result); dimv = ARR_DIMS(v); lb = ARR_LBOUND(v); for (i = 0; i < ARR_NDIM(v); i++) { sprintf(p, "[%d:%d]", lb[i], dimv[i] + lb[i] - 1); p += strlen(p); } VARATT_SIZEP(result) = strlen(VARDATA(result)) + VARHDRSZ; PG_RETURN_TEXT_P(result);}/*----------------------------------------------------------------------------- * array_lower : * returns the lower dimension, of the DIM requested, for * the array pointed to by "v", as an int4 *---------------------------------------------------------------------------- */Datumarray_lower(PG_FUNCTION_ARGS){ ArrayType *v = PG_GETARG_ARRAYTYPE_P(0); int reqdim = PG_GETARG_INT32(1); int *lb; int result; /* Sanity check: does it look like an array at all? */ if (ARR_NDIM(v) <= 0 || ARR_NDIM(v) > MAXDIM) PG_RETURN_NULL(); /* Sanity check: was the requested dim valid */ if (reqdim <= 0 || reqdim > ARR_NDIM(v)) PG_RETURN_NULL(); lb = ARR_LBOUND(v); result = lb[reqdim - 1]; PG_RETURN_INT32(result);}/*----------------------------------------------------------------------------- * array_upper : * returns the upper dimension, of the DIM requested, for * the array pointed to by "v", as an int4 *---------------------------------------------------------------------------- */Datumarray_upper(PG_FUNCTION_ARGS){ ArrayType *v = PG_GETARG_ARRAYTYPE_P(0); int reqdim = PG_GETARG_INT32(1); int *dimv, *lb; int result; /* Sanity check: does it look like an array at all? */ if (ARR_NDIM(v) <= 0 || ARR_NDIM(v) > MAXDIM) PG_RETURN_NULL(); /* Sanity check: was the requested dim valid */ if (reqdim <= 0 || reqdim > ARR_NDIM(v)) PG_RETURN_NULL(); lb = ARR_LBOUND(v); dimv = ARR_DIMS(v); result = dimv[reqdim - 1] + lb[reqdim - 1] - 1; PG_RETURN_INT32(result);}/*--------------------------------------------------------------------------- * array_ref : * This routine takes an array pointer and an index array and returns * the referenced item as a Datum. Note that for a pass-by-reference * datatype, the returned Datum is a pointer into the array object. *--------------------------------------------------------------------------- */Datumarray_ref(ArrayType *array, int nSubscripts, int *indx, int arraylen, int elmlen, bool elmbyval, char elmalign, bool *isNull){ int i, ndim, *dim, *lb, offset, fixedDim[1], fixedLb[1]; char *arraydataptr, *retptr; if (array == (ArrayType *) NULL) RETURN_NULL(Datum); if (arraylen > 0) { /* * fixed-length arrays -- these are assumed to be 1-d, 0-based */ ndim = 1; fixedDim[0] = arraylen / elmlen; fixedLb[0] = 0; dim = fixedDim; lb = fixedLb; arraydataptr = (char *) array; } else { /* detoast input array if necessary */ array = DatumGetArrayTypeP(PointerGetDatum(array)); ndim = ARR_NDIM(array); dim = ARR_DIMS(array); lb = ARR_LBOUND(array); arraydataptr = ARR_DATA_PTR(array); } /* * Return NULL for invalid subscript */ if (ndim != nSubscripts || ndim <= 0 || ndim > MAXDIM) RETURN_NULL(Datum); for (i = 0; i < ndim; i++) if (indx[i] < lb[i] || indx[i] >= (dim[i] + lb[i])) RETURN_NULL(Datum); /*
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?