Avoid using list_length() to test for empty list.
authorTom Lane <[email protected]>
Wed, 17 Aug 2022 15:12:35 +0000 (11:12 -0400)
committerTom Lane <[email protected]>
Wed, 17 Aug 2022 15:12:35 +0000 (11:12 -0400)
The standard way to check for list emptiness is to compare the
List pointer to NIL; our list code goes out of its way to ensure
that that is the only representation of an empty list.  (An
acceptable alternative is a plain boolean test for non-null
pointer, but explicit mention of NIL is usually preferable.)

Various places didn't get that memo and expressed the condition
with list_length(), which might not be so bad except that there
were such a variety of ways to check it exactly: equal to zero,
less than or equal to zero, less than one, yadda yadda.  In the
name of code readability, let's standardize all those spellings
as "list == NIL" or "list != NIL".  (There's probably some
microscopic efficiency gain too, though few of these look to be
at all performance-critical.)

A very small number of cases were left as-is because they seemed
more consistent with other adjacent list_length tests that way.

Peter Smith, with bikeshedding from a number of us

Discussion: https://postgr.es/m/CAHut+PtQYe+ENX5KrONMfugf0q6NHg4hR5dAhqEXEc2eefFeig@mail.gmail.com

28 files changed:
src/backend/catalog/objectaddress.c
src/backend/catalog/pg_depend.c
src/backend/commands/event_trigger.c
src/backend/commands/functioncmds.c
src/backend/commands/publicationcmds.c
src/backend/commands/statscmds.c
src/backend/commands/subscriptioncmds.c
src/backend/commands/tablecmds.c
src/backend/commands/typecmds.c
src/backend/executor/execPartition.c
src/backend/libpq/auth.c
src/backend/libpq/hba.c
src/backend/optimizer/path/costsize.c
src/backend/optimizer/plan/createplan.c
src/backend/optimizer/plan/planner.c
src/backend/partitioning/partprune.c
src/backend/replication/logical/tablesync.c
src/backend/replication/pgoutput/pgoutput.c
src/backend/rewrite/rewriteDefine.c
src/backend/statistics/mcv.c
src/backend/storage/lmgr/lmgr.c
src/backend/utils/adt/jsonb_gin.c
src/backend/utils/adt/jsonpath_exec.c
src/backend/utils/adt/jsonpath_gram.y
src/backend/utils/adt/ruleutils.c
src/backend/utils/adt/selfuncs.c
src/backend/utils/adt/tsquery.c
src/test/modules/test_ddl_deparse/test_ddl_deparse.c

