From a52b4fb1313cbd367d765a2a8704a63709cbbd5d Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Mon, 7 Mar 2005 04:42:17 +0000 Subject: [PATCH] Adjust creation/destruction of TupleDesc data structure to reduce the number of palloc calls. This has a salutory impact on plpgsql operations with record variables (which create and destroy tupdescs constantly) and probably helps a bit in some other cases too. --- src/backend/access/common/tupdesc.c | 135 ++++++++++++---------------- src/backend/catalog/index.c | 9 +- src/backend/utils/cache/relcache.c | 20 ++--- src/include/access/tupdesc.h | 20 +++-- 4 files changed, 81 insertions(+), 103 deletions(-) diff --git a/src/backend/access/common/tupdesc.c b/src/backend/access/common/tupdesc.c index bc79ec29ff..0d1d402210 100644 --- a/src/backend/access/common/tupdesc.c +++ b/src/backend/access/common/tupdesc.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/access/common/tupdesc.c,v 1.108 2004/12/31 21:59:07 pgsql Exp $ + * $PostgreSQL: pgsql/src/backend/access/common/tupdesc.c,v 1.109 2005/03/07 04:42:16 tgl Exp $ * * NOTES * some of the executor utility code such as "ExecTypeFromTL" should be @@ -31,19 +31,19 @@ #include "utils/typcache.h" -/* ---------------------------------------------------------------- - * CreateTemplateTupleDesc - * - * This function allocates and zeros a tuple descriptor structure. +/* + * CreateTemplateTupleDesc + * This function allocates an empty tuple descriptor structure. * * Tuple type ID information is initially set for an anonymous record type; * caller can overwrite this if needed. - * ---------------------------------------------------------------- */ TupleDesc CreateTemplateTupleDesc(int natts, bool hasoid) { TupleDesc desc; + char *stg; + int attroffset; /* * sanity checks @@ -51,15 +51,33 @@ CreateTemplateTupleDesc(int natts, bool hasoid) AssertArg(natts >= 0); /* - * Allocate enough memory for the tuple descriptor, and zero the - * attrs[] array since TupleDescInitEntry assumes that the array is - * filled with NULL pointers. + * Allocate enough memory for the tuple descriptor, including the + * attribute rows, and set up the attribute row pointers. + * + * Note: we assume that sizeof(struct tupleDesc) is a multiple of + * the struct pointer alignment requirement, and hence we don't need + * to insert alignment padding between the struct and the array of + * attribute row pointers. */ - desc = (TupleDesc) palloc(sizeof(struct tupleDesc)); + attroffset = sizeof(struct tupleDesc) + natts * sizeof(Form_pg_attribute); + attroffset = MAXALIGN(attroffset); + stg = palloc(attroffset + natts * MAXALIGN(ATTRIBUTE_TUPLE_SIZE)); + desc = (TupleDesc) stg; if (natts > 0) - desc->attrs = (Form_pg_attribute *) - palloc0(natts * sizeof(Form_pg_attribute)); + { + Form_pg_attribute *attrs; + int i; + + attrs = (Form_pg_attribute *) (stg + sizeof(struct tupleDesc)); + desc->attrs = attrs; + stg += attroffset; + for (i = 0; i < natts; i++) + { + attrs[i] = (Form_pg_attribute) stg; + stg += MAXALIGN(ATTRIBUTE_TUPLE_SIZE); + } + } else desc->attrs = NULL; @@ -75,15 +93,16 @@ CreateTemplateTupleDesc(int natts, bool hasoid) return desc; } -/* ---------------------------------------------------------------- - * CreateTupleDesc - * +/* + * CreateTupleDesc * This function allocates a new TupleDesc pointing to a given - * Form_pg_attribute array + * Form_pg_attribute array. + * + * Note: if the TupleDesc is ever freed, the Form_pg_attribute array + * will not be freed thereby. * * Tuple type ID information is initially set for an anonymous record type; * caller can overwrite this if needed. - * ---------------------------------------------------------------- */ TupleDesc CreateTupleDesc(int natts, bool hasoid, Form_pg_attribute *attrs) @@ -106,14 +125,12 @@ CreateTupleDesc(int natts, bool hasoid, Form_pg_attribute *attrs) return desc; } -/* ---------------------------------------------------------------- - * CreateTupleDescCopy - * +/* + * CreateTupleDescCopy * This function creates a new TupleDesc by copying from an existing - * TupleDesc + * TupleDesc. * - * !!! Constraints and defaults are not copied !!! - * ---------------------------------------------------------------- + * !!! Constraints and defaults are not copied !!! */ TupleDesc CreateTupleDescCopy(TupleDesc tupdesc) @@ -121,38 +138,25 @@ CreateTupleDescCopy(TupleDesc tupdesc) TupleDesc desc; int i; - desc = (TupleDesc) palloc(sizeof(struct tupleDesc)); - desc->natts = tupdesc->natts; - if (desc->natts > 0) + desc = CreateTemplateTupleDesc(tupdesc->natts, tupdesc->tdhasoid); + + for (i = 0; i < desc->natts; i++) { - desc->attrs = (Form_pg_attribute *) - palloc(desc->natts * sizeof(Form_pg_attribute)); - for (i = 0; i < desc->natts; i++) - { - desc->attrs[i] = (Form_pg_attribute) palloc(ATTRIBUTE_TUPLE_SIZE); - memcpy(desc->attrs[i], tupdesc->attrs[i], ATTRIBUTE_TUPLE_SIZE); - desc->attrs[i]->attnotnull = false; - desc->attrs[i]->atthasdef = false; - } + memcpy(desc->attrs[i], tupdesc->attrs[i], ATTRIBUTE_TUPLE_SIZE); + desc->attrs[i]->attnotnull = false; + desc->attrs[i]->atthasdef = false; } - else - desc->attrs = NULL; - - desc->constr = NULL; desc->tdtypeid = tupdesc->tdtypeid; desc->tdtypmod = tupdesc->tdtypmod; - desc->tdhasoid = tupdesc->tdhasoid; return desc; } -/* ---------------------------------------------------------------- - * CreateTupleDescCopyConstr - * +/* + * CreateTupleDescCopyConstr * This function creates a new TupleDesc by copying from an existing - * TupleDesc (including its constraints and defaults) - * ---------------------------------------------------------------- + * TupleDesc (including its constraints and defaults). */ TupleDesc CreateTupleDescCopyConstr(TupleDesc tupdesc) @@ -161,20 +165,12 @@ CreateTupleDescCopyConstr(TupleDesc tupdesc) TupleConstr *constr = tupdesc->constr; int i; - desc = (TupleDesc) palloc(sizeof(struct tupleDesc)); - desc->natts = tupdesc->natts; - if (desc->natts > 0) + desc = CreateTemplateTupleDesc(tupdesc->natts, tupdesc->tdhasoid); + + for (i = 0; i < desc->natts; i++) { - desc->attrs = (Form_pg_attribute *) - palloc(desc->natts * sizeof(Form_pg_attribute)); - for (i = 0; i < desc->natts; i++) - { - desc->attrs[i] = (Form_pg_attribute) palloc(ATTRIBUTE_TUPLE_SIZE); - memcpy(desc->attrs[i], tupdesc->attrs[i], ATTRIBUTE_TUPLE_SIZE); - } + memcpy(desc->attrs[i], tupdesc->attrs[i], ATTRIBUTE_TUPLE_SIZE); } - else - desc->attrs = NULL; if (constr) { @@ -208,12 +204,9 @@ CreateTupleDescCopyConstr(TupleDesc tupdesc) desc->constr = cpy; } - else - desc->constr = NULL; desc->tdtypeid = tupdesc->tdtypeid; desc->tdtypmod = tupdesc->tdtypmod; - desc->tdhasoid = tupdesc->tdhasoid; return desc; } @@ -226,10 +219,6 @@ FreeTupleDesc(TupleDesc tupdesc) { int i; - for (i = 0; i < tupdesc->natts; i++) - pfree(tupdesc->attrs[i]); - if (tupdesc->attrs) - pfree(tupdesc->attrs); if (tupdesc->constr) { if (tupdesc->constr->num_defval > 0) @@ -379,12 +368,10 @@ equalTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2) return true; } -/* ---------------------------------------------------------------- - * TupleDescInitEntry - * +/* + * TupleDescInitEntry * This function initializes a single attribute structure in - * a preallocated tuple descriptor. - * ---------------------------------------------------------------- + * a previously allocated tuple descriptor. */ void TupleDescInitEntry(TupleDesc desc, @@ -404,18 +391,12 @@ TupleDescInitEntry(TupleDesc desc, AssertArg(PointerIsValid(desc)); AssertArg(attributeNumber >= 1); AssertArg(attributeNumber <= desc->natts); - AssertArg(!PointerIsValid(desc->attrs[attributeNumber - 1])); - - /* - * allocate storage for this attribute - */ - - att = (Form_pg_attribute) palloc(ATTRIBUTE_TUPLE_SIZE); - desc->attrs[attributeNumber - 1] = att; /* * initialize the attribute fields */ + att = desc->attrs[attributeNumber - 1]; + att->attrelid = 0; /* dummy value */ /* diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c index 0d389c4084..a3bcca272e 100644 --- a/src/backend/catalog/index.c +++ b/src/backend/catalog/index.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/catalog/index.c,v 1.245 2005/03/04 20:21:05 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/catalog/index.c,v 1.246 2005/03/07 04:42:16 tgl Exp $ * * * INTERFACE ROUTINES @@ -97,14 +97,11 @@ ConstructTupleDescriptor(Relation heapRelation, for (i = 0; i < numatts; i++) { AttrNumber atnum = indexInfo->ii_KeyAttrNumbers[i]; - Form_pg_attribute to; + Form_pg_attribute to = indexTupDesc->attrs[i]; HeapTuple tuple; Form_pg_type typeTup; Oid keyType; - indexTupDesc->attrs[i] = to = - (Form_pg_attribute) palloc0(ATTRIBUTE_TUPLE_SIZE); - if (atnum != 0) { /* Simple index column */ @@ -152,6 +149,8 @@ ConstructTupleDescriptor(Relation heapRelation, /* Expressional index */ Node *indexkey; + MemSet(to, 0, ATTRIBUTE_TUPLE_SIZE); + if (indexpr_item == NULL) /* shouldn't happen */ elog(ERROR, "too few entries in indexprs list"); indexkey = (Node *) lfirst(indexpr_item); diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c index 50ffb0f1b0..d1143381d2 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.215 2005/01/10 20:02:23 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/cache/relcache.c,v 1.216 2005/03/07 04:42:16 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -491,12 +491,8 @@ RelationBuildTupleDesc(RelationBuildDescInfo buildinfo, elog(ERROR, "invalid attribute number %d for %s", attp->attnum, RelationGetRelationName(relation)); - relation->rd_att->attrs[attp->attnum - 1] = - (Form_pg_attribute) MemoryContextAlloc(CacheMemoryContext, - ATTRIBUTE_TUPLE_SIZE); - - memcpy((char *) (relation->rd_att->attrs[attp->attnum - 1]), - (char *) attp, + memcpy(relation->rd_att->attrs[attp->attnum - 1], + attp, ATTRIBUTE_TUPLE_SIZE); /* Update constraint/default info */ @@ -1338,9 +1334,8 @@ formrdesc(const char *relationName, Oid relationReltype, has_not_null = false; for (i = 0; i < natts; i++) { - relation->rd_att->attrs[i] = (Form_pg_attribute) palloc(ATTRIBUTE_TUPLE_SIZE); - memcpy((char *) relation->rd_att->attrs[i], - (char *) &att[i], + memcpy(relation->rd_att->attrs[i], + &att[i], ATTRIBUTE_TUPLE_SIZE); has_not_null |= att[i].attnotnull; /* make sure attcacheoff is valid */ @@ -3044,9 +3039,8 @@ load_relcache_init_file(void) { if ((nread = fread(&len, 1, sizeof(len), fp)) != sizeof(len)) goto read_failed; - - rel->rd_att->attrs[i] = (Form_pg_attribute) palloc(len); - + if (len != ATTRIBUTE_TUPLE_SIZE) + goto read_failed; if ((nread = fread(rel->rd_att->attrs[i], 1, len, fp)) != len) goto read_failed; diff --git a/src/include/access/tupdesc.h b/src/include/access/tupdesc.h index 8ffb2e70c8..f9b89ed253 100644 --- a/src/include/access/tupdesc.h +++ b/src/include/access/tupdesc.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/access/tupdesc.h,v 1.46 2004/12/31 22:03:21 pgsql Exp $ + * $PostgreSQL: pgsql/src/include/access/tupdesc.h,v 1.47 2005/03/07 04:42:17 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -42,13 +42,17 @@ typedef struct tupleConstr } TupleConstr; /* - * This structure contains all information (i.e. from Classes - * pg_attribute, pg_attrdef, pg_constraint) for the structure of a tuple. + * This struct is passed around within the backend to describe the structure + * of tuples. For tuples coming from on-disk relations, the information is + * collected from the pg_attribute, pg_attrdef, and pg_constraint catalogs. + * Transient row types (such as the result of a join query) have anonymous + * TupleDesc structs that generally omit any constraint info; therefore the + * structure is designed to let the constraints be omitted efficiently. * * Note that only user attributes, not system attributes, are mentioned in * TupleDesc; with the exception that tdhasoid indicates if OID is present. * - * If the tuple is known to correspond to a named rowtype (such as a table's + * If the tupdesc is known to correspond to a named rowtype (such as a table's * rowtype) then tdtypeid identifies that type and tdtypmod is -1. Otherwise * tdtypeid is RECORDOID, and tdtypmod can be either -1 for a fully anonymous * row type, or a value >= 0 to allow the rowtype to be looked up in the @@ -56,13 +60,13 @@ typedef struct tupleConstr */ typedef struct tupleDesc { - int natts; /* Number of attributes in the tuple */ + int natts; /* number of attributes in the tuple */ Form_pg_attribute *attrs; - /* attrs[N] is a pointer to the description of Attribute Number N+1. */ - TupleConstr *constr; + /* attrs[N] is a pointer to the description of Attribute Number N+1 */ + TupleConstr *constr; /* constraints, or NULL if none */ Oid tdtypeid; /* composite type ID for tuple type */ int32 tdtypmod; /* typmod for tuple type */ - bool tdhasoid; /* Tuple has oid attribute in its header */ + bool tdhasoid; /* tuple has oid attribute in its header */ } *TupleDesc; -- GitLab