Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 8dcc8e3

Browse files
committed
Refactor ExecGetJunkAttribute to avoid searching for junk attributes
by name on each and every row processed. Profiling suggests this may buy a percent or two for simple UPDATE scenarios, which isn't huge, but when it's so easy to get ...
1 parent 406d028 commit 8dcc8e3

File tree

4 files changed

+90
-54
lines changed

4 files changed

+90
-54
lines changed

src/backend/executor/execJunk.c

Lines changed: 33 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/executor/execJunk.c,v 1.54 2006/07/14 14:52:18 momjian Exp $
11+
* $PostgreSQL: pgsql/src/backend/executor/execJunk.c,v 1.55 2006/12/04 02:06:55 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -26,24 +26,25 @@
2626
* never make it out of the executor, i.e. they are never printed,
2727
* returned or stored on disk. Their only purpose in life is to
2828
* store some information useful only to the executor, mainly the values
29-
* of some system attributes like "ctid" or rule locks.
29+
* of system attributes like "ctid", or sort key columns that are not to
30+
* be output.
3031
*
3132
* The general idea is the following: A target list consists of a list of
3233
* TargetEntry nodes containing expressions. Each TargetEntry has a field
3334
* called 'resjunk'. If the value of this field is true then the
3435
* corresponding attribute is a "junk" attribute.
3536
*
36-
* When we initialize a plan we call 'ExecInitJunkFilter' to create
37-
* and store the appropriate information in the 'es_junkFilter' attribute of
37+
* When we initialize a plan we call ExecInitJunkFilter to create
38+
* and store the appropriate information in the es_junkFilter attribute of
3839
* EState.
3940
*
40-
* We then execute the plan ignoring the "resjunk" attributes.
41+
* We then execute the plan, treating the resjunk attributes like any others.
4142
*
4243
* Finally, when at the top level we get back a tuple, we can call
43-
* ExecGetJunkAttribute to retrieve the value of the junk attributes we
44-
* are interested in, and ExecFilterJunk or ExecRemoveJunk to remove all
45-
* the junk attributes from a tuple. This new "clean" tuple is then printed,
46-
* replaced, deleted or inserted.
44+
* ExecFindJunkAttribute/ExecGetJunkAttribute to retrieve the values of the
45+
* junk attributes we are interested in, and ExecFilterJunk or ExecRemoveJunk
46+
* to remove all the junk attributes from a tuple. This new "clean" tuple is
47+
* then printed, replaced, deleted or inserted.
4748
*
4849
*-------------------------------------------------------------------------
4950
*/
@@ -201,26 +202,16 @@ ExecInitJunkFilterConversion(List *targetList,
201202
}
202203

203204
/*
204-
* ExecGetJunkAttribute
205-
*
206-
* Given a tuple (slot), the junk filter and a junk attribute's name,
207-
* extract & return the value and isNull flag of this attribute.
205+
* ExecFindJunkAttribute
208206
*
209-
* It returns false iff no junk attribute with such name was found.
207+
* Locate the specified junk attribute in the junk filter's targetlist,
208+
* and return its resno. Returns InvalidAttrNumber if not found.
210209
*/
211-
bool
212-
ExecGetJunkAttribute(JunkFilter *junkfilter,
213-
TupleTableSlot *slot,
214-
char *attrName,
215-
Datum *value,
216-
bool *isNull)
210+
AttrNumber
211+
ExecFindJunkAttribute(JunkFilter *junkfilter, const char *attrName)
217212
{
218213
ListCell *t;
219214

220-
/*
221-
* Look in the junkfilter's target list for an attribute with the given
222-
* name
223-
*/
224215
foreach(t, junkfilter->jf_targetList)
225216
{
226217
TargetEntry *tle = lfirst(t);
@@ -229,13 +220,27 @@ ExecGetJunkAttribute(JunkFilter *junkfilter,
229220
(strcmp(tle->resname, attrName) == 0))
230221
{
231222
/* We found it ! */
232-
*value = slot_getattr(slot, tle->resno, isNull);
233-
return true;
223+
return tle->resno;
234224
}
235225
}
236226

237-
/* Ooops! We couldn't find this attribute... */
238-
return false;
227+
return InvalidAttrNumber;
228+
}
229+
230+
/*
231+
* ExecGetJunkAttribute
232+
*
233+
* Given a junk filter's input tuple (slot) and a junk attribute's number
234+
* previously found by ExecFindJunkAttribute, extract & return the value and
235+
* isNull flag of the attribute.
236+
*/
237+
Datum
238+
ExecGetJunkAttribute(TupleTableSlot *slot, AttrNumber attno,
239+
bool *isNull)
240+
{
241+
Assert(attno > 0);
242+
243+
return slot_getattr(slot, attno, isNull);
239244
}
240245

