mirror of
https://github.com/sqlite/sqlite.git
synced 2025-10-21 11:13:54 +03:00
Add new table-valued functions jsonb_each() and jsonb_tree() that work just
like json_each() and json_tree() except that the "value" column is JSONB instead of JSON text when the "type" is 'object' or 'array'. FossilOrigin-Name: dfc41cb3aad7fedd834baaaba0d8e3aeb55a249af4f0934397652ea9c59dc9fc
This commit is contained in:
21
manifest
21
manifest
@@ -1,5 +1,5 @@
|
||||
C In\sc-pp.c,\suse\s(void)x\sinstead\sof\san\sempty\sif(x){}\sto\sflag\sunused\sarguments.
|
||||
D 2025-09-26T11:14:15.429
|
||||
C Add\snew\stable-valued\sfunctions\sjsonb_each()\sand\sjsonb_tree()\sthat\swork\sjust\nlike\sjson_each()\sand\sjson_tree()\sexcept\sthat\sthe\s"value"\scolumn\sis\sJSONB\ninstead\sof\sJSON\stext\swhen\sthe\s"type"\sis\s'object'\sor\s'array'.
|
||||
D 2025-09-26T11:36:10.296
|
||||
F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x
|
||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||
@@ -681,7 +681,7 @@ F src/btmutex.c 30dada73a819a1ef5b7583786370dce1842e12e1ad941e4d05ac29695528daea
|
||||
F src/btree.c cb5b8ceb9baa02a63a2f83dec09c4153e1cfbdf9c2adef5c62c26d2160eeb067
|
||||
F src/btree.h e823c46d87f63d904d735a24b76146d19f51f04445ea561f71cc3382fd1307f0
|
||||
F src/btreeInt.h 9c0f9ea5c9b5f4dcaea18111d43efe95f2ac276cd86d770dce10fd99ccc93886
|
||||
F src/build.c 1ba7a4f00f0e7281131eb0a83218b2a6a952840303e48ac8059ae1a6271c7ab2
|
||||
F src/build.c f3c5f5b6b4b6654d3680c15b31a1a2ba4fdf0c3b1e8bea10cb20233c5423972f
|
||||
F src/callback.c acae8c8dddda41ee85cfdf19b926eefe830f371069f8aadca3aa39adf5b1c859
|
||||
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
|
||||
F src/date.c b6f92001f4b1f73f21774927488661d28f4dac9cd9701ed96486d96b44f5b058
|
||||
@@ -698,10 +698,10 @@ F src/hash.h 46b92795a95bfefb210f52f0c316e9d7cdbcdd7e7fcfb0d8be796d3a5767cddf
|
||||
F src/hwtime.h f9c2dfb84dce7acf95ce6d289e46f5f9d3d1afd328e53da8f8e9008e3b3caae6
|
||||
F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
|
||||
F src/insert.c dfd311b0ac2d4f6359e62013db67799757f4d2cc56cca5c10f4888acfbbfa3fd
|
||||
F src/json.c eb5aa0f1fd049058352250b81810c9ab63ab8d57264e19c86c3060b4ea076511
|
||||
F src/json.c 0f11267c9dbe83e4cdca56d213f021b0e9516d31317e485e3508687cfb65bf36
|
||||
F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa
|
||||
F src/loadext.c 3326993a09553c6b38cc52d4f9cc2e47dcfc8736ffd853fcb0cb49bc9e3d523c
|
||||
F src/main.c 4315e426f5898d994f47a5a17169b48120cd440307ab6d07850ff3d1eabf3726
|
||||
F src/main.c ce69a2650e3d359ed6a8a2867ccafb27ac62ce1d39f3120a84ff513320952a6c
|
||||
F src/malloc.c 410e570b30c26cc36e3372577df50f7a96ee3eed5b2b161c6b6b48773c650c5e
|
||||
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
|
||||
F src/mem1.c 3bb59158c38e05f6270e761a9f435bf19827a264c13d1631c58b84bdc96d73b2
|
||||
@@ -742,7 +742,7 @@ F src/shell.c.in 175630658a5fce0277cddf4991c56931ed061b3af36061be3e56ef113588452
|
||||
F src/sqlite.h.in 5732519a2acb09066032ceac21f25996eb3f28f807a4468e30633c7c70faae1c
|
||||
F src/sqlite3.rc 015537e6ac1eec6c7050e17b616c2ffe6f70fca241835a84a4f0d5937383c479
|
||||
F src/sqlite3ext.h 3f0c4ed6934e7309a61c6f3c30f70a30a5b869f785bb3d9f721a36c5e4359126
|
||||
F src/sqliteInt.h 01ab337beb08582828b8db542034eaf832778aa670ae6ade7e70f1d998ebdf17
|
||||
F src/sqliteInt.h 673c7c5d7e77552452b21499717233329809f252458f77a798977737f51b31b8
|
||||
F src/sqliteLimit.h fe70bd8983e5d317a264f2ea97473b359faf3ebb0827877a76813f5cf0cdc364
|
||||
F src/status.c 0e72e4f6be6ccfde2488eb63210297e75f569f3ce9920f6c3d77590ec6ce5ffd
|
||||
F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
|
||||
@@ -2170,8 +2170,9 @@ F tool/version-info.c 3b36468a90faf1bbd59c65fd0eb66522d9f941eedd364fabccd7227350
|
||||
F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee87c1b31a7
|
||||
F tool/warnings.sh 1ad0169b022b280bcaaf94a7fa231591be96b514230ab5c98fbf15cd7df842dd
|
||||
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
|
||||
P 69086be8a155d70d9dd7b655b66809250b24fe6d5bcdc6cb5e0275446a43f51d
|
||||
R 8b9f282903dcc4cedb182b829fff60d8
|
||||
U stephan
|
||||
Z 679bbd728f16a232de94ff4c271a958c
|
||||
P df9ab8a35517e3a2baf4b19d07d46ce3f8b48043ccdeadef22bffc12e80461c3 c50a3c45a20e5b9d48e749818bea06dfa99b729535e0617347c6ece1d277a447
|
||||
R 31c139330d7eefdf010cffbd7465fd3c
|
||||
T +closed c50a3c45a20e5b9d48e749818bea06dfa99b729535e0617347c6ece1d277a447
|
||||
U drh
|
||||
Z fd0622101369a3b80a24218729fa1f33
|
||||
# Remove this line to create a well-formed Fossil manifest.
|
||||
|
@@ -1 +1 @@
|
||||
df9ab8a35517e3a2baf4b19d07d46ce3f8b48043ccdeadef22bffc12e80461c3
|
||||
dfc41cb3aad7fedd834baaaba0d8e3aeb55a249af4f0934397652ea9c59dc9fc
|
||||
|
@@ -433,6 +433,11 @@ Table *sqlite3LocateTable(
|
||||
if( pMod==0 && sqlite3_strnicmp(zName, "pragma_", 7)==0 ){
|
||||
pMod = sqlite3PragmaVtabRegister(db, zName);
|
||||
}
|
||||
#ifndef SQLITE_OMIT_JSON
|
||||
if( pMod==0 && sqlite3_strnicmp(zName, "json", 4)==0 ){
|
||||
pMod = sqlite3JsonVtabRegister(db, zName);
|
||||
}
|
||||
#endif
|
||||
if( pMod && sqlite3VtabEponymousTableInit(pParse, pMod) ){
|
||||
testcase( pMod->pEpoTab==0 );
|
||||
return pMod->pEpoTab;
|
||||
|
103
src/json.c
103
src/json.c
@@ -3153,19 +3153,27 @@ static void jsonReturnTextJsonFromBlob(
|
||||
**
|
||||
** If the value is a primitive, return it as an SQL value.
|
||||
** If the value is an array or object, return it as either
|
||||
** JSON text or the BLOB encoding, depending on the JSON_B flag
|
||||
** on the userdata.
|
||||
** JSON text or the BLOB encoding, depending on the eMode flag
|
||||
** as follows:
|
||||
**
|
||||
** eMode==0 JSONB if the JSON_B flag is set in userdata or
|
||||
** text if the JSON_B flag is omitted from userdata.
|
||||
**
|
||||
** eMode==1 Text
|
||||
**
|
||||
** eMode==2 JSONB
|
||||
*/
|
||||
static void jsonReturnFromBlob(
|
||||
JsonParse *pParse, /* Complete JSON parse tree */
|
||||
u32 i, /* Index of the node */
|
||||
sqlite3_context *pCtx, /* Return value for this function */
|
||||
int textOnly /* return text JSON. Disregard user-data */
|
||||
int eMode /* Format of return: text of JSONB */
|
||||
){
|
||||
u32 n, sz;
|
||||
int rc;
|
||||
sqlite3 *db = sqlite3_context_db_handle(pCtx);
|
||||
|
||||
assert( eMode>=0 && eMode<=2 );
|
||||
n = jsonbPayloadSize(pParse, i, &sz);
|
||||
if( n==0 ){
|
||||
sqlite3_result_error(pCtx, "malformed JSON", -1);
|
||||
@@ -3284,8 +3292,14 @@ static void jsonReturnFromBlob(
|
||||
}
|
||||
case JSONB_ARRAY:
|
||||
case JSONB_OBJECT: {
|
||||
int flags = textOnly ? 0 : SQLITE_PTR_TO_INT(sqlite3_user_data(pCtx));
|
||||
if( flags & JSON_BLOB ){
|
||||
if( eMode==0 ){
|
||||
if( (SQLITE_PTR_TO_INT(sqlite3_user_data(pCtx)) & JSON_BLOB)!=0 ){
|
||||
eMode = 2;
|
||||
}else{
|
||||
eMode = 1;
|
||||
}
|
||||
}
|
||||
if( eMode==2 ){
|
||||
sqlite3_result_blob(pCtx, &pParse->aBlob[i], sz+n, SQLITE_TRANSIENT);
|
||||
}else{
|
||||
jsonReturnTextJsonFromBlob(pCtx, &pParse->aBlob[i], sz+n);
|
||||
@@ -4932,6 +4946,7 @@ struct JsonEachCursor {
|
||||
u32 nRoot; /* Size of the root path in bytes */
|
||||
u8 eType; /* Type of the container for element i */
|
||||
u8 bRecursive; /* True for json_tree(). False for json_each() */
|
||||
u8 eMode; /* 1 for json_each(). 2 for jsonb_each() */
|
||||
u32 nParent; /* Current nesting depth */
|
||||
u32 nParentAlloc; /* Space allocated for aParent[] */
|
||||
JsonParent *aParent; /* Parent elements of i */
|
||||
@@ -4943,6 +4958,8 @@ typedef struct JsonEachConnection JsonEachConnection;
|
||||
struct JsonEachConnection {
|
||||
sqlite3_vtab base; /* Base class - must be first */
|
||||
sqlite3 *db; /* Database connection */
|
||||
u8 eMode; /* 1 for json_each(). 2 for jsonb_each() */
|
||||
u8 bRecursive; /* True for json_tree(). False for json_each() */
|
||||
};
|
||||
|
||||
|
||||
@@ -4985,6 +5002,8 @@ static int jsonEachConnect(
|
||||
if( pNew==0 ) return SQLITE_NOMEM;
|
||||
sqlite3_vtab_config(db, SQLITE_VTAB_INNOCUOUS);
|
||||
pNew->db = db;
|
||||
pNew->eMode = argv[0][4]=='b' ? 2 : 1;
|
||||
pNew->bRecursive = argv[0][4+pNew->eMode]=='t';
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
@@ -4996,8 +5015,8 @@ static int jsonEachDisconnect(sqlite3_vtab *pVtab){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/* constructor for a JsonEachCursor object for json_each(). */
|
||||
static int jsonEachOpenEach(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
|
||||
/* constructor for a JsonEachCursor object for json_each()/json_tree(). */
|
||||
static int jsonEachOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
|
||||
JsonEachConnection *pVtab = (JsonEachConnection*)p;
|
||||
JsonEachCursor *pCur;
|
||||
|
||||
@@ -5005,21 +5024,13 @@ static int jsonEachOpenEach(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
|
||||
pCur = sqlite3DbMallocZero(pVtab->db, sizeof(*pCur));
|
||||
if( pCur==0 ) return SQLITE_NOMEM;
|
||||
pCur->db = pVtab->db;
|
||||
pCur->eMode = pVtab->eMode;
|
||||
pCur->bRecursive = pVtab->bRecursive;
|
||||
jsonStringZero(&pCur->path);
|
||||
*ppCursor = &pCur->base;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/* constructor for a JsonEachCursor object for json_tree(). */
|
||||
static int jsonEachOpenTree(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
|
||||
int rc = jsonEachOpenEach(p, ppCursor);
|
||||
if( rc==SQLITE_OK ){
|
||||
JsonEachCursor *pCur = (JsonEachCursor*)*ppCursor;
|
||||
pCur->bRecursive = 1;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Reset a JsonEachCursor back to its original state. Free any memory
|
||||
** held. */
|
||||
static void jsonEachCursorReset(JsonEachCursor *p){
|
||||
@@ -5224,7 +5235,7 @@ static int jsonEachColumn(
|
||||
}
|
||||
case JEACH_VALUE: {
|
||||
u32 i = jsonSkipLabel(p);
|
||||
jsonReturnFromBlob(&p->sParse, i, ctx, 1);
|
||||
jsonReturnFromBlob(&p->sParse, i, ctx, p->eMode);
|
||||
if( (p->sParse.aBlob[i] & 0x0f)>=JSONB_ARRAY ){
|
||||
sqlite3_result_subtype(ctx, JSON_SUBTYPE);
|
||||
}
|
||||
@@ -5468,36 +5479,7 @@ static sqlite3_module jsonEachModule = {
|
||||
jsonEachBestIndex, /* xBestIndex */
|
||||
jsonEachDisconnect, /* xDisconnect */
|
||||
0, /* xDestroy */
|
||||
jsonEachOpenEach, /* xOpen - open a cursor */
|
||||
jsonEachClose, /* xClose - close a cursor */
|
||||
jsonEachFilter, /* xFilter - configure scan constraints */
|
||||
jsonEachNext, /* xNext - advance a cursor */
|
||||
jsonEachEof, /* xEof - check for end of scan */
|
||||
jsonEachColumn, /* xColumn - read data */
|
||||
jsonEachRowid, /* xRowid - read data */
|
||||
0, /* xUpdate */
|
||||
0, /* xBegin */
|
||||
0, /* xSync */
|
||||
0, /* xCommit */
|
||||
0, /* xRollback */
|
||||
0, /* xFindMethod */
|
||||
0, /* xRename */
|
||||
0, /* xSavepoint */
|
||||
0, /* xRelease */
|
||||
0, /* xRollbackTo */
|
||||
0, /* xShadowName */
|
||||
0 /* xIntegrity */
|
||||
};
|
||||
|
||||
/* The methods of the json_tree virtual table. */
|
||||
static sqlite3_module jsonTreeModule = {
|
||||
0, /* iVersion */
|
||||
0, /* xCreate */
|
||||
jsonEachConnect, /* xConnect */
|
||||
jsonEachBestIndex, /* xBestIndex */
|
||||
jsonEachDisconnect, /* xDisconnect */
|
||||
0, /* xDestroy */
|
||||
jsonEachOpenTree, /* xOpen - open a cursor */
|
||||
jsonEachOpen, /* xOpen - open a cursor */
|
||||
jsonEachClose, /* xClose - close a cursor */
|
||||
jsonEachFilter, /* xFilter - configure scan constraints */
|
||||
jsonEachNext, /* xNext - advance a cursor */
|
||||
@@ -5586,21 +5568,20 @@ void sqlite3RegisterJsonFunctions(void){
|
||||
|
||||
#if !defined(SQLITE_OMIT_VIRTUALTABLE) && !defined(SQLITE_OMIT_JSON)
|
||||
/*
|
||||
** Register the JSON table-valued functions
|
||||
** Register the JSON table-valued function named zName and return a
|
||||
** pointer to its Module object. Return NULL if something goes wrong.
|
||||
*/
|
||||
int sqlite3JsonTableFunctions(sqlite3 *db){
|
||||
int rc = SQLITE_OK;
|
||||
static const struct {
|
||||
const char *zName;
|
||||
sqlite3_module *pModule;
|
||||
} aMod[] = {
|
||||
{ "json_each", &jsonEachModule },
|
||||
{ "json_tree", &jsonTreeModule },
|
||||
};
|
||||
Module *sqlite3JsonVtabRegister(sqlite3 *db, const char *zName){
|
||||
unsigned int i;
|
||||
for(i=0; i<sizeof(aMod)/sizeof(aMod[0]) && rc==SQLITE_OK; i++){
|
||||
rc = sqlite3_create_module(db, aMod[i].zName, aMod[i].pModule, 0);
|
||||
static const char *azModule[] = {
|
||||
"json_each", "json_tree", "jsonb_each", "jsonb_tree"
|
||||
};
|
||||
assert( sqlite3HashFind(&db->aModule, zName)==0 );
|
||||
for(i=0; i<sizeof(azModule)/sizeof(azModule[0]); i++){
|
||||
if( sqlite3StrICmp(azModule[i],zName)==0 ){
|
||||
return sqlite3VtabCreateModule(db, azModule[i], &jsonEachModule, 0, 0);
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
return 0;
|
||||
}
|
||||
#endif /* !defined(SQLITE_OMIT_VIRTUALTABLE) && !defined(SQLITE_OMIT_JSON) */
|
||||
|
@@ -74,9 +74,6 @@ static int (*const sqlite3BuiltinExtensions[])(sqlite3*) = {
|
||||
sqlite3DbstatRegister,
|
||||
#endif
|
||||
sqlite3TestExtInit,
|
||||
#if !defined(SQLITE_OMIT_VIRTUALTABLE) && !defined(SQLITE_OMIT_JSON)
|
||||
sqlite3JsonTableFunctions,
|
||||
#endif
|
||||
#ifdef SQLITE_ENABLE_STMTVTAB
|
||||
sqlite3StmtVtabInit,
|
||||
#endif
|
||||
|
@@ -5220,7 +5220,7 @@ void sqlite3RegisterDateTimeFunctions(void);
|
||||
void sqlite3RegisterJsonFunctions(void);
|
||||
void sqlite3RegisterPerConnectionBuiltinFunctions(sqlite3*);
|
||||
#if !defined(SQLITE_OMIT_VIRTUALTABLE) && !defined(SQLITE_OMIT_JSON)
|
||||
int sqlite3JsonTableFunctions(sqlite3*);
|
||||
Module *sqlite3JsonVtabRegister(sqlite3*,const char*);
|
||||
#endif
|
||||
int sqlite3SafetyCheckOk(sqlite3*);
|
||||
int sqlite3SafetyCheckSickOrOk(sqlite3*);
|
||||
|
Reference in New Issue
Block a user