📄 arrayfuncs.c
字号:
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)); p = ARR_DATA_PTR(v); overall_length = 1; /* don't forget to count \0 at end. */ for (i = 0; i < nitems; i++) { Datum itemvalue; bool needquote; itemvalue = fetch_att(p, typbyval, typlen); values[i] = DatumGetCString(FunctionCall1(&my_extra->proc, itemvalue)); p = att_addlength(p, typlen, PointerGetDatum(p)); p = (char *) att_align(p, typalign); /* count data plus backslashes; detect chars needing quotes */ if (values[i][0] == '\0') needquote = true; /* force quotes for empty string */ else needquote = false; for (tmp = values[i]; *tmp != '\0'; tmp++) { char ch = *tmp; overall_length += 1; if (ch == '"' || ch == '\\') { needquote = true;#ifndef TCL_ARRAYS overall_length += 1;#endif } else if (ch == '{' || ch == '}' || ch == typdelim || isspace((unsigned char) ch)) needquote = true; } needquotes[i] = needquote; /* Count the pair of double quotes, if needed */ if (needquote) overall_length += 2; /* and the comma */ overall_length += 1; } /* * count total number of curly braces in output string */ for (i = j = 0, k = 1; i < ndim; i++) k *= dims[i], j += k; dims_str[0] = '\0'; /* 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] + dims[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; i++) indx[i] = 0; j = 0; k = 0; do { for (i = j; i < ndim - 1; i++) APPENDCHAR('{'); if (needquotes[k]) { APPENDCHAR('"');#ifndef TCL_ARRAYS for (tmp = values[k]; *tmp; tmp++) { char ch = *tmp; if (ch == '"' || ch == '\\') *p++ = '\\'; *p++ = ch; } *p = '\0';#else APPENDSTR(values[k]);#endif APPENDCHAR('"'); } else APPENDSTR(values[k]); pfree(values[k++]); for (i = ndim - 1; i >= 0; i--) { indx[i] = (indx[i] + 1) % dims[i]; if (indx[i]) { APPENDCHAR(typdelim); break; } else APPENDCHAR('}'); } j = i; } while (j != -1);#undef APPENDSTR#undef APPENDCHAR pfree(values); pfree(needquotes); PG_RETURN_CSTRING(retval);}/*--------------------------------------------------------------------- * array_recv : * converts an array from the external binary format to * its internal format. * return value : * the internal representation of the input array *-------------------------------------------------------------------- */Datumarray_recv(PG_FUNCTION_ARGS){ StringInfo buf = (StringInfo) PG_GETARG_POINTER(0); Oid spec_element_type = PG_GETARG_OID(1); /* type of an array * element */ int32 typmod = PG_GETARG_INT32(2); /* typmod for array elements */ Oid element_type; int typlen; bool typbyval; char typalign; Oid typioparam; int i, nitems; int32 nbytes; Datum *dataPtr; ArrayType *retval; int ndim, flags, dim[MAXDIM], lBound[MAXDIM]; ArrayMetaState *my_extra; /* Get the array header information */ ndim = pq_getmsgint(buf, 4); if (ndim < 0) /* we do allow zero-dimension arrays */ ereport(ERROR, (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION), errmsg("invalid number of dimensions: %d", ndim))); if (ndim > MAXDIM) ereport(ERROR, (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)", ndim, MAXDIM))); flags = pq_getmsgint(buf, 4); if (flags != 0) ereport(ERROR, (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION), errmsg("invalid array flags"))); element_type = pq_getmsgint(buf, sizeof(Oid)); if (element_type != spec_element_type) { /* XXX Can we allow taking the input element type in any cases? */ ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("wrong element type"))); } for (i = 0; i < ndim; i++) { dim[i] = pq_getmsgint(buf, 4); lBound[i] = pq_getmsgint(buf, 4); } nitems = ArrayGetNItems(ndim, dim); /* * We arrange to look up info about element type, including its receive * 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 receive proc */ get_type_io_data(element_type, IOFunc_receive, &my_extra->typlen, &my_extra->typbyval, &my_extra->typalign, &my_extra->typdelim, &my_extra->typioparam, &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; } if (nitems == 0) { /* Return empty array ... but not till we've validated element_type */ retval = (ArrayType *) palloc0(sizeof(ArrayType)); retval->size = sizeof(ArrayType); retval->elemtype = element_type; PG_RETURN_ARRAYTYPE_P(retval); } typlen = my_extra->typlen; typbyval = my_extra->typbyval; typalign = my_extra->typalign; typioparam = my_extra->typioparam; dataPtr = ReadArrayBinary(buf, nitems, &my_extra->proc, typioparam, typmod, typlen, typbyval, typalign, &nbytes); nbytes += ARR_OVERHEAD(ndim); retval = (ArrayType *) palloc0(nbytes); retval->size = nbytes; retval->ndim = ndim; retval->elemtype = element_type; memcpy(ARR_DIMS(retval), dim, ndim * sizeof(int)); memcpy(ARR_LBOUND(retval), 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 typioparam, int32 typmod, 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] = FunctionCall3(receiveproc, PointerGetDatum(&elem_buf), ObjectIdGetDatum(typioparam), Int32GetDatum(typmod)); /* 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; 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->typioparam, &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; 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(FunctionCall1(&my_extra->proc, itemvalue)); /* We assume the result will not have been toasted */ pq_sendint(&buf, VARSIZE(outputbytes) - VARHDRSZ, 4); pq_sendbytes(&buf, VARDATA(outputbytes),
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -