Re: POC: converting Lists into arrays

Поиск
Список
Период
Сортировка
От Tom Lane
Тема Re: POC: converting Lists into arrays
Дата
Msg-id 10893.1551299206@sss.pgh.pa.us
обсуждение исходный текст
Ответ на Re: POC: converting Lists into arrays  (Tom Lane <tgl@sss.pgh.pa.us>)
Ответы Re: POC: converting Lists into arrays  (Robert Haas <robertmhaas@gmail.com>)
Re: POC: converting Lists into arrays  (Alvaro Herrera <alvherre@2ndquadrant.com>)
Re: POC: converting Lists into arrays  (David Rowley <david.rowley@2ndquadrant.com>)
Список pgsql-hackers
I wrote:
> I did find a number of places where getting rid of explicit lnext()
> calls led to just plain cleaner code.  Most of these were places that
> could be using forboth() or forthree() and just weren't.  There's
> also several places that are crying out for a forfour() macro, so
> I'm not sure why we've stubbornly refused to provide it.  I'm a bit
> inclined to just fix those things in the name of code readability,
> independent of this patch.

0001 below does this.  I found a couple of places that could use
forfive(), as well.  I think this is a clear legibility and
error-proofing win, and we should just push it.

> I also noticed that there's quite a lot of places that are testing
> lnext(cell) for being NULL or not.  What that really means is whether
> this cell is last in the list or not, so maybe readability would be
> improved by defining a macro along the lines of list_cell_is_last().
> Any thoughts about that?

0002 below does this.  I'm having a hard time deciding whether this
part is a good idea or just code churn.  It might be more readable
(especially to newbies) but I can't evaluate that very objectively.
I'm particularly unsure about whether we need two macros; though the
way I initially tried it with just list_cell_is_last() seemed kind of
double-negatively confusing in the places where the test needs to be
not-last.  Also, are these macro names too long, and if so what would
be better?

Also: if we accept either or both of these, should we back-patch the
macro additions, so that these new macros will be available for use
in back-patched code?  I'm not sure that forfour/forfive have enough
use-cases to worry about that; but the is-last macros would have a
better case for that, I think.

            regards, tom lane

diff --git a/src/backend/access/common/tupdesc.c b/src/backend/access/common/tupdesc.c
index 47e80ae..832c3e9 100644
--- a/src/backend/access/common/tupdesc.c
+++ b/src/backend/access/common/tupdesc.c
@@ -902,23 +902,12 @@ BuildDescFromLists(List *names, List *types, List *typmods, List *collations)
     desc = CreateTemplateTupleDesc(natts);

     attnum = 0;
