📄 arrayfuncs.c
字号:
/*------------------------------------------------------------------------- * * arrayfuncs.c * Special functions for arrays. * * Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION * $Header: /usr/local/cvsroot/pgsql/src/backend/utils/adt/arrayfuncs.c,v 1.43.2.1 1999/08/02 05:24:49 scrappy Exp $ * *------------------------------------------------------------------------- */#include <ctype.h>#include "postgres.h"#include "catalog/catalog.h"#include "catalog/pg_type.h"#include "fmgr.h"#include "libpq/be-fsstubs.h"#include "libpq/libpq-fs.h"#include "storage/fd.h"#include "utils/array.h"#include "utils/memutils.h"#include "utils/syscache.h"#define ASSGN "="/* An array has the following internal structure: * <nbytes> - total number of bytes * <ndim> - number of dimensions of the array * <flags> - bit mask of flags * <dim> - size of each array axis * <dim_lower> - lower boundary of each dimension * <actual data> - whatever is the stored data *//*-=-=--=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-*/static int _ArrayCount(char *str, int *dim, int typdelim);static char *_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);#ifdef LOARRAYstatic char *_ReadLOArray(char *str, int *nbytes, int *fd, bool *chunkFlag, int ndim, int *dim, int baseSize);#endifstatic void _CopyArrayEls(char **values, char *p, int nitems, int typlen, char typalign, bool typbyval);static void system_cache_lookup(Oid element_type, bool input, int *typlen, bool *typbyval, char *typdelim, Oid *typelem, Oid *proc, char *typalign);static Datum _ArrayCast(char *value, bool byval, int len);#ifdef LOARRAYstatic char *_AdvanceBy1word(char *str, char **word);#endifstatic void _ArrayRange(int *st, int *endp, int bsize, char *destPtr, ArrayType *array, int from);static int _ArrayClipCount(int *stI, int *endpI, ArrayType *array);static void _LOArrayRange(int *st, int *endp, int bsize, int srcfd, int destfd, ArrayType *array, int isSrcLO, bool *isNull);static void _ReadArray(int *st, int *endp, int bsize, int srcfd, int destfd, ArrayType *array, int isDestLO, bool *isNull);static int ArrayCastAndSet(char *src, bool typbyval, int typlen, char *dest);static int SanityCheckInput(int ndim, int n, int *dim, int *lb, int *indx);static int array_read(char *destptr, int eltsize, int nitems, char *srcptr);static char *array_seek(char *ptr, int eltsize, int nitems);/*--------------------------------------------------------------------- * array_in : * converts an array from the external format in "string" to * it internal format. * return value : * the internal representation of the input array *-------------------------------------------------------------------- */char *array_in(char *string, /* input array in external form */ Oid element_type, /* type OID of an array element */ int32 typmod){ int typlen; bool typbyval, done; char typdelim; Oid typinput; Oid typelem; char *string_save, *p, *q, *r; FmgrInfo inputproc; int i, nitems; int32 nbytes; char *dataPtr; ArrayType *retval = NULL; int ndim, dim[MAXDIM], lBound[MAXDIM]; char typalign; system_cache_lookup(element_type, true, &typlen, &typbyval, &typdelim, &typelem, &typinput, &typalign); fmgr_info(typinput, &inputproc); string_save = (char *) palloc(strlen(string) + 3); strcpy(string_save, string); /* --- read array dimensions ---------- */ p = q = string_save; done = false; for (ndim = 0; !done;) { while (isspace(*p)) p++; if (*p == '[') { p++; if ((r = (char *) strchr(p, ':')) == (char *) NULL) lBound[ndim] = 1; else { *r = '\0'; lBound[ndim] = atoi(p); p = r + 1; } for (q = p; isdigit(*q); q++); if (*q != ']') elog(ERROR, "array_in: missing ']' in array declaration"); *q = '\0'; dim[ndim] = atoi(p); if ((dim[ndim] < 0) || (lBound[ndim] < 0)) elog(ERROR, "array_in: array dimensions need to be positive"); dim[ndim] = dim[ndim] - lBound[ndim] + 1; if (dim[ndim] < 0) elog(ERROR, "array_in: upper_bound cannot be < lower_bound"); p = q + 1; ndim++; } else done = true; } if (ndim == 0) { if (*p == '{') { ndim = _ArrayCount(p, dim, typdelim); for (i = 0; i < ndim; lBound[i++] = 1); } else elog(ERROR, "array_in: Need to specify dimension"); } else { while (isspace(*p)) p++; if (strncmp(p, ASSGN, strlen(ASSGN))) elog(ERROR, "array_in: missing assignment operator"); p += strlen(ASSGN); while (isspace(*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 = getNitems(ndim, dim); if (nitems == 0) { char *emptyArray = palloc(sizeof(ArrayType)); MemSet(emptyArray, 0, sizeof(ArrayType)); *(int32 *) emptyArray = sizeof(ArrayType); return emptyArray; } if (*p == '{') { /* array not a large object */ dataPtr = (char *) _ReadArrayStr(p, nitems, ndim, dim, &inputproc, typelem, typmod, typdelim, typlen, typbyval, typalign, &nbytes); nbytes += ARR_OVERHEAD(ndim); retval = (ArrayType *) palloc(nbytes); MemSet(retval, 0, nbytes); memmove(retval, (char *) &nbytes, sizeof(int)); memmove((char *) ARR_NDIM_PTR(retval), (char *) &ndim, sizeof(int)); SET_LO_FLAG(false, retval); memmove((char *) ARR_DIMS(retval), (char *) dim, ndim * sizeof(int)); memmove((char *) ARR_LBOUND(retval), (char *) lBound, ndim * sizeof(int)); /* * dataPtr is an array of arbitraystuff even though its type is * char* cast to char** to pass to _CopyArrayEls for now - jolly */ _CopyArrayEls((char **) dataPtr, ARR_DATA_PTR(retval), nitems, typlen, typalign, typbyval); } else {#ifdef LOARRAY int dummy, bytes; bool chunked = false; dataPtr = _ReadLOArray(p, &bytes, &dummy, &chunked, ndim, dim, typlen); nbytes = bytes + ARR_OVERHEAD(ndim); retval = (ArrayType *) palloc(nbytes); MemSet(retval, 0, nbytes); memmove(retval, (char *) &nbytes, sizeof(int)); memmove((char *) ARR_NDIM_PTR(retval), (char *) &ndim, sizeof(int)); SET_LO_FLAG(true, retval); SET_CHUNK_FLAG(chunked, retval); memmove((char *) ARR_DIMS(retval), (char *) dim, ndim * sizeof(int)); memmove((char *) ARR_LBOUND(retval), (char *) lBound, ndim * sizeof(int)); memmove(ARR_DATA_PTR(retval), dataPtr, bytes);#endif elog(ERROR, "large object arrays not supported"); } pfree(string_save); return (char *) 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 int_ArrayCount(char *str, int *dim, int typdelim){ int nest_level = 0, i; int ndim = 0, temp[MAXDIM]; bool scanning_string = false; bool eoArray = false; char *q; for (i = 0; i < MAXDIM; ++i) temp[i] = dim[i] = 0; if (strncmp(str, "{}", 2) == 0) return 0; q = str; while (eoArray != true) { bool done = false; while (!done) { switch (*q) { case '\\': /* skip escaped characters (\ and ") inside strings */ if (scanning_string && *(q + 1)) q++; break; case '\0': /* * Signal a premature end of the string. DZ - * 2-9-1996 */ elog(ERROR, "malformed array constant: %s", str); break; case '\"': scanning_string = !scanning_string; break; case '{': if (!scanning_string) { temp[nest_level] = 0; nest_level++; } break; case '}': if (!scanning_string) { if (!ndim) ndim = nest_level; nest_level--; if (nest_level) temp[nest_level - 1]++; if (nest_level == 0) eoArray = done = true; } break; default: if (!ndim) ndim = nest_level; if (*q == typdelim && !scanning_string) done = true; break; } if (!done) q++; } temp[ndim - 1]++; q++; if (!eoArray) while (isspace(*q)) q++; } for (i = 0; i < ndim; ++i) dim[i] = temp[i]; return ndim;}/*--------------------------------------------------------------------------- * _ReadArrayStr : * parses the array string pointed by "arrayStr" and converts it in the * 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. * result : * returns the internal representation of the array elements * nbytes is set to the size of the array in its internal representation. *--------------------------------------------------------------------------- */static char *_ReadArrayStr(char *arrayStr, int nitems, int ndim, int *dim, FmgrInfo *inputproc, /* function used for the * conversion */ Oid typelem, int32 typmod, char typdelim, int typlen, bool typbyval, char typalign, int *nbytes){ int i, nest_level = 0; char *p, *q, *r, **values; bool scanning_string = false; int indx[MAXDIM], prod[MAXDIM]; bool eoArray = false; mda_get_prod(ndim, dim, prod); for (i = 0; i < ndim; indx[i++] = 0); /* read array enclosed within {} */ values = (char **) palloc(nitems * sizeof(char *)); MemSet(values, 0, nitems * sizeof(char *)); q = p = arrayStr; while (!eoArray) { bool done = false; int i = -1; while (!done) { switch (*q) { case '\\': /* Crunch the string on top of the backslash. */ for (r = q; *r != '\0'; r++) *r = *(r + 1); break; case '\"': if (!scanning_string) { while (p != q) p++; p++; /* get p past first doublequote */ } else *q = '\0'; scanning_string = !scanning_string; break; case '{': if (!scanning_string) { p++; nest_level++; if (nest_level > ndim) elog(ERROR, "array_in: illformed array constant"); indx[nest_level - 1] = 0; indx[ndim - 1] = 0; } break; case '}': if (!scanning_string) { if (i == -1) i = tuple2linear(ndim, indx, prod); nest_level--; if (nest_level == 0) eoArray = done = true; else { *q = '\0'; indx[nest_level - 1]++; } } break; default: if (*q == typdelim && !scanning_string) { if (i == -1) i = tuple2linear(ndim, indx, prod); done = true; indx[ndim - 1]++; } break; } if (!done) q++; } *q = '\0'; if (i >= nitems) elog(ERROR, "array_in: illformed array constant"); values[i] = (*fmgr_faddr(inputproc)) (p, typelem, typmod); p = ++q; if (!eoArray) /* * if not at the end of the array skip white space */ while (isspace(*q)) { p++; q++; } } if (typlen > 0) { *nbytes = nitems * typlen; if (!typbyval) for (i = 0; i < nitems; i++) if (!values[i]) { values[i] = palloc(typlen); MemSet(values[i], 0, typlen); } } else { for (i = 0, *nbytes = 0; i < nitems; i++) { if (values[i]) { if (typalign == 'd') *nbytes += MAXALIGN(*(int32 *) values[i]); else *nbytes += INTALIGN(*(int32 *) values[i]); } else { *nbytes += sizeof(int32); values[i] = palloc(sizeof(int32)); *(int32 *) values[i] = sizeof(int32); } } } return (char *) values;}/*---------------------------------------------------------------------------- * Read data about an array to be stored as a large object *---------------------------------------------------------------------------- */#ifdef LOARRAYstatic char *_ReadLOArray(char *str, int *nbytes, int *fd, bool *chunkFlag, int ndim, int *dim, int baseSize){ char *inputfile, *accessfile = NULL, *chunkfile = NULL; char *retStr, *_AdvanceBy1word(); Oid lobjId; str = _AdvanceBy1word(str, &inputfile); while (str != NULL) { char *word; str = _AdvanceBy1word(str, &word); if (!strcmp(word, "-chunk")) { if (str == NULL) elog(ERROR, "array_in: access pattern file required"); str = _AdvanceBy1word(str, &accessfile); } else if (!strcmp(word, "-noreorg")) { if (str == NULL) elog(ERROR, "array_in: chunk file required"); str = _AdvanceBy1word(str, &chunkfile); } else elog(ERROR, "usage: <input file> -chunk DEFAULT/<access pattern file> -invert/-native [-noreorg <chunk file>]"); } if (inputfile == NULL) elog(ERROR, "array_in: missing file name"); lobjId = lo_creat(0); *fd = lo_open(lobjId, INV_READ); if (*fd < 0) elog(ERROR, "Large object create failed"); retStr = inputfile; *nbytes = strlen(retStr) + 2; if (accessfile) { FILE *afd;#ifndef __CYGWIN32__ if ((afd = AllocateFile(accessfile, "r")) == NULL)#else if ((afd = AllocateFile(accessfile, "r")) == NULL)#endif elog(ERROR, "unable to open access pattern file"); *chunkFlag = true; retStr = _ChunkArray(*fd, afd, ndim, dim, baseSize, nbytes, chunkfile); FreeFile(afd); } return retStr;}#endifstatic void_CopyArrayEls(char **values, char *p, int nitems, int typlen, char typalign, bool typbyval){ int i; for (i = 0; i < nitems; i++) { int inc; inc = ArrayCastAndSet(values[i], typbyval, typlen, p); p += inc; if (!typbyval) pfree(values[i]); } pfree(values);}/*------------------------------------------------------------------------- * array_out : * takes the internal representation of an array and returns a string * containing the array in its external format. *------------------------------------------------------------------------- */char *array_out(ArrayType *v, Oid element_type){ int typlen; bool typbyval; char typdelim; Oid typoutput, typelem; FmgrInfo outputproc; char typalign; char *p, *tmp, *retval, **values, delim[2]; int nitems, overall_length, i, j, k,#ifndef TCL_ARRAYS l,#endif indx[MAXDIM]; bool dummy_bool; int ndim, *dim; if (v == (ArrayType *) NULL) return (char *) NULL; if (ARR_IS_LO(v) == true) { char *p, *save_p; int nbytes; /* get a wide string to print to */ p = array_dims(v, &dummy_bool);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -