arrayfuncs.c
来自「postgresql8.3.4源码,开源数据库」· C语言 代码 · 共 2,484 行 · 第 1/5 页
C
2,484 行
bitmask = 1; for (i = 0; i < nitems; i++) { bool needquote; /* Get source element, checking for NULL */ if (bitmap && (*bitmap & bitmask) == 0) { values[i] = pstrdup("NULL"); overall_length += 4; needquote = false; } else { Datum itemvalue; itemvalue = fetch_att(p, typbyval, typlen); values[i] = OutputFunctionCall(&my_extra->proc, itemvalue); p = att_addlength_pointer(p, typlen, p); p = (char *) att_align_nominal(p, typalign); /* count data plus backslashes; detect chars needing quotes */ if (values[i][0] == '\0') needquote = true; /* force quotes for empty string */ else if (pg_strcasecmp(values[i], "NULL") == 0) needquote = true; /* force quotes for literal NULL */ 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; /* advance bitmap pointer if any */ if (bitmap) { bitmask <<= 1; if (bitmask == 0x100) { bitmap++; bitmask = 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; Datum *dataPtr; bool *nullsPtr; bool hasnulls; int32 nbytes; int32 dataoffset; 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 && flags != 1) 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); } /* This checks for overflow of array dimensions */ 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 */ PG_RETURN_ARRAYTYPE_P(construct_empty_array(element_type)); } typlen = my_extra->typlen; typbyval = my_extra->typbyval; typalign = my_extra->typalign; typioparam = my_extra->typioparam; dataPtr = (Datum *) palloc(nitems * sizeof(Datum)); nullsPtr = (bool *) palloc(nitems * sizeof(bool)); ReadArrayBinary(buf, nitems, &my_extra->proc, typioparam, typmod, typlen, typbyval, typalign, dataPtr, nullsPtr, &hasnulls, &nbytes); if (hasnulls) { dataoffset = ARR_OVERHEAD_WITHNULLS(ndim, nitems); nbytes += dataoffset; } else { dataoffset = 0; /* marker for no null bitmap */ nbytes += ARR_OVERHEAD_NONULLS(ndim); } retval = (ArrayType *) palloc(nbytes); SET_VARSIZE(retval, nbytes); retval->ndim = ndim; retval->dataoffset = dataoffset; retval->elemtype = element_type; memcpy(ARR_DIMS(retval), dim, ndim * sizeof(int)); memcpy(ARR_LBOUND(retval), lBound, ndim * sizeof(int)); CopyArrayEls(retval, dataPtr, nullsPtr, nitems, typlen, typbyval, typalign, true); pfree(dataPtr); pfree(nullsPtr); PG_RETURN_ARRAYTYPE_P(retval);}/* * ReadArrayBinary: * collect the data elements of an array being read in binary style. * * Inputs: * buf: the data buffer to read from. * nitems: total number of array elements (already read). * receiveproc: type-specific receive procedure for element datatype. * typioparam, typmod: auxiliary values to pass to receiveproc. * 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 voidReadArrayBinary(StringInfo buf, int nitems, FmgrInfo *receiveproc, Oid typioparam, int32 typmod, int typlen, bool typbyval, char typalign, Datum *values, bool *nulls, bool *hasnulls, int32 *nbytes){ int i; bool hasnull; int32 totbytes; 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 < -1 || itemlen > (buf->len - buf->cursor)) ereport(ERROR, (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION), errmsg("insufficient data left in message"))); if (itemlen == -1) { /* -1 length means NULL */ values[i] = ReceiveFunctionCall(receiveproc, NULL, typioparam, typmod); nulls[i] = true; continue; } /* * 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] = ReceiveFunctionCall(receiveproc, &elem_buf, typioparam, typmod); nulls[i] = false; /* 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; } /* * 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;}/* * 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 = ARR_ELEMTYPE(v); int typlen; bool typbyval; char typalign; char *p; bits8 *bitmap; int bitmask; int nitems, i; int ndim, *dim; StringInfoData buf; ArrayMetaState *my_extra; /* * 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 = ~element_type; } 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, ARR_HASNULL(v) ? 1 : 0, 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);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?