Raise an error if any PATH argument to json_array_insert() is not the path
of an array element. Add some test cases for json_array_insert(). FossilOrigin-Name: 96b7d2c60a3f8a9f9d69313bad599a3a5ad335cb382263e4254e2d20929d5e55
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
C Add\snew\sSQL\sfunction:\sjson_array_insert().\s\sSuggested\sin\n[forum:/forumpost/2026-01-17T10:40:39z|forum\sthread\s2026-01-17T10:40:39z].\nThis\scheck-in\sseems\sto\swork,\sbut\scontains\sno\stest\scases.\s\sAlso,\sno\serror\nis\sraised\sif\sthe\sPATH\sdoes\snot\sreference\san\sarray.\s\sPrototype\sonly.
|
||||
D 2026-01-17T14:23:28.371
|
||||
C Raise\san\serror\sif\sany\sPATH\sargument\sto\sjson_array_insert()\sis\snot\sthe\spath\nof\san\sarray\selement.\s\sAdd\ssome\stest\scases\sfor\sjson_array_insert().
|
||||
D 2026-01-17T19:01:37.597
|
||||
F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x
|
||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||
@@ -699,7 +699,7 @@ F src/hash.h 46b92795a95bfefb210f52f0c316e9d7cdbcdd7e7fcfb0d8be796d3a5767cddf
|
||||
F src/hwtime.h 21c2cf1f736e7b97502c3674d0c386db3f06870d6f10d0cf8174e2a4b8cb726e
|
||||
F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
|
||||
F src/insert.c dfd311b0ac2d4f6359e62013db67799757f4d2cc56cca5c10f4888acfbbfa3fd
|
||||
F src/json.c 091c280965ebc673b8d0d15bd132b3243298d7603ce25749c9f0de28429e328e
|
||||
F src/json.c 95c20b077a8ec3b471122d312a907b1e5298ae93f924b0a96640022b6420a941
|
||||
F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa
|
||||
F src/loadext.c d6559d2b39c9bde6b104b83adeafbe5db3a514aae4d3d40afc58de522a03043b
|
||||
F src/main.c 21fb86045bbf6b6329251a0ce6771735b6c71287cc9fcda1f2005d4ac5f25b52
|
||||
@@ -1361,6 +1361,7 @@ F test/json105.test 043838b56e68f3252a0dcf5be1689016f6f3f05056f8dcfcdc9d074f4d93
|
||||
F test/json106.test 4aed3afd16549045d198a8d9cea00deea96e1f2ecf55864dce96cac558b8abef
|
||||
F test/json107.test 59054e815c8f6b67d634d44ace421cf975828fb5651c4460aa66015c8e19d562
|
||||
F test/json108.test 0a5f1e2d4b35a1bc33052563d2a5ede03052e2099e58cb424547656c898e0f49
|
||||
F test/json109.test 441cea5d73c24a1a34d284101740dfae5a082237c048c8a66b03aeebe5e3643e
|
||||
F test/json501.test b95e2d14988b682a5cadf079dd6162f0f85fb74cd59c6b1f1624110104a974eb
|
||||
F test/json502.test 4ef68e4f272dfb083d4cbceb4e9e51d67ec1186a185e0c13637c50a4dc2f9796
|
||||
F test/jsonb01.test f4cdfb4cf5a0c940091b17675ed9583f45add0c938f07d65b0de0e19d3a9a101
|
||||
@@ -2192,11 +2193,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee
|
||||
F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98
|
||||
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
|
||||
F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c
|
||||
P f8f89d2e10f06b54acf58a3b0543aef749c3d2b65670d4cc71530dea7997651e
|
||||
R 5eaa4c6199eb51b03923e8f6a4a1b985
|
||||
T *branch * json_array_insert
|
||||
T *sym-json_array_insert *
|
||||
T -sym-trunk *
|
||||
P d6c82c8248f8b1ce3d2c01a92e7d1058beac2b2ccac3b122a2cd385c77dc76df
|
||||
R 767eeb44449b6ebf81d3929fe2071be1
|
||||
U drh
|
||||
Z 59a65265ad7dd2e433c1fd0eebddff23
|
||||
Z 9b7f5476077742ae15428954dd628d31
|
||||
# Remove this line to create a well-formed Fossil manifest.
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
d6c82c8248f8b1ce3d2c01a92e7d1058beac2b2ccac3b122a2cd385c77dc76df
|
||||
96b7d2c60a3f8a9f9d69313bad599a3a5ad335cb382263e4254e2d20929d5e55
|
||||
|
||||
+29
-15
@@ -2874,7 +2874,8 @@ static int jsonLabelCompare(
|
||||
*/
|
||||
#define JSON_LOOKUP_ERROR 0xffffffff
|
||||
#define JSON_LOOKUP_NOTFOUND 0xfffffffe
|
||||
#define JSON_LOOKUP_PATHERROR 0xfffffffd
|
||||
#define JSON_LOOKUP_NOTARRAY 0xfffffffd
|
||||
#define JSON_LOOKUP_PATHERROR 0xfffffffc
|
||||
#define JSON_LOOKUP_ISERROR(x) ((x)>=JSON_LOOKUP_PATHERROR)
|
||||
|
||||
/* Forward declaration */
|
||||
@@ -2903,7 +2904,7 @@ static u32 jsonLookupStep(JsonParse*,u32,const char*,u32);
|
||||
static u32 jsonCreateEditSubstructure(
|
||||
JsonParse *pParse, /* The original JSONB that is being edited */
|
||||
JsonParse *pIns, /* Populate this with the blob data to insert */
|
||||
const char *zTail /* Tail of the path that determins substructure */
|
||||
const char *zTail /* Tail of the path that determines substructure */
|
||||
){
|
||||
static const u8 emptyObject[] = { JSONB_ARRAY, JSONB_OBJECT };
|
||||
int rc;
|
||||
@@ -2968,7 +2969,11 @@ static u32 jsonLookupStep(
|
||||
/* Already exists, so json_insert() is a no-op */
|
||||
}else if( pParse->eEdit==JEDIT_AINS ){
|
||||
/* json_array_insert() */
|
||||
jsonBlobEdit(pParse, iRoot, 0, pParse->aIns, pParse->nIns);
|
||||
if( zPath[-1]!=']' ){
|
||||
return JSON_LOOKUP_NOTARRAY;
|
||||
}else{
|
||||
jsonBlobEdit(pParse, iRoot, 0, pParse->aIns, pParse->nIns);
|
||||
}
|
||||
}else{
|
||||
/* json_set() or json_replace() */
|
||||
jsonBlobEdit(pParse, iRoot, sz, pParse->aIns, pParse->nIns);
|
||||
@@ -3041,6 +3046,9 @@ static u32 jsonLookupStep(
|
||||
testcase( pParse->eEdit==JEDIT_INS );
|
||||
testcase( pParse->eEdit==JEDIT_SET );
|
||||
testcase( pParse->eEdit==JEDIT_AINS );
|
||||
if( pParse->eEdit==JEDIT_AINS && sqlite3_strglob("*]",&zPath[i])!=0 ){
|
||||
return JSON_LOOKUP_NOTARRAY;
|
||||
}
|
||||
memset(&ix, 0, sizeof(ix));
|
||||
ix.db = pParse->db;
|
||||
jsonBlobAppendNode(&ix, rawKey?JSONB_TEXTRAW:JSONB_TEXT5, nKey, 0);
|
||||
@@ -3441,9 +3449,15 @@ static int jsonFunctionArgToBlob(
|
||||
*/
|
||||
static char *jsonBadPathError(
|
||||
sqlite3_context *ctx, /* The function call containing the error */
|
||||
const char *zPath /* The path with the problem */
|
||||
const char *zPath, /* The path with the problem */
|
||||
int rc /* Maybe JSON_LOOKUP_NOTARRAY */
|
||||
){
|
||||
char *zMsg = sqlite3_mprintf("bad JSON path: %Q", zPath);
|
||||
char *zMsg;
|
||||
if( rc==JSON_LOOKUP_NOTARRAY ){
|
||||
zMsg = sqlite3_mprintf("not an array element: %Q", zPath);
|
||||
}else{
|
||||
zMsg = sqlite3_mprintf("bad JSON path: %Q", zPath);
|
||||
}
|
||||
if( ctx==0 ) return zMsg;
|
||||
if( zMsg ){
|
||||
sqlite3_result_error(ctx, zMsg, -1);
|
||||
@@ -3518,7 +3532,7 @@ jsonInsertIntoBlob_patherror:
|
||||
if( rc==JSON_LOOKUP_ERROR ){
|
||||
sqlite3_result_error(ctx, "malformed JSON", -1);
|
||||
}else{
|
||||
jsonBadPathError(ctx, zPath);
|
||||
jsonBadPathError(ctx, zPath, rc);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -3960,7 +3974,7 @@ static void jsonArrayLengthFunc(
|
||||
if( i==JSON_LOOKUP_NOTFOUND ){
|
||||
/* no-op */
|
||||
}else if( i==JSON_LOOKUP_PATHERROR ){
|
||||
jsonBadPathError(ctx, zPath);
|
||||
jsonBadPathError(ctx, zPath, 0);
|
||||
}else{
|
||||
sqlite3_result_error(ctx, "malformed JSON", -1);
|
||||
}
|
||||
@@ -4065,7 +4079,7 @@ static void jsonExtractFunc(
|
||||
j = jsonLookupStep(p, 0, jx.zBuf, 0);
|
||||
jsonStringReset(&jx);
|
||||
}else{
|
||||
jsonBadPathError(ctx, zPath);
|
||||
jsonBadPathError(ctx, zPath, 0);
|
||||
goto json_extract_error;
|
||||
}
|
||||
if( j<p->nBlob ){
|
||||
@@ -4100,7 +4114,7 @@ static void jsonExtractFunc(
|
||||
sqlite3_result_error(ctx, "malformed JSON", -1);
|
||||
goto json_extract_error;
|
||||
}else{
|
||||
jsonBadPathError(ctx, zPath);
|
||||
jsonBadPathError(ctx, zPath, 0);
|
||||
goto json_extract_error;
|
||||
}
|
||||
}
|
||||
@@ -4429,7 +4443,7 @@ static void jsonRemoveFunc(
|
||||
if( rc==JSON_LOOKUP_NOTFOUND ){
|
||||
continue; /* No-op */
|
||||
}else if( rc==JSON_LOOKUP_PATHERROR ){
|
||||
jsonBadPathError(ctx, zPath);
|
||||
jsonBadPathError(ctx, zPath, rc);
|
||||
}else{
|
||||
sqlite3_result_error(ctx, "malformed JSON", -1);
|
||||
}
|
||||
@@ -4441,7 +4455,7 @@ static void jsonRemoveFunc(
|
||||
return;
|
||||
|
||||
json_remove_patherror:
|
||||
jsonBadPathError(ctx, zPath);
|
||||
jsonBadPathError(ctx, zPath, 0);
|
||||
|
||||
json_remove_done:
|
||||
jsonParseFree(p);
|
||||
@@ -4521,7 +4535,7 @@ static void jsonTypeFunc(
|
||||
zPath = (const char*)sqlite3_value_text(argv[1]);
|
||||
if( zPath==0 ) goto json_type_done;
|
||||
if( zPath[0]!='$' ){
|
||||
jsonBadPathError(ctx, zPath);
|
||||
jsonBadPathError(ctx, zPath, 0);
|
||||
goto json_type_done;
|
||||
}
|
||||
i = jsonLookupStep(p, 0, zPath+1, 0);
|
||||
@@ -4529,7 +4543,7 @@ static void jsonTypeFunc(
|
||||
if( i==JSON_LOOKUP_NOTFOUND ){
|
||||
/* no-op */
|
||||
}else if( i==JSON_LOOKUP_PATHERROR ){
|
||||
jsonBadPathError(ctx, zPath);
|
||||
jsonBadPathError(ctx, zPath, 0);
|
||||
}else{
|
||||
sqlite3_result_error(ctx, "malformed JSON", -1);
|
||||
}
|
||||
@@ -5433,7 +5447,7 @@ static int jsonEachFilter(
|
||||
if( zRoot==0 ) return SQLITE_OK;
|
||||
if( zRoot[0]!='$' ){
|
||||
sqlite3_free(cur->pVtab->zErrMsg);
|
||||
cur->pVtab->zErrMsg = jsonBadPathError(0, zRoot);
|
||||
cur->pVtab->zErrMsg = jsonBadPathError(0, zRoot, 0);
|
||||
jsonEachCursorReset(p);
|
||||
return cur->pVtab->zErrMsg ? SQLITE_ERROR : SQLITE_NOMEM;
|
||||
}
|
||||
@@ -5451,7 +5465,7 @@ static int jsonEachFilter(
|
||||
return SQLITE_OK;
|
||||
}
|
||||
sqlite3_free(cur->pVtab->zErrMsg);
|
||||
cur->pVtab->zErrMsg = jsonBadPathError(0, zRoot);
|
||||
cur->pVtab->zErrMsg = jsonBadPathError(0, zRoot, 0);
|
||||
jsonEachCursorReset(p);
|
||||
return cur->pVtab->zErrMsg ? SQLITE_ERROR : SQLITE_NOMEM;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
# 2026-01-17
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
# Test cases for json_array_insert().
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix json109
|
||||
|
||||
do_execsql_test 1.1 {
|
||||
SELECT json_array_insert('[1,2,3]','$[0]',999,'$[0]',888);
|
||||
} {{[888,999,1,2,3]}}
|
||||
do_execsql_test 1.2 {
|
||||
SELECT json_array_insert('[1,2,3]','$[0]',999,'$[#]',888);
|
||||
} {{[999,1,2,3,888]}}
|
||||
do_execsql_test 1.3 {
|
||||
SELECT json_array_insert('[1,2,3]','$[1]',888);
|
||||
} {{[1,888,2,3]}}
|
||||
do_execsql_test 1.4 {
|
||||
SELECT json_array_insert('[1,2,3]','$[2]',888);
|
||||
} {{[1,2,888,3]}}
|
||||
do_execsql_test 1.5 {
|
||||
SELECT json_array_insert('[1,2,3]','$[3]',888);
|
||||
} {{[1,2,3,888]}}
|
||||
do_execsql_test 1.6 {
|
||||
SELECT json_array_insert('[1,2,3]','$[#-1]',888);
|
||||
} {{[1,2,888,3]}}
|
||||
do_execsql_test 1.7 {
|
||||
SELECT json_array_insert('[1,2,3]','$[#-2]',888);
|
||||
} {{[1,888,2,3]}}
|
||||
do_execsql_test 1.8 {
|
||||
SELECT json_array_insert('[1,2,3]','$[#-3]',888);
|
||||
} {{[888,1,2,3]}}
|
||||
do_execsql_test 1.9 {
|
||||
SELECT json_array_insert('[1,2,3]','$[#-4]',888);
|
||||
} {{[1,2,3]}}
|
||||
|
||||
do_catchsql_test 2.1 {
|
||||
SELECT json_array_insert('{a:[1,2,3]}','$.a',888);
|
||||
} {1 {not an array element: '$.a'}}
|
||||
do_catchsql_test 2.2 {
|
||||
SELECT json_array_insert('{a:[1,2,3]}','$.b',888);
|
||||
} {1 {not an array element: '$.b'}}
|
||||
do_catchsql_test 2.3 {
|
||||
SELECT json_array_insert('{a:[1,2,3]}','$.b[0]',888);
|
||||
} {0 {{{"a":[1,2,3],"b":[888]}}}}
|
||||
do_catchsql_test 2.4 {
|
||||
SELECT json_array_insert('{a:[1,2,3]}','$.b.c.d[0]',888);
|
||||
} {0 {{{"a":[1,2,3],"b":{"c":{"d":[888]}}}}}}
|
||||
do_catchsql_test 2.5 {
|
||||
SELECT json_array_insert('{a:[1,2,3]}','$.b.c.d[0',888);
|
||||
} {1 {not an array element: '$.b.c.d[0'}}
|
||||
do_catchsql_test 2.6 {
|
||||
SELECT json_array_insert('{a:[1,2,3]}','$.b.c.d',888);
|
||||
} {1 {not an array element: '$.b.c.d'}}
|
||||
do_catchsql_test 2.7 {
|
||||
SELECT json_array_insert('{a:[1,2,3]}','$[0]',888);
|
||||
} {0 {{{"a":[1,2,3]}}}}
|
||||
do_catchsql_test 2.8 {
|
||||
SELECT json_array_insert('{a:[1,2,3]}','$.b[0]',888,'$.a[1]','999','$.c',0);
|
||||
} {1 {not an array element: '$.c'}}
|
||||
|
||||
finish_test
|
||||
Reference in New Issue
Block a user