Skip to content

Commit a52b4fb

Browse files
committed
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.
1 parent e3d7de6 commit a52b4fb

File tree

4 files changed

+81
-103
lines changed

4 files changed

+81
-103
lines changed

src/backend/access/common/tupdesc.c

Lines changed: 58 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/access/common/tupdesc.c,v 1.108 2004/12/31 21:59:07 pgsql Exp $
11+
* $PostgreSQL: pgsql/src/backend/access/common/tupdesc.c,v 1.109 2005/03/07 04:42:16 tgl Exp $
1212
*
1313
* NOTES
1414
* some of the executor utility code such as "ExecTypeFromTL" should be
@@ -31,35 +31,53 @@
3131
#include "utils/typcache.h"
3232

3333

34-
/* ----------------------------------------------------------------
35-
* CreateTemplateTupleDesc
36-
*
37-
* This function allocates and zeros a tuple descriptor structure.
34+
/*
35+
* CreateTemplateTupleDesc
36+
* This function allocates an empty tuple descriptor structure.
3837
*
3938
* Tuple type ID information is initially set for an anonymous record type;
4039
* caller can overwrite this if needed.
41-
* ----------------------------------------------------------------
4240
*/
4341
TupleDesc
4442
CreateTemplateTupleDesc(int natts, bool hasoid)
4543
{
4644
TupleDesc desc;
45+
char *stg;
46+
int attroffset;
4747

4848
/*
4949
* sanity checks
5050
*/
5151
AssertArg(natts >= 0);
5252

5353
/*
54-
* Allocate enough memory for the tuple descriptor, and zero the
55-
* attrs[] array since TupleDescInitEntry assumes that the array is
56-
* filled with NULL pointers.
54+
* Allocate enough memory for the tuple descriptor, including the
55+
* attribute rows, and set up the attribute row pointers.
56+
*
57+
* Note: we assume that sizeof(struct tupleDesc) is a multiple of
58+
* the struct pointer alignment requirement, and hence we don't need
59+
* to insert alignment padding between the struct and the array of
60+
* attribute row pointers.
5761
*/
58-
desc = (TupleDesc) palloc(sizeof(struct tupleDesc));
62+
attroffset = sizeof(struct tupleDesc) + natts * sizeof(Form_pg_attribute);
63+
attroffset = MAXALIGN(attroffset);
64+
stg = palloc(attroffset + natts * MAXALIGN(ATTRIBUTE_TUPLE_SIZE));
65+
desc = (TupleDesc) stg;
5966

6067
if (natts > 0)
61-
desc->attrs = (Form_pg_attribute *)
62-
palloc0(natts * sizeof(Form_pg_attribute));
68+
{
69+
Form_pg_attribute *attrs;
70+
int i;
71+
72+
attrs = (Form_pg_attribute *) (stg + sizeof(struct tupleDesc));
73+
desc->attrs = attrs;
74+
stg += attroffset;
75+
for (i = 0; i < natts; i++)
76+
{
77+
attrs[i] = (Form_pg_attribute) stg;
78+
stg += MAXALIGN(ATTRIBUTE_TUPLE_SIZE);
79+
}
80+
}
6381
else
6482
desc->attrs = NULL;
6583

@@ -75,15 +93,16 @@ CreateTemplateTupleDesc(int natts, bool hasoid)
7593
return desc;
7694
}
7795

78-
/* ----------------------------------------------------------------
79-
* CreateTupleDesc
80-
*
96+
/*
97+
* CreateTupleDesc
8198
* This function allocates a new TupleDesc pointing to a given
82-
* Form_pg_attribute array
99+
* Form_pg_attribute array.
100+
*
101+
* Note: if the TupleDesc is ever freed, the Form_pg_attribute array
102+
* will not be freed thereby.
83103
*
84104
* Tuple type ID information is initially set for an anonymous record type;
85105
* caller can overwrite this if needed.
86-
* ----------------------------------------------------------------
87106
*/
88107
TupleDesc
89108
CreateTupleDesc(int natts, bool hasoid, Form_pg_attribute *attrs)
@@ -106,53 +125,38 @@ CreateTupleDesc(int natts, bool hasoid, Form_pg_attribute *attrs)
106125
return desc;
107126
}
108127