-
-    l2 = list_head(types);
-    l3 = list_head(typmods);
-    l4 = list_head(collations);
-    foreach(l1, names)
+    forfour(l1, names, l2, types, l3, typmods, l4, collations)
     {
         char       *attname = strVal(lfirst(l1));
-        Oid            atttypid;
-        int32        atttypmod;
-        Oid            attcollation;
-
-        atttypid = lfirst_oid(l2);
-        l2 = lnext(l2);
-        atttypmod = lfirst_int(l3);
-        l3 = lnext(l3);
-        attcollation = lfirst_oid(l4);
-        l4 = lnext(l4);
+        Oid            atttypid = lfirst_oid(l2);
+        int32        atttypmod = lfirst_int(l3);
+        Oid            attcollation = lfirst_oid(l4);

         attnum++;

diff --git a/src/backend/executor/execExpr.c b/src/backend/executor/execExpr.c
index db3777d..7cbf9d3 100644
--- a/src/backend/executor/execExpr.c
+++ b/src/backend/executor/execExpr.c
@@ -1683,7 +1683,6 @@ ExecInitExprRec(Expr *node, ExprState *state,
                            *l_opfamily,
                            *l_inputcollid;
                 ListCell   *lc;
-                int            off;

                 /*
                  * 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->inputcollids) == nopers);

-                off = 0;
-                for (off = 0,
-                     l_left_expr = list_head(rcexpr->largs),
-                     l_right_expr = list_head(rcexpr->rargs),
-                     l_opno = list_head(rcexpr->opnos),
-                     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))
+                forfive(l_left_expr, rcexpr->largs,
+                        l_right_expr, rcexpr->rargs,
+                        l_opno, rcexpr->opnos,
+                        l_opfamily, rcexpr->opfamilies,
+                        l_inputcollid, rcexpr->inputcollids)
                 {
                     Expr       *left_expr = (Expr *) lfirst(l_left_expr);
                     Expr       *right_expr = (Expr *) lfirst(l_right_expr);
diff --git a/src/backend/executor/nodeIndexscan.c b/src/backend/executor/nodeIndexscan.c
index 324356e..8b29437 100644
--- a/src/backend/executor/nodeIndexscan.c
+++ b/src/backend/executor/nodeIndexscan.c
@@ -1332,12 +1332,12 @@ ExecIndexBuildScanKeys(PlanState *planstate, Relation index,
         {
             /* (indexkey, indexkey, ...) op (expression, expression, ...) */
             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;
             int            n_sub_key;
+            ListCell   *largs_cell;
+            ListCell   *rargs_cell;
+            ListCell   *opnos_cell;
+            ListCell   *collids_cell;

             Assert(!isorderby);

@@ -1346,19 +1346,22 @@ ExecIndexBuildScanKeys(PlanState *planstate, Relation index,
             n_sub_key = 0;

             /* 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];
                 int            flags = SK_ROW_MEMBER;
                 Datum        scanvalue;
                 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 = (Expr *) lfirst(largs_cell);
-                largs_cell = lnext(largs_cell);
-
                 if (leftop && IsA(leftop, RelabelType))
                     leftop = ((RelabelType *) leftop)->arg;

@@ -1374,9 +1377,6 @@ ExecIndexBuildScanKeys(PlanState *planstate, Relation index,
                  * We have to look up the operator's associated btree support
                  * function
                  */
-                opno = lfirst_oid(opnos_cell);
-                opnos_cell = lnext(opnos_cell);
-
                 if (index->rd_rel->relam != BTREE_AM_OID ||
                     varattno < 1 || varattno > indnkeyatts)
                     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",
                          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 = (Expr *) lfirst(rargs_cell);
-                rargs_cell = lnext(rargs_cell);
-
                 if (rightop && IsA(rightop, RelabelType))
                     rightop = ((RelabelType *) rightop)->arg;

diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c
index c721054..555c91f 100644
--- a/src/backend/optimizer/plan/subselect.c
+++ b/src/backend/optimizer/plan/subselect.c
@@ -1680,9 +1680,7 @@ convert_EXISTS_to_ANY(PlannerInfo *root, Query *subselect,
      */
     tlist = testlist = paramids = NIL;
     resno = 1;
-    /* there's no "forfour" so we have to chase one of the lists manually */
-    cc = list_head(opcollations);
-    forthree(lc, leftargs, rc, rightargs, oc, opids)
+    forfour(lc, leftargs, rc, rightargs, oc, opids, cc, opcollations)
     {
         Node       *leftarg = (Node *) lfirst(lc);
         Node       *rightarg = (Node *) lfirst(rc);
@@ -1690,7 +1688,6 @@ convert_EXISTS_to_ANY(PlannerInfo *root, Query *subselect,
         Oid            opcollation = lfirst_oid(cc);
         Param       *param;

-        cc = lnext(cc);
         param = generate_new_exec_param(root,
                                         exprType(rightarg),
                                         exprTypmod(rightarg),
diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c
index 55eeb51..eb815c2 100644
--- a/src/backend/optimizer/prep/prepunion.c
+++ b/src/backend/optimizer/prep/prepunion.c
@@ -1130,17 +1130,14 @@ generate_setop_tlist(List *colTypes, List *colCollations,
     TargetEntry *tle;
     Node       *expr;

-    /* there's no forfour() so we must chase one list manually */
-    rtlc = list_head(refnames_tlist);
-    forthree(ctlc, colTypes, cclc, colCollations, itlc, input_tlist)
+    forfour(ctlc, colTypes, cclc, colCollations,
+            itlc, input_tlist, rtlc, refnames_tlist)
     {
         Oid            colType = lfirst_oid(ctlc);
         Oid            colColl = lfirst_oid(cclc);
         TargetEntry *inputtle = (TargetEntry *) lfirst(itlc);
         TargetEntry *reftle = (TargetEntry *) lfirst(rtlc);

-        rtlc = lnext(rtlc);
-
         Assert(inputtle->resno == resno);
         Assert(reftle->resno == resno);
         Assert(!inputtle->resjunk);
diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c
index e3544ef..5efd86e 100644
--- a/src/backend/parser/analyze.c
+++ b/src/backend/parser/analyze.c
@@ -831,18 +831,14 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
      */
     rte = pstate->p_target_rangetblentry;
     qry->targetList = NIL;
-    icols = list_head(icolumns);
-    attnos = list_head(attrnos);
-    foreach(lc, exprList)
+    Assert(list_length(exprList) <= list_length(icolumns));
+    forthree(lc, exprList, icols, icolumns, attnos, attrnos)
     {
         Expr       *expr = (Expr *) lfirst(lc);
-        ResTarget  *col;
-        AttrNumber    attr_num;
+        ResTarget  *col = lfirst_node(ResTarget, icols);
+        AttrNumber    attr_num = (AttrNumber) lfirst_int(attnos);
         TargetEntry *tle;

-        col = lfirst_node(ResTarget, icols);
-        attr_num = (AttrNumber) lfirst_int(attnos);
-
         tle = makeTargetEntry(expr,
                               attr_num,
                               col->name,
@@ -851,9 +848,6 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt)

         rte->insertedCols = bms_add_member(rte->insertedCols,
                                            attr_num - FirstLowInvalidHeapAttributeNumber);
-
-        icols = lnext(icols);
-        attnos = lnext(attnos);
     }

     /* Process ON CONFLICT, if any. */
@@ -950,19 +944,16 @@ transformInsertRow(ParseState *pstate, List *exprlist,
      * Prepare columns for assignment to target table.
      */
     result = NIL;
-    icols = list_head(icolumns);
-    attnos = list_head(attrnos);
-    foreach(lc, exprlist)
+    forthree(lc, exprlist, icols, icolumns, attnos, attrnos)
     {
         Expr       *expr = (Expr *) lfirst(lc);
-        ResTarget  *col;
-
-        col = lfirst_node(ResTarget, icols);
+        ResTarget  *col = lfirst_node(ResTarget, icols);
+        int            attno = lfirst_int(attnos);

         expr = transformAssignedExpr(pstate, expr,
                                      EXPR_KIND_INSERT_TARGET,
                                      col->name,
-                                     lfirst_int(attnos),
+                                     attno,
                                      col->indirection,
                                      col->location);

@@ -991,9 +982,6 @@ transformInsertRow(ParseState *pstate, List *exprlist,
         }

         result = lappend(result, expr);
-
-        icols = lnext(icols);
-        attnos = lnext(attnos);
     }

     return result;
@@ -1699,11 +1687,11 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
     qry->targetList = NIL;
     targetvars = NIL;
     targetnames = NIL;
-    left_tlist = list_head(leftmostQuery->targetList);

-    forthree(lct, sostmt->colTypes,
-             lcm, sostmt->colTypmods,
-             lcc, sostmt->colCollations)
+    forfour(lct, sostmt->colTypes,
+            lcm, sostmt->colTypmods,
+            lcc, sostmt->colCollations,
+            left_tlist, leftmostQuery->targetList)
     {
         Oid            colType = lfirst_oid(lct);
         int32        colTypmod = lfirst_int(lcm);
@@ -1729,7 +1717,6 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
         qry->targetList = lappend(qry->targetList, tle);
         targetvars = lappend(targetvars, var);
         targetnames = lappend(targetnames, makeString(colName));
-        left_tlist = lnext(left_tlist);
     }

     /*
@@ -2201,10 +2188,9 @@ determineRecursiveColTypes(ParseState *pstate, Node *larg, List *nrtargetlist)
      * dummy result expressions of the non-recursive term.
      */
     targetList = NIL;
-    left_tlist = list_head(leftmostQuery->targetList);
     next_resno = 1;

-    foreach(nrtl, nrtargetlist)
+    forboth(nrtl, nrtargetlist, left_tlist, leftmostQuery->targetList)
     {
         TargetEntry *nrtle = (TargetEntry *) lfirst(nrtl);
         TargetEntry *lefttle = (TargetEntry *) lfirst(left_tlist);
@@ -2218,7 +2204,6 @@ determineRecursiveColTypes(ParseState *pstate, Node *larg, List *nrtargetlist)
                               colName,
                               false);
         targetList = lappend(targetList, tle);
-        left_tlist = lnext(left_tlist);
     }

     /* Now build CTE's output column info using dummy targetlist */
diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c
index 5222231..654ee80 100644
--- a/src/backend/parser/parse_func.c
+++ b/src/backend/parser/parse_func.c
@@ -2124,13 +2124,12 @@ LookupFuncWithArgs(ObjectType objtype, ObjectWithArgs *func, bool noError)
                                FUNC_MAX_ARGS,
                                FUNC_MAX_ARGS)));

-    args_item = list_head(func->objargs);
-    for (i = 0; i < argcount; i++)
+    i = 0;
+    foreach(args_item, func->objargs)
     {
         TypeName   *t = (TypeName *) lfirst(args_item);

-        argoids[i] = LookupTypeNameOid(NULL, t, noError);
-        args_item = lnext(args_item);
+        argoids[i++] = LookupTypeNameOid(NULL, t, noError);
     }

     /*
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 1258092..85055bb 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -9811,31 +9811,18 @@ get_tablefunc(TableFunc *tf, deparse_context *context, bool showimplicit)
         ListCell   *l5;
         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 ");
-        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));
-            Oid            typid;
-            int32        typmod;
-            Node       *colexpr;
-            Node       *coldefexpr;
-            bool        ordinality = tf->ordinalitycol == colnum;
+            Oid            typid = lfirst_oid(l2);
+            int32        typmod = lfirst_int(l3);
+            Node       *colexpr = (Node *) lfirst(l4);
+            Node       *coldefexpr = (Node *) lfirst(l5);
+            bool        ordinality = (tf->ordinalitycol == colnum);
             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)
                 appendStringInfoString(buf, ", ");
             colnum++;
@@ -10349,12 +10336,11 @@ get_from_clause_coldeflist(RangeTblFunction *rtfunc,

     appendStringInfoChar(buf, '(');

-    /* there's no forfour(), so must chase one list the hard way */
     i = 0;
-    l4 = list_head(rtfunc->funccolnames);
-    forthree(l1, rtfunc->funccoltypes,
-             l2, rtfunc->funccoltypmods,
-             l3, rtfunc->funccolcollations)
+    forfour(l1, rtfunc->funccoltypes,
+            l2, rtfunc->funccoltypmods,
+            l3, rtfunc->funccolcollations,
+            l4, rtfunc->funccolnames)
     {
         Oid            atttypid = lfirst_oid(l1);
         int32        atttypmod = lfirst_int(l2);
@@ -10378,7 +10364,6 @@ get_from_clause_coldeflist(RangeTblFunction *rtfunc,
             appendStringInfo(buf, " COLLATE %s",
                              generate_collation_name(attcollation));

-        l4 = lnext(l4);
         i++;
     }

diff --git a/src/include/nodes/pg_list.h b/src/include/nodes/pg_list.h
index 4624604..8dd22e7 100644
--- a/src/include/nodes/pg_list.h
+++ b/src/include/nodes/pg_list.h
@@ -205,6 +205,32 @@ list_length(const List *l)
          (cell1) != NULL && (cell2) != NULL && (cell3) != NULL;        \
          (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_int(List *list, int datum);
 extern List *lappend_oid(List *list, Oid datum);
diff --git a/contrib/postgres_fdw/deparse.c b/contrib/postgres_fdw/deparse.c
index 92a0ab6..e8de6ac 100644
--- a/contrib/postgres_fdw/deparse.c
+++ b/contrib/postgres_fdw/deparse.c
@@ -2617,7 +2617,7 @@ deparseFuncExpr(FuncExpr *node, deparse_expr_cxt *context)
     {
         if (!first)
             appendStringInfoString(buf, ", ");
-        if (use_variadic && lnext(arg) == NULL)
+        if (use_variadic && list_cell_is_last(arg))
             appendStringInfoString(buf, "VARIADIC ");
         deparseExpr((Expr *) lfirst(arg), context);
         first = false;
@@ -2945,7 +2945,7 @@ deparseAggref(Aggref *node, deparse_expr_cxt *context)
                 first = false;

                 /* Add VARIADIC */
-                if (use_variadic && lnext(arg) == NULL)
+                if (use_variadic && list_cell_is_last(arg))
                     appendStringInfoString(buf, "VARIADIC ");

                 deparseExpr((Expr *) n, context);
diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c
index 1831ea8..c3d898e 100644
--- a/src/backend/commands/explain.c
+++ b/src/backend/commands/explain.c
@@ -254,7 +254,7 @@ ExplainQuery(ParseState *pstate, ExplainStmt *stmt, const char *queryString,
                             queryString, params, queryEnv);

             /* Separate plans with an appropriate separator */
-            if (lnext(l) != NULL)
+            if (list_cell_is_not_last(l))
                 ExplainSeparatePlans(es);
         }
     }
diff --git a/src/backend/commands/prepare.c b/src/backend/commands/prepare.c
index a98c836..f7a1333 100644
--- a/src/backend/commands/prepare.c
+++ b/src/backend/commands/prepare.c
@@ -692,7 +692,7 @@ ExplainExecuteQuery(ExecuteStmt *execstmt, IntoClause *into, ExplainState *es,
         /* No need for CommandCounterIncrement, as ExplainOnePlan did it */

         /* Separate plans with an appropriate separator */
-        if (lnext(p) != NULL)
+        if (list_cell_is_not_last(p))
             ExplainSeparatePlans(es);
     }

diff --git a/src/backend/commands/seclabel.c b/src/backend/commands/seclabel.c
index 9db8228..e0cc3e9 100644
--- a/src/backend/commands/seclabel.c
+++ b/src/backend/commands/seclabel.c
@@ -58,7 +58,7 @@ ExecSecLabelStmt(SecLabelStmt *stmt)
             ereport(ERROR,
                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                      errmsg("no security label providers have been loaded")));
-        if (lnext(list_head(label_provider_list)) != NULL)
+        if (list_length(label_provider_list) > 1)
             ereport(ERROR,
                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                      errmsg("must specify provider when multiple security label providers have been loaded")));
diff --git a/src/backend/commands/tsearchcmds.c b/src/backend/commands/tsearchcmds.c
index 8e5eec2..7c8990a 100644
--- a/src/backend/commands/tsearchcmds.c
+++ b/src/backend/commands/tsearchcmds.c
@@ -1558,7 +1558,7 @@ serialize_deflist(List *deflist)
             appendStringInfoChar(&buf, ch);
         }
         appendStringInfoChar(&buf, '\'');
-        if (lnext(l) != NULL)
+        if (list_cell_is_not_last(l))
             appendStringInfoString(&buf, ", ");
     }

diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index 65302fe..7232552 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -218,7 +218,7 @@ _outList(StringInfo str, const List *node)
         if (IsA(node, List))
         {
             outNode(str, lfirst(lc));
-            if (lnext(lc))
+            if (list_cell_is_not_last(lc))
                 appendStringInfoChar(str, ' ');
         }
         else if (IsA(node, IntList))
diff --git a/src/backend/nodes/print.c b/src/backend/nodes/print.c
index 4b9e141..8fb8634 100644
--- a/src/backend/nodes/print.c
+++ b/src/backend/nodes/print.c
@@ -410,7 +410,7 @@ print_expr(const Node *expr, const List *rtable)
         foreach(l, e->args)
         {
             print_expr(lfirst(l), rtable);
-            if (lnext(l))
+            if (list_cell_is_not_last(l))
                 printf(",");
         }
         printf(")");
@@ -453,7 +453,7 @@ print_pathkeys(const List *pathkeys, const List *rtable)
             print_expr((Node *) mem->em_expr, rtable);
         }
         printf(")");
-        if (lnext(i))
+        if (list_cell_is_not_last(i))
             printf(", ");
     }
     printf(")\n");
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index 0debac7..0c14af2 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -3721,7 +3721,7 @@ print_restrictclauses(PlannerInfo *root, List *clauses)
         RestrictInfo *c = lfirst(l);

         print_expr((Node *) c->clause, root->parse->rtable);
-        if (lnext(l))
+        if (list_cell_is_not_last(l))
             printf(", ");
     }
 }
diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c
index 3434219..bd94800 100644
--- a/src/backend/optimizer/path/indxpath.c
+++ b/src/backend/optimizer/path/indxpath.c
@@ -1558,7 +1558,7 @@ choose_bitmap_and(PlannerInfo *root, RelOptInfo *rel, List *paths)
                 /* reject new path, remove it from paths list */
                 paths = list_delete_cell(paths, lnext(lastcell), lastcell);
             }
-            Assert(lnext(lastcell) == NULL);
+            Assert(list_cell_is_last(lastcell));
         }

         /* Keep the cheapest AND-group (or singleton) */
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index bc81535..e6a7d00 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -4581,7 +4581,7 @@ create_one_window_path(PlannerInfo *root,
                                              -1.0);
         }

-        if (lnext(l))
+        if (list_cell_is_not_last(l))
         {
             /*
              * Add the current WindowFuncs to the output target for this
diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c
index 555c91f..0f8663f 100644
--- a/src/backend/optimizer/plan/subselect.c
+++ b/src/backend/optimizer/plan/subselect.c
@@ -565,7 +565,7 @@ build_subplan(PlannerInfo *root, Plan *plan, PlannerInfo *subroot,
         {
             ptr += sprintf(ptr, "$%d%s",
                            lfirst_int(lc),
-                           lnext(lc) ? "," : ")");
+                           list_cell_is_not_last(lc) ? "," : ")");
         }
     }

diff --git a/src/backend/optimizer/util/tlist.c b/src/backend/optimizer/util/tlist.c
index 14d1c67..a5e7207 100644
--- a/src/backend/optimizer/util/tlist.c
+++ b/src/backend/optimizer/util/tlist.c
@@ -997,7 +997,7 @@ split_pathtarget_at_srfs(PlannerInfo *root,
         List       *level_srfs = (List *) lfirst(lc1);
         PathTarget *ntarget;

-        if (lnext(lc1) == NULL)
+        if (list_cell_is_last(lc1))
         {
             ntarget = target;
         }
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 0279013..96077ec 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -15509,7 +15509,7 @@ makeColumnRef(char *colname, List *indirection,
         else if (IsA(lfirst(l), A_Star))
         {
             /* We only allow '*' at the end of a ColumnRef */
-            if (lnext(l) != NULL)
+            if (list_cell_is_not_last(l))
                 parser_yyerror("improper use of \"*\"");
         }
         nfields++;
