From 648ecb0b755eeacbc7f7d4da2e72339b6981448d Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Wed, 18 Mar 2026 11:27:28 -0400
Subject: [PATCH v2 2/2] Remove JsonValueListLength().

The callers only need to distinguish whether lists have zero, one,
or more than one member, so JsonValueListLength() does more work
than is needed.  Replace it with simple tests that determine
precisely those states.

Since this function was used at most once per jsonpath operation,
this isn't going to move the needle in the least performance-wise.
But it seems neater.
---
 src/backend/utils/adt/jsonpath_exec.c | 71 ++++++++++++++-------------
 1 file changed, 38 insertions(+), 33 deletions(-)

diff --git a/src/backend/utils/adt/jsonpath_exec.c b/src/backend/utils/adt/jsonpath_exec.c
index 4f08706363a..ce3dc67b46b 100644
--- a/src/backend/utils/adt/jsonpath_exec.c
+++ b/src/backend/utils/adt/jsonpath_exec.c
@@ -362,8 +362,9 @@ static JsonBaseObjectInfo setBaseObject(JsonPathExecContext *cxt,
 static void JsonValueListInit(JsonValueList *jvl);
 static void JsonValueListClear(JsonValueList *jvl);
 static void JsonValueListAppend(JsonValueList *jvl, const JsonbValue *jbv);
-static int	JsonValueListLength(const JsonValueList *jvl);
 static bool JsonValueListIsEmpty(JsonValueList *jvl);
+static bool JsonValueListIsSingleton(JsonValueList *jvl);
+static bool JsonValueListIsMultiple(JsonValueList *jvl);
 static JsonbValue *JsonValueListHead(JsonValueList *jvl);
 static void JsonValueListInitIterator(JsonValueList *jvl,
 									  JsonValueListIterator *it);
@@ -501,7 +502,7 @@ jsonb_path_match_internal(FunctionCallInfo fcinfo, bool tz)
 	PG_FREE_IF_COPY(jb, 0);
 	PG_FREE_IF_COPY(jp, 1);
 
-	if (JsonValueListLength(&found) == 1)
+	if (JsonValueListIsSingleton(&found))
 	{
 		JsonbValue *jbv = JsonValueListHead(&found);
 
@@ -2191,7 +2192,7 @@ executeBinaryArithmExpr(JsonPathExecContext *cxt, JsonPathItem *jsp,
 		return jper;
 	}
 
-	if (JsonValueListLength(&lseq) != 1 ||
+	if (!JsonValueListIsSingleton(&lseq) ||
 		!(lval = getScalar(JsonValueListHead(&lseq), jbvNumeric)))
 	{
 		JsonValueListClear(&lseq);
@@ -2202,7 +2203,7 @@ executeBinaryArithmExpr(JsonPathExecContext *cxt, JsonPathItem *jsp,
 									 jspOperationName(jsp->type)))));
 	}
 
