mirror of
https://github.com/sqlite/sqlite.git
synced 2025-07-27 20:41:58 +03:00
Get the json_group_array() and json_group_object() SQL functions working
as window functions. FossilOrigin-Name: 916cdc83f5a45e0b6f61c52ff5fde70d54bcd0dfaa4a32f9ac709fe0ddbb480b
This commit is contained in:
@ -1802,7 +1802,7 @@ static void jsonArrayStep(
|
|||||||
jsonAppendValue(pStr, argv[0]);
|
jsonAppendValue(pStr, argv[0]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
static void jsonArrayFinal(sqlite3_context *ctx){
|
static void jsonArrayCompute(sqlite3_context *ctx, int isFinal){
|
||||||
JsonString *pStr;
|
JsonString *pStr;
|
||||||
pStr = (JsonString*)sqlite3_aggregate_context(ctx, 0);
|
pStr = (JsonString*)sqlite3_aggregate_context(ctx, 0);
|
||||||
if( pStr ){
|
if( pStr ){
|
||||||
@ -1811,16 +1811,60 @@ static void jsonArrayFinal(sqlite3_context *ctx){
|
|||||||
if( pStr->bErr ){
|
if( pStr->bErr ){
|
||||||
if( pStr->bErr==1 ) sqlite3_result_error_nomem(ctx);
|
if( pStr->bErr==1 ) sqlite3_result_error_nomem(ctx);
|
||||||
assert( pStr->bStatic );
|
assert( pStr->bStatic );
|
||||||
}else{
|
}else if( isFinal ){
|
||||||
sqlite3_result_text(ctx, pStr->zBuf, pStr->nUsed,
|
sqlite3_result_text(ctx, pStr->zBuf, pStr->nUsed,
|
||||||
pStr->bStatic ? SQLITE_TRANSIENT : sqlite3_free);
|
pStr->bStatic ? SQLITE_TRANSIENT : sqlite3_free);
|
||||||
pStr->bStatic = 1;
|
pStr->bStatic = 1;
|
||||||
|
}else{
|
||||||
|
sqlite3_result_text(ctx, pStr->zBuf, pStr->nUsed, SQLITE_TRANSIENT);
|
||||||
|
pStr->nUsed--;
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
sqlite3_result_text(ctx, "[]", 2, SQLITE_STATIC);
|
sqlite3_result_text(ctx, "[]", 2, SQLITE_STATIC);
|
||||||
}
|
}
|
||||||
sqlite3_result_subtype(ctx, JSON_SUBTYPE);
|
sqlite3_result_subtype(ctx, JSON_SUBTYPE);
|
||||||
}
|
}
|
||||||
|
static void jsonArrayValue(sqlite3_context *ctx){
|
||||||
|
jsonArrayCompute(ctx, 0);
|
||||||
|
}
|
||||||
|
static void jsonArrayFinal(sqlite3_context *ctx){
|
||||||
|
jsonArrayCompute(ctx, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef SQLITE_OMIT_WINDOWFUNC
|
||||||
|
/*
|
||||||
|
** This method works for both json_group_array() and json_group_object().
|
||||||
|
** It works by removing the first element of the group by searching forward
|
||||||
|
** to the first comma (",") that is not within a string and deleting all
|
||||||
|
** text through that comma.
|
||||||
|
*/
|
||||||
|
static void jsonGroupInverse(
|
||||||
|
sqlite3_context *ctx,
|
||||||
|
int argc,
|
||||||
|
sqlite3_value **argv
|
||||||
|
){
|
||||||
|
int i;
|
||||||
|
int inStr = 0;
|
||||||
|
char *z;
|
||||||
|
JsonString *pStr;
|
||||||
|
pStr = (JsonString*)sqlite3_aggregate_context(ctx, 0);
|
||||||
|
if( !pStr ) return;
|
||||||
|
z = pStr->zBuf;
|
||||||
|
for(i=1; z[i]!=',' || inStr; i++){
|
||||||
|
assert( i<pStr->nUsed );
|
||||||
|
if( z[i]=='"' ){
|
||||||
|
inStr = !inStr;
|
||||||
|
}else if( z[i]=='\\' ){
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pStr->nUsed -= i;
|
||||||
|
memmove(&z[1], &z[i+1], pStr->nUsed-1);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
# define jsonGroupInverse 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** json_group_obj(NAME,VALUE)
|
** json_group_obj(NAME,VALUE)
|
||||||
@ -1852,7 +1896,7 @@ static void jsonObjectStep(
|
|||||||
jsonAppendValue(pStr, argv[1]);
|
jsonAppendValue(pStr, argv[1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
static void jsonObjectFinal(sqlite3_context *ctx){
|
static void jsonObjectCompute(sqlite3_context *ctx, int isFinal){
|
||||||
JsonString *pStr;
|
JsonString *pStr;
|
||||||
pStr = (JsonString*)sqlite3_aggregate_context(ctx, 0);
|
pStr = (JsonString*)sqlite3_aggregate_context(ctx, 0);
|
||||||
if( pStr ){
|
if( pStr ){
|
||||||
@ -1860,16 +1904,26 @@ static void jsonObjectFinal(sqlite3_context *ctx){
|
|||||||
if( pStr->bErr ){
|
if( pStr->bErr ){
|
||||||
if( pStr->bErr==1 ) sqlite3_result_error_nomem(ctx);
|
if( pStr->bErr==1 ) sqlite3_result_error_nomem(ctx);
|
||||||
assert( pStr->bStatic );
|
assert( pStr->bStatic );
|
||||||
}else{
|
}else if( isFinal ){
|
||||||
sqlite3_result_text(ctx, pStr->zBuf, pStr->nUsed,
|
sqlite3_result_text(ctx, pStr->zBuf, pStr->nUsed,
|
||||||
pStr->bStatic ? SQLITE_TRANSIENT : sqlite3_free);
|
pStr->bStatic ? SQLITE_TRANSIENT : sqlite3_free);
|
||||||
pStr->bStatic = 1;
|
pStr->bStatic = 1;
|
||||||
|
}else{
|
||||||
|
sqlite3_result_text(ctx, pStr->zBuf, pStr->nUsed, SQLITE_TRANSIENT);
|
||||||
|
pStr->nUsed--;
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
sqlite3_result_text(ctx, "{}", 2, SQLITE_STATIC);
|
sqlite3_result_text(ctx, "{}", 2, SQLITE_STATIC);
|
||||||
}
|
}
|
||||||
sqlite3_result_subtype(ctx, JSON_SUBTYPE);
|
sqlite3_result_subtype(ctx, JSON_SUBTYPE);
|
||||||
}
|
}
|
||||||
|
static void jsonObjectValue(sqlite3_context *ctx){
|
||||||
|
jsonObjectCompute(ctx, 0);
|
||||||
|
}
|
||||||
|
static void jsonObjectFinal(sqlite3_context *ctx){
|
||||||
|
jsonObjectCompute(ctx, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||||
@ -2377,9 +2431,12 @@ int sqlite3Json1Init(sqlite3 *db){
|
|||||||
int nArg;
|
int nArg;
|
||||||
void (*xStep)(sqlite3_context*,int,sqlite3_value**);
|
void (*xStep)(sqlite3_context*,int,sqlite3_value**);
|
||||||
void (*xFinal)(sqlite3_context*);
|
void (*xFinal)(sqlite3_context*);
|
||||||
|
void (*xValue)(sqlite3_context*);
|
||||||
} aAgg[] = {
|
} aAgg[] = {
|
||||||
{ "json_group_array", 1, jsonArrayStep, jsonArrayFinal },
|
{ "json_group_array", 1,
|
||||||
{ "json_group_object", 2, jsonObjectStep, jsonObjectFinal },
|
jsonArrayStep, jsonArrayFinal, jsonArrayValue },
|
||||||
|
{ "json_group_object", 2,
|
||||||
|
jsonObjectStep, jsonObjectFinal, jsonObjectValue },
|
||||||
};
|
};
|
||||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||||
static const struct {
|
static const struct {
|
||||||
@ -2397,9 +2454,10 @@ int sqlite3Json1Init(sqlite3 *db){
|
|||||||
aFunc[i].xFunc, 0, 0);
|
aFunc[i].xFunc, 0, 0);
|
||||||
}
|
}
|
||||||
for(i=0; i<sizeof(aAgg)/sizeof(aAgg[0]) && rc==SQLITE_OK; i++){
|
for(i=0; i<sizeof(aAgg)/sizeof(aAgg[0]) && rc==SQLITE_OK; i++){
|
||||||
rc = sqlite3_create_function(db, aAgg[i].zName, aAgg[i].nArg,
|
rc = sqlite3_create_window_function(db, aAgg[i].zName, aAgg[i].nArg,
|
||||||
SQLITE_UTF8 | SQLITE_DETERMINISTIC, 0,
|
SQLITE_UTF8 | SQLITE_DETERMINISTIC, 0,
|
||||||
0, aAgg[i].xStep, aAgg[i].xFinal);
|
aAgg[i].xStep, aAgg[i].xFinal,
|
||||||
|
aAgg[i].xValue, jsonGroupInverse, 0);
|
||||||
}
|
}
|
||||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||||
for(i=0; i<sizeof(aMod)/sizeof(aMod[0]) && rc==SQLITE_OK; i++){
|
for(i=0; i<sizeof(aMod)/sizeof(aMod[0]) && rc==SQLITE_OK; i++){
|
||||||
|
18
manifest
18
manifest
@ -1,5 +1,5 @@
|
|||||||
C Return\san\serror\sif\sa\s"RANGE"\swindow-frame\suses\s"<expr>\sPRECEDING"\sor\s"<expr>\nFOLLOWING".
|
C Get\sthe\sjson_group_array()\sand\sjson_group_object()\sSQL\sfunctions\sworking\nas\swindow\sfunctions.
|
||||||
D 2018-07-05T18:34:53.220
|
D 2018-07-05T20:05:29.904
|
||||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||||
F Makefile.in 0a3a6c81e6fcb969ff9106e882f0a08547014ba463cb6beca4c4efaecc924ee6
|
F Makefile.in 0a3a6c81e6fcb969ff9106e882f0a08547014ba463cb6beca4c4efaecc924ee6
|
||||||
@ -281,7 +281,7 @@ F ext/misc/eval.c 6ea9b22a5fa0dd973b67ca4e53555be177bc0b7b263aadf1024429457c82c0
|
|||||||
F ext/misc/fileio.c 48c7751c78fc4cdd29d8c862fd2f3f98bbfefa2a3cf1ca1496df4bf02eb8cded
|
F ext/misc/fileio.c 48c7751c78fc4cdd29d8c862fd2f3f98bbfefa2a3cf1ca1496df4bf02eb8cded
|
||||||
F ext/misc/fuzzer.c 7c64b8197bb77b7d64eff7cac7848870235d4c25
|
F ext/misc/fuzzer.c 7c64b8197bb77b7d64eff7cac7848870235d4c25
|
||||||
F ext/misc/ieee754.c f190d0cc5182529acb15babd177781be1ac1718c
|
F ext/misc/ieee754.c f190d0cc5182529acb15babd177781be1ac1718c
|
||||||
F ext/misc/json1.c 02f5f0d9c131df79f4ee168d2b426f0f0d273b7771fc0bb5293c4e7692d9a2ee
|
F ext/misc/json1.c 8dca18a64560481f566fe03e26b60dfc95b665c709be86934d261ac21d6f1c2f
|
||||||
F ext/misc/memvfs.c ab36f49e02ebcdf85a1e08dc4d8599ea8f343e073ac9e0bca18a98b7e1ec9567
|
F ext/misc/memvfs.c ab36f49e02ebcdf85a1e08dc4d8599ea8f343e073ac9e0bca18a98b7e1ec9567
|
||||||
F ext/misc/mmapwarm.c 70b618f2d0bde43fae288ad0b7498a629f2b6f61b50a27e06fae3cd23c83af29
|
F ext/misc/mmapwarm.c 70b618f2d0bde43fae288ad0b7498a629f2b6f61b50a27e06fae3cd23c83af29
|
||||||
F ext/misc/nextchar.c 35c8b8baacb96d92abbb34a83a997b797075b342
|
F ext/misc/nextchar.c 35c8b8baacb96d92abbb34a83a997b797075b342
|
||||||
@ -566,7 +566,7 @@ F src/upsert.c 47edd408cc73f8d3c00a140550d1ad180b407c146285947969dd09874802bf88
|
|||||||
F src/utf.c 810fbfebe12359f10bc2a011520a6e10879ab2a163bcb26c74768eab82ea62a5
|
F src/utf.c 810fbfebe12359f10bc2a011520a6e10879ab2a163bcb26c74768eab82ea62a5
|
||||||
F src/util.c d9eb0a6c4aae1b00a7369eadd7ca0bbe946cb4c953b6751aa20d357c2f482157
|
F src/util.c d9eb0a6c4aae1b00a7369eadd7ca0bbe946cb4c953b6751aa20d357c2f482157
|
||||||
F src/vacuum.c 36e7d21a20c0bf6ef4ef7c399d192b5239410b7c4d3c1070fba4e30810d0b855
|
F src/vacuum.c 36e7d21a20c0bf6ef4ef7c399d192b5239410b7c4d3c1070fba4e30810d0b855
|
||||||
F src/vdbe.c 37b942ccdd224dd51bd80312b8d236f27c7c728e76c3f425c50e9d8ecff3b7b4
|
F src/vdbe.c ff748307932fac5a5a983a20a4d8805aff7b0f310ca58cff4051df96d34a4dc8
|
||||||
F src/vdbe.h 847735b3e083285aa225d2bf1fe97107a0a2b8942c80d643cdb764990705820d
|
F src/vdbe.h 847735b3e083285aa225d2bf1fe97107a0a2b8942c80d643cdb764990705820d
|
||||||
F src/vdbeInt.h 6b5cbd338dc9aaad343fb11b455e47463b0474d9f79710f50e647158941146e0
|
F src/vdbeInt.h 6b5cbd338dc9aaad343fb11b455e47463b0474d9f79710f50e647158941146e0
|
||||||
F src/vdbeapi.c e35f813312b0f6e8e2835b357f121e0d1da6d3013bac3e367fe4efd518e7a2ec
|
F src/vdbeapi.c e35f813312b0f6e8e2835b357f121e0d1da6d3013bac3e367fe4efd518e7a2ec
|
||||||
@ -1028,7 +1028,7 @@ F test/jrnlmode2.test 8759a1d4657c064637f8b079592651530db738419e1d649c6df7048cd7
|
|||||||
F test/jrnlmode3.test 556b447a05be0e0963f4311e95ab1632b11c9eaa
|
F test/jrnlmode3.test 556b447a05be0e0963f4311e95ab1632b11c9eaa
|
||||||
F test/json101.test b40a9f5395d8e669b0bc3eb550ad2ae9e5ada01fbce23c446c2a30a305a6d575
|
F test/json101.test b40a9f5395d8e669b0bc3eb550ad2ae9e5ada01fbce23c446c2a30a305a6d575
|
||||||
F test/json102.test eeb54efa221e50b74a2d6fb9259963b48d7414dca3ce2fdfdeed45cb28487bc1
|
F test/json102.test eeb54efa221e50b74a2d6fb9259963b48d7414dca3ce2fdfdeed45cb28487bc1
|
||||||
F test/json103.test c5f6b85e69de05f6b3195f9f9d5ce9cd179099a0
|
F test/json103.test aff6b7a4c17d5a20b487a7bc1a274bfdc63b829413bdfb83bedac42ec7f67e3b
|
||||||
F test/json104.test 877d5845f6303899b7889ea5dd1bea99076e3100574d5c536082245c5805dcaa
|
F test/json104.test 877d5845f6303899b7889ea5dd1bea99076e3100574d5c536082245c5805dcaa
|
||||||
F test/keyword1.test 37ef6bba5d2ed5b07ecdd6810571de2956599dff
|
F test/keyword1.test 37ef6bba5d2ed5b07ecdd6810571de2956599dff
|
||||||
F test/kvtest.c 94da54bb66aae7a54e47cf7e4ea4acecc0f217560f79ad3abfcc0361d6d557ba
|
F test/kvtest.c 94da54bb66aae7a54e47cf7e4ea4acecc0f217560f79ad3abfcc0361d6d557ba
|
||||||
@ -1745,7 +1745,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
|||||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||||
P 73391283101288251fe5d030ba12bcdabe8a781d41086afe3564c58c05d0fd5c
|
P 786c87ba4150509e141baab32c51e64bbd3ce323735e0f47d65ed54d14215bc4
|
||||||
R e2d8bd888d8359c89112b96b5805f3f9
|
R d772fd50a83277dafc7b2d62ea89dd92
|
||||||
U dan
|
U drh
|
||||||
Z 61151c44890df0915ca49d8561fa462d
|
Z fcfb43d365d0b34e61224fdf77a12270
|
||||||
|
@ -1 +1 @@
|
|||||||
786c87ba4150509e141baab32c51e64bbd3ce323735e0f47d65ed54d14215bc4
|
916cdc83f5a45e0b6f61c52ff5fde70d54bcd0dfaa4a32f9ac709fe0ddbb480b
|
@ -6411,7 +6411,7 @@ case OP_AggStep: {
|
|||||||
** P4 is a pointer to the FuncDef for this function. The P2
|
** P4 is a pointer to the FuncDef for this function. The P2
|
||||||
** argument is not used by this opcode. It is only there to disambiguate
|
** argument is not used by this opcode. It is only there to disambiguate
|
||||||
** functions that can take varying numbers of arguments. The
|
** functions that can take varying numbers of arguments. The
|
||||||
** P4 argument is only needed for the degenerate case where
|
** P4 argument is only needed for the case where
|
||||||
** the step function was not previously called.
|
** the step function was not previously called.
|
||||||
*/
|
*/
|
||||||
case OP_AggFinal: {
|
case OP_AggFinal: {
|
||||||
|
@ -75,4 +75,24 @@ do_execsql_test json103-300 {
|
|||||||
FROM t1;
|
FROM t1;
|
||||||
} {{[1,"abc"]} {[{"x":1},{"x":"abc"}]}}
|
} {{[1,"abc"]} {[{"x":1},{"x":"abc"}]}}
|
||||||
|
|
||||||
|
# json_group_array() and json_group_object() work as window functions.
|
||||||
|
#
|
||||||
|
ifcapable windowfunc {
|
||||||
|
do_execsql_test json103-400 {
|
||||||
|
CREATE TABLE t4(x);
|
||||||
|
INSERT INTO t4 VALUES
|
||||||
|
(1),
|
||||||
|
('a,b'),
|
||||||
|
(3),
|
||||||
|
('x"y'),
|
||||||
|
(5),
|
||||||
|
(6),
|
||||||
|
(7);
|
||||||
|
SELECT json_group_array(x) OVER (ROWS 2 PRECEDING) FROM t4;
|
||||||
|
} {{[1]} {[1,"a,b"]} {[1,"a,b",3]} {["a,b",3,"x\"y"]} {[3,"x\"y",5]} {["x\"y",5,6]} {[5,6,7]}}
|
||||||
|
do_execsql_test json103-410 {
|
||||||
|
SELECT json_group_object(rowid, x) OVER (ROWS 2 PRECEDING) FROM t4;
|
||||||
|
} {{{"1":1}} {{"1":1,"2":"a,b"}} {{"1":1,"2":"a,b","3":3}} {{"2":"a,b","3":3,"4":"x\"y"}} {{"3":3,"4":"x\"y","5":5}} {{"4":"x\"y","5":5,"6":6}} {{"5":5,"6":6,"7":7}}}
|
||||||
|
}
|
||||||
|
|
||||||
finish_test
|
finish_test
|
||||||
|
Reference in New Issue
Block a user