@@ -15698,7 +15698,7 @@ check_indirection(List *indirection, core_yyscan_t yyscanner)
     {
         if (IsA(lfirst(l), A_Star))
         {
-            if (lnext(l) != NULL)
+            if (list_cell_is_not_last(l))
                 parser_yyerror("improper use of \"*\"");
         }
     }
diff --git a/src/backend/replication/basebackup.c b/src/backend/replication/basebackup.c
index def6c03..ab32e59 100644
--- a/src/backend/replication/basebackup.c
+++ b/src/backend/replication/basebackup.c
@@ -355,7 +355,7 @@ perform_base_backup(basebackup_options *opt)
              */
             if (opt->includewal && ti->path == NULL)
             {
-                Assert(lnext(lc) == NULL);
+                Assert(list_cell_is_last(lc));
             }
             else
                 pq_putemptymessage('c');    /* CopyDone */
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index 8b4d94c..82f275e 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -1224,7 +1224,7 @@ exec_simple_query(const char *query_string)

         PortalDrop(portal, false);

-        if (lnext(parsetree_item) == NULL)
+        if (list_cell_is_last(parsetree_item))
         {
             /*
              * If this is the last parsetree of the query string, close down
diff --git a/src/backend/tcop/pquery.c b/src/backend/tcop/pquery.c
index 7f15933..9a31ff1 100644
--- a/src/backend/tcop/pquery.c
+++ b/src/backend/tcop/pquery.c
@@ -1334,7 +1334,7 @@ PortalRunMulti(Portal portal,
          * Increment command counter between queries, but not after the last
          * one.
          */
-        if (lnext(stmtlist_item) != NULL)
+        if (list_cell_is_not_last(stmtlist_item))
             CommandCounterIncrement();

         /*
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index 6ec795f..3a67d4d 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -1070,7 +1070,7 @@ ProcessUtilitySlow(ParseState *pstate,
                         }

                         /* Need CCI between commands */
-                        if (lnext(l) != NULL)
+                        if (list_cell_is_not_last(l))
                             CommandCounterIncrement();
                     }