241246
/*

src/backend/executor/execMain.c

Lines changed: 44 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
*
2727
*
2828
* IDENTIFICATION
29-
* $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.280 2006/10/04 00:29:52 momjian Exp $
29+
* $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.281 2006/12/04 02:06:55 tgl Exp $
3030
*
3131
*-------------------------------------------------------------------------
3232
*/
@@ -567,7 +567,9 @@ InitPlan(QueryDesc *queryDesc, int eflags)
567567
}
568568

569569
/*
570-
* Have to lock relations selected FOR UPDATE/FOR SHARE
570+
* Have to lock relations selected FOR UPDATE/FOR SHARE before we
571+
* initialize the plan tree, else we'd be doing a lock upgrade.
572+
* While we are at it, build the ExecRowMark list.
571573
*/
572574
estate->es_rowMarks = NIL;
573575
foreach(l, parseTree->rowMarks)
@@ -583,7 +585,8 @@ InitPlan(QueryDesc *queryDesc, int eflags)
583585
erm->rti = rc->rti;
584586
erm->forUpdate = rc->forUpdate;
585587
erm->noWait = rc->noWait;
586-
snprintf(erm->resname, sizeof(erm->resname), "ctid%u", rc->rti);
588+
/* We'll set up ctidAttno below */
589+
erm->ctidAttNo = InvalidAttrNumber;
587590
estate->es_rowMarks = lappend(estate->es_rowMarks, erm);
588591
}
589592

@@ -703,6 +706,16 @@ InitPlan(QueryDesc *queryDesc, int eflags)
703706
j = ExecInitJunkFilter(subplan->plan->targetlist,
704707
resultRelInfo->ri_RelationDesc->rd_att->tdhasoid,
705708
ExecAllocTableSlot(estate->es_tupleTable));
709+
/*
710+
* Since it must be UPDATE/DELETE, there had better be
711+
* a "ctid" junk attribute in the tlist ... but ctid could
712+
* be at a different resno for each result relation.
713+
* We look up the ctid resnos now and save them in the
714+
* junkfilters.
715+
*/
716+
j->jf_junkAttNo = ExecFindJunkAttribute(j, "ctid");
717+
if (!AttributeNumberIsValid(j->jf_junkAttNo))
718+
elog(ERROR, "could not find junk ctid column");
706719
resultRelInfo->ri_junkFilter = j;
707720
resultRelInfo++;
708721
}
@@ -726,9 +739,30 @@ InitPlan(QueryDesc *queryDesc, int eflags)
726739
if (estate->es_result_relation_info)
727740
estate->es_result_relation_info->ri_junkFilter = j;
728741