-	if (JsonValueListLength(&rseq) != 1 ||
+	if (!JsonValueListIsSingleton(&rseq) ||
 		!(rval = getScalar(JsonValueListHead(&rseq), jbvNumeric)))
 	{
 		JsonValueListClear(&lseq);
@@ -3560,7 +3561,7 @@ getArrayIndex(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbValue *jb,
 		return res;
 	}
 
-	if (JsonValueListLength(&found) != 1 ||
+	if (!JsonValueListIsSingleton(&found) ||
 		!(jbv = getScalar(JsonValueListHead(&found), jbvNumeric)))
 	{
 		JsonValueListClear(&found);
@@ -3660,22 +3661,35 @@ JsonValueListAppend(JsonValueList *jvl, const JsonbValue *jbv)
 	}
 }
 
-static int
-JsonValueListLength(const JsonValueList *jvl)
-{
-	int			len = 0;
-
-	for (const JsonValueList *chunk = jvl; chunk != NULL; chunk = chunk->next)
-		len += chunk->nitems;
-	return len;
-}
-
 static bool
 JsonValueListIsEmpty(JsonValueList *jvl)
 {
+	/* We need not examine extra chunks for this */
 	return (jvl->nitems == 0);
 }
 
+static bool
+JsonValueListIsSingleton(JsonValueList *jvl)
+{
+#if BASE_JVL_ITEMS > 1
+	/* We need not examine extra chunks in this case */
+	return (jvl->nitems == 1);
+#else
+	return (jvl->nitems == 1 && jvl->next == NULL);
+#endif
+}
+
+static bool
+JsonValueListIsMultiple(JsonValueList *jvl)
+{
+#if BASE_JVL_ITEMS > 1
+	/* We need not examine extra chunks in this case */
+	return (jvl->nitems > 1);
+#else
+	return (jvl->nitems == 1 && jvl->next != NULL);
+#endif
+}
+
 static JsonbValue *
 JsonValueListHead(JsonValueList *jvl)
 {
@@ -4034,11 +4048,9 @@ JsonPathQuery(Datum jb, JsonPath *jp, JsonWrapper wrapper, bool *empty,
 			  bool *error, List *vars,
 			  const char *column_name)
 {
-	JsonbValue *singleton;
 	bool		wrap;
 	JsonValueList found;
 	JsonPathExecResult res;
-	int			count;
 
 	JsonValueListInit(&found);
 
@@ -4056,9 +4068,7 @@ JsonPathQuery(Datum jb, JsonPath *jp, JsonWrapper wrapper, bool *empty,
 	/*
 	 * Determine whether to wrap the result in a JSON array or not.
 	 *
-	 * First, count the number of SQL/JSON items in the returned
-	 * JsonValueList. If the list is empty (singleton == NULL), no wrapping is
-	 * necessary.
+	 * If the returned JsonValueList is empty, no wrapping is necessary.
 	 *
 	 * If the wrapper mode is JSW_NONE or JSW_UNSPEC, wrapping is explicitly
 	 * disabled. This enforces a WITHOUT WRAPPER clause, which is also the
@@ -4071,16 +4081,14 @@ JsonPathQuery(Datum jb, JsonPath *jp, JsonWrapper wrapper, bool *empty,
 	 * For JSW_CONDITIONAL, wrapping occurs only if there is more than one
 	 * SQL/JSON item in the list, enforcing a WITH CONDITIONAL WRAPPER clause.
 	 */
-	count = JsonValueListLength(&found);
-	singleton = count > 0 ? JsonValueListHead(&found) : NULL;
-	if (singleton == NULL)
+	if (JsonValueListIsEmpty(&found))
 		wrap = false;
 	else if (wrapper == JSW_NONE || wrapper == JSW_UNSPEC)
 		wrap = false;
 	else if (wrapper == JSW_UNCONDITIONAL)
 		wrap = true;
 	else if (wrapper == JSW_CONDITIONAL)
-		wrap = count > 1;
+		wrap = JsonValueListIsMultiple(&found);
 	else
 	{
 		elog(ERROR, "unrecognized json wrapper %d", (int) wrapper);
@@ -4090,8 +4098,8 @@ JsonPathQuery(Datum jb, JsonPath *jp, JsonWrapper wrapper, bool *empty,
 	if (wrap)
 		return JsonbPGetDatum(JsonbValueToJsonb(wrapItemsInArray(&found)));
 
-	/* No wrapping means only one item is expected. */
-	if (count > 1)
+	/* No wrapping means at most one item is expected. */
+	if (JsonValueListIsMultiple(&found))
 	{
 		if (error)
 		{
@@ -4112,8 +4120,8 @@ JsonPathQuery(Datum jb, JsonPath *jp, JsonWrapper wrapper, bool *empty,
 					 errhint("Use the WITH WRAPPER clause to wrap SQL/JSON items into an array.")));
 	}
 
-	if (singleton)
-		return JsonbPGetDatum(JsonbValueToJsonb(singleton));
+	if (!JsonValueListIsEmpty(&found))
+		return JsonbPGetDatum(JsonbValueToJsonb(JsonValueListHead(&found)));
 
 	*empty = true;
 	return PointerGetDatum(NULL);
@@ -4132,7 +4140,6 @@ JsonPathValue(Datum jb, JsonPath *jp, bool *empty, bool *error, List *vars,
 	JsonbValue *res;
 	JsonValueList found;
 	JsonPathExecResult jper PG_USED_FOR_ASSERTS_ONLY;
-	int			count;
 
 	JsonValueListInit(&found);
 
@@ -4149,15 +4156,13 @@ JsonPathValue(Datum jb, JsonPath *jp, bool *empty, bool *error, List *vars,
 		return NULL;
 	}
 
-	count = JsonValueListLength(&found);
-
-	*empty = (count == 0);
+	*empty = JsonValueListIsEmpty(&found);
 
 	if (*empty)
 		return NULL;
 
 	/* JSON_VALUE expects to get only singletons. */
-	if (count > 1)
+	if (JsonValueListIsMultiple(&found))
 	{
 		if (error)
 		{
-- 
2.43.7

