diff --git a/pkg/sql/logictest/testdata/logic_test/json_index b/pkg/sql/logictest/testdata/logic_test/json_index index 7fd4f6d1f4fe..6bc46105923e 100644 --- a/pkg/sql/logictest/testdata/logic_test/json_index +++ b/pkg/sql/logictest/testdata/logic_test/json_index @@ -18,13 +18,13 @@ INSERT INTO t VALUES query T SELECT x FROM t ORDER BY x ---- +[] "a" "aa" "abcdefghi" "b" 1 100 -[] {"a": "b"} @@ -36,13 +36,13 @@ INSERT INTO t VALUES query T SELECT x FROM t@t_pkey ORDER BY x ---- +[] "a" "aa" "abcdefghi" "b" 1 100 -[] {"a": "b"} # Use the index for point lookups. @@ -75,12 +75,12 @@ query T SELECT x FROM t@t_pkey WHERE x > '1' ORDER BY x ---- 100 -[] {"a": "b"} query T SELECT x FROM t@t_pkey WHERE x < '1' ORDER BY x ---- +[] "a" "aa" "abcdefghi" @@ -90,12 +90,12 @@ SELECT x FROM t@t_pkey WHERE x < '1' ORDER BY x query T SELECT x FROM t@t_pkey WHERE x > '1' OR x < '1' ORDER BY x ---- +[] "a" "aa" "abcdefghi" "b" 100 -[] {"a": "b"} query T @@ -107,12 +107,12 @@ query T SELECT x FROM t@t_pkey WHERE x > '1' OR x < '1' ORDER BY x DESC ---- {"a": "b"} -[] 100 "b" "abcdefghi" "aa" "a" +[] # Adding more primitive JSON values. statement ok @@ -127,6 +127,7 @@ INSERT INTO t VALUES query T SELECT x FROM t@t_pkey ORDER BY x ---- +[] null "Testing Punctuation?!." "a" @@ -139,18 +140,17 @@ null 100 false true -[] {"a": "b"} query T SELECT x FROM t@t_pkey WHERE x > 'true' ORDER BY x ---- -[] {"a": "b"} query T SELECT x FROM t@t_pkey WHERE x < 'false' ORDER BY x ---- +[] null "Testing Punctuation?!." "a" @@ -444,12 +444,12 @@ INSERT INTO t VALUES query T SELECT x FROM t@i ORDER BY x; ---- +[] null "crdb" 1 false true -[] [null] [1] [{"a": "b"}] @@ -483,4 +483,3 @@ query T rowsort SELECT t1.x FROM t1 INNER LOOKUP JOIN t2 ON t1.x = t2.x ---- [1, [2, 3]] - diff --git a/pkg/sql/opt/exec/execbuilder/testdata/json b/pkg/sql/opt/exec/execbuilder/testdata/json index 4d0adf966e3c..84fea0d3e5ad 100644 --- a/pkg/sql/opt/exec/execbuilder/testdata/json +++ b/pkg/sql/opt/exec/execbuilder/testdata/json @@ -252,20 +252,20 @@ INSERT INTO composite VALUES (1, '1.00'::JSONB), (2, '1'::JSONB), (3, '2'::JSONB (4, '3.0'::JSONB), (5, '"a"'::JSONB) ---- CPut /Table/108/1/1/0 -> /TUPLE/ -InitPut /Table/108/2/"G*\x02\x00\x00\x89\x88" -> /BYTES/0x2f0f0c200000002000000403348964 +InitPut /Table/108/2/"H*\x02\x00\x00\x89\x88" -> /BYTES/0x2f0f0c200000002000000403348964 CPut /Table/108/1/2/0 -> /TUPLE/ -InitPut /Table/108/2/"G*\x02\x00\x00\x8a\x88" -> /BYTES/ +InitPut /Table/108/2/"H*\x02\x00\x00\x8a\x88" -> /BYTES/ CPut /Table/108/1/3/0 -> /TUPLE/ -InitPut /Table/108/2/"G*\x04\x00\x00\x8b\x88" -> /BYTES/ +InitPut /Table/108/2/"H*\x04\x00\x00\x8b\x88" -> /BYTES/ CPut /Table/108/1/4/0 -> /TUPLE/ -InitPut /Table/108/2/"G*\x06\x00\x00\x8c\x88" -> /BYTES/0x2f0f0c20000000200000040334891e +InitPut /Table/108/2/"H*\x06\x00\x00\x8c\x88" -> /BYTES/0x2f0f0c20000000200000040334891e CPut /Table/108/1/5/0 -> /TUPLE/ -InitPut /Table/108/2/"F\x12a\x00\x01\x00\x8d\x88" -> /BYTES/ +InitPut /Table/108/2/"G\x12a\x00\x01\x00\x8d\x88" -> /BYTES/ query T kvtrace SELECT j FROM composite where j = '1.00'::JSONB ---- -Scan /Table/108/2/"G*\x02\x00\x0{0"-1"} +Scan /Table/108/2/"H*\x02\x00\x0{0"-1"} query T SELECT j FROM composite ORDER BY j; diff --git a/pkg/sql/rowenc/keyside/json.go b/pkg/sql/rowenc/keyside/json.go index d98dd74cc4e1..163ed3d43164 100644 --- a/pkg/sql/rowenc/keyside/json.go +++ b/pkg/sql/rowenc/keyside/json.go @@ -79,7 +79,7 @@ func decodeJSONKey(buf []byte, dir encoding.Direction) (json.JSON, []byte, error } buf = buf[1:] // removing the terminator jsonVal = json.FromDecimal(dec) - case encoding.JSONArray, encoding.JSONArrayDesc: + case encoding.JSONArray, encoding.JSONArrayDesc, encoding.JsonEmptyArray, encoding.JsonEmptyArrayDesc: jsonVal, buf, err = decodeJSONArray(buf, dir) if err != nil { return nil, nil, errors.NewAssertionErrorWithWrappedErrf(err, "could not decode JSON Array") diff --git a/pkg/util/encoding/encoding.go b/pkg/util/encoding/encoding.go index 22f573d86edf..0a420f7baa65 100644 --- a/pkg/util/encoding/encoding.go +++ b/pkg/util/encoding/encoding.go @@ -106,13 +106,17 @@ const ( // Defining different key markers, for the ascending designation, // for handling different JSON values. - jsonNullKeyMarker = voidMarker + 1 - jsonStringKeyMarker = jsonNullKeyMarker + 1 - jsonNumberKeyMarker = jsonStringKeyMarker + 1 - jsonFalseKeyMarker = jsonNumberKeyMarker + 1 - jsonTrueKeyMarker = jsonFalseKeyMarker + 1 - jsonArrayKeyMarker = jsonTrueKeyMarker + 1 - jsonObjectKeyMarker = jsonArrayKeyMarker + 1 + + // Postgres currently has a special case (maybe a bug) where + // the empty JSON Array sorts before all other JSON values. + jsonEmptyArrayKeyMarker = voidMarker + 1 + jsonNullKeyMarker = jsonEmptyArrayKeyMarker + 1 + jsonStringKeyMarker = jsonNullKeyMarker + 1 + jsonNumberKeyMarker = jsonStringKeyMarker + 1 + jsonFalseKeyMarker = jsonNumberKeyMarker + 1 + jsonTrueKeyMarker = jsonFalseKeyMarker + 1 + jsonArrayKeyMarker = jsonTrueKeyMarker + 1 + jsonObjectKeyMarker = jsonArrayKeyMarker + 1 arrayKeyTerminator byte = 0x00 arrayKeyDescendingTerminator byte = 0xFF @@ -126,13 +130,14 @@ const ( // Defining different key markers, for the descending designation, // for handling different JSON values. - jsonNullKeyDescendingMarker = jsonObjectKeyMarker + 7 - jsonStringKeyDescendingMarker = jsonNullKeyDescendingMarker - 1 - jsonNumberKeyDescendingMarker = jsonStringKeyDescendingMarker - 1 - jsonFalseKeyDescendingMarker = jsonNumberKeyDescendingMarker - 1 - jsonTrueKeyDescendingMarker = jsonFalseKeyDescendingMarker - 1 - jsonArrayKeyDescendingMarker = jsonTrueKeyDescendingMarker - 1 - jsonObjectKeyDescendingMarker = jsonArrayKeyDescendingMarker - 1 + jsonEmptyArrayKeyDescendingMarker = jsonObjectKeyMarker + 8 + jsonNullKeyDescendingMarker = jsonEmptyArrayKeyDescendingMarker - 1 + jsonStringKeyDescendingMarker = jsonNullKeyDescendingMarker - 1 + jsonNumberKeyDescendingMarker = jsonStringKeyDescendingMarker - 1 + jsonFalseKeyDescendingMarker = jsonNumberKeyDescendingMarker - 1 + jsonTrueKeyDescendingMarker = jsonFalseKeyDescendingMarker - 1 + jsonArrayKeyDescendingMarker = jsonTrueKeyDescendingMarker - 1 + jsonObjectKeyDescendingMarker = jsonArrayKeyDescendingMarker - 1 // Terminators for JSON Key encoding. jsonKeyTerminator byte = 0x00 @@ -1750,6 +1755,9 @@ const ( JSONArrayDesc Type = 39 JSONObject Type = 40 JSONObjectDesc Type = 41 + // Special case + JsonEmptyArray Type = 42 + JsonEmptyArrayDesc Type = 43 ) // typMap maps an encoded type byte to a decoded Type. It's got 256 slots, one @@ -1810,6 +1818,10 @@ func slowPeekType(b []byte) Type { return JSONArray case m == jsonArrayKeyDescendingMarker: return JSONArrayDesc + case m == jsonEmptyArrayKeyMarker: + return JsonEmptyArray + case m == jsonEmptyArrayKeyDescendingMarker: + return JsonEmptyArrayDesc case m == jsonObjectKeyMarker: return JSONObject case m == jsonObjectKeyDescendingMarker: @@ -1970,7 +1982,8 @@ func PeekLength(b []byte) (int, error) { length, err := getArrayOrJSONLength(b[1:], dir, IsJSONKeyDone) return 1 + length, err case jsonArrayKeyMarker, jsonArrayKeyDescendingMarker, - jsonObjectKeyMarker, jsonObjectKeyDescendingMarker: + jsonObjectKeyMarker, jsonObjectKeyDescendingMarker, + jsonEmptyArrayKeyMarker, jsonEmptyArrayKeyDescendingMarker: dir := Ascending if (m == jsonArrayKeyDescendingMarker) || (m == jsonObjectKeyDescendingMarker) { @@ -3461,12 +3474,20 @@ func EncodeJSONTrueKeyMarker(buf []byte, dir Direction) []byte { // EncodeJSONArrayKeyMarker adds a JSON Array key encoding marker // to buf and returns the new buffer. -func EncodeJSONArrayKeyMarker(buf []byte, dir Direction) []byte { +func EncodeJSONArrayKeyMarker(buf []byte, dir Direction, length int64) []byte { switch dir { case Ascending: - return append(buf, jsonArrayKeyMarker) + if length == 0 { + return append(buf, jsonEmptyArrayKeyMarker) + } else { + return append(buf, jsonArrayKeyMarker) + } case Descending: - return append(buf, jsonArrayKeyDescendingMarker) + if length == 0 { + return append(buf, jsonEmptyArrayKeyDescendingMarker) + } else { + return append(buf, jsonArrayKeyDescendingMarker) + } default: panic("invalid direction") } @@ -3582,7 +3603,7 @@ func ValidateAndConsumeJSONKeyMarker(buf []byte, dir Direction) ([]byte, Type, e case Descending: switch typ { case JSONNullDesc, JSONNumberDesc, JSONStringDesc, JSONFalseDesc, - JSONTrueDesc, JSONArrayDesc, JSONObjectDesc: + JSONTrueDesc, JSONArrayDesc, JSONObjectDesc, JsonEmptyArrayDesc: return buf[1:], typ, nil default: return nil, Unknown, errors.Newf("invalid type found %s", typ) @@ -3590,7 +3611,7 @@ func ValidateAndConsumeJSONKeyMarker(buf []byte, dir Direction) ([]byte, Type, e case Ascending: switch typ { case JSONNull, JSONNumber, JSONString, JSONFalse, JSONTrue, JSONArray, - JSONObject: + JSONObject, JsonEmptyArray: return buf[1:], typ, nil default: return nil, Unknown, errors.Newf("invalid type found %s", typ) diff --git a/pkg/util/encoding/type_string.go b/pkg/util/encoding/type_string.go index d62dae712a22..8d2c1a46a903 100644 --- a/pkg/util/encoding/type_string.go +++ b/pkg/util/encoding/type_string.go @@ -50,11 +50,13 @@ func _() { _ = x[JSONArrayDesc-39] _ = x[JSONObject-40] _ = x[JSONObjectDesc-41] + _ = x[JsonEmptyArray-42] + _ = x[JsonEmptyArrayDesc-43] } -const _Type_name = "UnknownNullNotNullIntFloatDecimalBytesBytesDescTimeDurationTrueFalseUUIDArrayIPAddrJSONTupleBitArrayBitArrayDescTimeTZGeoGeoDescArrayKeyAscArrayKeyDescBox2DVoidTSQueryTSVectorJSONNullJSONNullDescJSONStringJSONStringDescJSONNumberJSONNumberDescJSONFalseJSONFalseDescJSONTrueJSONTrueDescJSONArrayJSONArrayDescJSONObjectJSONObjectDesc" +const _Type_name = "UnknownNullNotNullIntFloatDecimalBytesBytesDescTimeDurationTrueFalseUUIDArrayIPAddrJSONTupleBitArrayBitArrayDescTimeTZGeoGeoDescArrayKeyAscArrayKeyDescBox2DVoidTSQueryTSVectorJSONNullJSONNullDescJSONStringJSONStringDescJSONNumberJSONNumberDescJSONFalseJSONFalseDescJSONTrueJSONTrueDescJSONArrayJSONArrayDescJSONObjectJSONObjectDescJsonEmptyArrayJsonEmptyArrayDesc" -var _Type_index = [...]uint16{0, 7, 11, 18, 21, 26, 33, 38, 47, 51, 59, 63, 68, 72, 77, 83, 87, 92, 100, 112, 118, 121, 128, 139, 151, 156, 160, 167, 175, 183, 195, 205, 219, 229, 243, 252, 265, 273, 285, 294, 307, 317, 331} +var _Type_index = [...]uint16{0, 7, 11, 18, 21, 26, 33, 38, 47, 51, 59, 63, 68, 72, 77, 83, 87, 92, 100, 112, 118, 121, 128, 139, 151, 156, 160, 167, 175, 183, 195, 205, 219, 229, 243, 252, 265, 273, 285, 294, 307, 317, 331, 345, 363} func (i Type) String() string { if i < 0 || i >= Type(len(_Type_index)-1) { diff --git a/pkg/util/json/json.go b/pkg/util/json/json.go index 0327355ebae4..03e0fc65a77b 100644 --- a/pkg/util/json/json.go +++ b/pkg/util/json/json.go @@ -1978,7 +1978,7 @@ func (j jsonTrue) EncodeForwardIndex(buf []byte, dir encoding.Direction) ([]byte } func (j jsonArray) EncodeForwardIndex(buf []byte, dir encoding.Direction) ([]byte, error) { - buf = encoding.EncodeJSONArrayKeyMarker(buf, dir) + buf = encoding.EncodeJSONArrayKeyMarker(buf, dir, int64(len(j))) buf = encoding.EncodeJSONValueLength(buf, dir, int64(len(j))) var err error