109-
/* ----------------------------------------------------------------
110-
* CreateTupleDescCopy
111-
*
128+
/*
129+
* CreateTupleDescCopy
112130
* This function creates a new TupleDesc by copying from an existing
113-
* TupleDesc
131+
* TupleDesc.
114132
*
115-
* !!! Constraints and defaults are not copied !!!
116-
* ----------------------------------------------------------------
133+
* !!! Constraints and defaults are not copied !!!
117134
*/
118135
TupleDesc
119136
CreateTupleDescCopy(TupleDesc tupdesc)
120137
{
121138
TupleDesc desc;
122139
int i;
123140

124-
desc = (TupleDesc) palloc(sizeof(struct tupleDesc));
125-
desc->natts = tupdesc->natts;
126-
if (desc->natts > 0)
141+
desc = CreateTemplateTupleDesc(tupdesc->natts, tupdesc->tdhasoid);
142+
143+
for (i = 0; i < desc->natts; i++)
127144
{
128-
desc->attrs = (Form_pg_attribute *)
129-
palloc(desc->natts * sizeof(Form_pg_attribute));
130-
for (i = 0; i < desc->natts; i++)
131-
{
132-
desc->attrs[i] = (Form_pg_attribute) palloc(ATTRIBUTE_TUPLE_SIZE);
133-
memcpy(desc->attrs[i], tupdesc->attrs[i], ATTRIBUTE_TUPLE_SIZE);
134-
desc->attrs[i]->attnotnull = false;
135-
desc->attrs[i]->atthasdef = false;
136-
}
145+
memcpy(desc->attrs[i], tupdesc->attrs[i], ATTRIBUTE_TUPLE_SIZE);
146+
desc->attrs[i]->attnotnull = false;
147+
desc->attrs[i]->atthasdef = false;
137148
}
138-
else
139-
desc->attrs = NULL;
140-
141-
desc->constr = NULL;
142149

143150
desc->tdtypeid = tupdesc->tdtypeid;
144151
desc->tdtypmod = tupdesc->tdtypmod;
145-
desc->tdhasoid = tupdesc->tdhasoid;
146152

147153
return desc;
148154
}
149155

150-
/* ----------------------------------------------------------------
151-
* CreateTupleDescCopyConstr
152-
*
156+
/*
157+
* CreateTupleDescCopyConstr
153158
* This function creates a new TupleDesc by copying from an existing
154-
* TupleDesc (including its constraints and defaults)
155-
* ----------------------------------------------------------------
159+
* TupleDesc (including its constraints and defaults).
156160
*/
157161
TupleDesc
158162
CreateTupleDescCopyConstr(TupleDesc tupdesc)
@@ -161,20 +165,12 @@ CreateTupleDescCopyConstr(TupleDesc tupdesc)
161165
TupleConstr *constr = tupdesc->constr;
162166
int i;
163167

164-
desc = (TupleDesc) palloc(sizeof(struct tupleDesc));
165-
desc->natts = tupdesc->natts;
166-
if (desc->natts > 0)
168+
desc = CreateTemplateTupleDesc(tupdesc->natts, tupdesc->tdhasoid);
169+
170+
for (i = 0; i < desc->natts; i++)
167171
{
168-
desc->attrs = (Form_pg_attribute *)
169-
palloc(desc->natts * sizeof(Form_pg_attribute));
170-
for (i = 0; i < desc->natts; i++)
171-
{
172-
desc->attrs[i] = (Form_pg_attribute) palloc(ATTRIBUTE_TUPLE_SIZE);
173-
memcpy(desc->attrs[i], tupdesc->attrs[i], ATTRIBUTE_TUPLE_SIZE);
174-
}
172+
memcpy(desc->attrs[i], tupdesc->attrs[i], ATTRIBUTE_TUPLE_SIZE);
175173
}
176-
else
177-
desc->attrs = NULL;
178174

179175
if (constr)
180176
{
@@ -208,12 +204,9 @@ CreateTupleDescCopyConstr(TupleDesc tupdesc)
208204

209205
desc->constr = cpy;
210206
}
211-
else
212-
desc->constr = NULL;
213207