index 6080ff8f5f74c5e1d4243508b2d018227785f802..dab375f2b26752153765bdfc7d2e91a0b6e16156 100644 (file)
@@ -2186,7 +2186,7 @@ pg_get_object_address(PG_FUNCTION_ARGS)
        else
        {
                name = textarray_to_strvaluelist(namearr);
-               if (list_length(name) < 1)
+               if (name == NIL)
                        ereport(ERROR,
                                        (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                                         errmsg("name list length must be at least %d", 1)));
index 89bbb5c9e48bf51d2712570d3844b2248b581081..0eff255160bfe26ecf9d2bc36da81039a4a1e462 100644 (file)
@@ -947,7 +947,7 @@ getIdentitySequence(Oid relid, AttrNumber attnum, bool missing_ok)
 
        if (list_length(seqlist) > 1)
                elog(ERROR, "more than one owned sequence found");
-       else if (list_length(seqlist) < 1)
+       else if (seqlist == NIL)
        {
                if (missing_ok)
                        return InvalidOid;
index eef3e5d56e5e28e2a492720a85d42720df2e3dab..9f8fee7c1682b48273e202c8dcceb224ced70cc6 100644 (file)
@@ -1143,9 +1143,9 @@ trackDroppedObjectsNeeded(void)
         * true if any sql_drop, table_rewrite, ddl_command_end event trigger
         * exists
         */
-       return list_length(EventCacheLookup(EVT_SQLDrop)) > 0 ||
-               list_length(EventCacheLookup(EVT_TableRewrite)) > 0 ||
-               list_length(EventCacheLookup(EVT_DDLCommandEnd)) > 0;
+       return (EventCacheLookup(EVT_SQLDrop) != NIL) ||
+               (EventCacheLookup(EVT_TableRewrite) != NIL) ||
+               (EventCacheLookup(EVT_DDLCommandEnd) != NIL);
 }
 
 /*
@@ -1616,7 +1616,7 @@ EventTriggerAlterTableEnd(void)
        parent = currentEventTriggerState->currentCommand->parent;
 
        /* If no subcommands, don't collect */
-       if (list_length(currentEventTriggerState->currentCommand->d.alterTable.subcmds) != 0)
+       if (currentEventTriggerState->currentCommand->d.alterTable.subcmds != NIL)
        {
                MemoryContext oldcxt;
 
index 59e3af626faff66ff25ece9178fe6f390ea54a7a..e7e37146f6922b0ee552b46a64b17c305e5ed49d 100644 (file)
@@ -419,7 +419,7 @@ interpret_function_parameter_list(ParseState *pstate,
                         * Make sure no variables are referred to (this is probably dead
                         * code now that add_missing_from is history).
                         */
-                       if (list_length(pstate->p_rtable) != 0 ||
+                       if (pstate->p_rtable != NIL ||
                                contain_var_clause(def))
                                ereport(ERROR,
                                                (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
@@ -1209,7 +1209,7 @@ CreateFunction(ParseState *pstate, CreateFunctionStmt *stmt)
                returnsSet = false;
        }
 
-       if (list_length(trftypes_list) > 0)
+       if (trftypes_list != NIL)
        {
                ListCell   *lc;
                Datum      *arr;
index 89a005540f68d5e0efada85f85a30ecb50e30228..8b574b86c47b044d7ba932d6b2fb420e3e64fa86 100644 (file)
@@ -848,12 +848,12 @@ CreatePublication(ParseState *pstate, CreatePublicationStmt *stmt)
                                                                   &schemaidlist);
 
                /* FOR ALL TABLES IN SCHEMA requires superuser */
-               if (list_length(schemaidlist) > 0 && !superuser())
+               if (schemaidlist != NIL && !superuser())
                        ereport(ERROR,
                                        errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                                        errmsg("must be superuser to create FOR ALL TABLES IN SCHEMA publication"));
 
-               if (list_length(relations) > 0)
+               if (relations != NIL)
                {
                        List       *rels;
 
@@ -871,7 +871,7 @@ CreatePublication(ParseState *pstate, CreatePublicationStmt *stmt)
                        CloseTableList(rels);
                }
 
-               if (list_length(schemaidlist) > 0)
+               if (schemaidlist != NIL)
                {
                        /*
                         * Schema lock is held until the publication is created to prevent
index 7c62bebfd2d9117ee42df16ebe27a1d15a0f66b1..55216d28916bf5ef3f1de56c4826238ce7f20eb3 100644 (file)
@@ -339,7 +339,7 @@ CreateStatistics(CreateStatsStmt *stmt)
        if ((list_length(stmt->exprs) == 1) && (list_length(stxexprs) == 1))
        {
                /* statistics kinds not specified */
-               if (list_length(stmt->stat_types) > 0)
+               if (stmt->stat_types != NIL)
                        ereport(ERROR,
                                        (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                         errmsg("when building statistics on a single expression, statistics kinds may not be specified")));
@@ -391,7 +391,7 @@ CreateStatistics(CreateStatsStmt *stmt)
         * automatically. This allows calculating good estimates for stats that
         * consider per-clause estimates (e.g. functional dependencies).
         */
-       build_expressions = (list_length(stxexprs) > 0);
+       build_expressions = (stxexprs != NIL);
 
        /*
         * Check that at least two columns were specified in the statement, or
index f73dfb6067fb10e806822b88ebfea735572fee2b..670b219c8d4c1c8e36883e2a668e1c27eaa2c612 100644 (file)
@@ -410,7 +410,7 @@ get_publications_str(List *publications, StringInfo dest, bool quote_literal)
        ListCell   *lc;
        bool            first = true;
 
-       Assert(list_length(publications) > 0);
+       Assert(publications != NIL);
 
        foreach(lc, publications)
        {
index 70b94bbb397d434215e43aea094aa3f4067510ff..8d7c68b8b3cbf013ad3c0859a2c2023a2992d5c5 100644 (file)
@@ -2097,7 +2097,7 @@ ExecuteTruncateGuts(List *explicit_rels,
         * Assemble an array of relids so we can write a single WAL record for the
         * whole action.
         */
-       if (list_length(relids_logged) > 0)
+       if (relids_logged != NIL)
        {
                xl_heap_truncate xlrec;
                int                     i = 0;
@@ -16264,11 +16264,11 @@ ATPrepChangePersistence(Relation rel, bool toLogged)
        }
 
        /*
-        * Check that the table is not part any publication when changing to
-        * UNLOGGED as UNLOGGED tables can't be published.
+        * Check that the table is not part of any publication when changing to
+        * UNLOGGED, as UNLOGGED tables can't be published.
         */
        if (!toLogged &&
-               list_length(GetRelationPublications(RelationGetRelid(rel))) > 0)
+               GetRelationPublications(RelationGetRelid(rel)) != NIL)
                ereport(ERROR,
                                (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
                                 errmsg("cannot change table \"%s\" to unlogged because it is part of a publication",
index d0d87a1184a76b5624ebe06190c31334a8daba37..33b64fd2793b66929cf45c37e904187d87eb657c 100644 (file)
@@ -3503,7 +3503,7 @@ domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid,
         * Domains don't allow variables (this is probably dead code now that
         * add_missing_from is history, but let's be sure).
         */
-       if (list_length(pstate->p_rtable) != 0 ||
+       if (pstate->p_rtable != NIL ||
                contain_var_clause(expr))
                ereport(ERROR,
                                (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
index eb4910610243bc79f6675370bca792ee96526c24..ac03271882f17d3b7f5ab72e0efe3af00526c2ea 100644 (file)
@@ -685,7 +685,7 @@ ExecInitPartitionInfo(ModifyTableState *mtstate, EState *estate,
                 * list and searching for ancestry relationships to each index in the
                 * ancestor table.
                 */
-               if (list_length(rootResultRelInfo->ri_onConflictArbiterIndexes) > 0)
+               if (rootResultRelInfo->ri_onConflictArbiterIndexes != NIL)
                {
                        List       *childIdxs;
 
index 290eb17325b4b36328c04d778441adf2d1df5038..1545ff9f1610b3d24774b1975efb95b226c1919d 100644 (file)
@@ -2915,14 +2915,14 @@ CheckRADIUSAuth(Port *port)
        Assert(offsetof(radius_packet, vector) == 4);
 
        /* Verify parameters */
-       if (list_length(port->hba->radiusservers) < 1)
+       if (port->hba->radiusservers == NIL)
        {
                ereport(LOG,
                                (errmsg("RADIUS server not specified")));
                return STATUS_ERROR;
        }
 
-       if (list_length(port->hba->radiussecrets) < 1)
+       if (port->hba->radiussecrets == NIL)
        {
                ereport(LOG,
                                (errmsg("RADIUS secret not specified")));
index 857b9e5eb246ade63af217ec98bad6045bfdc1fc..1447588c4aeb6f57b9b7d2fe3d4af8047e73a4f1 100644 (file)
@@ -1564,7 +1564,7 @@ parse_hba_line(TokenizedAuthLine *tok_line, int elevel)
                MANDATORY_AUTH_ARG(parsedline->radiusservers, "radiusservers", "radius");
                MANDATORY_AUTH_ARG(parsedline->radiussecrets, "radiussecrets", "radius");
 
-               if (list_length(parsedline->radiusservers) < 1)
+               if (parsedline->radiusservers == NIL)
                {
                        ereport(elevel,
                                        (errcode(ERRCODE_CONFIG_FILE_ERROR),
@@ -1575,7 +1575,7 @@ parse_hba_line(TokenizedAuthLine *tok_line, int elevel)
                        return NULL;
                }
 
-               if (list_length(parsedline->radiussecrets) < 1)
+               if (parsedline->radiussecrets == NIL)
                {
                        ereport(elevel,
                                        (errcode(ERRCODE_CONFIG_FILE_ERROR),
index fb28e6411aa7a4d935f0f6d1821a0ef2945a66cf..7292d68dbcfa242e51fece610a376c114195f402 100644 (file)
@@ -1957,7 +1957,7 @@ compute_cpu_sort_cost(PlannerInfo *root, List *pathkeys, int nPresortedKeys,
        List       *cache_varinfos = NIL;
 
        /* fallback if pathkeys is unknown */
-       if (list_length(pathkeys) == 0)
+       if (pathkeys == NIL)
        {
                /*
                 * If we'll use a bounded heap-sort keeping just K tuples in memory,
index e37f2933eb8d52a05412db512d526ad85555cb99..aa9d4e51b9e0746c5b4c29a3764b31df142b2d6f 100644 (file)
@@ -2462,7 +2462,7 @@ create_groupingsets_plan(PlannerInfo *root, GroupingSetsPath *best_path)
 
                        if (rollup->is_hashed)
                                strat = AGG_HASHED;
-                       else if (list_length(linitial(rollup->gsets)) == 0)
+                       else if (linitial(rollup->gsets) == NIL)
                                strat = AGG_PLAIN;
                        else
                                strat = AGG_SORTED;
index 64632db73cdcba13810cf0c1470fb9db3b00a044..e636596b579186d069663919ef496646864567e4 100644 (file)
@@ -3097,7 +3097,7 @@ reorder_grouping_sets(List *groupingsets, List *sortclause)
                GroupingSetData *gs = makeNode(GroupingSetData);
 
                while (list_length(sortclause) > list_length(previous) &&
-                          list_length(new_elems) > 0)
+                          new_elems != NIL)
                {
                        SortGroupClause *sc = list_nth(sortclause, list_length(previous));
                        int                     ref = sc->tleSortGroupRef;
@@ -4120,7 +4120,7 @@ consider_groupingsets_paths(PlannerInfo *root,
        /*
         * If we have sorted input but nothing we can do with it, bail.
         */
-       if (list_length(gd->rollups) == 0)
+       if (gd->rollups == NIL)
                return;
 
        /*
@@ -6477,7 +6477,7 @@ add_paths_to_grouping_rel(PlannerInfo *root, RelOptInfo *input_rel,
                                                                                                                                group_clauses,
                                                                                                                                orderAggPathkeys);
 
-                       Assert(list_length(pathkey_orderings) > 0);
+                       Assert(pathkey_orderings != NIL);
 
                        /* process all potentially interesting grouping reorderings */
                        foreach(lc2, pathkey_orderings)
@@ -6650,7 +6650,7 @@ add_paths_to_grouping_rel(PlannerInfo *root, RelOptInfo *input_rel,
                                                                                                                                        group_clauses,
                                                                                                                                        orderAggPathkeys);
 
-                               Assert(list_length(pathkey_orderings) > 0);
+                               Assert(pathkey_orderings != NIL);
 
                                /* process all potentially interesting grouping reorderings */
                                foreach(lc2, pathkey_orderings)
@@ -6994,7 +6994,7 @@ create_partial_grouping_paths(PlannerInfo *root,
                                                                                                                                group_clauses,
                                                                                                                                orderAggPathkeys);
 
-                       Assert(list_length(pathkey_orderings) > 0);
+                       Assert(pathkey_orderings != NIL);
 
                        /* process all potentially interesting grouping reorderings */
                        foreach(lc2, pathkey_orderings)
@@ -7145,7 +7145,7 @@ create_partial_grouping_paths(PlannerInfo *root,
                                                                                                                                group_clauses,
                                                                                                                                orderAggPathkeys);
 
-                       Assert(list_length(pathkey_orderings) > 0);
+                       Assert(pathkey_orderings != NIL);
 
                        /* process all potentially interesting grouping reorderings */
                        foreach(lc2, pathkey_orderings)
index 9d3c05aed3b23d210f2a59b1fda7d08f20c8cf9b..fc19232c7b92637506a752e1d82a399fc62fa880 100644 (file)
@@ -2383,7 +2383,7 @@ get_steps_using_prefix(GeneratePruningStepsContext *context,
                   context->rel->part_scheme->strategy == PARTITION_STRATEGY_HASH);
 
        /* Quick exit if there are no values to prefix with. */
-       if (list_length(prefix) == 0)
+       if (prefix == NIL)
        {
                PartitionPruneStep *step;
 
index 6a01ffd273f28504d5313a847d85a81c5fd46a55..bfcb80b495595f3cd4726ddcf74d3710d1a5dcab 100644 (file)
@@ -383,7 +383,7 @@ process_syncing_tables_for_apply(XLogRecPtr current_lsn)
         * immediate restarts.  We don't need it if there are no tables that need
         * syncing.
         */
-       if (table_states_not_ready && !last_start_times)
+       if (table_states_not_ready != NIL && !last_start_times)
        {
                HASHCTL         ctl;
 
@@ -397,7 +397,7 @@ process_syncing_tables_for_apply(XLogRecPtr current_lsn)
         * Clean up the hash table when we're done with all tables (just to
         * release the bit of memory).
         */
-       else if (!table_states_not_ready && last_start_times)
+       else if (table_states_not_ready == NIL && last_start_times)
        {
                hash_destroy(last_start_times);
                last_start_times = NULL;
@@ -1498,7 +1498,7 @@ FetchTableStates(bool *started_tx)
                 * if table_state_not_ready was empty we still need to check again to
                 * see if there are 0 tables.
                 */
-               has_subrels = (list_length(table_states_not_ready) > 0) ||
+               has_subrels = (table_states_not_ready != NIL) ||
                        HasSubscriptionRelations(MySubscription->oid);
 
                table_states_valid = true;
@@ -1534,7 +1534,7 @@ AllTablesyncsReady(void)
         * Return false when there are no tables in subscription or not all tables
         * are in ready state; true otherwise.
         */
-       return has_subrels && list_length(table_states_not_ready) == 0;
+       return has_subrels && (table_states_not_ready == NIL);
 }
 
 /*
index a3c1ba8a4021cd687c03eb071ea1ce4fd74f9386..62e0ffecd8fc39cd3bb9470c07c4e58421036f80 100644 (file)
@@ -450,7 +450,7 @@ pgoutput_startup(LogicalDecodingContext *ctx, OutputPluginOptions *opt,
                                         errmsg("client sent proto_version=%d but we only support protocol %d or higher",
                                                        data->protocol_version, LOGICALREP_PROTO_MIN_VERSION_NUM)));
 
-               if (list_length(data->publication_names) < 1)
+               if (data->publication_names == NIL)
                        ereport(ERROR,
                                        (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                                         errmsg("publication_names parameter missing")));
index a5a1fb887f22afb2910721f1141fa1385098579c..213eabfbb9f610ed69dbb5bc0b1a83197da708d2 100644 (file)
@@ -313,7 +313,7 @@ DefineQueryRewrite(const char *rulename,
                 *
                 * So there cannot be INSTEAD NOTHING, ...
                 */
-               if (list_length(action) == 0)
+               if (action == NIL)
                        ereport(ERROR,
                                        (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                         errmsg("INSTEAD NOTHING rules on SELECT are not implemented"),
index 6d9a098479d3ff55db1ac3a4632bb4e980c29f94..5410a68bc91fd30165b8e4e6b344c8b8ae11ae88 100644 (file)
@@ -1610,7 +1610,6 @@ mcv_get_match_bitmap(PlannerInfo *root, List *clauses,
 
        /* The bitmap may be partially built. */
        Assert(clauses != NIL);
-       Assert(list_length(clauses) >= 1);
        Assert(mcvlist != NULL);
        Assert(mcvlist->nitems > 0);
        Assert(mcvlist->nitems <= STATS_MCVLIST_MAX_ITEMS);
index 1543da61620db2071546cb30d8852cf8a02269dd..1043068bac7b89ea7f6e055f794150ea2bbb76b0 100644 (file)
@@ -913,7 +913,7 @@ WaitForLockersMultiple(List *locktags, LOCKMODE lockmode, bool progress)
        int                     done = 0;
 
        /* Done if no locks to wait for */
-       if (list_length(locktags) == 0)
+       if (locktags == NIL)
                return;
 
        /* Collect the transactions we need to wait on */
index c5325acde4fbb6fd2c52b887128a20c463881e2e..731eb018d4e434846384db62f814cc230260e6b4 100644 (file)
@@ -567,7 +567,7 @@ extract_jsp_path_expr(JsonPathGinContext *cxt, JsonPathGinPath path,
        /* extract a list of nodes to be AND-ed */
        List       *nodes = extract_jsp_path_expr_nodes(cxt, path, jsp, scalar);
 
-       if (list_length(nodes) <= 0)
+       if (nodes == NIL)
                /* no nodes were extracted => full scan is needed for this path */
                return NULL;
 
index 10c7e64aab35dfb08487ad1d3e3c6c16ce8945d7..5b6a48057219e9122572f7e23e62fb5a67802395 100644 (file)
@@ -2552,7 +2552,7 @@ JsonValueListLength(const JsonValueList *jvl)
 static bool
 JsonValueListIsEmpty(JsonValueList *jvl)
 {
-       return !jvl->singleton && list_length(jvl->list) <= 0;
+       return !jvl->singleton && (jvl->list == NIL);
 }
 
 static JsonbValue *
index f903dba3e341d7e26b6e564d7c92680e2547f9e7..ce5d5af8916af674c1e7f87921187f788b5c72c6 100644 (file)
@@ -459,7 +459,7 @@ makeIndexArray(List *list)
        ListCell   *cell;
        int                     i = 0;
 
-       Assert(list_length(list) > 0);
+       Assert(list != NIL);
        v->value.array.nelems = list_length(list);
 
        v->value.array.elems = palloc(sizeof(v->value.array.elems[0]) *
index d575aa006622c737321b1f60f5c4b949afb98a75..8964f73b929b0b68461398e40a940f71f51130e6 100644 (file)
@@ -8114,7 +8114,7 @@ get_parameter(Param *param, deparse_context *context)
                                {
                                        deparse_namespace *dpns = lfirst(lc);
 
-                                       if (list_length(dpns->rtable_names) > 0)
+                                       if (dpns->rtable_names != NIL)
                                        {
                                                should_qualify = true;
                                                break;
index d35e5605de8020f945872b44752eaedbe39a1b82..50b588e3d0f047d43cc5517f9fb07fda9fade99b 100644 (file)
@@ -3408,7 +3408,7 @@ estimate_num_groups_incremental(PlannerInfo *root, List *groupExprs,
         * for normal cases with GROUP BY or DISTINCT, but it is possible for
         * corner cases with set operations.)
         */
-       if (groupExprs == NIL || (pgset && list_length(*pgset) < 1))
+       if (groupExprs == NIL || (pgset && *pgset == NIL))
                return 1.0;
 
        /*
index f54f2988149f5d0fd5dc184255ea52e75c259daf..f49e6bb157871aa47f54556c8f28fd967fb55bf8 100644 (file)
@@ -829,7 +829,7 @@ parse_tsquery(char *buf,
 
        close_tsvector_parser(state.valstate);
 
-       if (list_length(state.polstr) == 0)
+       if (state.polstr == NIL)
        {
                ereport(NOTICE,
                                (errmsg("text-search query doesn't contain lexemes: \"%s\"",
index bdbe05ceebcb3cced7c9afe2a09bfbff3bb47ba1..133594999bd246826bc6b48e67ac15b8afc7c72d 100644 (file)
@@ -95,7 +95,7 @@ get_altertable_subcmdinfo(PG_FUNCTION_ARGS)
 
        SetSingleFuncCall(fcinfo, 0);
 
-       if (list_length(cmd->d.alterTable.subcmds) == 0)
+       if (cmd->d.alterTable.subcmds == NIL)
                elog(ERROR, "empty alter table subcommand list");
 
        foreach(cell, cmd->d.alterTable.subcmds)