jsonb_test.go 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990
  1. package executor
  2. import (
  3. "encoding/json"
  4. "errors"
  5. "strings"
  6. "testing"
  7. "github.com/danfragoso/pizzasql-next/pkg/analyzer"
  8. "github.com/danfragoso/pizzasql-next/pkg/pgerror"
  9. "github.com/danfragoso/pizzasql-next/pkg/storage"
  10. )
  11. // jsonbExec parses and executes one statement, returning the value at (0, 0).
  12. func jsonbValue(t *testing.T, e *Executor, sql string) interface{} {
  13. t.Helper()
  14. res := execMust(t, e, sql)
  15. if len(res.Rows) == 0 || len(res.Rows[0]) == 0 {
  16. t.Fatalf("%s: no value", sql)
  17. }
  18. return res.Rows[0][0]
  19. }
  20. func jsonbErrorCode(t *testing.T, err error) string {
  21. t.Helper()
  22. switch {
  23. case err == nil:
  24. return ""
  25. case errors.Is(err, pgerror.ErrInvalidText):
  26. return pgerror.CodeInvalidText
  27. case errors.Is(err, pgerror.ErrInvalidParameter):
  28. return pgerror.CodeInvalidParameter
  29. case errors.Is(err, pgerror.ErrFeatureNotSupported):
  30. return pgerror.CodeFeatureNotSupported
  31. case errors.Is(err, pgerror.ErrDatatypeMismatch):
  32. return pgerror.CodeDatatypeMismatch
  33. case errors.Is(err, pgerror.ErrInvalidColumnReference):
  34. return pgerror.CodeInvalidColumnReference
  35. }
  36. var analysisErr *analyzer.AnalysisError
  37. if errors.As(err, &analysisErr) && analysisErr.Type == analyzer.ErrTypeMismatch {
  38. return pgerror.CodeDatatypeMismatch
  39. }
  40. return "other:" + err.Error()
  41. }
  42. func TestJSONBCanonicalization(t *testing.T) {
  43. pool, schema, table := newTestDB(t)
  44. e := newExec(schema, table)
  45. execMust(t, e, "CREATE TABLE docs (id INTEGER PRIMARY KEY, doc JSONB)")
  46. execMust(t, e, `INSERT INTO docs VALUES (1, '{"b": 1, "a": 2, "b": 3}')`)
  47. execMust(t, e, `INSERT INTO docs VALUES (2, '{"z": 1.50, "y": 1e2, "x": -0.0, "w": 1.0}')`)
  48. execMust(t, e, `INSERT INTO docs VALUES (3, ' [ 1 , { "b" : 2 , "a" : 1 } ] ')`)
  49. want := map[int64]string{
  50. 1: `{"a":2,"b":3}`,
  51. 2: `{"w":1,"x":0,"y":100,"z":1.5}`,
  52. 3: `[1,{"a":1,"b":2}]`,
  53. }
  54. res := execMust(t, e, "SELECT id, doc FROM docs ORDER BY id")
  55. for _, row := range res.Rows {
  56. id := row[0].(int64)
  57. if row[1] != want[id] {
  58. t.Fatalf("row %d doc = %v, want %s", id, row[1], want[id])
  59. }
  60. }
  61. // A JSONB column rejects malformed documents and stores nothing.
  62. if _, err := execSQL(e, `INSERT INTO docs VALUES (4, 'not json')`); jsonbErrorCode(t, err) != pgerror.CodeInvalidText {
  63. t.Fatalf("malformed JSONB insert error = %v", err)
  64. }
  65. if res := execMust(t, e, "SELECT COUNT(*) FROM docs WHERE id = 4"); res.Rows[0][0] != int64(0) {
  66. t.Fatalf("malformed JSONB insert stored a row")
  67. }
  68. // Non-text input is not silently stringified, matching array columns.
  69. if _, err := execSQL(e, `INSERT INTO docs VALUES (5, 5)`); jsonbErrorCode(t, err) != pgerror.CodeInvalidText {
  70. t.Fatalf("integer JSONB insert error = %v", err)
  71. }
  72. // Canonicalization is idempotent, and a fresh executor over the same store
  73. // reads back the same bytes (no hidden normalization at read time).
  74. reloadedSchema := storage.NewSchemaManager(pool, "testdb")
  75. reloadedTable := storage.NewTableManager(pool, reloadedSchema, "testdb")
  76. reloaded := newExec(reloadedSchema, reloadedTable)
  77. res = execMust(t, reloaded, "SELECT id, doc FROM docs ORDER BY id")
  78. for _, row := range res.Rows {
  79. id := row[0].(int64)
  80. if row[1] != want[id] {
  81. t.Fatalf("reloaded row %d doc = %v, want %s", id, row[1], want[id])
  82. }
  83. canonical, err := CanonicalizeJSONB(row[1].(string))
  84. if err != nil || canonical != row[1] {
  85. t.Fatalf("row %d is not a canonical fixed point: %q (%v)", id, row[1], err)
  86. }
  87. }
  88. }
  89. func TestJSONBCastsAndToJSONB(t *testing.T) {
  90. _, schema, table := newTestDB(t)
  91. e := newExec(schema, table)
  92. cases := []struct {
  93. sql string
  94. want interface{}
  95. }{
  96. {`SELECT '{"b":2,"a":1}'::jsonb`, `{"a":1,"b":2}`},
  97. {`SELECT CAST(' [1, 2] ' AS JSONB)`, `[1,2]`},
  98. {`SELECT ('{"a":1}'::jsonb)::jsonb`, `{"a":1}`},
  99. {`SELECT to_jsonb(5)`, `5`},
  100. {`SELECT to_jsonb('x')`, `"x"`},
  101. {`SELECT to_jsonb(TRUE)`, `true`},
  102. {`SELECT to_jsonb(NULL)`, nil},
  103. {`SELECT to_jsonb(ARRAY[1,2])`, `[1,2]`},
  104. {`SELECT to_jsonb(ARRAY['a','b'])`, `["a","b"]`},
  105. {`SELECT to_jsonb('{"a":1}'::jsonb)`, `{"a":1}`},
  106. {`SELECT CAST('{"a":1}'::jsonb AS TEXT)`, `{"a":1}`},
  107. }
  108. for _, tc := range cases {
  109. if got := jsonbValue(t, e, tc.sql); got != tc.want {
  110. t.Errorf("%s = %v (%T), want %v", tc.sql, got, got, tc.want)
  111. }
  112. }
  113. for _, sql := range []string{
  114. `SELECT 'not json'::jsonb`,
  115. `SELECT '{"a":}'::jsonb`,
  116. `SELECT '{"a":1} trailing'::jsonb`,
  117. `SELECT 5::jsonb`,
  118. `SELECT '{"a":1e999999}'::jsonb`,
  119. } {
  120. if _, err := execSQL(e, sql); jsonbErrorCode(t, err) != pgerror.CodeInvalidText {
  121. t.Errorf("%s error = %v, want 22P02", sql, err)
  122. }
  123. }
  124. // The JSON1 normalization function and its json() sibling keep working.
  125. if got := jsonbValue(t, e, `SELECT jsonb('{"a":1}')`); got != `{"a":1}` {
  126. t.Fatalf("jsonb() = %v", got)
  127. }
  128. if got := jsonbValue(t, e, `SELECT jsonb_valid('{"a":1}')`); got != int64(1) {
  129. t.Fatalf("jsonb_valid() = %v", got)
  130. }
  131. }
  132. func TestJSONBArrowOperators(t *testing.T) {
  133. _, schema, table := newTestDB(t)
  134. e := newExec(schema, table)
  135. execMust(t, e, "CREATE TABLE docs (id INTEGER PRIMARY KEY, doc JSONB)")
  136. execMust(t, e, `INSERT INTO docs VALUES (1, '{"a":1,"s":"x","n":null,"arr":[10,{"b":2}]}')`)
  137. cases := []struct {
  138. sql string
  139. want interface{}
  140. }{
  141. {`SELECT doc -> 'a' FROM docs`, `1`},
  142. {`SELECT doc -> 's' FROM docs`, `"x"`},
  143. {`SELECT doc ->> 's' FROM docs`, `x`},
  144. {`SELECT doc -> 'n' FROM docs`, `null`},
  145. {`SELECT doc ->> 'n' FROM docs`, nil},
  146. {`SELECT doc -> 'missing' FROM docs`, nil},
  147. {`SELECT doc ->> 'missing' FROM docs`, nil},
  148. {`SELECT doc -> 'arr' -> 0 FROM docs`, `10`},
  149. {`SELECT doc -> 'arr' -> -1 ->> 'b' FROM docs`, `2`},
  150. {`SELECT doc -> 'arr' -> 3 FROM docs`, nil},
  151. {`SELECT doc -> '$."arr"[1]' ->> 'b' FROM docs`, `2`},
  152. {`SELECT NULL::jsonb -> 'a'`, nil},
  153. {`SELECT doc -> NULL FROM docs`, nil},
  154. }
  155. for _, tc := range cases {
  156. if got := jsonbValue(t, e, tc.sql); got != tc.want {
  157. t.Errorf("%s = %v (%T), want %v", tc.sql, got, got, tc.want)
  158. }
  159. }
  160. // The JSON text surface is unchanged: a text-backed document still returns
  161. // JSON1 coercions for ->>.
  162. if got := jsonbValue(t, e, `SELECT '{"a":true}' ->> 'a'`); got != int64(1) {
  163. t.Fatalf("JSON1 ->> boolean = %v (%T), want int64 1", got, got)
  164. }
  165. }
  166. func TestJSONBPathOperators(t *testing.T) {
  167. _, schema, table := newTestDB(t)
  168. e := newExec(schema, table)
  169. cases := []struct {
  170. sql string
  171. want interface{}
  172. }{
  173. {`SELECT '{"a":{"b":2}}'::jsonb #> '{a,b}'`, `2`},
  174. {`SELECT '{"a":{"b":2}}'::jsonb #>> '{a,b}'`, `2`},
  175. {`SELECT '{"a":[1,2,3]}'::jsonb #> '{a,-1}'`, `3`},
  176. {`SELECT '{"a":{"b":2}}'::jsonb #> '$."a"."b"'`, `2`},
  177. {`SELECT '{"a":{"b":2}}'::jsonb #> ARRAY['a','b']`, `2`},
  178. {`SELECT '{"a":1}'::jsonb #> '{missing}'`, nil},
  179. {`SELECT '{"a":1}'::jsonb #- '{a}'`, `{}`},
  180. {`SELECT '{"a":{"b":1},"c":2}'::jsonb #- '{a,b}'`, `{"a":{},"c":2}`},
  181. {`SELECT '[1,2,3]'::jsonb #- '{1}'`, `[1,3]`},
  182. {`SELECT '{"a":1}'::jsonb #- '{missing}'`, `{"a":1}`},
  183. {`SELECT NULL::jsonb #> '{a}'`, nil},
  184. }
  185. for _, tc := range cases {
  186. if got := jsonbValue(t, e, tc.sql); got != tc.want {
  187. t.Errorf("%s = %v (%T), want %v", tc.sql, got, got, tc.want)
  188. }
  189. }
  190. // Wildcards, slices, and unbounded expansion are rejected, not approximated.
  191. for _, sql := range []string{
  192. `SELECT '{"a":1}'::jsonb #> '$[*]'`,
  193. `SELECT '{"a":1}'::jsonb #> '$.**'`,
  194. `SELECT '{"a":1}'::jsonb -> '$[*]'`,
  195. `SELECT '{"a":1}'::jsonb #- '$[0:1]'`,
  196. } {
  197. if _, err := execSQL(e, sql); jsonbErrorCode(t, err) != pgerror.CodeFeatureNotSupported {
  198. t.Errorf("%s error = %v, want 0A000", sql, err)
  199. }
  200. }
  201. }
  202. func TestJSONBContainmentAndExistence(t *testing.T) {
  203. _, schema, table := newTestDB(t)
  204. e := newExec(schema, table)
  205. cases := []struct {
  206. sql string
  207. want interface{}
  208. }{
  209. {`SELECT '{"a":1,"b":{"c":2}}'::jsonb @> '{"a":1}'::jsonb`, true},
  210. {`SELECT '{"a":1,"b":{"c":2}}'::jsonb @> '{"b":{"c":2}}'::jsonb`, true},
  211. {`SELECT '{"a":1,"b":{"c":2}}'::jsonb @> '{"b":{}}'::jsonb`, true},
  212. {`SELECT '{"a":1}'::jsonb @> '{"b":1}'::jsonb`, false},
  213. {`SELECT '{"a":1}'::jsonb @> '{"a":1,"b":2}'::jsonb`, false},
  214. {`SELECT '[1,2,3]'::jsonb @> '[3,1]'::jsonb`, true},
  215. {`SELECT '[1,2,3]'::jsonb @> '[4]'::jsonb`, false},
  216. {`SELECT '[1,2]'::jsonb @> '1'::jsonb`, true},
  217. {`SELECT '["a"]'::jsonb @> '"a"'::jsonb`, true},
  218. {`SELECT '[true]'::jsonb @> 'true'::jsonb`, true},
  219. {`SELECT '[null]'::jsonb @> 'null'::jsonb`, true},
  220. {`SELECT '[1]'::jsonb @> '2'::jsonb`, false},
  221. {`SELECT '{"a":[1,2]}'::jsonb @> '{"a":[2]}'::jsonb`, true},
  222. {`SELECT '{"a":null}'::jsonb @> '{"a":null}'::jsonb`, true},
  223. {`SELECT '{"a":null}'::jsonb @> '{"a":1}'::jsonb`, false},
  224. {`SELECT '{"a":1.0}'::jsonb @> '{"a":1}'::jsonb`, true},
  225. {`SELECT '{"a":1}'::jsonb <@ '{"a":1,"b":2}'::jsonb`, true},
  226. {`SELECT '{"a":1}'::jsonb @> '{"a":1}'`, true},
  227. {`SELECT NULL::jsonb @> '{}'::jsonb`, nil},
  228. {`SELECT '{"a":1}'::jsonb @> NULL::jsonb`, nil},
  229. {`SELECT '{"a":1}'::jsonb ? 'a'`, true},
  230. {`SELECT '{"a":1}'::jsonb ? 'b'`, false},
  231. {`SELECT '[1,"x"]'::jsonb ? 'x'`, true},
  232. {`SELECT '[1,"x"]'::jsonb ? '1'`, false},
  233. {`SELECT '"x"'::jsonb ? 'x'`, false},
  234. {`SELECT 'null'::jsonb ? 'x'`, false},
  235. {`SELECT '{"a":1,"b":2}'::jsonb ?| '{b,c}'`, true},
  236. {`SELECT '{"a":1,"b":2}'::jsonb ?| '{c,d}'`, false},
  237. {`SELECT '{"a":1,"b":2}'::jsonb ?& '{a,b}'`, true},
  238. {`SELECT '{"a":1,"b":2}'::jsonb ?& '{a,c}'`, false},
  239. {`SELECT '{"1":true}'::jsonb ? '1'`, true},
  240. {`SELECT '{"1":true}'::jsonb ?| '{1,2}'`, true},
  241. {`SELECT '[1,"x"]'::jsonb ?| '{x}'`, true},
  242. {`SELECT NULL::jsonb ? 'a'`, nil},
  243. }
  244. for _, tc := range cases {
  245. if got := jsonbValue(t, e, tc.sql); got != tc.want {
  246. t.Errorf("%s = %v (%T), want %v", tc.sql, got, got, tc.want)
  247. }
  248. }
  249. // Containment needs a jsonb operand on at least one side.
  250. if _, err := execSQL(e, `SELECT '{"a":1}' @> '{"a":1}'`); jsonbErrorCode(t, err) != pgerror.CodeDatatypeMismatch {
  251. t.Errorf("text @> text error = %v, want 42804", err)
  252. }
  253. }
  254. func TestJSONBConcatAndDelete(t *testing.T) {
  255. _, schema, table := newTestDB(t)
  256. e := newExec(schema, table)
  257. cases := []struct {
  258. sql string
  259. want interface{}
  260. }{
  261. {`SELECT '{"a":1}'::jsonb || '{"b":2,"a":3}'::jsonb`, `{"a":3,"b":2}`},
  262. {`SELECT '[1]'::jsonb || '[2,3]'::jsonb`, `[1,2,3]`},
  263. {`SELECT '[1]'::jsonb || '2'::jsonb`, `[1,2]`},
  264. {`SELECT '{"a":1}'::jsonb || '[1]'::jsonb`, `[{"a":1},1]`},
  265. {`SELECT '1'::jsonb || '2'::jsonb`, `[1,2]`},
  266. {`SELECT NULL::jsonb || '{}'::jsonb`, nil},
  267. {`SELECT '{"a":1,"b":2}'::jsonb - 'a'`, `{"b":2}`},
  268. {`SELECT '{"a":1,"b":2}'::jsonb - '{a,b}'::text[]`, `{}`},
  269. {`SELECT '[1,2,3]'::jsonb - 1`, `[1,3]`},
  270. {`SELECT '[1,2,3]'::jsonb - -1`, `[1,2]`},
  271. {`SELECT '[1,2,3]'::jsonb - 9`, `[1,2,3]`},
  272. {`SELECT '["a","b","a"]'::jsonb - 'a'`, `["b"]`},
  273. {`SELECT '"x"'::jsonb - 'a'`, `"x"`},
  274. {`SELECT NULL::jsonb - 'a'`, nil},
  275. }
  276. for _, tc := range cases {
  277. if got := jsonbValue(t, e, tc.sql); got != tc.want {
  278. t.Errorf("%s = %v (%T), want %v", tc.sql, got, got, tc.want)
  279. }
  280. }
  281. // Text concatenation is unchanged when neither side is jsonb.
  282. if got := jsonbValue(t, e, `SELECT 'a' || 'b'`); got != "ab" {
  283. t.Fatalf("text concatenation = %v", got)
  284. }
  285. if _, err := execSQL(e, `SELECT '{"a":1}'::jsonb - 1`); jsonbErrorCode(t, err) != pgerror.CodeInvalidParameter {
  286. t.Errorf("jsonb - integer on object error = %v, want 22023", err)
  287. }
  288. }
  289. func TestJSONBScalarFunctions(t *testing.T) {
  290. _, schema, table := newTestDB(t)
  291. e := newExec(schema, table)
  292. cases := []struct {
  293. sql string
  294. want interface{}
  295. }{
  296. {`SELECT jsonb_typeof('{"a":1}')`, "object"},
  297. {`SELECT jsonb_typeof('[1]')`, "array"},
  298. {`SELECT jsonb_typeof('"x"')`, "string"},
  299. {`SELECT jsonb_typeof('1.50')`, "number"},
  300. {`SELECT jsonb_typeof('true')`, "boolean"},
  301. {`SELECT jsonb_typeof('null')`, "null"},
  302. {`SELECT jsonb_typeof(NULL)`, nil},
  303. {`SELECT jsonb_array_length('[1,2,3]')`, int64(3)},
  304. {`SELECT jsonb_array_length('[]')`, int64(0)},
  305. {`SELECT jsonb_array_length(NULL)`, nil},
  306. {`SELECT jsonb_pretty('{"b":2,"a":[1]}')`, "{\n \"a\": [\n 1\n ],\n \"b\": 2\n}"},
  307. {`SELECT jsonb_strip_nulls('{"a":null,"b":{"c":null,"d":1},"e":[null,1]}')`, `{"b":{"d":1},"e":[null,1]}`},
  308. {`SELECT jsonb_build_object('b', 1, 'a', 'x')`, `{"a":"x","b":1}`},
  309. {`SELECT jsonb_build_object('a', NULL)`, `{"a":null}`},
  310. {`SELECT jsonb_build_object('a', '{"b":1}'::jsonb)`, `{"a":{"b":1}}`},
  311. {`SELECT jsonb_build_array(1, 'x', NULL, TRUE)`, `[1,"x",null,true]`},
  312. {`SELECT jsonb_build_array()`, `[]`},
  313. {`SELECT jsonb_build_object()`, `{}`},
  314. {`SELECT jsonb_set('{"a":1}', '{a}', '2')`, `{"a":2}`},
  315. {`SELECT jsonb_set('{"a":1}', '{b}', '2')`, `{"a":1,"b":2}`},
  316. {`SELECT jsonb_set('{"a":1}', '{b}', '2', false)`, `{"a":1}`},
  317. {`SELECT jsonb_set('{"a":{"b":1}}', '{a,b}', '2')`, `{"a":{"b":2}}`},
  318. {`SELECT jsonb_set('{"a":{"b":1}}', '{x,b}', '2')`, `{"a":{"b":1}}`},
  319. {`SELECT jsonb_set('[1,2]', '{2}', '3')`, `[1,2,3]`},
  320. {`SELECT jsonb_set('[1,2]', '{5}', '3')`, `[1,2,3]`},
  321. {`SELECT jsonb_set('[1,2]', '{5}', '3', false)`, `[1,2]`},
  322. {`SELECT jsonb_set('[1,2]', '{-3}', '9')`, `[9,1,2]`},
  323. {`SELECT jsonb_set('[1,2]', '{-3}', '9', false)`, `[1,2]`},
  324. {`SELECT jsonb_set('{"a":1}', '{}', '2')`, `{"a":1}`},
  325. {`SELECT jsonb_insert('{"a":1}', '{}', '2')`, `{"a":1}`},
  326. {`SELECT jsonb_set('{"a":1}', '{a,b}', '2')`, `{"a":1}`},
  327. {`SELECT jsonb_insert('{"a":1}', '{a,b}', '2')`, `{"a":1}`},
  328. {`SELECT jsonb_set('{"a":1}', NULL, '2')`, nil},
  329. {`SELECT jsonb_insert('{"a":1}', NULL, '2')`, nil},
  330. {`SELECT jsonb_insert('{"a":[0,1,2]}', '{a,1}', '"n"')`, `{"a":[0,"n",1,2]}`},
  331. {`SELECT jsonb_insert('{"a":[0,1,2]}', '{a,1}', '"n"', true)`, `{"a":[0,1,"n",2]}`},
  332. {`SELECT jsonb_insert('{"a":1}', '{b}', '2')`, `{"a":1,"b":2}`},
  333. {`SELECT jsonb_insert('[0,1,2]', '{5}', '9')`, `[0,1,2,9]`},
  334. {`SELECT jsonb_insert('[0,1,2]', '{-3}', '9')`, `[9,0,1,2]`},
  335. {`SELECT jsonb_insert('[0,1,2]', '{-1}', '9', true)`, `[0,1,2,9]`},
  336. {`SELECT jsonb_insert('[0,1,2]', '{-2}', '9')`, `[0,9,1,2]`},
  337. {`SELECT jsonb_insert('[0,1,2]', '{-2}', '9', true)`, `[0,1,9,2]`},
  338. {`SELECT jsonb_set('{"a":1}', '{a}', NULL)`, nil},
  339. {`SELECT jsonb_insert('[0,1]', '{-1}', '9')`, `[0,9,1]`},
  340. // The JSON1 $ path form keeps its previous value semantics: a plain SQL
  341. // string becomes a JSON string, while a jsonb-typed value is embedded.
  342. {`SELECT jsonb_set('{"a":1}', '$.b', '2')`, `{"a":1,"b":"2"}`},
  343. {`SELECT jsonb_set('{"a":1}', '$.a', '2')`, `{"a":"2"}`},
  344. {`SELECT jsonb_set('{"a":1}', '$.b', '{"x":1}'::jsonb)`, `{"a":1,"b":{"x":1}}`},
  345. {`SELECT jsonb_set('{"a":1}', '$.b', 1.5)`, `{"a":1,"b":1.5}`},
  346. {`SELECT jsonb_insert('{}', '$.b', 2.5)`, `{"b":2.5}`},
  347. {`SELECT jsonb_replace('{"b":0}', '$.b', 2.5)`, `{"b":2.5}`},
  348. {`SELECT jsonb_insert('{"a":1}', '$.b', '2')`, `{"a":1,"b":"2"}`},
  349. {`SELECT jsonb_replace('{"a":1}', '$.a', '2')`, `{"a":"2"}`},
  350. {`SELECT jsonb_remove('{"a":1,"b":2}', '$.a')`, `{"b":2}`},
  351. }
  352. for _, tc := range cases {
  353. if got := jsonbValue(t, e, tc.sql); got != tc.want {
  354. t.Errorf("%s = %v (%T), want %v", tc.sql, got, got, tc.want)
  355. }
  356. }
  357. // JSON1 scalar functions keep their text surface.
  358. if got := jsonbValue(t, e, `SELECT json_type('{"a":1.5}', '$.a')`); got != "real" {
  359. t.Fatalf("json_type text surface = %v", got)
  360. }
  361. if got := jsonbValue(t, e, `SELECT json_set('{"a":1}', '$.b', '2')`); got != `{"a":1,"b":"2"}` {
  362. t.Fatalf("json_set text surface = %v", got)
  363. }
  364. for _, tc := range []struct {
  365. sql string
  366. code string
  367. }{
  368. {`SELECT jsonb_array_length('{"a":1}')`, pgerror.CodeInvalidParameter},
  369. {`SELECT jsonb_typeof('not json')`, pgerror.CodeInvalidText},
  370. {`SELECT jsonb_build_object('a')`, pgerror.CodeInvalidParameter},
  371. {`SELECT jsonb_build_object(NULL, 1)`, pgerror.CodeInvalidParameter},
  372. {`SELECT jsonb_set('[1,2]', '{a}', '2')`, pgerror.CodeInvalidText},
  373. {`SELECT jsonb_insert('[1,2]', '{a}', '2')`, pgerror.CodeInvalidText},
  374. {`SELECT jsonb_insert('{"a":1}', '{a}', '2')`, pgerror.CodeInvalidParameter},
  375. {`SELECT jsonb_set('1', '{a}', '2')`, pgerror.CodeInvalidParameter},
  376. {`SELECT jsonb_insert('1', '{a}', '2')`, pgerror.CodeInvalidParameter},
  377. } {
  378. if _, err := execSQL(e, tc.sql); jsonbErrorCode(t, err) != tc.code {
  379. t.Errorf("%s error = %v, want %s", tc.sql, err, tc.code)
  380. }
  381. }
  382. }
  383. func TestJSONBSetReturningFunctionsInFrom(t *testing.T) {
  384. _, schema, table := newTestDB(t)
  385. e := newExec(schema, table)
  386. res := execMust(t, e, `SELECT * FROM jsonb_each('{"b":2,"a":{"c":1}}')`)
  387. if len(res.Columns) != 2 || res.Columns[0] != "key" || res.Columns[1] != "value" {
  388. t.Fatalf("jsonb_each columns = %v", res.Columns)
  389. }
  390. if res.RowCount != 2 || res.Rows[0][0] != "a" || res.Rows[0][1] != `{"c":1}` || res.Rows[1][0] != "b" || res.Rows[1][1] != `2` {
  391. t.Fatalf("jsonb_each rows = %v", res.Rows)
  392. }
  393. if len(res.ColumnTypes) != 2 || res.ColumnTypes[1] != "JSONB" {
  394. t.Fatalf("jsonb_each column types = %v", res.ColumnTypes)
  395. }
  396. res = execMust(t, e, `SELECT e.key, e.value FROM jsonb_each('{"a":1}') AS e`)
  397. if res.RowCount != 1 || res.Rows[0][0] != "a" || res.Rows[0][1] != `1` {
  398. t.Fatalf("aliased jsonb_each rows = %v", res.Rows)
  399. }
  400. // PostgreSQL's AS alias(col, ...) list renames the output columns.
  401. res = execMust(t, e, `SELECT e.k, e.v FROM jsonb_each('{"a":1}') AS e(k, v)`)
  402. if len(res.Columns) != 2 || res.Columns[0] != "k" || res.Columns[1] != "v" {
  403. t.Fatalf("jsonb_each renamed columns = %v", res.Columns)
  404. }
  405. if res.RowCount != 1 || res.Rows[0][0] != "a" || res.Rows[0][1] != `1` || res.ColumnTypes[1] != "JSONB" {
  406. t.Fatalf("jsonb_each renamed rows = %v types = %v", res.Rows, res.ColumnTypes)
  407. }
  408. res = execMust(t, e, `SELECT * FROM jsonb_each_text('{"a":true}') AS e(name, text_value)`)
  409. if len(res.Columns) != 2 || res.Columns[0] != "name" || res.Columns[1] != "text_value" {
  410. t.Fatalf("jsonb_each_text renamed columns = %v", res.Columns)
  411. }
  412. if res.Rows[0][1] != "true" {
  413. t.Fatalf("jsonb_each_text renamed rows = %v", res.Rows)
  414. }
  415. res = execMust(t, e, `SELECT element FROM jsonb_array_elements('[1,2]') AS t(element) WHERE element @> '1'::jsonb`)
  416. if res.RowCount != 1 || res.Rows[0][0] != `1` {
  417. t.Fatalf("jsonb_array_elements renamed rows = %v", res.Rows)
  418. }
  419. res = execMust(t, e, `SELECT key, value FROM jsonb_each_text('{"a":null,"b":true}')`)
  420. if res.RowCount != 2 || res.Rows[0][0] != "a" || res.Rows[0][1] != nil || res.Rows[1][1] != "true" {
  421. t.Fatalf("jsonb_each_text rows = %v", res.Rows)
  422. }
  423. res = execMust(t, e, `SELECT value FROM jsonb_array_elements('[1,{"a":2}]')`)
  424. if res.RowCount != 2 || res.Rows[0][0] != `1` || res.Rows[1][0] != `{"a":2}` {
  425. t.Fatalf("jsonb_array_elements rows = %v", res.Rows)
  426. }
  427. if res.ColumnTypes[0] != "JSONB" {
  428. t.Fatalf("jsonb_array_elements type = %v", res.ColumnTypes)
  429. }
  430. res = execMust(t, e, `SELECT value FROM jsonb_array_elements_text('[1,null,"x"]')`)
  431. if res.RowCount != 3 || res.Rows[0][0] != "1" || res.Rows[1][0] != nil || res.Rows[2][0] != "x" {
  432. t.Fatalf("jsonb_array_elements_text rows = %v", res.Rows)
  433. }
  434. res = execMust(t, e, `SELECT jsonb_object_keys FROM jsonb_object_keys('{"b":1,"a":2}')`)
  435. if res.RowCount != 2 || res.Rows[0][0] != "a" || res.Rows[1][0] != "b" {
  436. t.Fatalf("jsonb_object_keys rows = %v", res.Rows)
  437. }
  438. // A NULL document produces no rows.
  439. res = execMust(t, e, `SELECT * FROM jsonb_array_elements(NULL)`)
  440. if res.RowCount != 0 {
  441. t.Fatalf("jsonb_array_elements(NULL) rows = %v", res.Rows)
  442. }
  443. // Wrong document types and projections of set-returning functions are
  444. // rejected clearly instead of executing as scalar calls.
  445. for _, tc := range []struct {
  446. sql string
  447. code string
  448. }{
  449. {`SELECT * FROM jsonb_array_elements('{"a":1}')`, pgerror.CodeInvalidParameter},
  450. {`SELECT * FROM jsonb_each('[1]')`, pgerror.CodeInvalidParameter},
  451. {`SELECT * FROM jsonb_object_keys('[1]')`, pgerror.CodeInvalidParameter},
  452. {`SELECT * FROM jsonb_each('null')`, pgerror.CodeInvalidParameter},
  453. {`SELECT * FROM jsonb_array_elements('null')`, pgerror.CodeInvalidParameter},
  454. {`SELECT jsonb_each('{"a":1}')`, pgerror.CodeFeatureNotSupported},
  455. {`SELECT jsonb_array_elements('[1]')`, pgerror.CodeFeatureNotSupported},
  456. {`SELECT * FROM jsonb_each('{"a":1}') AS e JOIN docs d ON TRUE`, pgerror.CodeFeatureNotSupported},
  457. {`SELECT * FROM jsonb_each('{"a":1}') AS e(k)`, pgerror.CodeInvalidColumnReference},
  458. {`SELECT * FROM jsonb_array_elements('[1]') AS t(a, b)`, pgerror.CodeInvalidColumnReference},
  459. } {
  460. if _, err := execSQL(e, tc.sql); jsonbErrorCode(t, err) != tc.code {
  461. t.Errorf("%s error = %v, want %s", tc.sql, err, tc.code)
  462. }
  463. }
  464. }
  465. func TestJSONBEqualityOrderingAndDistinct(t *testing.T) {
  466. _, schema, table := newTestDB(t)
  467. e := newExec(schema, table)
  468. execMust(t, e, "CREATE TABLE docs (id INTEGER PRIMARY KEY, doc JSONB)")
  469. execMust(t, e, `INSERT INTO docs VALUES (1, '{"b":1,"a":2}'), (2, '{"a":2,"b":1}'), (3, '[1,2]')`)
  470. if got := jsonbValue(t, e, `SELECT '{"b":1,"a":2}'::jsonb = '{"a":2, "b": 1}'::jsonb`); got != true {
  471. t.Fatalf("jsonb equality = %v, want true", got)
  472. }
  473. if got := jsonbValue(t, e, `SELECT '{"a":1}'::jsonb = '[1]'::jsonb`); got != false {
  474. t.Fatalf("jsonb inequality = %v, want false", got)
  475. }
  476. if got := jsonbValue(t, e, `SELECT doc IS NOT DISTINCT FROM '{"a":2,"b":1}'::jsonb FROM docs WHERE id = 2`); got != true {
  477. t.Fatalf("IS NOT DISTINCT FROM = %v", got)
  478. }
  479. if got := jsonbValue(t, e, `SELECT '{"b":1,"a":2}'::jsonb IS DISTINCT FROM '{"a":2,"b":1.0}'::jsonb`); got != false {
  480. t.Fatalf("IS DISTINCT FROM key-order/number-spelling = %v, want false", got)
  481. }
  482. res := execMust(t, e, `SELECT COUNT(*) FROM docs WHERE doc = '{"a":2,"b":1}'::jsonb`)
  483. if res.Rows[0][0] != int64(2) {
  484. t.Fatalf("key-order-independent equality matched %v rows, want 2", res.Rows[0][0])
  485. }
  486. res = execMust(t, e, `SELECT DISTINCT doc FROM docs ORDER BY doc`)
  487. if res.RowCount != 2 {
  488. t.Fatalf("DISTINCT jsonb rows = %v, want 2", res.Rows)
  489. }
  490. // Canonical numeric scalars order numerically, and non-scalars order by
  491. // canonical text.
  492. execMust(t, e, "CREATE TABLE scalars (id INTEGER PRIMARY KEY, v JSONB)")
  493. execMust(t, e, `INSERT INTO scalars VALUES (1, '10'), (2, '2')`)
  494. res = execMust(t, e, `SELECT v FROM scalars ORDER BY v`)
  495. if res.RowCount != 2 || res.Rows[0][0] != `2` || res.Rows[1][0] != `10` {
  496. t.Fatalf("jsonb scalar ordering = %v", res.Rows)
  497. }
  498. res = execMust(t, e, `SELECT doc FROM docs WHERE id IN (1,3) ORDER BY doc`)
  499. if res.RowCount != 2 || res.Rows[0][0] != `[1,2]` || res.Rows[1][0] != `{"a":2,"b":1}` {
  500. t.Fatalf("jsonb text ordering = %v", res.Rows)
  501. }
  502. // A jsonb column cannot be compared with a number.
  503. if _, err := execSQL(e, `SELECT id FROM docs WHERE doc = 5`); err == nil {
  504. t.Fatal("jsonb = integer was accepted")
  505. }
  506. }
  507. func TestJSONBRejectedShapes(t *testing.T) {
  508. _, schema, table := newTestDB(t)
  509. e := newExec(schema, table)
  510. execMust(t, e, "CREATE TABLE docs (id INTEGER PRIMARY KEY, doc JSONB)")
  511. for _, sql := range []string{
  512. `SELECT jsonb_path_exists('{"a":1}', '$.a')`,
  513. `SELECT jsonb_path_query('{"a":1}', '$.a')`,
  514. `CREATE INDEX docs_gin ON docs USING GIN (doc)`,
  515. `CREATE INDEX docs_expr ON docs ((doc -> 'a'))`,
  516. `CREATE TABLE bad_arrays (doc JSONB[])`,
  517. } {
  518. if _, err := execSQL(e, sql); jsonbErrorCode(t, err) != pgerror.CodeFeatureNotSupported {
  519. t.Errorf("%s error = %v, want 0A000", sql, err)
  520. }
  521. }
  522. // A scalar extraction index over jsonb is a text expression and stays legal.
  523. execMust(t, e, `CREATE INDEX docs_kind ON docs ((doc ->> 'kind'))`)
  524. }
  525. func TestJSONBColumnMetadataAndDefaults(t *testing.T) {
  526. _, schema, table := newTestDB(t)
  527. e := newExec(schema, table)
  528. execMust(t, e, `CREATE TABLE docs (id INTEGER PRIMARY KEY, doc JSONB DEFAULT '{"b":2,"a":1}')`)
  529. execMust(t, e, `INSERT INTO docs (id) VALUES (1)`)
  530. res := execMust(t, e, `SELECT doc FROM docs`)
  531. if res.Rows[0][0] != `{"a":1,"b":2}` {
  532. t.Fatalf("canonical default = %v", res.Rows[0][0])
  533. }
  534. if len(res.ColumnTypes) != 1 || res.ColumnTypes[0] != "JSONB" {
  535. t.Fatalf("column types = %v, want [JSONB]", res.ColumnTypes)
  536. }
  537. // ALTER TABLE backfills the canonical default into existing rows.
  538. execMust(t, e, "CREATE TABLE raw (id INTEGER PRIMARY KEY)")
  539. execMust(t, e, "INSERT INTO raw VALUES (1)")
  540. execMust(t, e, `ALTER TABLE raw ADD COLUMN doc JSONB DEFAULT '{"b":2,"a":1}'`)
  541. res = execMust(t, e, `SELECT doc FROM raw`)
  542. if res.Rows[0][0] != `{"a":1,"b":2}` {
  543. t.Fatalf("backfilled default = %v", res.Rows[0][0])
  544. }
  545. // UPDATE canonicalizes too.
  546. execMust(t, e, `UPDATE raw SET doc = '{"z": 1.50}'`)
  547. res = execMust(t, e, `SELECT doc FROM raw`)
  548. if res.Rows[0][0] != `{"z":1.5}` {
  549. t.Fatalf("updated doc = %v", res.Rows[0][0])
  550. }
  551. }
  552. func TestCanonicalJSONBNumber(t *testing.T) {
  553. cases := map[string]string{
  554. "0": "0",
  555. "-0": "0",
  556. "-0.0": "0",
  557. "1": "1",
  558. "1.0": "1",
  559. "1.50": "1.5",
  560. "1e2": "100",
  561. "1E+2": "100",
  562. "1e-2": "0.01",
  563. "-12.340": "-12.34",
  564. "123456789012345678901234567890": "123456789012345678901234567890",
  565. }
  566. for input, want := range cases {
  567. got, err := canonicalJSONBNumber(json.Number(input))
  568. if err != nil || got != want {
  569. t.Errorf("canonicalJSONBNumber(%q) = %q, %v; want %q", input, got, err, want)
  570. }
  571. }
  572. for _, input := range []string{"1e999999", "1e-999999"} {
  573. if _, err := canonicalJSONBNumber(json.Number(input)); err == nil {
  574. t.Errorf("canonicalJSONBNumber(%q) accepted an unbounded expansion", input)
  575. }
  576. }
  577. }
  578. // JSON operations must keep working from a derived table and a CTE, where the
  579. // column type travels through Result column metadata.
  580. func TestJSONBTypePropagation(t *testing.T) {
  581. _, schema, table := newTestDB(t)
  582. e := newExec(schema, table)
  583. execMust(t, e, "CREATE TABLE docs (id INTEGER PRIMARY KEY, doc JSONB)")
  584. execMust(t, e, `INSERT INTO docs VALUES (1, '{"a":1}')`)
  585. if got := jsonbValue(t, e, `SELECT doc -> 'a' FROM (SELECT doc FROM docs) AS d`); got != `1` {
  586. t.Fatalf("derived jsonb -> = %v", got)
  587. }
  588. if got := jsonbValue(t, e, `SELECT doc ? 'a' FROM (SELECT doc FROM docs) AS d`); got != true {
  589. t.Fatalf("derived jsonb ? = %v", got)
  590. }
  591. if got := jsonbValue(t, e, `WITH c AS (SELECT doc FROM docs) SELECT doc @> '{"a":1}' FROM c`); got != true {
  592. t.Fatalf("CTE jsonb @> = %v", got)
  593. }
  594. if got := jsonbValue(t, e, `SELECT COALESCE(doc, '{}'::jsonb) ->> 'a' FROM docs`); got != "1" {
  595. t.Fatalf("COALESCE jsonb ->> = %v", got)
  596. }
  597. // A jsonb column keeps its type when it is the left side of a join and when
  598. // it is referenced through an alias.
  599. res := execMust(t, e, `SELECT a.id FROM docs AS a JOIN docs AS b ON a.id = b.id WHERE a.doc @> '{"a":1}'`)
  600. if res.RowCount != 1 || res.Rows[0][0] != int64(1) {
  601. t.Fatalf("joined jsonb containment rows = %v", res.Rows)
  602. }
  603. if got := jsonbValue(t, e, `SELECT a.doc -> 'a' FROM docs AS a`); got != `1` {
  604. t.Fatalf("aliased jsonb -> = %v", got)
  605. }
  606. if got := jsonbValue(t, e, `SELECT MAX(jsonb_build_object('a', doc)) FROM docs`); got != `{"a":{"a":1}}` {
  607. t.Fatalf("jsonb build function inside an aggregate = %v", got)
  608. }
  609. }
  610. func TestJSONBRejectsUnboundedCanonicalExpansion(t *testing.T) {
  611. _, schema, table := newTestDB(t)
  612. e := newExec(schema, table)
  613. if _, err := execSQL(e, `SELECT '{"a":1e999999}'::jsonb`); !strings.Contains(err.Error(), "invalid input syntax") {
  614. t.Fatalf("unbounded number error = %v", err)
  615. }
  616. }
  617. // A PostgreSQL path element is resolved against the container it reaches:
  618. // numeric-looking text is an object key in an object and an integer index in an
  619. // array. This must hold for #>, #>>, #-, jsonb_set, and jsonb_insert.
  620. func TestJSONBNumericLookingObjectKeys(t *testing.T) {
  621. _, schema, table := newTestDB(t)
  622. e := newExec(schema, table)
  623. cases := []struct {
  624. sql string
  625. want interface{}
  626. }{
  627. {`SELECT '{"1":{"2":3}}'::jsonb #> '{1,2}'`, `3`},
  628. {`SELECT '{"1":{"2":3}}'::jsonb #>> '{1,2}'`, `3`},
  629. {`SELECT '{"1":{"2":3}}'::jsonb #- '{1,2}'`, `{"1":{}}`},
  630. {`SELECT jsonb_set('{"1":{"2":3}}', '{1,2}', '4')`, `{"1":{"2":4}}`},
  631. {`SELECT jsonb_insert('{"1":{"2":3}}', '{1,3}', '4')`, `{"1":{"2":3,"3":4}}`},
  632. {`SELECT '{"01":"x"}'::jsonb #> '{01}'`, `"x"`},
  633. {`SELECT '{"-1":"x"}'::jsonb #> '{-1}'`, `"x"`},
  634. {`SELECT '{"1.5":"x"}'::jsonb #> '{1.5}'`, `"x"`},
  635. {`SELECT jsonb_set('{"01":"x"}', '{01}', '"y"')`, `{"01":"y"}`},
  636. {`SELECT jsonb_insert('{"01":"x"}', '{02}', '"y"')`, `{"01":"x","02":"y"}`},
  637. {`SELECT jsonb_set('{"-1":"x"}', '{-1}', '"y"')`, `{"-1":"y"}`},
  638. {`SELECT jsonb_insert('{"-1":"x"}', '{-2}', '"y"')`, `{"-1":"x","-2":"y"}`},
  639. {`SELECT '{"1.5":"x"}'::jsonb #- '{1.5}'`, `{}`},
  640. {`SELECT jsonb_set('{"1.5":"x"}', '{1.5}', '"y"')`, `{"1.5":"y"}`},
  641. {`SELECT '[10,20]'::jsonb #> '{01}'`, `20`},
  642. {`SELECT '[10,20]'::jsonb #> '{-1}'`, `20`},
  643. {`SELECT '[10,20]'::jsonb #> '{a}'`, nil},
  644. }
  645. for _, tc := range cases {
  646. if got := jsonbValue(t, e, tc.sql); got != tc.want {
  647. t.Errorf("%s = %v (%T), want %v", tc.sql, got, got, tc.want)
  648. }
  649. }
  650. // A non-integer path element on an array is an error for #-, matching
  651. // PostgreSQL's path mutation and delete behavior.
  652. if _, err := execSQL(e, `SELECT '[10,20]'::jsonb #- '{a}'`); jsonbErrorCode(t, err) != pgerror.CodeInvalidText {
  653. t.Errorf("#- array non-integer element error = %v, want 22P02", err)
  654. }
  655. }
  656. // #- must produce jsonb metadata and keep jsonb semantics for chained
  657. // operators, not fall back to text.
  658. func TestJSONBPathDeleteKeepsJSONBType(t *testing.T) {
  659. _, schema, table := newTestDB(t)
  660. e := newExec(schema, table)
  661. res := execMust(t, e, `SELECT '{"t":true}'::jsonb #- '{x}'`)
  662. if len(res.ColumnTypes) != 1 || res.ColumnTypes[0] != "JSONB" {
  663. t.Fatalf("#- column type = %v, want JSONB", res.ColumnTypes)
  664. }
  665. if got := jsonbValue(t, e, `SELECT ('{"t":true}'::jsonb #- '{x}') ->> 't'`); got != "true" {
  666. t.Fatalf("#- ->> = %v (%T), want true text", got, got)
  667. }
  668. if got := jsonbValue(t, e, `SELECT ('{"t":true}'::jsonb #- '{x}') = '{"t":true}'::jsonb`); got != true {
  669. t.Fatalf("#- jsonb equality = %v", got)
  670. }
  671. if got := jsonbValue(t, e, `SELECT ('{"t":true}'::jsonb #- '{x}') ? 't'`); got != true {
  672. t.Fatalf("#- ? = %v", got)
  673. }
  674. }
  675. // jsonb equality and ordering use exact canonical bytes, not float64. DISTINCT,
  676. // GROUP BY, and containment must agree with =.
  677. func TestJSONBExactEqualityAndAggregateAgreement(t *testing.T) {
  678. _, schema, table := newTestDB(t)
  679. e := newExec(schema, table)
  680. for _, sql := range []string{
  681. `SELECT '1'::jsonb = '1.0000000000000000001'::jsonb`,
  682. `SELECT '9007199254740993'::jsonb = '9007199254740992'::jsonb`,
  683. } {
  684. if got := jsonbValue(t, e, sql); got != false {
  685. t.Errorf("%s = %v, want false", sql, got)
  686. }
  687. }
  688. if got := jsonbValue(t, e, `SELECT '1'::jsonb = '1.0'::jsonb`); got != true {
  689. t.Fatalf("1 = 1.0 = %v, want true", got)
  690. }
  691. if got := jsonbValue(t, e, `SELECT '1'::jsonb < '1.0000000000000000001'::jsonb`); got != true {
  692. t.Fatalf("1 < 1.0000000000000000001 = %v, want true", got)
  693. }
  694. if got := jsonbValue(t, e, `SELECT '1'::jsonb IS DISTINCT FROM '1.0000000000000000001'::jsonb`); got != true {
  695. t.Fatalf("1 IS DISTINCT FROM 1.0000000000000000001 = %v, want true", got)
  696. }
  697. if got := jsonbValue(t, e, `SELECT CASE '1'::jsonb WHEN '1.0000000000000000001'::jsonb THEN 'same' ELSE 'different' END`); got != "different" {
  698. t.Fatalf("simple CASE exact jsonb equality = %v, want different", got)
  699. }
  700. if got := jsonbValue(t, e, `SELECT '1'::jsonb IN ('1.0'::jsonb, '1.0000000000000000001'::jsonb)`); got != true {
  701. t.Fatalf("jsonb IN = %v, want true", got)
  702. }
  703. if got := jsonbValue(t, e, `SELECT '{"n":1}'::jsonb @> '{"n":1.0000000000000000001}'::jsonb`); got != false {
  704. t.Fatalf("containment rounded a number: %v, want false", got)
  705. }
  706. if got := jsonbValue(t, e, `SELECT '{"n":1}'::jsonb @> '{"n":1.0}'::jsonb`); got != true {
  707. t.Fatalf("containment of equal canonical numbers = %v, want true", got)
  708. }
  709. execMust(t, e, "CREATE TABLE exact (id INTEGER PRIMARY KEY, doc JSONB)")
  710. execMust(t, e, `INSERT INTO exact VALUES (1, '1'), (2, '1.0'), (3, '1.0000000000000000001'), (4, '9007199254740993'), (5, '9007199254740992')`)
  711. if res := execMust(t, e, `SELECT DISTINCT doc FROM exact`); res.RowCount != 4 {
  712. t.Fatalf("DISTINCT exact jsonb rows = %v, want 4", res.Rows)
  713. }
  714. res := execMust(t, e, `SELECT doc, COUNT(*) FROM exact GROUP BY doc ORDER BY doc`)
  715. if res.RowCount != 4 {
  716. t.Fatalf("GROUP BY exact jsonb rows = %v, want 4", res.Rows)
  717. }
  718. if res.Rows[0][1] != int64(2) {
  719. t.Fatalf("GROUP BY merged canonical numbers = %v, want two spellings of 1", res.Rows[0])
  720. }
  721. res = execMust(t, e, `SELECT COUNT(*) FROM exact WHERE doc = '1'::jsonb`)
  722. if res.Rows[0][0] != int64(2) {
  723. t.Fatalf("equality count = %v, want 2", res.Rows[0][0])
  724. }
  725. res = execMust(t, e, `SELECT COUNT(*) FROM exact WHERE doc @> '1'::jsonb`)
  726. if res.Rows[0][0] != int64(2) {
  727. t.Fatalf("containment count = %v, want 2", res.Rows[0][0])
  728. }
  729. }
  730. // A jsonb extraction result must not be silently compared with a SQL number.
  731. func TestJSONBExtractionComparisonTypeError(t *testing.T) {
  732. _, schema, table := newTestDB(t)
  733. e := newExec(schema, table)
  734. for _, sql := range []string{
  735. `SELECT '{"a":1}'::jsonb -> 'a' = 1`,
  736. `SELECT '{"a":1}'::jsonb -> 'a' = TRUE`,
  737. } {
  738. if _, err := execSQL(e, sql); jsonbErrorCode(t, err) != pgerror.CodeDatatypeMismatch {
  739. t.Errorf("%s error = %v, want 42804", sql, err)
  740. }
  741. }
  742. if got := jsonbValue(t, e, `SELECT '{"a":1}'::jsonb -> 'a' = '1'::jsonb`); got != true {
  743. t.Fatalf("jsonb -> = jsonb = %v, want true", got)
  744. }
  745. }
  746. // PostgreSQL array containment is duplicate-insensitive: each candidate
  747. // element only needs some matching container element, and duplicates may
  748. // consume the same match.
  749. func TestJSONBArrayContainmentDuplicates(t *testing.T) {
  750. _, schema, table := newTestDB(t)
  751. e := newExec(schema, table)
  752. cases := []struct {
  753. sql string
  754. want interface{}
  755. }{
  756. {`SELECT '[1]'::jsonb @> '[1,1]'::jsonb`, true},
  757. {`SELECT '[1,1]'::jsonb @> '[1]'::jsonb`, true},
  758. {`SELECT '[1,2,2]'::jsonb @> '[2,2]'::jsonb`, true},
  759. {`SELECT '[1,2]'::jsonb @> '[2,2]'::jsonb`, true},
  760. {`SELECT '[1,2]'::jsonb @> '[2,3]'::jsonb`, false},
  761. {`SELECT '[1]'::jsonb @> '1'::jsonb`, true},
  762. }
  763. for _, tc := range cases {
  764. if got := jsonbValue(t, e, tc.sql); got != tc.want {
  765. t.Errorf("%s = %v, want %v", tc.sql, got, tc.want)
  766. }
  767. }
  768. }
  769. // A JSONB column written before native JSONB may hold non-canonical text. Reads
  770. // canonicalize it so projection, DISTINCT, GROUP BY, and ORDER BY all observe
  771. // the canonical value.
  772. func TestJSONBLegacyValuesCanonicalizeOnRead(t *testing.T) {
  773. _, schema, table := newTestDB(t)
  774. e := newExec(schema, table)
  775. execMust(t, e, "CREATE TABLE legacy (id INTEGER PRIMARY KEY, doc JSONB)")
  776. legacy := []string{
  777. `{ "a" : 1 }`,
  778. `{"a":1}`,
  779. ` { "a" :1 } `,
  780. `{"b": 2,"a": 1}`,
  781. `{"a":1,"b":2}`,
  782. ` { "b" : 2, "a" : 1 } `,
  783. }
  784. for i, raw := range legacy {
  785. if err := table.Insert("legacy", storage.Row{"id": int64(i + 1), "doc": raw}); err != nil {
  786. t.Fatalf("legacy insert %d: %v", i, err)
  787. }
  788. }
  789. e = newExec(schema, table)
  790. res := execMust(t, e, `SELECT doc FROM legacy ORDER BY id`)
  791. if res.RowCount != len(legacy) {
  792. t.Fatalf("legacy rows = %d", res.RowCount)
  793. }
  794. for _, row := range res.Rows {
  795. if row[0] != `{"a":1}` && row[0] != `{"a":1,"b":2}` {
  796. t.Fatalf("legacy read = %v, want canonical text", row[0])
  797. }
  798. }
  799. res = execMust(t, e, `SELECT DISTINCT doc FROM legacy`)
  800. if res.RowCount != 2 {
  801. t.Fatalf("legacy DISTINCT rows = %v, want 2", res.Rows)
  802. }
  803. res = execMust(t, e, `SELECT DISTINCT * FROM legacy`)
  804. if res.RowCount != len(legacy) {
  805. t.Fatalf("legacy DISTINCT * rows = %d", res.RowCount)
  806. }
  807. res = execMust(t, e, `SELECT * FROM legacy ORDER BY id`)
  808. for _, row := range res.Rows {
  809. if row[1] != `{"a":1}` && row[1] != `{"a":1,"b":2}` {
  810. t.Fatalf("legacy SELECT * read = %v, want canonical text", row[1])
  811. }
  812. }
  813. if got := jsonbValue(t, e, `SELECT COUNT(DISTINCT doc) FROM legacy`); got != int64(2) {
  814. t.Fatalf("legacy COUNT(DISTINCT doc) = %v, want 2", got)
  815. }
  816. res = execMust(t, e, `SELECT doc, COUNT(*) FROM legacy GROUP BY doc`)
  817. if res.RowCount != 2 {
  818. t.Fatalf("legacy GROUP BY rows = %v, want 2", res.Rows)
  819. }
  820. res = execMust(t, e, `SELECT id FROM legacy ORDER BY doc, id`)
  821. if res.RowCount != len(legacy) {
  822. t.Fatalf("legacy ORDER BY rows = %d", res.RowCount)
  823. }
  824. if got := jsonbValue(t, e, `SELECT doc FROM legacy WHERE id = 1`); got != `{"a":1}` {
  825. t.Fatalf("legacy selected value = %v, want canonical", got)
  826. }
  827. }
  828. // Escapes that encoding/json would silently rewrite are invalid jsonb input.
  829. func TestJSONBRejectsNULAndLoneSurrogates(t *testing.T) {
  830. _, schema, table := newTestDB(t)
  831. e := newExec(schema, table)
  832. for _, sql := range []string{
  833. `SELECT '{"a":"\u0000"}'::jsonb`,
  834. `SELECT '"\ud800"'::jsonb`,
  835. `SELECT '"\ud800x"'::jsonb`,
  836. `SELECT '"\udc00"'::jsonb`,
  837. `SELECT '{"\u0000":1}'::jsonb`,
  838. } {
  839. if _, err := execSQL(e, sql); jsonbErrorCode(t, err) != pgerror.CodeInvalidText {
  840. t.Errorf("%s error = %v, want 22P02", sql, err)
  841. }
  842. }
  843. if got := jsonbValue(t, e, `SELECT '"\u0041"'::jsonb`); got != `"A"` {
  844. t.Fatalf("escaped ASCII = %v", got)
  845. }
  846. if got := jsonbValue(t, e, `SELECT '"\ud83d\ude00"'::jsonb`); got != "\"\U0001F600\"" {
  847. t.Fatalf("surrogate pair = %v", got)
  848. }
  849. }
  850. // Zero-row text set-returning functions must still report TEXT for the value
  851. // column.
  852. func TestJSONBTextSetReturningTypesOnNull(t *testing.T) {
  853. _, schema, table := newTestDB(t)
  854. e := newExec(schema, table)
  855. res := execMust(t, e, `SELECT * FROM jsonb_each_text(NULL)`)
  856. if res.RowCount != 0 || len(res.ColumnTypes) != 2 || res.ColumnTypes[0] != "TEXT" || res.ColumnTypes[1] != "TEXT" {
  857. t.Fatalf("jsonb_each_text(NULL) = rows %d types %v, want 0 [TEXT TEXT]", res.RowCount, res.ColumnTypes)
  858. }
  859. res = execMust(t, e, `SELECT * FROM jsonb_array_elements_text(NULL)`)
  860. if res.RowCount != 0 || len(res.ColumnTypes) != 1 || res.ColumnTypes[0] != "TEXT" {
  861. t.Fatalf("jsonb_array_elements_text(NULL) = rows %d types %v, want 0 [TEXT]", res.RowCount, res.ColumnTypes)
  862. }
  863. }
  864. // JSON1 $ path patch values may be non-integral numeric expressions. They are
  865. // normalized to json.Number before encoding, including values read from REAL
  866. // columns.
  867. func TestJSONBJSON1PatchFloatValues(t *testing.T) {
  868. _, schema, table := newTestDB(t)
  869. e := newExec(schema, table)
  870. execMust(t, e, "CREATE TABLE realvals (id INTEGER PRIMARY KEY, r REAL)")
  871. execMust(t, e, `INSERT INTO realvals VALUES (1, 1.5)`)
  872. for _, tc := range []struct {
  873. sql string
  874. want string
  875. }{
  876. {`SELECT jsonb_set('{"a":1}', '$.b', 1.5)`, `{"a":1,"b":1.5}`},
  877. {`SELECT jsonb_set('{"a":1}', '$.b', 2.5)`, `{"a":1,"b":2.5}`},
  878. {`SELECT jsonb_insert('{}', '$.b', 2.5)`, `{"b":2.5}`},
  879. {`SELECT jsonb_replace('{"b":0}', '$.b', 2.5)`, `{"b":2.5}`},
  880. {`SELECT jsonb_set('{"a":1}', '$.b', r) FROM realvals`, `{"a":1,"b":1.5}`},
  881. {`SELECT jsonb_insert('{}', '$.b', r) FROM realvals`, `{"b":1.5}`},
  882. } {
  883. if got := jsonbValue(t, e, tc.sql); got != tc.want {
  884. t.Errorf("%s = %v, want %s", tc.sql, got, tc.want)
  885. }
  886. }
  887. }
  888. // HAVING evaluates simple CASE and IS DISTINCT FROM through the aggregate
  889. // expression path; it must use the same exact jsonb comparison as the
  890. // top-level evaluators.
  891. func TestJSONBAggregateHavingExactJSONB(t *testing.T) {
  892. _, schema, table := newTestDB(t)
  893. e := newExec(schema, table)
  894. execMust(t, e, "CREATE TABLE ex (id INTEGER PRIMARY KEY, doc JSONB)")
  895. execMust(t, e, `INSERT INTO ex VALUES (1, '1'), (2, '1.0000000000000000001')`)
  896. if got := jsonbValue(t, e, `SELECT COUNT(*) FROM ex GROUP BY doc HAVING '1'::jsonb IS DISTINCT FROM '1.0000000000000000001'::jsonb`); got != int64(1) {
  897. t.Fatalf("HAVING IS DISTINCT FROM group count = %v, want 1", got)
  898. }
  899. res := execMust(t, e, `SELECT doc, COUNT(*) FROM ex GROUP BY doc HAVING '1'::jsonb IS DISTINCT FROM '1.0000000000000000001'::jsonb ORDER BY doc`)
  900. if res.RowCount != 2 {
  901. t.Fatalf("HAVING IS DISTINCT FROM rows = %v, want 2 groups", res.Rows)
  902. }
  903. res = execMust(t, e, `SELECT doc, COUNT(*) FROM ex GROUP BY doc HAVING '1'::jsonb IS NOT DISTINCT FROM '1.0000000000000000001'::jsonb`)
  904. if res.RowCount != 0 {
  905. t.Fatalf("HAVING IS NOT DISTINCT FROM rows = %v, want 0", res.Rows)
  906. }
  907. res = execMust(t, e, `SELECT doc, COUNT(*) FROM ex GROUP BY doc HAVING CASE '1'::jsonb WHEN '1.0000000000000000001'::jsonb THEN FALSE ELSE TRUE END ORDER BY doc`)
  908. if res.RowCount != 2 {
  909. t.Fatalf("HAVING CASE rows = %v, want 2 groups", res.Rows)
  910. }
  911. }