214208
desc->tdtypeid = tupdesc->tdtypeid;
215209
desc->tdtypmod = tupdesc->tdtypmod;
216-
desc->tdhasoid = tupdesc->tdhasoid;
217210

218211
return desc;
219212
}
@@ -226,10 +219,6 @@ FreeTupleDesc(TupleDesc tupdesc)
226219
{
227220
int i;
228221

229-
for (i = 0; i < tupdesc->natts; i++)
230-
pfree(tupdesc->attrs[i]);
231-
if (tupdesc->attrs)
232-
pfree(tupdesc->attrs);
233222
if (tupdesc->constr)
234223
{
235224
if (tupdesc->constr->num_defval > 0)
@@ -379,12 +368,10 @@ equalTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2)
379368
return true;
380369
}
381370

382-
/* ----------------------------------------------------------------
383-
* TupleDescInitEntry
384-
*
371+
/*
372+
* TupleDescInitEntry
385373
* This function initializes a single attribute structure in
386-
* a preallocated tuple descriptor.
387-
* ----------------------------------------------------------------
374+
* a previously allocated tuple descriptor.
388375
*/
389376
void
390377
TupleDescInitEntry(TupleDesc desc,
@@ -404,18 +391,12 @@ TupleDescInitEntry(TupleDesc desc,
404391
AssertArg(PointerIsValid(desc));
405392
AssertArg(attributeNumber >= 1);
406393
AssertArg(attributeNumber <= desc->natts);
407-
AssertArg(!PointerIsValid(desc->attrs[attributeNumber - 1]));
408-
409-
/*
410-
* allocate storage for this attribute
411-
*/
412-
413-
att = (Form_pg_attribute) palloc(ATTRIBUTE_TUPLE_SIZE);
414-
desc->attrs[attributeNumber - 1] = att;
415394

416395
/*
417396
* initialize the attribute fields
418397
*/
398+
att = desc->attrs[attributeNumber - 1];
399+
419400
att->attrelid = 0; /* dummy value */
420401

421402
/*

src/backend/catalog/index.c

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/catalog/index.c,v 1.245 2005/03/04 20:21:05 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/catalog/index.c,v 1.246 2005/03/07 04:42:16 tgl Exp $
1212
*
1313
*
1414
* INTERFACE ROUTINES
@@ -97,14 +97,11 @@ ConstructTupleDescriptor(Relation heapRelation,
9797
for (i = 0; i < numatts; i++)
9898
{
9999
AttrNumber atnum = indexInfo->ii_KeyAttrNumbers[i];
100-
Form_pg_attribute to;
100+
Form_pg_attribute to = indexTupDesc->attrs[i];
101101
HeapTuple tuple;
102102
Form_pg_type typeTup;
103103
Oid keyType;
104104

105-
indexTupDesc->attrs[i] = to =
106-
(Form_pg_attribute) palloc0(ATTRIBUTE_TUPLE_SIZE);
107-
108105
if (atnum != 0)
109106
{
110107
/* Simple index column */
@@ -152,6 +149,8 @@ ConstructTupleDescriptor(Relation heapRelation,
152149
/* Expressional index */
153150
Node *indexkey;
154151

152+
MemSet(to, 0, ATTRIBUTE_TUPLE_SIZE);
153+
155154
if (indexpr_item == NULL) /* shouldn't happen */
156155
elog(ERROR, "too few entries in indexprs list");
157156
indexkey = (Node *) lfirst(indexpr_item);

src/backend/utils/cache/relcache.c

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/utils/cache/relcache.c,v 1.215 2005/01/10 20:02:23 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/utils/cache/relcache.c,v 1.216 2005/03/07 04:42:16 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -491,12 +491,8 @@ RelationBuildTupleDesc(RelationBuildDescInfo buildinfo,
491491
elog(ERROR, "invalid attribute number %d for %s",
492492
attp->attnum, RelationGetRelationName(relation));
493493

494-
relation->rd_att->attrs[attp->attnum - 1] =
495-
(Form_pg_attribute) MemoryContextAlloc(CacheMemoryContext,
496-
ATTRIBUTE_TUPLE_SIZE);
497-
498-
memcpy((char *) (relation->rd_att->attrs[attp->attnum - 1]),
499-
(char *) attp,
494+
memcpy(relation->rd_att->attrs[attp->attnum - 1],
495+
attp,
500496
ATTRIBUTE_TUPLE_SIZE);
501497

502498
/* Update constraint/default info */
@@ -1338,9 +1334,8 @@ formrdesc(const char *relationName, Oid relationReltype,
13381334
has_not_null = false;
13391335
for (i = 0; i < natts; i++)
13401336
{
1341-
relation->rd_att->attrs[i] = (Form_pg_attribute) palloc(ATTRIBUTE_TUPLE_SIZE);
1342-
memcpy((char *) relation->rd_att->attrs[i],
1343-
(char *) &att[i],
1337+
memcpy(relation->rd_att->attrs[i],
1338+
&att[i],
13441339
ATTRIBUTE_TUPLE_SIZE);
13451340
has_not_null |= att[i].attnotnull;
13461341
/* make sure attcacheoff is valid */
@@ -3044,9 +3039,8 @@ load_relcache_init_file(void)
30443039
{
30453040
if ((nread = fread(&len, 1, sizeof(len), fp)) != sizeof(len))
30463041
goto read_failed;
3047-
3048-
rel->rd_att->attrs[i] = (Form_pg_attribute) palloc(len);
3049-
3042+
if (len != ATTRIBUTE_TUPLE_SIZE)
3043+
goto read_failed;
30503044
if ((nread = fread(rel->rd_att->attrs[i], 1, len, fp)) != len)
30513045
goto read_failed;
30523046

src/include/access/tupdesc.h

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
10-
* $PostgreSQL: pgsql/src/include/access/tupdesc.h,v 1.46 2004/12/31 22:03:21 pgsql Exp $
10+
* $PostgreSQL: pgsql/src/include/access/tupdesc.h,v 1.47 2005/03/07 04:42:17 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -42,27 +42,31 @@ typedef struct tupleConstr
4242
} TupleConstr;
4343

4444
/*
45-
* This structure contains all information (i.e. from Classes
46-
* pg_attribute, pg_attrdef, pg_constraint) for the structure of a tuple.
45+
* This struct is passed around within the backend to describe the structure
46+
* of tuples. For tuples coming from on-disk relations, the information is
47+
* collected from the pg_attribute, pg_attrdef, and pg_constraint catalogs.
48+
* Transient row types (such as the result of a join query) have anonymous
49+
* TupleDesc structs that generally omit any constraint info; therefore the
50+
* structure is designed to let the constraints be omitted efficiently.
4751
*
4852
* Note that only user attributes, not system attributes, are mentioned in
4953
* TupleDesc; with the exception that tdhasoid indicates if OID is present.
5054
*
51-
* If the tuple is known to correspond to a named rowtype (such as a table's
55+
* If the tupdesc is known to correspond to a named rowtype (such as a table's
5256
* rowtype) then tdtypeid identifies that type and tdtypmod is -1. Otherwise
5357
* tdtypeid is RECORDOID, and tdtypmod can be either -1 for a fully anonymous
5458
* row type, or a value >= 0 to allow the rowtype to be looked up in the
5559
* typcache.c type cache.
5660
*/
5761
typedef struct tupleDesc
5862
{
59-
int natts; /* Number of attributes in the tuple */
63+
int natts; /* number of attributes in the tuple */
6064
Form_pg_attribute *attrs;
61-
/* attrs[N] is a pointer to the description of Attribute Number N+1. */
62-
TupleConstr *constr;
65+
/* attrs[N] is a pointer to the description of Attribute Number N+1 */
66+
TupleConstr *constr; /* constraints, or NULL if none */
6367
Oid tdtypeid; /* composite type ID for tuple type */
6468
int32 tdtypmod; /* typmod for tuple type */
65-
bool tdhasoid; /* Tuple has oid attribute in its header */
69+
bool tdhasoid; /* tuple has oid attribute in its header */
6670
} *TupleDesc;
6771

6872

0 commit comments

Comments
 (0)