arrayfuncs.c
来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 2,367 行 · 第 1/5 页
C
2,367 行
ptr++; itemstart = ptr; 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\"", arrayStr))); break; case '\\': { char *cptr; /* Crunch the string on top of the backslash. */ for (cptr = ptr; *cptr != '\0'; cptr++) *cptr = *(cptr + 1); if (*ptr == '\0') ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("malformed array literal: \"%s\"", arrayStr))); break; } case '\"': { char *cptr; scanning_string = !scanning_string; /* Crunch the string on top of the quote. */ for (cptr = ptr; *cptr != '\0'; cptr++) *cptr = *(cptr + 1); /* Back up to not miss following character. */ ptr--; break; } case '{': if (!scanning_string) { if (nest_level >= ndim) ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("malformed array literal: \"%s\"", arrayStr))); nest_level++; indx[nest_level - 1] = 0; /* skip leading whitespace */ while (isspace((unsigned char) *(ptr + 1))) ptr++; itemstart = ptr + 1; } break; case '}': if (!scanning_string) { if (nest_level == 0) ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("malformed array literal: \"%s\"", arrayStr))); if (i == -1) i = ArrayGetOffset0(ndim, indx, prod); indx[nest_level - 1] = 0; nest_level--; if (nest_level == 0) eoArray = itemdone = true; else { /* * tricky coding: terminate item value string * at first '}', but don't process it till we * see a typdelim char or end of array. This * handles case where several '}'s appear * successively in a multidimensional array. */ *ptr = '\0'; indx[nest_level - 1]++; } } break; default: if (*ptr == typdelim && !scanning_string) { if (i == -1) i = ArrayGetOffset0(ndim, indx, prod); itemdone = true; indx[ndim - 1]++; } break; } if (!itemdone) ptr++; } *ptr++ = '\0'; if (i < 0 || i >= nitems) ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("malformed array literal: \"%s\"", arrayStr))); values[i] = FunctionCall3(inputproc, CStringGetDatum(itemstart), ObjectIdGetDatum(typelem), Int32GetDatum(typmod)); } /* * Initialize any unset items and compute total data space needed */ if (typlen > 0) { *nbytes = nitems * att_align(typlen, typalign); if (!typbyval) for (i = 0; i < nitems; i++) if (values[i] == (Datum) 0) values[i] = PointerGetDatum(palloc0(typlen)); } else { Assert(!typbyval); *nbytes = 0; for (i = 0; i < nitems; i++) { if (values[i] != (Datum) 0) { /* 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); } else if (typlen == -1) { /* dummy varlena value (XXX bogus, see notes above) */ values[i] = PointerGetDatum(palloc(sizeof(int32))); VARATT_SIZEP(DatumGetPointer(values[i])) = sizeof(int32); *nbytes += sizeof(int32); *nbytes = att_align(*nbytes, typalign); } else { /* dummy cstring value */ Assert(typlen == -2); values[i] = PointerGetDatum(palloc(1)); *((char *) DatumGetPointer(values[i])) = '\0'; *nbytes += 1; *nbytes = att_align(*nbytes, typalign); } } } return values;}/*---------- * Copy data into an array object from a temporary array of Datums. * * p: pointer to start of array data area * values: array of Datums to be copied * 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(char *p, Datum *values, int nitems, int typlen, bool typbyval, char typalign, bool freedata){ int i; if (typbyval) freedata = false; for (i = 0; i < nitems; i++) { p += ArrayCastAndSet(values[i], typlen, typbyval, typalign, p); if (freedata) pfree(DatumGetPointer(values[i])); }}/*------------------------------------------------------------------------- * 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; int typlen; bool typbyval; char typalign; char typdelim; Oid typelem; char *p, *tmp, *retval, **values; bool *needquotes; int nitems, overall_length, i, j, k, indx[MAXDIM]; int ndim, *dim; ArrayMetaState *my_extra; element_type = ARR_ELEMTYPE(v); /* * 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 = InvalidOid; } 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->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; ndim = ARR_NDIM(v); dim = ARR_DIMS(v); nitems = ArrayGetNItems(ndim, dim); if (nitems == 0) { retval = pstrdup("{}"); PG_RETURN_CSTRING(retval); } /* * 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; /* [TRH] don't forget to count \0 at end. */ for (i = 0; i < nitems; i++) { Datum itemvalue; bool nq; itemvalue = fetch_att(p, typbyval, typlen); values[i] = DatumGetCString(FunctionCall3(&my_extra->proc, itemvalue, ObjectIdGetDatum(typelem), Int32GetDatum(-1))); p = att_addlength(p, typlen, PointerGetDatum(p)); p = (char *) att_align(p, typalign); /* count data plus backslashes; detect chars needing quotes */ nq = (values[i][0] == '\0'); /* force quotes for empty string */ for (tmp = values[i]; *tmp; tmp++) { char ch = *tmp; overall_length += 1; if (ch == '"' || ch == '\\') { nq = true;#ifndef TCL_ARRAYS overall_length += 1;#endif } else if (ch == '{' || ch == '}' || ch == typdelim || isspace((unsigned char) ch)) nq = true; } needquotes[i] = nq; /* Count the pair of double quotes, if needed */ if (nq) 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; k *= dim[i++], j += k); retval = (char *) palloc(overall_length + 2 * j); p = retval;#define APPENDSTR(str) (strcpy(p, (str)), p += strlen(p))#define APPENDCHAR(ch) (*p++ = (ch), *p = '\0') APPENDCHAR('{'); for (i = 0; i < ndim; 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) % dim[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 */ Oid element_type; int typlen; bool typbyval; char typalign; Oid typelem; 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); if (nitems == 0) { /* Return empty array */ retval = (ArrayType *) palloc0(sizeof(ArrayType)); retval->size = sizeof(ArrayType); retval->elemtype = element_type; PG_RETURN_ARRAYTYPE_P(retval); } /* * 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 = InvalidOid; } if (my_extra->element_type != element_type) { /* Get info about element type, including its receive proc */ get_type_io_data(element_type, IOFunc_receive,
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?