Document strange jsonb sort order for empty top level arrays
authorAndrew Dunstan <andrew@dunslane.net>
Fri, 3 Jan 2025 14:23:46 +0000 (09:23 -0500)
committerAndrew Dunstan <andrew@dunslane.net>
Fri, 3 Jan 2025 15:36:30 +0000 (10:36 -0500)
Slightly faulty logic in the original jsonb code (commit d9134d0a355)
results in an empty top level array sorting less than a json null. We
can't change the sort order now since it would affect btree indexes over
jsonb, so document the anomaly.

Backpatch to all live branches (13 .. 17)

In master, also add a code comment noting the anomaly.

Reported-by: Yan Chengpen
Reviewed-by: Jian He
Discussion: https://postgr.es/m/OSBPR01MB45199DD8DA2D1CECD50518188E272@OSBPR01MB4519.jpnprd01.prod.outlook.com

doc/src/sgml/json.sgml
src/backend/utils/adt/jsonb_util.c

index 54648c459c127eae73da6ed1ec532d6c78e58163..206eadb8f7bafe84ef655aa3eb3b5c498274a7e7 100644 (file)
@@ -584,12 +584,13 @@ SELECT jdoc->'guid', jdoc->'name' FROM api WHERE jdoc @@ '$.tags[*] == "qui"';
     The <literal>btree</literal> ordering for <type>jsonb</type> datums is seldom
     of great interest, but for completeness it is:
 <synopsis>
-<replaceable>Object</replaceable> > <replaceable>Array</replaceable> > <replaceable>Boolean</replaceable> > <replaceable>Number</replaceable> > <replaceable>String</replaceable> > <replaceable>Null</replaceable>
+<replaceable>Object</replaceable> > <replaceable>Array</replaceable> > <replaceable>Boolean</replaceable> > <replaceable>Number</replaceable> > <replaceable>String</replaceable> > <replaceable>null</replaceable>
 
 <replaceable>Object with n pairs</replaceable> > <replaceable>object with n - 1 pairs</replaceable>
 
 <replaceable>Array with n elements</replaceable> > <replaceable>array with n - 1 elements</replaceable>
 </synopsis>
+      with the exception that (for historical reasons) an empty top level array sorts less than <replaceable>null</replaceable>.
       Objects with equal numbers of pairs are compared in the order:
 <synopsis>
 <replaceable>key-1</replaceable>, <replaceable>value-1</replaceable>, <replaceable>key-2</replaceable> ...
index 806d1aa3a98d49ad51e261bd6fa360098f5f16aa..773f3690c7b9e4fa4ac416c5bc0965c6036442bb 100644 (file)
@@ -246,6 +246,13 @@ compareJsonbContainers(JsonbContainer *a, JsonbContainer *b)
                         */
                        if (va.val.array.rawScalar != vb.val.array.rawScalar)
                            res = (va.val.array.rawScalar) ? -1 : 1;
+
+                       /*
+                        * There should be an "else" here, to prevent us from
+                        * overriding the above, but we can't change the sort
+                        * order now, so there is a mild anomaly that an empty
+                        * top level array sorts less than null.
+                        */
                        if (va.val.array.nElems != vb.val.array.nElems)
                            res = (va.val.array.nElems > vb.val.array.nElems) ? 1 : -1;
                        break;