@@ -1151,7 +1151,7 @@ ProcessUtilitySlow(ParseState *pstate,
                             }

                             /* Need CCI between commands */
-                            if (lnext(l) != NULL)
+                            if (list_cell_is_not_last(l))
                                 CommandCounterIncrement();
                         }

diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 85055bb..564bd49 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -2722,7 +2722,7 @@ pg_get_functiondef(PG_FUNCTION_ARGS)
                         char       *curname = (char *) lfirst(lc);

                         simple_quote_literal(&buf, curname);
-                        if (lnext(lc))
+                        if (list_cell_is_not_last(lc))
                             appendStringInfoString(&buf, ", ");
                     }
                 }
@@ -8081,7 +8081,7 @@ get_rule_expr(Node *node, deparse_context *context,
                         appendStringInfo(buf, "hashed %s", splan->plan_name);
                     else
                         appendStringInfoString(buf, splan->plan_name);
-                    if (lnext(lc))
+                    if (list_cell_is_not_last(lc))
                         appendStringInfoString(buf, " or ");
                 }
                 appendStringInfoChar(buf, ')');
@@ -9189,7 +9189,7 @@ get_func_expr(FuncExpr *expr, deparse_context *context,
     {
         if (nargs++ > 0)
             appendStringInfoString(buf, ", ");
-        if (use_variadic && lnext(l) == NULL)
+        if (use_variadic && list_cell_is_last(l))
             appendStringInfoString(buf, "VARIADIC ");
         get_rule_expr((Node *) lfirst(l), context, true);
     }
diff --git a/src/include/nodes/pg_list.h b/src/include/nodes/pg_list.h
index 8dd22e7..a35772d 100644
--- a/src/include/nodes/pg_list.h
+++ b/src/include/nodes/pg_list.h
@@ -133,6 +133,9 @@ list_length(const List *l)
 #define llast_oid(l)            lfirst_oid(list_tail(l))
 #define llast_node(type,l)        castNode(type, llast(l))

+#define list_cell_is_last(l)        (lnext(l) == NULL)
+#define list_cell_is_not_last(l)    (lnext(l) != NULL)
+
 /*
  * Convenience macros for building fixed-length lists
  */

В списке pgsql-hackers по дате отправления:

Предыдущее
От: Tom Lane
Дата:
Сообщение: Re: Index INCLUDE vs. Bitmap Index Scan
Следующее
От: Robert Haas
Дата:
Сообщение: Re: POC: converting Lists into arrays