729-
/* For SELECT, want to return the cleaned tuple type */
730742
if (operation == CMD_SELECT)
743+
{
744+
/* For SELECT, want to return the cleaned tuple type */
731745
tupType = j->jf_cleanTupType;
746+
/* For SELECT FOR UPDATE/SHARE, find the ctid attrs now */
747+
foreach(l, estate->es_rowMarks)
748+
{
749+
ExecRowMark *erm = (ExecRowMark *) lfirst(l);
750+
char resname[32];
751+
752+
snprintf(resname, sizeof(resname), "ctid%u", erm->rti);
753+
erm->ctidAttNo = ExecFindJunkAttribute(j, resname);
754+
if (!AttributeNumberIsValid(erm->ctidAttNo))
755+
elog(ERROR, "could not find junk \"%s\" column",
756+
resname);
757+
}
758+
}
759+
else if (operation == CMD_UPDATE || operation == CMD_DELETE)
760+
{
761+
/* For UPDATE/DELETE, find the ctid junk attr now */
762+
j->jf_junkAttNo = ExecFindJunkAttribute(j, "ctid");
763+
if (!AttributeNumberIsValid(j->jf_junkAttNo))
764+
elog(ERROR, "could not find junk ctid column");
765+
}
732766
}
733767
}
734768
else
@@ -1111,13 +1145,8 @@ lnext: ;
11111145
*/
11121146
if (operation == CMD_UPDATE || operation == CMD_DELETE)
11131147
{
1114-
if (!ExecGetJunkAttribute(junkfilter,
1115-
slot,
1116-
"ctid",
1117-
&datum,
1118-
&isNull))
1119-
elog(ERROR, "could not find junk ctid column");
1120-
1148+
datum = ExecGetJunkAttribute(slot, junkfilter->jf_junkAttNo,
1149+
&isNull);
11211150
/* shouldn't ever get a null result... */
11221151
if (isNull)
11231152
elog(ERROR, "ctid is NULL");
@@ -1146,17 +1175,12 @@ lnext: ;
11461175
LockTupleMode lockmode;
11471176
HTSU_Result test;
11481177

1149-
if (!ExecGetJunkAttribute(junkfilter,
1150-
slot,
1151-
erm->resname,
1152-
&datum,
1153-
&isNull))
1154-
elog(ERROR, "could not find junk \"%s\" column",
1155-
erm->resname);
1156-
1178+
datum = ExecGetJunkAttribute(slot,
1179+
erm->ctidAttNo,
1180+
&isNull);
11571181
/* shouldn't ever get a null result... */
11581182
if (isNull)
1159-
elog(ERROR, "\"%s\" is NULL", erm->resname);
1183+
elog(ERROR, "ctid is NULL");
11601184

11611185
tuple.t_self = *((ItemPointer) DatumGetPointer(datum));
11621186

src/include/executor/executor.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
10-
* $PostgreSQL: pgsql/src/include/executor/executor.h,v 1.130 2006/10/04 00:30:08 momjian Exp $
10+
* $PostgreSQL: pgsql/src/include/executor/executor.h,v 1.131 2006/12/04 02:06:55 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -110,8 +110,10 @@ extern JunkFilter *ExecInitJunkFilter(List *targetList, bool hasoid,
110110
extern JunkFilter *ExecInitJunkFilterConversion(List *targetList,
111111
TupleDesc cleanTupType,
112112
TupleTableSlot *slot);
113-
extern bool ExecGetJunkAttribute(JunkFilter *junkfilter, TupleTableSlot *slot,
114-
char *attrName, Datum *value, bool *isNull);
113+
extern AttrNumber ExecFindJunkAttribute(JunkFilter *junkfilter,
114+
const char *attrName);
115+
extern Datum ExecGetJunkAttribute(TupleTableSlot *slot, AttrNumber attno,
116+
bool *isNull);
115117
extern TupleTableSlot *ExecFilterJunk(JunkFilter *junkfilter,
116118
TupleTableSlot *slot);
117119
extern HeapTuple ExecRemoveJunk(JunkFilter *junkfilter, TupleTableSlot *slot);

src/include/nodes/execnodes.h

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
10-
* $PostgreSQL: pgsql/src/include/nodes/execnodes.h,v 1.161 2006/09/28 20:51:42 tgl Exp $
10+
* $PostgreSQL: pgsql/src/include/nodes/execnodes.h,v 1.162 2006/12/04 02:06:55 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -226,7 +226,8 @@ typedef struct ProjectionInfo
226226
* the tuple to be updated. This is needed to do the update, but we
227227
* don't want the ctid to be part of the stored new tuple! So, we
228228
* apply a "junk filter" to remove the junk attributes and form the
229-
* real output tuple.
229+
* real output tuple. The junkfilter code also provides routines to
230+
* extract the values of the junk attribute(s) from the input tuple.
230231
*
231232
* targetList: the original target list (including junk attributes).
232233
* cleanTupType: the tuple descriptor for the "clean" tuple (with
@@ -235,6 +236,9 @@ typedef struct ProjectionInfo
235236
* attribute numbers of the "original" tuple and the
236237
* attribute numbers of the "clean" tuple.
237238
* resultSlot: tuple slot used to hold cleaned tuple.
239+
* junkAttNo: not used by junkfilter code. Can be used by caller
240+
* to remember the attno of a specific junk attribute
241+
* (execMain.c stores the "ctid" attno here).
238242
* ----------------
239243
*/
240244
typedef struct JunkFilter
@@ -244,6 +248,7 @@ typedef struct JunkFilter
244248
TupleDesc jf_cleanTupType;
245249
AttrNumber *jf_cleanMap;
246250
TupleTableSlot *jf_resultSlot;
251+
AttrNumber jf_junkAttNo;
247252
} JunkFilter;
248253

249254
/* ----------------
@@ -352,7 +357,7 @@ typedef struct ExecRowMark
352357
Index rti; /* its range table index */
353358
bool forUpdate; /* true = FOR UPDATE, false = FOR SHARE */
354359
bool noWait; /* NOWAIT option */
355-
char resname[32]; /* name for its ctid junk attribute */
360+
AttrNumber ctidAttNo; /* resno of its ctid junk attribute */
356361
} ExecRowMark;
357362

358363

0 commit comments

Comments
 (0)