diff options
| author | Tom Lane <tgl@sss.pgh.pa.us> | 2005-03-29 00:17:27 +0000 |
|---|---|---|
| committer | Tom Lane <tgl@sss.pgh.pa.us> | 2005-03-29 00:17:27 +0000 |
| commit | 70c9763d4815ac847f0f7694f43eb6a59a236868 (patch) | |
| tree | 7d8aa05f668f1ef7809ff521b6c1e12d31125fd7 /src/backend/utils | |
| parent | 119191609c507528b20d74c59be69f2129127575 (diff) | |
| download | postgresql-70c9763d4815ac847f0f7694f43eb6a59a236868.tar.gz | |
Convert oidvector and int2vector into variable-length arrays. This
change saves a great deal of space in pg_proc and its primary index,
and it eliminates the former requirement that INDEX_MAX_KEYS and
FUNC_MAX_ARGS have the same value. INDEX_MAX_KEYS is still embedded
in the on-disk representation (because it affects index tuple header
size), but FUNC_MAX_ARGS is not. I believe it would now be possible
to increase FUNC_MAX_ARGS at little cost, but haven't experimented yet.
There are still a lot of vestigial references to FUNC_MAX_ARGS, which
I will clean up in a separate pass. However, getting rid of it
altogether would require changing the FunctionCallInfoData struct,
and I'm not sure I want to buy into that.
Diffstat (limited to 'src/backend/utils')
| -rw-r--r-- | src/backend/utils/adt/arrayfuncs.c | 4 | ||||
| -rw-r--r-- | src/backend/utils/adt/format_type.c | 27 | ||||
| -rw-r--r-- | src/backend/utils/adt/int.c | 105 | ||||
| -rw-r--r-- | src/backend/utils/adt/oid.c | 154 | ||||
| -rw-r--r-- | src/backend/utils/adt/regproc.c | 6 | ||||
| -rw-r--r-- | src/backend/utils/adt/ruleutils.c | 27 | ||||
| -rw-r--r-- | src/backend/utils/cache/lsyscache.c | 31 | ||||
| -rw-r--r-- | src/backend/utils/cache/relcache.c | 121 | ||||
| -rw-r--r-- | src/backend/utils/cache/syscache.c | 12 | ||||
| -rw-r--r-- | src/backend/utils/fmgr/fmgr.c | 4 |
10 files changed, 312 insertions, 179 deletions
diff --git a/src/backend/utils/adt/arrayfuncs.c b/src/backend/utils/adt/arrayfuncs.c index 3ceac9cf4a..47edcc5a57 100644 --- a/src/backend/utils/adt/arrayfuncs.c +++ b/src/backend/utils/adt/arrayfuncs.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/adt/arrayfuncs.c,v 1.117 2005/03/24 21:50:37 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/arrayfuncs.c,v 1.118 2005/03/29 00:17:08 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -56,7 +56,7 @@ * * * There are also some "fixed-length array" datatypes, such as NAME and - * OIDVECTOR. These are simply a sequence of a fixed number of items each + * POINT. These are simply a sequence of a fixed number of items each * of a fixed-length datatype, with no overhead; the item size must be * a multiple of its alignment requirement, because we do no padding. * We support subscripting on these types, but array_in() and array_out() diff --git a/src/backend/utils/adt/format_type.c b/src/backend/utils/adt/format_type.c index 346b6a27f0..0280196af9 100644 --- a/src/backend/utils/adt/format_type.c +++ b/src/backend/utils/adt/format_type.c @@ -8,7 +8,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/adt/format_type.c,v 1.39 2004/12/31 22:01:21 pgsql Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/format_type.c,v 1.40 2005/03/29 00:17:08 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -140,12 +140,15 @@ format_type_internal(Oid type_oid, int32 typemod, /* * Check if it's an array (and not a domain --- we don't want to show * the substructure of a domain type). Fixed-length array types such - * as "name" shouldn't get deconstructed either. + * as "name" shouldn't get deconstructed either. As of Postgres 8.1, + * rather than checking typlen we check the toast property, and don't + * deconstruct "plain storage" array types --- this is because we don't + * want to show oidvector as oid[]. */ array_base_type = typeform->typelem; if (array_base_type != InvalidOid && - typeform->typlen == -1 && + typeform->typstorage != 'p' && typeform->typtype != 'd') { /* Switch our attention to the array element type */ @@ -459,29 +462,17 @@ type_maximum_size(Oid type_oid, int32 typemod) /* * oidvectortypes - converts a vector of type OIDs to "typname" list - * - * The interface for this function is wrong: it should be told how many - * OIDs are significant in the input vector, so that trailing InvalidOid - * argument types can be recognized. */ Datum oidvectortypes(PG_FUNCTION_ARGS) { - Oid *oidArray = (Oid *) PG_GETARG_POINTER(0); + oidvector *oidArray = (oidvector *) PG_GETARG_POINTER(0); char *result; - int numargs; + int numargs = oidArray->dim1; int num; size_t total; size_t left; - /* Try to guess how many args there are :-( */ - numargs = 0; - for (num = 0; num < FUNC_MAX_ARGS; num++) - { - if (oidArray[num] != InvalidOid) - numargs = num + 1; - } - total = 20 * numargs + 1; result = palloc(total); result[0] = '\0'; @@ -489,7 +480,7 @@ oidvectortypes(PG_FUNCTION_ARGS) for (num = 0; num < numargs; num++) { - char *typename = format_type_internal(oidArray[num], -1, + char *typename = format_type_internal(oidArray->values[num], -1, false, true); size_t slen = strlen(typename); diff --git a/src/backend/utils/adt/int.c b/src/backend/utils/adt/int.c index db36ac963e..d00a7d166a 100644 --- a/src/backend/utils/adt/int.c +++ b/src/backend/utils/adt/int.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/adt/int.c,v 1.65 2005/02/27 08:31:30 neilc Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/int.c,v 1.66 2005/03/29 00:17:08 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -33,8 +33,10 @@ #include <ctype.h> #include <limits.h> +#include "catalog/pg_type.h" #include "funcapi.h" #include "libpq/pqformat.h" +#include "utils/array.h" #include "utils/builtins.h" @@ -47,6 +49,8 @@ #define SAMESIGN(a,b) (((a) < 0) == ((b) < 0)) +#define Int2VectorSize(n) (offsetof(int2vector, values) + (n) * sizeof(int2)) + typedef struct { int32 current; @@ -109,20 +113,49 @@ int2send(PG_FUNCTION_ARGS) } /* - * int2vectorin - converts "num num ..." to internal form + * construct int2vector given a raw array of int2s * - * Note: Fills any missing slots with zeroes. + * If int2s is NULL then caller must fill values[] afterward + */ +int2vector * +buildint2vector(const int2 *int2s, int n) +{ + int2vector *result; + + result = (int2vector *) palloc0(Int2VectorSize(n)); + + if (n > 0 && int2s) + memcpy(result->values, int2s, n * sizeof(int2)); + + /* + * Attach standard array header. For historical reasons, we set the + * index lower bound to 0 not 1. + */ + result->size = Int2VectorSize(n); + result->ndim = 1; + result->flags = 0; + result->elemtype = INT2OID; + result->dim1 = n; + result->lbound1 = 0; + + return result; +} + +/* + * int2vectorin - converts "num num ..." to internal form */ Datum int2vectorin(PG_FUNCTION_ARGS) { char *intString = PG_GETARG_CSTRING(0); - int16 *result = (int16 *) palloc(sizeof(int16[INDEX_MAX_KEYS])); - int slot; + int2vector *result; + int n; + + result = (int2vector *) palloc0(Int2VectorSize(FUNC_MAX_ARGS)); - for (slot = 0; *intString && slot < INDEX_MAX_KEYS; slot++) + for (n = 0; *intString && n < FUNC_MAX_ARGS; n++) { - if (sscanf(intString, "%hd", &result[slot]) != 1) + if (sscanf(intString, "%hd", &result->values[n]) != 1) break; while (*intString && isspace((unsigned char) *intString)) intString++; @@ -136,8 +169,12 @@ int2vectorin(PG_FUNCTION_ARGS) (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("int2vector has too many elements"))); - while (slot < INDEX_MAX_KEYS) - result[slot++] = 0; + result->size = Int2VectorSize(n); + result->ndim = 1; + result->flags = 0; + result->elemtype = INT2OID; + result->dim1 = n; + result->lbound1 = 0; PG_RETURN_POINTER(result); } @@ -148,24 +185,19 @@ int2vectorin(PG_FUNCTION_ARGS) Datum int2vectorout(PG_FUNCTION_ARGS) { - int16 *int2Array = (int16 *) PG_GETARG_POINTER(0); + int2vector *int2Array = (int2vector *) PG_GETARG_POINTER(0); int num, - maxnum; + nnums = int2Array->dim1; char *rp; char *result; - /* find last non-zero value in vector */ - for (maxnum = INDEX_MAX_KEYS - 1; maxnum >= 0; maxnum--) - if (int2Array[maxnum] != 0) - break; - /* assumes sign, 5 digits, ' ' */ - rp = result = (char *) palloc((maxnum + 1) * 7 + 1); - for (num = 0; num <= maxnum; num++) + rp = result = (char *) palloc(nnums * 7 + 1); + for (num = 0; num < nnums; num++) { if (num != 0) *rp++ = ' '; - pg_itoa(int2Array[num], rp); + pg_itoa(int2Array->values[num], rp); while (*++rp != '\0') ; } @@ -180,11 +212,19 @@ Datum int2vectorrecv(PG_FUNCTION_ARGS) { StringInfo buf = (StringInfo) PG_GETARG_POINTER(0); - int16 *result = (int16 *) palloc(sizeof(int16[INDEX_MAX_KEYS])); - int slot; - - for (slot = 0; slot < INDEX_MAX_KEYS; slot++) - result[slot] = (int16) pq_getmsgint(buf, sizeof(int16)); + int2vector *result; + + result = (int2vector *) + DatumGetPointer(DirectFunctionCall2(array_recv, + PointerGetDatum(buf), + ObjectIdGetDatum(INT2OID))); + /* sanity checks: int2vector must be 1-D, no nulls */ + if (result->ndim != 1 || + result->flags != 0 || + result->elemtype != INT2OID) + ereport(ERROR, + (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION), + errmsg("invalid int2vector data"))); PG_RETURN_POINTER(result); } @@ -194,14 +234,7 @@ int2vectorrecv(PG_FUNCTION_ARGS) Datum int2vectorsend(PG_FUNCTION_ARGS) { - int16 *int2Array = (int16 *) PG_GETARG_POINTER(0); - StringInfoData buf; - int slot; - - pq_begintypsend(&buf); - for (slot = 0; slot < INDEX_MAX_KEYS; slot++) - pq_sendint(&buf, int2Array[slot], sizeof(int16)); - PG_RETURN_BYTEA_P(pq_endtypsend(&buf)); + return array_send(fcinfo); } /* @@ -211,10 +244,12 @@ int2vectorsend(PG_FUNCTION_ARGS) Datum int2vectoreq(PG_FUNCTION_ARGS) { - int16 *arg1 = (int16 *) PG_GETARG_POINTER(0); - int16 *arg2 = (int16 *) PG_GETARG_POINTER(1); + int2vector *a = (int2vector *) PG_GETARG_POINTER(0); + int2vector *b = (int2vector *) PG_GETARG_POINTER(1); - PG_RETURN_BOOL(memcmp(arg1, arg2, INDEX_MAX_KEYS * sizeof(int16)) == 0); + if (a->dim1 != b->dim1) + PG_RETURN_BOOL(false); + PG_RETURN_BOOL(memcmp(a->values, b->values, a->dim1 * sizeof(int2)) == 0); } diff --git a/src/backend/utils/adt/oid.c b/src/backend/utils/adt/oid.c index ababe641b2..4329f07b83 100644 --- a/src/backend/utils/adt/oid.c +++ b/src/backend/utils/adt/oid.c @@ -8,20 +8,24 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/adt/oid.c,v 1.61 2005/02/11 04:08:58 neilc Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/oid.c,v 1.62 2005/03/29 00:17:08 tgl Exp $ * *------------------------------------------------------------------------- */ #include "postgres.h" #include <ctype.h> -#include <errno.h> #include <limits.h> +#include "catalog/pg_type.h" #include "libpq/pqformat.h" +#include "utils/array.h" #include "utils/builtins.h" +#define OidVectorSize(n) (offsetof(oidvector, values) + (n) * sizeof(Oid)) + + /***************************************************************************** * USER I/O ROUTINES * *****************************************************************************/ @@ -151,27 +155,54 @@ oidsend(PG_FUNCTION_ARGS) PG_RETURN_BYTEA_P(pq_endtypsend(&buf)); } +/* + * construct oidvector given a raw array of Oids + * + * If oids is NULL then caller must fill values[] afterward + */ +oidvector * +buildoidvector(const Oid *oids, int n) +{ + oidvector *result; + + result = (oidvector *) palloc0(OidVectorSize(n)); + + if (n > 0 && oids) + memcpy(result->values, oids, n * sizeof(Oid)); + + /* + * Attach standard array header. For historical reasons, we set the + * index lower bound to 0 not 1. + */ + result->size = OidVectorSize(n); + result->ndim = 1; + result->flags = 0; + result->elemtype = OIDOID; + result->dim1 = n; + result->lbound1 = 0; + + return result; +} /* * oidvectorin - converts "num num ..." to internal form - * - * Note: - * Fills any unsupplied positions with InvalidOid. */ Datum oidvectorin(PG_FUNCTION_ARGS) { char *oidString = PG_GETARG_CSTRING(0); - Oid *result = (Oid *) palloc(sizeof(Oid[INDEX_MAX_KEYS])); - int slot; + oidvector *result; + int n; - for (slot = 0; slot < INDEX_MAX_KEYS; slot++) + result = (oidvector *) palloc0(OidVectorSize(FUNC_MAX_ARGS)); + + for (n = 0; n < FUNC_MAX_ARGS; n++) { while (*oidString && isspace((unsigned char) *oidString)) oidString++; if (*oidString == '\0') break; - result[slot] = oidin_subr("oidvectorin", oidString, &oidString); + result->values[n] = oidin_subr("oidvectorin", oidString, &oidString); } while (*oidString && isspace((unsigned char) *oidString)) oidString++; @@ -179,8 +210,13 @@ oidvectorin(PG_FUNCTION_ARGS) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("oidvector has too many elements"))); - while (slot < INDEX_MAX_KEYS) - result[slot++] = InvalidOid; + + result->size = OidVectorSize(n); + result->ndim = 1; + result->flags = 0; + result->elemtype = OIDOID; + result->dim1 = n; + result->lbound1 = 0; PG_RETURN_POINTER(result); } @@ -191,24 +227,19 @@ oidvectorin(PG_FUNCTION_ARGS) Datum oidvectorout(PG_FUNCTION_ARGS) { - Oid *oidArray = (Oid *) PG_GETARG_POINTER(0); + oidvector *oidArray = (oidvector *) PG_GETARG_POINTER(0); int num, - maxnum; + nnums = oidArray->dim1; char *rp; char *result; - /* find last non-zero value in vector */ - for (maxnum = INDEX_MAX_KEYS - 1; maxnum >= 0; maxnum--) - if (oidArray[maxnum] != 0) - break; - /* assumes sign, 10 digits, ' ' */ - rp = result = (char *) palloc((maxnum + 1) * 12 + 1); - for (num = 0; num <= maxnum; num++) + rp = result = (char *) palloc(nnums * 12 + 1); + for (num = 0; num < nnums; num++) { if (num != 0) *rp++ = ' '; - sprintf(rp, "%u", oidArray[num]); + sprintf(rp, "%u", oidArray->values[num]); while (*++rp != '\0') ; } @@ -223,11 +254,19 @@ Datum oidvectorrecv(PG_FUNCTION_ARGS) { StringInfo buf = (StringInfo) PG_GETARG_POINTER(0); - Oid *result = (Oid *) palloc(sizeof(Oid[INDEX_MAX_KEYS])); - int slot; - - for (slot = 0; slot < INDEX_MAX_KEYS; slot++) - result[slot] = (Oid) pq_getmsgint(buf, sizeof(Oid)); + oidvector *result; + + result = (oidvector *) + DatumGetPointer(DirectFunctionCall2(array_recv, + PointerGetDatum(buf), + ObjectIdGetDatum(OIDOID))); + /* sanity checks: oidvector must be 1-D, no nulls */ + if (result->ndim != 1 || + result->flags != 0 || + result->elemtype != OIDOID) + ereport(ERROR, + (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION), + errmsg("invalid oidvector data"))); PG_RETURN_POINTER(result); } @@ -237,14 +276,7 @@ oidvectorrecv(PG_FUNCTION_ARGS) Datum oidvectorsend(PG_FUNCTION_ARGS) { - Oid *oidArray = (Oid *) PG_GETARG_POINTER(0); - StringInfoData buf; - int slot; - - pq_begintypsend(&buf); - for (slot = 0; slot < INDEX_MAX_KEYS; slot++) - pq_sendint(&buf, oidArray[slot], sizeof(Oid)); - PG_RETURN_BYTEA_P(pq_endtypsend(&buf)); + return array_send(fcinfo); } @@ -327,71 +359,49 @@ oidsmaller(PG_FUNCTION_ARGS) Datum oidvectoreq(PG_FUNCTION_ARGS) { - Oid *arg1 = (Oid *) PG_GETARG_POINTER(0); - Oid *arg2 = (Oid *) PG_GETARG_POINTER(1); + int32 cmp = DatumGetInt32(btoidvectorcmp(fcinfo)); - PG_RETURN_BOOL(memcmp(arg1, arg2, INDEX_MAX_KEYS * sizeof(Oid)) == 0); + PG_RETURN_BOOL(cmp == 0); } Datum oidvectorne(PG_FUNCTION_ARGS) { - Oid *arg1 = (Oid *) PG_GETARG_POINTER(0); - Oid *arg2 = (Oid *) PG_GETARG_POINTER(1); + int32 cmp = DatumGetInt32(btoidvectorcmp(fcinfo)); - PG_RETURN_BOOL(memcmp(arg1, arg2, INDEX_MAX_KEYS * sizeof(Oid)) != 0); + PG_RETURN_BOOL(cmp != 0); } Datum oidvectorlt(PG_FUNCTION_ARGS) { - Oid *arg1 = (Oid *) PG_GETARG_POINTER(0); - Oid *arg2 = (Oid *) PG_GETARG_POINTER(1); - int i; - - for (i = 0; i < INDEX_MAX_KEYS; i++) - if (arg1[i] != arg2[i]) - PG_RETURN_BOOL(arg1[i] < arg2[i]); - PG_RETURN_BOOL(false); + int32 cmp = DatumGetInt32(btoidvectorcmp(fcinfo)); + + PG_RETURN_BOOL(cmp < 0); } Datum oidvectorle(PG_FUNCTION_ARGS) { - Oid *arg1 = (Oid *) PG_GETARG_POINTER(0); - Oid *arg2 = (Oid *) PG_GETARG_POINTER(1); - int i; - - for (i = 0; i < INDEX_MAX_KEYS; i++) - if (arg1[i] != arg2[i]) - PG_RETURN_BOOL(arg1[i] <= arg2[i]); - PG_RETURN_BOOL(true); + int32 cmp = DatumGetInt32(btoidvectorcmp(fcinfo)); + + PG_RETURN_BOOL(cmp <= 0); } Datum oidvectorge(PG_FUNCTION_ARGS) { - Oid *arg1 = (Oid *) PG_GETARG_POINTER(0); - Oid *arg2 = (Oid *) PG_GETARG_POINTER(1); - int i; - - for (i = 0; i < INDEX_MAX_KEYS; i++) - if (arg1[i] != arg2[i]) - PG_RETURN_BOOL(arg1[i] >= arg2[i]); - PG_RETURN_BOOL(true); + int32 cmp = DatumGetInt32(btoidvectorcmp(fcinfo)); + + PG_RETURN_BOOL(cmp >= 0); } Datum oidvectorgt(PG_FUNCTION_ARGS) { - Oid *arg1 = (Oid *) PG_GETARG_POINTER(0); - Oid *arg2 = (Oid *) PG_GETARG_POINTER(1); - int i; - - for (i = 0; i < INDEX_MAX_KEYS; i++) - if (arg1[i] != arg2[i]) - PG_RETURN_BOOL(arg1[i] > arg2[i]); - PG_RETURN_BOOL(false); + int32 cmp = DatumGetInt32(btoidvectorcmp(fcinfo)); + + PG_RETURN_BOOL(cmp > 0); } Datum diff --git a/src/backend/utils/adt/regproc.c b/src/backend/utils/adt/regproc.c index a74d1feef4..42fddeb8d2 100644 --- a/src/backend/utils/adt/regproc.c +++ b/src/backend/utils/adt/regproc.c @@ -13,7 +13,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/adt/regproc.c,v 1.92 2004/12/31 22:01:22 pgsql Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/regproc.c,v 1.93 2005/03/29 00:17:08 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -98,7 +98,7 @@ regprocin(PG_FUNCTION_ARGS) CStringGetDatum(pro_name_or_oid)); hdesc = heap_openr(ProcedureRelationName, AccessShareLock); - sysscan = systable_beginscan(hdesc, ProcedureNameNspIndex, true, + sysscan = systable_beginscan(hdesc, ProcedureNameArgsNspIndex, true, SnapshotNow, 1, skey); while (HeapTupleIsValid(tuple = systable_getnext(sysscan))) @@ -336,7 +336,7 @@ format_procedure(Oid procedure_oid) quote_qualified_identifier(nspname, proname)); for (i = 0; i < nargs; i++) { - Oid thisargtype = procform->proargtypes[i]; + Oid thisargtype = procform->proargtypes.values[i]; if (i > 0) appendStringInfoChar(&buf, ','); diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c index f3458a5abe..814deff5e3 100644 --- a/src/backend/utils/adt/ruleutils.c +++ b/src/backend/utils/adt/ruleutils.c @@ -3,7 +3,7 @@ * back to source text * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.188 2005/01/13 17:19:10 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.189 2005/03/29 00:17:08 tgl Exp $ * * This software is copyrighted by Jan Wieck - Hamburg. * @@ -553,9 +553,10 @@ pg_get_triggerdef(PG_FUNCTION_ARGS) char *p; int i; - val = (bytea *) fastgetattr(ht_trig, - Anum_pg_trigger_tgargs, - tgrel->rd_att, &isnull); + val = (bytea *) + DatumGetPointer(fastgetattr(ht_trig, + Anum_pg_trigger_tgargs, + tgrel->rd_att, &isnull)); if (isnull) elog(ERROR, "tgargs is null for trigger %u", trigid); p = (char *) VARDATA(val); @@ -637,6 +638,9 @@ pg_get_indexdef_worker(Oid indexrelid, int colno, int prettyFlags) Oid indrelid; int keyno; Oid keycoltype; + Datum indclassDatum; + bool isnull; + oidvector *indclass; StringInfoData buf; char *str; char *sep; @@ -654,6 +658,12 @@ pg_get_indexdef_worker(Oid indexrelid, int colno, int prettyFlags) indrelid = idxrec->indrelid; Assert(indexrelid == idxrec->indexrelid); + /* Must get indclass the hard way */ + indclassDatum = SysCacheGetAttr(INDEXRELID, ht_idx, + Anum_pg_index_indclass, &isnull); + Assert(!isnull); + indclass = (oidvector *) DatumGetPointer(indclassDatum); + /* * Fetch the pg_class tuple of the index relation */ @@ -720,7 +730,7 @@ pg_get_indexdef_worker(Oid indexrelid, int colno, int prettyFlags) sep = ""; for (keyno = 0; keyno < idxrec->indnatts; keyno++) { - AttrNumber attnum = idxrec->indkey[keyno]; + AttrNumber attnum = idxrec->indkey.values[keyno]; if (!colno) appendStringInfo(&buf, sep); @@ -764,7 +774,7 @@ pg_get_indexdef_worker(Oid indexrelid, int colno, int prettyFlags) * Add the operator class name */ if (!colno) - get_opclass_name(idxrec->indclass[keyno], keycoltype, + get_opclass_name(indclass->values[keyno], keycoltype, &buf); } @@ -3537,7 +3547,10 @@ get_func_expr(FuncExpr *expr, deparse_context *context, nargs = 0; foreach(l, expr->args) { - Assert(nargs < FUNC_MAX_ARGS); + if (nargs >= FUNC_MAX_ARGS) + ereport(ERROR, + (errcode(ERRCODE_TOO_MANY_ARGUMENTS), + errmsg("too many arguments"))); argtypes[nargs] = exprType((Node *) lfirst(l)); nargs++; } diff --git a/src/backend/utils/cache/lsyscache.c b/src/backend/utils/cache/lsyscache.c index e417fcbec8..0b40a20b25 100644 --- a/src/backend/utils/cache/lsyscache.c +++ b/src/backend/utils/cache/lsyscache.c @@ -7,7 +7,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/cache/lsyscache.c,v 1.120 2005/01/27 23:36:12 neilc Exp $ + * $PostgreSQL: pgsql/src/backend/utils/cache/lsyscache.c,v 1.121 2005/03/29 00:17:11 tgl Exp $ * * NOTES * Eventually, the index information should go through here, too. @@ -774,14 +774,35 @@ get_func_rettype(Oid funcid) } /* + * get_func_nargs + * Given procedure id, return the number of arguments. + */ +int +get_func_nargs(Oid funcid) +{ + HeapTuple tp; + int result; + + tp = SearchSysCache(PROCOID, + ObjectIdGetDatum(funcid), + 0, 0, 0); + if (!HeapTupleIsValid(tp)) + elog(ERROR, "cache lookup failed for function %u", funcid); + + result = ((Form_pg_proc) GETSTRUCT(tp))->pronargs; + ReleaseSysCache(tp); + return result; +} + +/* * get_func_signature * Given procedure id, return the function's argument and result types. * (The return value is the result type.) * - * argtypes must point to a vector of size FUNC_MAX_ARGS. + * The arguments are returned as a palloc'd array. */ Oid -get_func_signature(Oid funcid, Oid *argtypes, int *nargs) +get_func_signature(Oid funcid, Oid **argtypes, int *nargs) { HeapTuple tp; Form_pg_proc procstruct; @@ -796,8 +817,10 @@ get_func_signature(Oid funcid, Oid *argtypes, int *nargs) procstruct = (Form_pg_proc) GETSTRUCT(tp); result = procstruct->prorettype; - memcpy(argtypes, procstruct->proargtypes, FUNC_MAX_ARGS * sizeof(Oid)); *nargs = (int) procstruct->pronargs; + Assert(*nargs == procstruct->proargtypes.dim1); + *argtypes = (Oid *) palloc(*nargs * sizeof(Oid)); + memcpy(*argtypes, procstruct->proargtypes.values, *nargs * sizeof(Oid)); ReleaseSysCache(tp); return result; diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c index a6660fc4d3..109a6e811a 100644 --- a/src/backend/utils/cache/relcache.c +++ b/src/backend/utils/cache/relcache.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/cache/relcache.c,v 1.217 2005/03/28 00:58:26 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/cache/relcache.c,v 1.218 2005/03/29 00:17:11 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -27,7 +27,6 @@ */ #include "postgres.h" -#include <errno.h> #include <sys/file.h> #include <fcntl.h> #include <unistd.h> @@ -81,6 +80,7 @@ static FormData_pg_attribute Desc_pg_class[Natts_pg_class] = {Schema_pg_class}; static FormData_pg_attribute Desc_pg_attribute[Natts_pg_attribute] = {Schema_pg_attribute}; static FormData_pg_attribute Desc_pg_proc[Natts_pg_proc] = {Schema_pg_proc}; static FormData_pg_attribute Desc_pg_type[Natts_pg_type] = {Schema_pg_type}; +static FormData_pg_attribute Desc_pg_index[Natts_pg_index] = {Schema_pg_index}; /* * Hash tables that index the relation cache @@ -267,10 +267,11 @@ static void RelationBuildTupleDesc(RelationBuildDescInfo buildinfo, static Relation RelationBuildDesc(RelationBuildDescInfo buildinfo, Relation oldrelation); static void RelationInitPhysicalAddr(Relation relation); +static TupleDesc GetPgIndexDescriptor(void); static void AttrDefaultFetch(Relation relation); static void CheckConstraintFetch(Relation relation); static List *insert_ordered_oid(List *list, Oid datum); -static void IndexSupportInitialize(Form_pg_index iform, +static void IndexSupportInitialize(oidvector *indclass, Oid *indexOperator, RegProcedure *indexSupport, StrategyNumber maxStrategyNumber, @@ -918,6 +919,8 @@ RelationInitIndexAccessInfo(Relation relation) { HeapTuple tuple; Form_pg_am aform; + Datum indclassDatum; + bool isnull; MemoryContext indexcxt; MemoryContext oldcontext; Oid *operator; @@ -946,6 +949,18 @@ RelationInitIndexAccessInfo(Relation relation) ReleaseSysCache(tuple); /* + * indclass cannot be referenced directly through the C struct, because + * it is after the variable-width indkey field. Therefore we extract + * the datum the hard way and provide a direct link in the relcache. + */ + indclassDatum = fastgetattr(relation->rd_indextuple, + Anum_pg_index_indclass, + GetPgIndexDescriptor(), + &isnull); + Assert(!isnull); + relation->rd_indclass = (oidvector *) DatumGetPointer(indclassDatum); + + /* * Make a copy of the pg_am entry for the index's access method */ tuple = SearchSysCache(AMOID, @@ -1014,7 +1029,7 @@ RelationInitIndexAccessInfo(Relation relation) * Fill the operator and support procedure OID arrays. (supportinfo is * left as zeroes, and is filled on-the-fly when used) */ - IndexSupportInitialize(relation->rd_index, + IndexSupportInitialize(relation->rd_indclass, operator, support, amstrategies, amsupport, natts); @@ -1028,7 +1043,7 @@ RelationInitIndexAccessInfo(Relation relation) /* * IndexSupportInitialize * Initializes an index's cached opclass information, - * given the index's pg_index tuple. + * given the index's pg_index.indclass entry. * * Data is returned into *indexOperator and *indexSupport, which are arrays * allocated by the caller. @@ -1040,7 +1055,7 @@ RelationInitIndexAccessInfo(Relation relation) * access method. */ static void -IndexSupportInitialize(Form_pg_index iform, +IndexSupportInitialize(oidvector *indclass, Oid *indexOperator, RegProcedure *indexSupport, StrategyNumber maxStrategyNumber, @@ -1049,19 +1064,15 @@ IndexSupportInitialize(Form_pg_index iform, { int attIndex; - /* - * XXX note that the following assumes the INDEX tuple is well formed - * and that the *key and *class are 0 terminated. - */ for (attIndex = 0; attIndex < maxAttributeNumber; attIndex++) { OpClassCacheEnt *opcentry; - if (!OidIsValid(iform->indclass[attIndex])) + if (!OidIsValid(indclass->values[attIndex])) elog(ERROR, "bogus pg_index tuple"); /* look up the info for this opclass, using a cache */ - opcentry = LookupOpclassInfo(iform->indclass[attIndex], + opcentry = LookupOpclassInfo(indclass->values[attIndex], maxStrategyNumber, maxSupportNumber); @@ -2479,6 +2490,53 @@ RelationCacheInitializePhase3(void) } } +/* + * GetPgIndexDescriptor -- get a predefined tuple descriptor for pg_index + * + * We need this kluge because we have to be able to access non-fixed-width + * fields of pg_index before we have the standard catalog caches available. + * We use predefined data that's set up in just the same way as the + * bootstrapped reldescs used by formrdesc(). The resulting tupdesc is + * not 100% kosher: it does not have the correct relation OID in attrelid, + * nor does it have a TupleConstr field. But it's good enough for the + * purpose of extracting fields. + */ +static TupleDesc +GetPgIndexDescriptor(void) +{ + static TupleDesc pgindexdesc = NULL; + MemoryContext oldcxt; + int i; + + /* Already done? */ + if (pgindexdesc) + return pgindexdesc; + + oldcxt = MemoryContextSwitchTo(CacheMemoryContext); + + pgindexdesc = CreateTemplateTupleDesc(Natts_pg_index, false); + pgindexdesc->tdtypeid = RECORDOID; /* not right, but we don't care */ + pgindexdesc->tdtypmod = -1; + + for (i = 0; i < Natts_pg_index; i++) + { + memcpy(pgindexdesc->attrs[i], + &Desc_pg_index[i], + ATTRIBUTE_TUPLE_SIZE); + /* make sure attcacheoff is valid */ + pgindexdesc->attrs[i]->attcacheoff = -1; + } + + /* initialize first attribute's attcacheoff, cf RelationBuildTupleDesc */ + pgindexdesc->attrs[0]->attcacheoff = 0; + + /* Note: we don't bother to set up a TupleConstr entry */ + + MemoryContextSwitchTo(oldcxt); + + return pgindexdesc; +} + static void AttrDefaultFetch(Relation relation) { @@ -2773,15 +2831,11 @@ RelationGetIndexExpressions(Relation relation) * After successfully completing the work, we copy it into the * relcache entry. This avoids problems if we get some sort of error * partway through. - * - * We make use of the syscache's copy of pg_index's tupledesc to access - * the non-fixed fields of the tuple. We assume that the syscache - * will be initialized before any access of a partial index could - * occur. (This would probably fail if we were to allow partial - * indexes on system catalogs.) - */ - exprsDatum = SysCacheGetAttr(INDEXRELID, relation->rd_indextuple, - Anum_pg_index_indexprs, &isnull); + */ + exprsDatum = heap_getattr(relation->rd_indextuple, + Anum_pg_index_indexprs, + GetPgIndexDescriptor(), + &isnull); Assert(!isnull); exprsString = DatumGetCString(DirectFunctionCall1(textout, exprsDatum)); result = (List *) stringToNode(exprsString); @@ -2845,15 +2899,11 @@ RelationGetIndexPredicate(Relation relation) * After successfully completing the work, we copy it into the * relcache entry. This avoids problems if we get some sort of error * partway through. - * - * We make use of the syscache's copy of pg_index's tupledesc to access - * the non-fixed fields of the tuple. We assume that the syscache - * will be initialized before any access of a partial index could - * occur. (This would probably fail if we were to allow partial - * indexes on system catalogs.) - */ - predDatum = SysCacheGetAttr(INDEXRELID, relation->rd_indextuple, - Anum_pg_index_indpred, &isnull); + */ + predDatum = heap_getattr(relation->rd_indextuple, + Anum_pg_index_indpred, + GetPgIndexDescriptor(), + &isnull); Assert(!isnull); predString = DatumGetCString(DirectFunctionCall1(textout, predDatum)); result = (List *) stringToNode(predString); @@ -2990,6 +3040,8 @@ load_relcache_init_file(void) Relation rel; Form_pg_class relform; bool has_not_null; + Datum indclassDatum; + bool isnull; /* first read the relation descriptor length */ if ((nread = fread(&len, 1, sizeof(len), fp)) != sizeof(len)) @@ -3081,6 +3133,14 @@ load_relcache_init_file(void) rel->rd_indextuple->t_data = (HeapTupleHeader) ((char *) rel->rd_indextuple + HEAPTUPLESIZE); rel->rd_index = (Form_pg_index) GETSTRUCT(rel->rd_indextuple); + /* fix up indclass pointer too */ + indclassDatum = fastgetattr(rel->rd_indextuple, + Anum_pg_index_indclass, + GetPgIndexDescriptor(), + &isnull); + Assert(!isnull); + rel->rd_indclass = (oidvector *) DatumGetPointer(indclassDatum); + /* next, read the access method tuple form */ if ((nread = fread(&len, 1, sizeof(len), fp)) != sizeof(len)) goto read_failed; @@ -3133,6 +3193,7 @@ load_relcache_init_file(void) Assert(rel->rd_index == NULL); Assert(rel->rd_indextuple == NULL); + Assert(rel->rd_indclass == NULL); Assert(rel->rd_am == NULL); Assert(rel->rd_indexcxt == NULL); Assert(rel->rd_operator == NULL); diff --git a/src/backend/utils/cache/syscache.c b/src/backend/utils/cache/syscache.c index 3435ac8ee0..b7b7ec249d 100644 --- a/src/backend/utils/cache/syscache.c +++ b/src/backend/utils/cache/syscache.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/cache/syscache.c,v 1.96 2004/12/31 22:01:25 pgsql Exp $ + * $PostgreSQL: pgsql/src/backend/utils/cache/syscache.c,v 1.97 2005/03/29 00:17:12 tgl Exp $ * * NOTES * These routines allow the parser/planner/executor to perform @@ -334,15 +334,15 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }}, - {ProcedureRelationName, /* PROCNAMENSP */ - ProcedureNameNspIndex, + {ProcedureRelationName, /* PROCNAMEARGSNSP */ + ProcedureNameArgsNspIndex, 0, - 4, + 3, { Anum_pg_proc_proname, - Anum_pg_proc_pronargs, Anum_pg_proc_proargtypes, - Anum_pg_proc_pronamespace + Anum_pg_proc_pronamespace, + 0 }}, {ProcedureRelationName, /* PROCOID */ ProcedureOidIndex, diff --git a/src/backend/utils/fmgr/fmgr.c b/src/backend/utils/fmgr/fmgr.c index e34a942aba..430cfeffc7 100644 --- a/src/backend/utils/fmgr/fmgr.c +++ b/src/backend/utils/fmgr/fmgr.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/fmgr/fmgr.c,v 1.90 2005/03/22 20:13:07 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/fmgr/fmgr.c,v 1.91 2005/03/29 00:17:15 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -344,7 +344,7 @@ fmgr_info_C_lang(Oid functionId, FmgrInfo *finfo, HeapTuple procedureTuple) for (i = 0; i < procedureStruct->pronargs; i++) { fnextra->arg_toastable[i] = - TypeIsToastable(procedureStruct->proargtypes[i]); + TypeIsToastable(procedureStruct->proargtypes.values[i]); } break; case 1: |
