Standardize some more loops that chase down parallel lists.

We have forboth() and forthree() macros that simplify iterating
through several parallel lists, but not everyplace that could
reasonably use those was doing so.  Also invent forfour() and
forfive() macros to do the same for four or five parallel lists,
and use those where applicable.

The immediate motivation for doing this is to reduce the number
of ad-hoc lnext() calls, to reduce the footprint of a WIP patch.
However, it seems like good cleanup and error-proofing anyway;
the places that were combining forthree() with a manually iterated
loop seem particularly illegible and bug-prone.

There was some speculation about restructuring related parsetree
representations to reduce the need for parallel list chasing of
this sort.  Perhaps that's a win, or perhaps not, but in any case
it would be considerably more invasive than this patch; and it's
not particularly related to my immediate goal of improving the
List infrastructure.  So I'll leave that question for another day.

Patch by me; thanks to David Rowley for review.

Discussion: https://postgr.es/m/11587.1550975080@sss.pgh.pa.us
This commit is contained in:
Tom Lane 2019-02-28 14:25:01 -05:00
parent 0a271df705
commit c94fb8e8ac
9 changed files with 76 additions and 115 deletions

View File

@ -902,23 +902,12 @@ BuildDescFromLists(List *names, List *types, List *typmods, List *collations)
desc = CreateTemplateTupleDesc(natts); desc = CreateTemplateTupleDesc(natts);
attnum = 0; attnum = 0;
forfour(l1, names, l2, types, l3, typmods, l4, collations)
l2 = list_head(types);
l3 = list_head(typmods);
l4 = list_head(collations);
foreach(l1, names)
{ {
char *attname = strVal(lfirst(l1)); char *attname = strVal(lfirst(l1));
Oid atttypid; Oid atttypid = lfirst_oid(l2);
int32 atttypmod; int32 atttypmod = lfirst_int(l3);
Oid attcollation; Oid attcollation = lfirst_oid(l4);
atttypid = lfirst_oid(l2);
l2 = lnext(l2);
atttypmod = lfirst_int(l3);
l3 = lnext(l3);
attcollation = lfirst_oid(l4);
l4 = lnext(l4);
attnum++; attnum++;

View File

@ -1683,7 +1683,6 @@ ExecInitExprRec(Expr *node, ExprState *state,
*l_opfamily, *l_opfamily,
*l_inputcollid; *l_inputcollid;
ListCell *lc; ListCell *lc;
int off;
/* /*
* Iterate over each field, prepare comparisons. To handle * Iterate over each field, prepare comparisons. To handle
@ -1695,20 +1694,11 @@ ExecInitExprRec(Expr *node, ExprState *state,
Assert(list_length(rcexpr->opfamilies) == nopers); Assert(list_length(rcexpr->opfamilies) == nopers);
Assert(list_length(rcexpr->inputcollids) == nopers); Assert(list_length(rcexpr->inputcollids) == nopers);
off = 0; forfive(l_left_expr, rcexpr->largs,
for (off = 0, l_right_expr, rcexpr->rargs,
l_left_expr = list_head(rcexpr->largs), l_opno, rcexpr->opnos,
l_right_expr = list_head(rcexpr->rargs), l_opfamily, rcexpr->opfamilies,
l_opno = list_head(rcexpr->opnos), l_inputcollid, rcexpr->inputcollids)
l_opfamily = list_head(rcexpr->opfamilies),
l_inputcollid = list_head(rcexpr->inputcollids);
off < nopers;
off++,
l_left_expr = lnext(l_left_expr),
l_right_expr = lnext(l_right_expr),
l_opno = lnext(l_opno),
l_opfamily = lnext(l_opfamily),
l_inputcollid = lnext(l_inputcollid))
{ {
Expr *left_expr = (Expr *) lfirst(l_left_expr); Expr *left_expr = (Expr *) lfirst(l_left_expr);
Expr *right_expr = (Expr *) lfirst(l_right_expr); Expr *right_expr = (Expr *) lfirst(l_right_expr);

View File

@ -1332,12 +1332,12 @@ ExecIndexBuildScanKeys(PlanState *planstate, Relation index,
{ {
/* (indexkey, indexkey, ...) op (expression, expression, ...) */ /* (indexkey, indexkey, ...) op (expression, expression, ...) */
RowCompareExpr *rc = (RowCompareExpr *) clause; RowCompareExpr *rc = (RowCompareExpr *) clause;
ListCell *largs_cell = list_head(rc->largs);
ListCell *rargs_cell = list_head(rc->rargs);
ListCell *opnos_cell = list_head(rc->opnos);
ListCell *collids_cell = list_head(rc->inputcollids);
ScanKey first_sub_key; ScanKey first_sub_key;
int n_sub_key; int n_sub_key;
ListCell *largs_cell;
ListCell *rargs_cell;
ListCell *opnos_cell;
ListCell *collids_cell;
Assert(!isorderby); Assert(!isorderby);
@ -1346,19 +1346,22 @@ ExecIndexBuildScanKeys(PlanState *planstate, Relation index,
n_sub_key = 0; n_sub_key = 0;
/* Scan RowCompare columns and generate subsidiary ScanKey items */ /* Scan RowCompare columns and generate subsidiary ScanKey items */
while (opnos_cell != NULL) forfour(largs_cell, rc->largs, rargs_cell, rc->rargs,
opnos_cell, rc->opnos, collids_cell, rc->inputcollids)
{ {
ScanKey this_sub_key = &first_sub_key[n_sub_key]; ScanKey this_sub_key = &first_sub_key[n_sub_key];
int flags = SK_ROW_MEMBER; int flags = SK_ROW_MEMBER;
Datum scanvalue; Datum scanvalue;
Oid inputcollation; Oid inputcollation;
leftop = (Expr *) lfirst(largs_cell);
rightop = (Expr *) lfirst(rargs_cell);
opno = lfirst_oid(opnos_cell);
inputcollation = lfirst_oid(collids_cell);
/* /*
* leftop should be the index key Var, possibly relabeled * leftop should be the index key Var, possibly relabeled
*/ */
leftop = (Expr *) lfirst(largs_cell);
largs_cell = lnext(largs_cell);
if (leftop && IsA(leftop, RelabelType)) if (leftop && IsA(leftop, RelabelType))
leftop = ((RelabelType *) leftop)->arg; leftop = ((RelabelType *) leftop)->arg;
@ -1374,9 +1377,6 @@ ExecIndexBuildScanKeys(PlanState *planstate, Relation index,
* We have to look up the operator's associated btree support * We have to look up the operator's associated btree support
* function * function
*/ */
opno = lfirst_oid(opnos_cell);
opnos_cell = lnext(opnos_cell);
if (index->rd_rel->relam != BTREE_AM_OID || if (index->rd_rel->relam != BTREE_AM_OID ||
varattno < 1 || varattno > indnkeyatts) varattno < 1 || varattno > indnkeyatts)
elog(ERROR, "bogus RowCompare index qualification"); elog(ERROR, "bogus RowCompare index qualification");
@ -1398,15 +1398,9 @@ ExecIndexBuildScanKeys(PlanState *planstate, Relation index,
elog(ERROR, "missing support function %d(%u,%u) in opfamily %u", elog(ERROR, "missing support function %d(%u,%u) in opfamily %u",
BTORDER_PROC, op_lefttype, op_righttype, opfamily); BTORDER_PROC, op_lefttype, op_righttype, opfamily);
inputcollation = lfirst_oid(collids_cell);
collids_cell = lnext(collids_cell);
/* /*
* rightop is the constant or variable comparison value * rightop is the constant or variable comparison value
*/ */
rightop = (Expr *) lfirst(rargs_cell);
rargs_cell = lnext(rargs_cell);
if (rightop && IsA(rightop, RelabelType)) if (rightop && IsA(rightop, RelabelType))
rightop = ((RelabelType *) rightop)->arg; rightop = ((RelabelType *) rightop)->arg;

View File

@ -1680,9 +1680,7 @@ convert_EXISTS_to_ANY(PlannerInfo *root, Query *subselect,
*/ */
tlist = testlist = paramids = NIL; tlist = testlist = paramids = NIL;
resno = 1; resno = 1;
/* there's no "forfour" so we have to chase one of the lists manually */ forfour(lc, leftargs, rc, rightargs, oc, opids, cc, opcollations)
cc = list_head(opcollations);
forthree(lc, leftargs, rc, rightargs, oc, opids)
{ {
Node *leftarg = (Node *) lfirst(lc); Node *leftarg = (Node *) lfirst(lc);
Node *rightarg = (Node *) lfirst(rc); Node *rightarg = (Node *) lfirst(rc);
@ -1690,7 +1688,6 @@ convert_EXISTS_to_ANY(PlannerInfo *root, Query *subselect,
Oid opcollation = lfirst_oid(cc); Oid opcollation = lfirst_oid(cc);
Param *param; Param *param;
cc = lnext(cc);
param = generate_new_exec_param(root, param = generate_new_exec_param(root,
exprType(rightarg), exprType(rightarg),
exprTypmod(rightarg), exprTypmod(rightarg),

View File

@ -1130,17 +1130,14 @@ generate_setop_tlist(List *colTypes, List *colCollations,
TargetEntry *tle; TargetEntry *tle;
Node *expr; Node *expr;
/* there's no forfour() so we must chase one list manually */ forfour(ctlc, colTypes, cclc, colCollations,
rtlc = list_head(refnames_tlist); itlc, input_tlist, rtlc, refnames_tlist)
forthree(ctlc, colTypes, cclc, colCollations, itlc, input_tlist)
{ {
Oid colType = lfirst_oid(ctlc); Oid colType = lfirst_oid(ctlc);
Oid colColl = lfirst_oid(cclc); Oid colColl = lfirst_oid(cclc);
TargetEntry *inputtle = (TargetEntry *) lfirst(itlc); TargetEntry *inputtle = (TargetEntry *) lfirst(itlc);
TargetEntry *reftle = (TargetEntry *) lfirst(rtlc); TargetEntry *reftle = (TargetEntry *) lfirst(rtlc);
rtlc = lnext(rtlc);
Assert(inputtle->resno == resno); Assert(inputtle->resno == resno);
Assert(reftle->resno == resno); Assert(reftle->resno == resno);
Assert(!inputtle->resjunk); Assert(!inputtle->resjunk);

View File

@ -831,18 +831,14 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
*/ */
rte = pstate->p_target_rangetblentry; rte = pstate->p_target_rangetblentry;
qry->targetList = NIL; qry->targetList = NIL;
icols = list_head(icolumns); Assert(list_length(exprList) <= list_length(icolumns));
attnos = list_head(attrnos); forthree(lc, exprList, icols, icolumns, attnos, attrnos)
foreach(lc, exprList)
{ {
Expr *expr = (Expr *) lfirst(lc); Expr *expr = (Expr *) lfirst(lc);
ResTarget *col; ResTarget *col = lfirst_node(ResTarget, icols);
AttrNumber attr_num; AttrNumber attr_num = (AttrNumber) lfirst_int(attnos);
TargetEntry *tle; TargetEntry *tle;
col = lfirst_node(ResTarget, icols);
attr_num = (AttrNumber) lfirst_int(attnos);
tle = makeTargetEntry(expr, tle = makeTargetEntry(expr,
attr_num, attr_num,
col->name, col->name,
@ -851,9 +847,6 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
rte->insertedCols = bms_add_member(rte->insertedCols, rte->insertedCols = bms_add_member(rte->insertedCols,
attr_num - FirstLowInvalidHeapAttributeNumber); attr_num - FirstLowInvalidHeapAttributeNumber);
icols = lnext(icols);
attnos = lnext(attnos);
} }
/* Process ON CONFLICT, if any. */ /* Process ON CONFLICT, if any. */
@ -950,19 +943,16 @@ transformInsertRow(ParseState *pstate, List *exprlist,
* Prepare columns for assignment to target table. * Prepare columns for assignment to target table.
*/ */
result = NIL; result = NIL;
icols = list_head(icolumns); forthree(lc, exprlist, icols, icolumns, attnos, attrnos)
attnos = list_head(attrnos);
foreach(lc, exprlist)
{ {
Expr *expr = (Expr *) lfirst(lc); Expr *expr = (Expr *) lfirst(lc);
ResTarget *col; ResTarget *col = lfirst_node(ResTarget, icols);
int attno = lfirst_int(attnos);
col = lfirst_node(ResTarget, icols);
expr = transformAssignedExpr(pstate, expr, expr = transformAssignedExpr(pstate, expr,
EXPR_KIND_INSERT_TARGET, EXPR_KIND_INSERT_TARGET,
col->name, col->name,
lfirst_int(attnos), attno,
col->indirection, col->indirection,
col->location); col->location);
@ -991,9 +981,6 @@ transformInsertRow(ParseState *pstate, List *exprlist,
} }
result = lappend(result, expr); result = lappend(result, expr);
icols = lnext(icols);
attnos = lnext(attnos);
} }
return result; return result;
@ -1699,11 +1686,11 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
qry->targetList = NIL; qry->targetList = NIL;
targetvars = NIL; targetvars = NIL;
targetnames = NIL; targetnames = NIL;
left_tlist = list_head(leftmostQuery->targetList);
forthree(lct, sostmt->colTypes, forfour(lct, sostmt->colTypes,
lcm, sostmt->colTypmods, lcm, sostmt->colTypmods,
lcc, sostmt->colCollations) lcc, sostmt->colCollations,
left_tlist, leftmostQuery->targetList)
{ {
Oid colType = lfirst_oid(lct); Oid colType = lfirst_oid(lct);
int32 colTypmod = lfirst_int(lcm); int32 colTypmod = lfirst_int(lcm);
@ -1729,7 +1716,6 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
qry->targetList = lappend(qry->targetList, tle); qry->targetList = lappend(qry->targetList, tle);
targetvars = lappend(targetvars, var); targetvars = lappend(targetvars, var);
targetnames = lappend(targetnames, makeString(colName)); targetnames = lappend(targetnames, makeString(colName));
left_tlist = lnext(left_tlist);
} }
/* /*
@ -2201,10 +2187,9 @@ determineRecursiveColTypes(ParseState *pstate, Node *larg, List *nrtargetlist)
* dummy result expressions of the non-recursive term. * dummy result expressions of the non-recursive term.
*/ */
targetList = NIL; targetList = NIL;
left_tlist = list_head(leftmostQuery->targetList);
next_resno = 1; next_resno = 1;
foreach(nrtl, nrtargetlist) forboth(nrtl, nrtargetlist, left_tlist, leftmostQuery->targetList)
{ {
TargetEntry *nrtle = (TargetEntry *) lfirst(nrtl); TargetEntry *nrtle = (TargetEntry *) lfirst(nrtl);
TargetEntry *lefttle = (TargetEntry *) lfirst(left_tlist); TargetEntry *lefttle = (TargetEntry *) lfirst(left_tlist);
@ -2218,7 +2203,6 @@ determineRecursiveColTypes(ParseState *pstate, Node *larg, List *nrtargetlist)
colName, colName,
false); false);
targetList = lappend(targetList, tle); targetList = lappend(targetList, tle);
left_tlist = lnext(left_tlist);
} }
/* Now build CTE's output column info using dummy targetlist */ /* Now build CTE's output column info using dummy targetlist */

View File

@ -2124,13 +2124,12 @@ LookupFuncWithArgs(ObjectType objtype, ObjectWithArgs *func, bool noError)
FUNC_MAX_ARGS, FUNC_MAX_ARGS,
FUNC_MAX_ARGS))); FUNC_MAX_ARGS)));
args_item = list_head(func->objargs); i = 0;
for (i = 0; i < argcount; i++) foreach(args_item, func->objargs)
{ {
TypeName *t = (TypeName *) lfirst(args_item); TypeName *t = (TypeName *) lfirst(args_item);
argoids[i] = LookupTypeNameOid(NULL, t, noError); argoids[i++] = LookupTypeNameOid(NULL, t, noError);
args_item = lnext(args_item);
} }
/* /*

View File

@ -9811,31 +9811,18 @@ get_tablefunc(TableFunc *tf, deparse_context *context, bool showimplicit)
ListCell *l5; ListCell *l5;
int colnum = 0; int colnum = 0;
l2 = list_head(tf->coltypes);
l3 = list_head(tf->coltypmods);
l4 = list_head(tf->colexprs);
l5 = list_head(tf->coldefexprs);
appendStringInfoString(buf, " COLUMNS "); appendStringInfoString(buf, " COLUMNS ");
foreach(l1, tf->colnames) forfive(l1, tf->colnames, l2, tf->coltypes, l3, tf->coltypmods,
l4, tf->colexprs, l5, tf->coldefexprs)
{ {
char *colname = strVal(lfirst(l1)); char *colname = strVal(lfirst(l1));
Oid typid; Oid typid = lfirst_oid(l2);
int32 typmod; int32 typmod = lfirst_int(l3);
Node *colexpr; Node *colexpr = (Node *) lfirst(l4);
Node *coldefexpr; Node *coldefexpr = (Node *) lfirst(l5);
bool ordinality = tf->ordinalitycol == colnum; bool ordinality = (tf->ordinalitycol == colnum);
bool notnull = bms_is_member(colnum, tf->notnulls); bool notnull = bms_is_member(colnum, tf->notnulls);
typid = lfirst_oid(l2);
l2 = lnext(l2);
typmod = lfirst_int(l3);
l3 = lnext(l3);
colexpr = (Node *) lfirst(l4);
l4 = lnext(l4);
coldefexpr = (Node *) lfirst(l5);
l5 = lnext(l5);
if (colnum > 0) if (colnum > 0)
appendStringInfoString(buf, ", "); appendStringInfoString(buf, ", ");
colnum++; colnum++;
@ -10349,12 +10336,11 @@ get_from_clause_coldeflist(RangeTblFunction *rtfunc,
appendStringInfoChar(buf, '('); appendStringInfoChar(buf, '(');
/* there's no forfour(), so must chase one list the hard way */
i = 0; i = 0;
l4 = list_head(rtfunc->funccolnames); forfour(l1, rtfunc->funccoltypes,
forthree(l1, rtfunc->funccoltypes, l2, rtfunc->funccoltypmods,
l2, rtfunc->funccoltypmods, l3, rtfunc->funccolcollations,
l3, rtfunc->funccolcollations) l4, rtfunc->funccolnames)
{ {
Oid atttypid = lfirst_oid(l1); Oid atttypid = lfirst_oid(l1);
int32 atttypmod = lfirst_int(l2); int32 atttypmod = lfirst_int(l2);
@ -10378,7 +10364,6 @@ get_from_clause_coldeflist(RangeTblFunction *rtfunc,
appendStringInfo(buf, " COLLATE %s", appendStringInfo(buf, " COLLATE %s",
generate_collation_name(attcollation)); generate_collation_name(attcollation));
l4 = lnext(l4);
i++; i++;
} }

View File

@ -205,6 +205,32 @@ list_length(const List *l)
(cell1) != NULL && (cell2) != NULL && (cell3) != NULL; \ (cell1) != NULL && (cell2) != NULL && (cell3) != NULL; \
(cell1) = lnext(cell1), (cell2) = lnext(cell2), (cell3) = lnext(cell3)) (cell1) = lnext(cell1), (cell2) = lnext(cell2), (cell3) = lnext(cell3))
/*
* forfour -
* the same for four lists
*/
#define forfour(cell1, list1, cell2, list2, cell3, list3, cell4, list4) \
for ((cell1) = list_head(list1), (cell2) = list_head(list2), \
(cell3) = list_head(list3), (cell4) = list_head(list4); \
(cell1) != NULL && (cell2) != NULL && \
(cell3) != NULL && (cell4) != NULL; \
(cell1) = lnext(cell1), (cell2) = lnext(cell2), \
(cell3) = lnext(cell3), (cell4) = lnext(cell4))
/*
* forfive -
* the same for five lists
*/
#define forfive(cell1, list1, cell2, list2, cell3, list3, cell4, list4, cell5, list5) \
for ((cell1) = list_head(list1), (cell2) = list_head(list2), \
(cell3) = list_head(list3), (cell4) = list_head(list4), \
(cell5) = list_head(list5); \
(cell1) != NULL && (cell2) != NULL && (cell3) != NULL && \
(cell4) != NULL && (cell5) != NULL; \
(cell1) = lnext(cell1), (cell2) = lnext(cell2), \
(cell3) = lnext(cell3), (cell4) = lnext(cell4), \
(cell5) = lnext(cell5))
extern List *lappend(List *list, void *datum); extern List *lappend(List *list, void *datum);
extern List *lappend_int(List *list, int datum); extern List *lappend_int(List *list, int datum);
extern List *lappend_oid(List *list, Oid datum); extern List *lappend_oid(List *list, Oid datum);