mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-05 15:55:57 +03:00
Add new API function sqlite3_create_window_function(), for creating new
aggregate window functions. FossilOrigin-Name: da03fb4318fd2613ec5c5b109a3974ac1120c19ed16bed4ca85bbdc4b35c998c
This commit is contained in:
@@ -419,6 +419,7 @@ TESTSRC = \
|
||||
$(TOP)/src/test_thread.c \
|
||||
$(TOP)/src/test_vfs.c \
|
||||
$(TOP)/src/test_windirent.c \
|
||||
$(TOP)/src/test_window.c \
|
||||
$(TOP)/src/test_wsd.c \
|
||||
$(TOP)/ext/fts3/fts3_term.c \
|
||||
$(TOP)/ext/fts3/fts3_test.c \
|
||||
|
@@ -1479,6 +1479,7 @@ TESTSRC = \
|
||||
$(TOP)\src\test_thread.c \
|
||||
$(TOP)\src\test_vfs.c \
|
||||
$(TOP)\src\test_windirent.c \
|
||||
$(TOP)\src\test_window.c \
|
||||
$(TOP)\src\test_wsd.c \
|
||||
$(TOP)\ext\fts3\fts3_term.c \
|
||||
$(TOP)\ext\fts3\fts3_test.c \
|
||||
|
1
main.mk
1
main.mk
@@ -349,6 +349,7 @@ TESTSRC = \
|
||||
$(TOP)/src/test_thread.c \
|
||||
$(TOP)/src/test_vfs.c \
|
||||
$(TOP)/src/test_windirent.c \
|
||||
$(TOP)/src/test_window.c \
|
||||
$(TOP)/src/test_wsd.c
|
||||
|
||||
# Extensions to be statically loaded.
|
||||
|
34
manifest
34
manifest
@@ -1,10 +1,10 @@
|
||||
C Add\sextra\sOOM\stest.
|
||||
D 2018-06-15T20:46:12.018
|
||||
C Add\snew\sAPI\sfunction\ssqlite3_create_window_function(),\sfor\screating\snew\naggregate\swindow\sfunctions.
|
||||
D 2018-06-18T16:55:22.801
|
||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||
F Makefile.in 498b77b89a8cb42f2ee20fcd6317f279a45c0d6ff40d27825f94b69884c09bbe
|
||||
F Makefile.in 0a3a6c81e6fcb969ff9106e882f0a08547014ba463cb6beca4c4efaecc924ee6
|
||||
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
|
||||
F Makefile.msc 0221c154ad20065906973f8fd4047346b995d31eaafd461383edca766f4282b6
|
||||
F Makefile.msc c1646e8f86c30ea63e56176deacef192ac87c663ce2c9083f459c45a7268934f
|
||||
F README.md 7764d56778d567913ef11c82da9ab94aefa0826f7c243351e4e2d7adaef6f373
|
||||
F VERSION d3e3afdec1165a5e593dcdfffd8e0f33a2b0186067eb51a073ef6c4aec34923d
|
||||
F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50
|
||||
@@ -417,7 +417,7 @@ F ext/userauth/userauth.c 3410be31283abba70255d71fd24734e017a4497f
|
||||
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
|
||||
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
|
||||
F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60
|
||||
F main.mk 9cad63ffa8c6b782d35debe0ef933312a0ddc75fed35492c7fe29dbe9701647a
|
||||
F main.mk d9872d31efa4a02e177f6d43b7fdae2a5f822e50d1eb72907f6575a567b85378
|
||||
F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83
|
||||
F mptest/config01.test 3c6adcbc50b991866855f1977ff172eb6d901271
|
||||
F mptest/config02.test 4415dfe36c48785f751e16e32c20b077c28ae504
|
||||
@@ -450,7 +450,7 @@ F src/delete.c 4c8c7604277a2041647f96b78f4b9a47858e9217e4fb333d35e7b5ab32c5b57f
|
||||
F src/expr.c 80c61121f3c87427e8c79a6ed0352e610e5a734508c2a094a6bf30ebca18ef1e
|
||||
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
|
||||
F src/fkey.c b1da9ef8dc834603bb0d28972378a7ce65897847f9a1e89ab800bbdf24c788ee
|
||||
F src/func.c a5ee3864264edea8fea4d2dfdf8296250cff9139343953da78d82837241659a9
|
||||
F src/func.c f1c244ba44950d94d4c2298903d16ca7ae3183bcf07936a9e01ab4f3f10b53e2
|
||||
F src/global.c 9bf034fd560bdd514715170ed8460bb7f823cec113f0569ef3f18a20c7ccd128
|
||||
F src/hash.c a12580e143f10301ed5166ea4964ae2853d3905a511d4e0c44497245c7ce1f7a
|
||||
F src/hash.h ab34c5c54a9e9de2e790b24349ba5aab3dbb4fd4
|
||||
@@ -459,7 +459,7 @@ F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
|
||||
F src/insert.c bcacf6a0d277f8fa0e4f9ffecda544a2330ca4478f904cd89564c2dd86d0b16b
|
||||
F src/legacy.c 134ab3e3fae00a0f67a5187981d6935b24b337bcf0f4b3e5c9fa5763da95bf4e
|
||||
F src/loadext.c 6aae5739198d96c51ae6eb97c4a5b1744c22ed7a5a565a5399a717780d48a36b
|
||||
F src/main.c a086ab7d6e4e3f07bd5789d16f977d425f9482e7b3baeeb2f17bde0e6bfb2bc1
|
||||
F src/main.c f6f4f8be5baa6e0d44b0249c49b251f8749156896039cc7c64c3afaa25a64eaf
|
||||
F src/malloc.c 07295435093ce354c6d9063ac05a2eeae28bd251d2e63c48b3d67c12c76f7e18
|
||||
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
|
||||
F src/mem1.c c12a42539b1ba105e3707d0e628ad70e611040d8f5e38cf942cee30c867083de
|
||||
@@ -497,10 +497,10 @@ F src/resolve.c a8cf3d6144f6a821f002dad72f80659691e827a96e6da6dedf8b263edefe3a80
|
||||
F src/rowset.c 7b7e7e479212e65b723bf40128c7b36dc5afdfac
|
||||
F src/select.c 7e8e439bf8bf732860566ccceebd57d934bf1aceca213c394d825dde60473f8e
|
||||
F src/shell.c.in 8578421c5fb2a972461b2a996f7173646e55e0dbd2a2eee30c8f5dc7d3dbadfd
|
||||
F src/sqlite.h.in 19de593baa0667854730e7b8bc2e3039c20ee80a4d537e9b5ec2038947fe3daf
|
||||
F src/sqlite.h.in 8dbfe617b70b01e661a9ba0b805facb1430df80096ea7508cf7903878b45e689
|
||||
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
|
||||
F src/sqlite3ext.h 9887b27e69c01e79c2cbe74ef73bf01af5b5703d6a7f0a4371e386d7249cb1c7
|
||||
F src/sqliteInt.h 97525ef265cfca3cf39c87b73dd1e39f9260ee2f25fb0cee64bbbe26eb9f3888
|
||||
F src/sqliteInt.h 94c8db9e2bfc0f9bead6c3c4f8c6172c93274b13b6388a840b1820590f7a62b0
|
||||
F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b
|
||||
F src/status.c 46e7aec11f79dad50965a5ca5fa9de009f7d6bde08be2156f1538a0a296d4d0e
|
||||
F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34
|
||||
@@ -548,13 +548,14 @@ F src/test_server.c a2615049954cbb9cfb4a62e18e2f0616e4dc38fe
|
||||
F src/test_sqllog.c 11e6ce7575f489155c604ac4b439f2ac1d3d5aef
|
||||
F src/test_superlock.c 4839644b9201da822f181c5bc406c0b2385f672e
|
||||
F src/test_syscall.c 1073306ba2e9bfc886771871a13d3de281ed3939
|
||||
F src/test_tclsh.c 58052fe48efe8f579834f4648d239569f2efc6285f5019ebdf0040f58d16238d
|
||||
F src/test_tclsh.c 06317648b0d85a85fd823f7973b55535c59a3156c1ef59394fe511f932cfa78d
|
||||
F src/test_tclvar.c 33ff42149494a39c5fbb0df3d25d6fafb2f668888e41c0688d07273dcb268dfc
|
||||
F src/test_thread.c 911d15fb14e19c0c542bdc8aabf981c2f10a4858
|
||||
F src/test_vfs.c f0186261a24de2671d080bcd8050732f0cb64f6e
|
||||
F src/test_vfstrace.c bab9594adc976cbe696ff3970728830b4c5ed698
|
||||
F src/test_windirent.c a895e2c068a06644eef91a7f0a32182445a893b9a0f33d0cdb4283dca2486ac1
|
||||
F src/test_windirent.h 90dfbe95442c9762357fe128dc7ae3dc199d006de93eb33ba3972e0a90484215
|
||||
F src/test_window.c 460361d710643823e54567073b780634d85b2fe54937d49de06c562d39e6cfb1
|
||||
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
|
||||
F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c
|
||||
F src/tokenize.c bbde32eac9eb1280f5292bcdfef66f5a57e43176cbf9347e0efab9f75e133f97
|
||||
@@ -565,7 +566,7 @@ F src/upsert.c 47edd408cc73f8d3c00a140550d1ad180b407c146285947969dd09874802bf88
|
||||
F src/utf.c 810fbfebe12359f10bc2a011520a6e10879ab2a163bcb26c74768eab82ea62a5
|
||||
F src/util.c d9eb0a6c4aae1b00a7369eadd7ca0bbe946cb4c953b6751aa20d357c2f482157
|
||||
F src/vacuum.c 36e7d21a20c0bf6ef4ef7c399d192b5239410b7c4d3c1070fba4e30810d0b855
|
||||
F src/vdbe.c 55bc870dcab52f7eac5a84d84e13e68122308997975d066f450a42c24d80df32
|
||||
F src/vdbe.c 16385bc816c97cc28c12ffa2151b8dc80617943b2e5871e7f0c9fdb4392c2c18
|
||||
F src/vdbe.h 9c8c245fa3785266c269ab02c135c836ff49a307612186686bcdae500f409945
|
||||
F src/vdbeInt.h d99f1c3da17b4ed271efc2f52898dd9a577dee077da47c2a014bc128f3cdba2a
|
||||
F src/vdbeapi.c af4a3de00d1851bcbc55b85dfbe52849aa2b1e17b4a5a1f3d9c257df7af361ff
|
||||
@@ -583,7 +584,7 @@ F src/where.c 0bcbf9e191ca07f9ea2008aa80e70ded46bcdffd26560c83397da501f00aece6
|
||||
F src/whereInt.h b90ef9b9707ef750eab2a7a080c48fb4900315033274689def32d0cf5a81ebe4
|
||||
F src/wherecode.c 3317f2b083a66d3e65a03edf316ade4ccb0a99c9956273282ebb579b95d4ba96
|
||||
F src/whereexpr.c 19cf35cdd9bf6d5589d8a5c960d99259761136187a2319a6e14d11cf1abe14c2
|
||||
F src/window.c d80ec071618365ed740495848c1ea05a674bf83c498acff10b3ab7a4209a37cc
|
||||
F src/window.c 7cd40b85402c84d89dfbbcc06700e4879673583ac33b487f172974a2c4cb6d41
|
||||
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
|
||||
F test/affinity2.test a6d901b436328bd67a79b41bb0ac2663918fe3bd
|
||||
F test/affinity3.test 6a101af2fc945ce2912f6fe54dd646018551710d
|
||||
@@ -1617,13 +1618,14 @@ F test/win32heap.test 10fd891266bd00af68671e702317726375e5407561d859be1aa04696f2
|
||||
F test/win32lock.test fbf107c91d8f5512be5a5b87c4c42ab9fdd54972
|
||||
F test/win32longpath.test 169c75a3b2e43481f4a62122510210c67b08f26d
|
||||
F test/win32nolock.test ac4f08811a562e45a5755e661f45ca85892bdbbc
|
||||
F test/window1.test 3398c54113aedf04f4bf63ec22e8f30f87f6d56caa5e6313df0f7f1ee6d927e1
|
||||
F test/window1.test af17e84722f8a8d525912056c9d6c7ee215d5474d9a9ecd729b761279a3f924f
|
||||
F test/window2.tcl 0983de5eade5eeda49469244799d5331bfe3199fca3f6c6d2a836aa08f4fba1b
|
||||
F test/window2.test 79747b2edde4ad424e0752b27529aedc86e91f3d8d88846fa17ff0cb67f65086
|
||||
F test/window3.tcl 654d61d73e10db089b22514d498bb23ec310f720c0f4b5f69f67fda83d672048
|
||||
F test/window3.test 41727668ee31d2ba50f78efcb5bf1bda2c5cffd889aa65243511004669d1ac25
|
||||
F test/window4.tcl ce0c14185ba651de53994df8ac11da472b6bbd3534e148ad3ce87de6aa0426ed
|
||||
F test/window4.test 13b8cac12e78017d6c1873742efcb120f3d5b2debfdb412271bfb84969087037
|
||||
F test/window5.test c912f9dbcc92889fceef1d204077509c4839b5b34d1acf369f31f31827bed2c9
|
||||
F test/windowfault.test 7d3655fcac44c903b1aa31d40e13d170c71b089551f0e6ed17b02f66fb731fb6
|
||||
F test/with1.test 58475190cd8caaeebea8cfeb2a264ec97a0c492b8ffe9ad20cefbb23df462f96
|
||||
F test/with2.test e0030e2f0267a910d6c0e4f46f2dfe941c1cc0d4f659ba69b3597728e7e8f1ab
|
||||
@@ -1741,7 +1743,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||
P fadd4dc119d8df0d871f4d839b7a11070e2ffb8927e84b3e7a94f34196db3de3
|
||||
R ac4dec8988017d1c9bddc25e0a619905
|
||||
P ac251f72608c27c1512a0b3457524f5378a0b13d93d829cf0ed8bc178bc54a73
|
||||
R 5e0493aa8c44623395101bd2a6083987
|
||||
U dan
|
||||
Z 6a66cbb2264aaed6cff49821f754986b
|
||||
Z b650c96a101f9d4fd4fed7a4c2d2087f
|
||||
|
@@ -1 +1 @@
|
||||
ac251f72608c27c1512a0b3457524f5378a0b13d93d829cf0ed8bc178bc54a73
|
||||
da03fb4318fd2613ec5c5b109a3974ac1120c19ed16bed4ca85bbdc4b35c998c
|
@@ -1771,10 +1771,10 @@ void sqlite3RegisterLikeFunctions(sqlite3 *db, int caseSensitive){
|
||||
}else{
|
||||
pInfo = (struct compareInfo*)&likeInfoNorm;
|
||||
}
|
||||
sqlite3CreateFunc(db, "like", 2, SQLITE_UTF8, pInfo, likeFunc, 0, 0, 0);
|
||||
sqlite3CreateFunc(db, "like", 3, SQLITE_UTF8, pInfo, likeFunc, 0, 0, 0);
|
||||
sqlite3CreateFunc(db, "like", 2, SQLITE_UTF8, pInfo, likeFunc, 0, 0, 0, 0, 0);
|
||||
sqlite3CreateFunc(db, "like", 3, SQLITE_UTF8, pInfo, likeFunc, 0, 0, 0, 0, 0);
|
||||
sqlite3CreateFunc(db, "glob", 2, SQLITE_UTF8,
|
||||
(struct compareInfo*)&globInfo, likeFunc, 0, 0, 0);
|
||||
(struct compareInfo*)&globInfo, likeFunc, 0, 0, 0, 0, 0);
|
||||
setLikeOptFlag(db, "glob", SQLITE_FUNC_LIKE | SQLITE_FUNC_CASE);
|
||||
setLikeOptFlag(db, "like",
|
||||
caseSensitive ? (SQLITE_FUNC_LIKE | SQLITE_FUNC_CASE) : SQLITE_FUNC_LIKE);
|
||||
|
90
src/main.c
90
src/main.c
@@ -1683,6 +1683,8 @@ int sqlite3CreateFunc(
|
||||
void (*xSFunc)(sqlite3_context*,int,sqlite3_value **),
|
||||
void (*xStep)(sqlite3_context*,int,sqlite3_value **),
|
||||
void (*xFinal)(sqlite3_context*),
|
||||
void (*xValue)(sqlite3_context*),
|
||||
void (*xInverse)(sqlite3_context*,int,sqlite3_value **),
|
||||
FuncDestructor *pDestructor
|
||||
){
|
||||
FuncDef *p;
|
||||
@@ -1716,10 +1718,10 @@ int sqlite3CreateFunc(
|
||||
}else if( enc==SQLITE_ANY ){
|
||||
int rc;
|
||||
rc = sqlite3CreateFunc(db, zFunctionName, nArg, SQLITE_UTF8|extraFlags,
|
||||
pUserData, xSFunc, xStep, xFinal, pDestructor);
|
||||
pUserData, xSFunc, xStep, xFinal, xValue, xInverse, pDestructor);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3CreateFunc(db, zFunctionName, nArg, SQLITE_UTF16LE|extraFlags,
|
||||
pUserData, xSFunc, xStep, xFinal, pDestructor);
|
||||
pUserData, xSFunc, xStep, xFinal, xValue, xInverse, pDestructor);
|
||||
}
|
||||
if( rc!=SQLITE_OK ){
|
||||
return rc;
|
||||
@@ -1765,38 +1767,32 @@ int sqlite3CreateFunc(
|
||||
testcase( p->funcFlags & SQLITE_DETERMINISTIC );
|
||||
p->xSFunc = xSFunc ? xSFunc : xStep;
|
||||
p->xFinalize = xFinal;
|
||||
p->xValue = xValue;
|
||||
p->xInverse = xInverse;
|
||||
p->pUserData = pUserData;
|
||||
p->nArg = (u16)nArg;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Create new user functions.
|
||||
** Worker function used by utf-8 APIs that create new functions:
|
||||
**
|
||||
** sqlite3_create_function()
|
||||
** sqlite3_create_function_v2()
|
||||
** sqlite3_create_window_function()
|
||||
*/
|
||||
int sqlite3_create_function(
|
||||
static int createFunctionApi(
|
||||
sqlite3 *db,
|
||||
const char *zFunc,
|
||||
int nArg,
|
||||
int enc,
|
||||
void *p,
|
||||
void (*xSFunc)(sqlite3_context*,int,sqlite3_value **),
|
||||
void (*xStep)(sqlite3_context*,int,sqlite3_value **),
|
||||
void (*xFinal)(sqlite3_context*)
|
||||
){
|
||||
return sqlite3_create_function_v2(db, zFunc, nArg, enc, p, xSFunc, xStep,
|
||||
xFinal, 0);
|
||||
}
|
||||
|
||||
int sqlite3_create_function_v2(
|
||||
sqlite3 *db,
|
||||
const char *zFunc,
|
||||
int nArg,
|
||||
int enc,
|
||||
void *p,
|
||||
void (*xSFunc)(sqlite3_context*,int,sqlite3_value **),
|
||||
void (*xStep)(sqlite3_context*,int,sqlite3_value **),
|
||||
void (*xSFunc)(sqlite3_context*,int,sqlite3_value**),
|
||||
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
|
||||
void (*xFinal)(sqlite3_context*),
|
||||
void (*xDestroy)(void *)
|
||||
void (*xValue)(sqlite3_context*),
|
||||
void (*xInverse)(sqlite3_context*,int,sqlite3_value**),
|
||||
void(*xDestroy)(void*)
|
||||
){
|
||||
int rc = SQLITE_ERROR;
|
||||
FuncDestructor *pArg = 0;
|
||||
@@ -1818,7 +1814,9 @@ int sqlite3_create_function_v2(
|
||||
pArg->xDestroy = xDestroy;
|
||||
pArg->pUserData = p;
|
||||
}
|
||||
rc = sqlite3CreateFunc(db, zFunc, nArg, enc, p, xSFunc, xStep, xFinal, pArg);
|
||||
rc = sqlite3CreateFunc(db, zFunc, nArg, enc, p,
|
||||
xSFunc, xStep, xFinal, xValue, xInverse, pArg
|
||||
);
|
||||
if( pArg && pArg->nRef==0 ){
|
||||
assert( rc!=SQLITE_OK );
|
||||
xDestroy(p);
|
||||
@@ -1831,6 +1829,52 @@ int sqlite3_create_function_v2(
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Create new user functions.
|
||||
*/
|
||||
int sqlite3_create_function(
|
||||
sqlite3 *db,
|
||||
const char *zFunc,
|
||||
int nArg,
|
||||
int enc,
|
||||
void *p,
|
||||
void (*xSFunc)(sqlite3_context*,int,sqlite3_value **),
|
||||
void (*xStep)(sqlite3_context*,int,sqlite3_value **),
|
||||
void (*xFinal)(sqlite3_context*)
|
||||
){
|
||||
return createFunctionApi(db, zFunc, nArg, enc, p, xSFunc, xStep,
|
||||
xFinal, 0, 0, 0);
|
||||
}
|
||||
int sqlite3_create_function_v2(
|
||||
sqlite3 *db,
|
||||
const char *zFunc,
|
||||
int nArg,
|
||||
int enc,
|
||||
void *p,
|
||||
void (*xSFunc)(sqlite3_context*,int,sqlite3_value **),
|
||||
void (*xStep)(sqlite3_context*,int,sqlite3_value **),
|
||||
void (*xFinal)(sqlite3_context*),
|
||||
void (*xDestroy)(void *)
|
||||
){
|
||||
return createFunctionApi(db, zFunc, nArg, enc, p, xSFunc, xStep,
|
||||
xFinal, 0, 0, xDestroy);
|
||||
}
|
||||
int sqlite3_create_window_function(
|
||||
sqlite3 *db,
|
||||
const char *zFunc,
|
||||
int nArg,
|
||||
int enc,
|
||||
void *p,
|
||||
void (*xStep)(sqlite3_context*,int,sqlite3_value **),
|
||||
void (*xFinal)(sqlite3_context*),
|
||||
void (*xValue)(sqlite3_context*),
|
||||
void (*xInverse)(sqlite3_context*,int,sqlite3_value **),
|
||||
void (*xDestroy)(void *)
|
||||
){
|
||||
return createFunctionApi(db, zFunc, nArg, enc, p, 0, xStep,
|
||||
xFinal, xValue, xInverse, xDestroy);
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_UTF16
|
||||
int sqlite3_create_function16(
|
||||
sqlite3 *db,
|
||||
@@ -1851,7 +1895,7 @@ int sqlite3_create_function16(
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
assert( !db->mallocFailed );
|
||||
zFunc8 = sqlite3Utf16to8(db, zFunctionName, -1, SQLITE_UTF16NATIVE);
|
||||
rc = sqlite3CreateFunc(db, zFunc8, nArg, eTextRep, p, xSFunc,xStep,xFinal,0);
|
||||
rc = sqlite3CreateFunc(db, zFunc8, nArg, eTextRep, p, xSFunc,xStep,xFinal,0,0,0);
|
||||
sqlite3DbFree(db, zFunc8);
|
||||
rc = sqlite3ApiExit(db, rc);
|
||||
sqlite3_mutex_leave(db->mutex);
|
||||
|
@@ -4741,6 +4741,18 @@ int sqlite3_create_function_v2(
|
||||
void (*xFinal)(sqlite3_context*),
|
||||
void(*xDestroy)(void*)
|
||||
);
|
||||
int sqlite3_create_window_function(
|
||||
sqlite3 *db,
|
||||
const char *zFunctionName,
|
||||
int nArg,
|
||||
int eTextRep,
|
||||
void *pApp,
|
||||
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
|
||||
void (*xFinal)(sqlite3_context*),
|
||||
void (*xValue)(sqlite3_context*),
|
||||
void (*xInverse)(sqlite3_context*,int,sqlite3_value**),
|
||||
void(*xDestroy)(void*)
|
||||
);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Text Encodings
|
||||
|
@@ -4244,7 +4244,10 @@ int sqlite3KeyInfoIsWriteable(KeyInfo*);
|
||||
#endif
|
||||
int sqlite3CreateFunc(sqlite3 *, const char *, int, int, void *,
|
||||
void (*)(sqlite3_context*,int,sqlite3_value **),
|
||||
void (*)(sqlite3_context*,int,sqlite3_value **), void (*)(sqlite3_context*),
|
||||
void (*)(sqlite3_context*,int,sqlite3_value **),
|
||||
void (*)(sqlite3_context*),
|
||||
void (*)(sqlite3_context*),
|
||||
void (*)(sqlite3_context*,int,sqlite3_value **),
|
||||
FuncDestructor *pDestructor
|
||||
);
|
||||
void sqlite3NoopDestructor(void*);
|
||||
|
@@ -105,6 +105,7 @@ const char *sqlite3TestInit(Tcl_Interp *interp){
|
||||
extern int Zipvfs_Init(Tcl_Interp*);
|
||||
#endif
|
||||
extern int TestExpert_Init(Tcl_Interp*);
|
||||
extern int Sqlitetest_window_Init(Tcl_Interp *);
|
||||
|
||||
Tcl_CmdInfo cmdInfo;
|
||||
|
||||
@@ -169,6 +170,7 @@ const char *sqlite3TestInit(Tcl_Interp *interp){
|
||||
Sqlitetestfts3_Init(interp);
|
||||
#endif
|
||||
TestExpert_Init(interp);
|
||||
Sqlitetest_window_Init(interp);
|
||||
|
||||
Tcl_CreateObjCommand(
|
||||
interp, "load_testfixture_extensions", load_testfixture_extensions,0,0
|
||||
|
194
src/test_window.c
Normal file
194
src/test_window.c
Normal file
@@ -0,0 +1,194 @@
|
||||
/*
|
||||
** 2018 June 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.
|
||||
**
|
||||
*************************************************************************
|
||||
*/
|
||||
|
||||
#include "sqlite3.h"
|
||||
|
||||
#ifdef SQLITE_TEST
|
||||
|
||||
#include "sqliteInt.h"
|
||||
#include <tcl.h>
|
||||
|
||||
extern int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb);
|
||||
extern const char *sqlite3ErrName(int);
|
||||
|
||||
typedef struct TestWindow TestWindow;
|
||||
struct TestWindow {
|
||||
Tcl_Obj *xStep;
|
||||
Tcl_Obj *xFinal;
|
||||
Tcl_Obj *xValue;
|
||||
Tcl_Obj *xInverse;
|
||||
Tcl_Interp *interp;
|
||||
};
|
||||
|
||||
typedef struct TestWindowCtx TestWindowCtx;
|
||||
struct TestWindowCtx {
|
||||
Tcl_Obj *pVal;
|
||||
};
|
||||
|
||||
static void doTestWindowStep(
|
||||
int bInverse,
|
||||
sqlite3_context *ctx,
|
||||
int nArg,
|
||||
sqlite3_value **apArg
|
||||
){
|
||||
int i;
|
||||
TestWindow *p = (TestWindow*)sqlite3_user_data(ctx);
|
||||
Tcl_Obj *pEval = Tcl_DuplicateObj(bInverse ? p->xInverse : p->xStep);
|
||||
TestWindowCtx *pCtx = sqlite3_aggregate_context(ctx, sizeof(TestWindowCtx));
|
||||
|
||||
Tcl_IncrRefCount(pEval);
|
||||
if( pCtx ){
|
||||
const char *zResult;
|
||||
int rc;
|
||||
if( pCtx->pVal ){
|
||||
Tcl_ListObjAppendElement(p->interp, pEval, Tcl_DuplicateObj(pCtx->pVal));
|
||||
}else{
|
||||
Tcl_ListObjAppendElement(p->interp, pEval, Tcl_NewStringObj("", -1));
|
||||
}
|
||||
for(i=0; i<nArg; i++){
|
||||
Tcl_Obj *pArg;
|
||||
pArg = Tcl_NewStringObj((const char*)sqlite3_value_text(apArg[i]), -1);
|
||||
Tcl_ListObjAppendElement(p->interp, pEval, pArg);
|
||||
}
|
||||
rc = Tcl_EvalObjEx(p->interp, pEval, TCL_EVAL_GLOBAL);
|
||||
if( rc!=TCL_OK ){
|
||||
zResult = Tcl_GetStringResult(p->interp);
|
||||
sqlite3_result_error(ctx, zResult, -1);
|
||||
}else{
|
||||
if( pCtx->pVal ) Tcl_DecrRefCount(pCtx->pVal);
|
||||
pCtx->pVal = Tcl_DuplicateObj(Tcl_GetObjResult(p->interp));
|
||||
Tcl_IncrRefCount(pCtx->pVal);
|
||||
}
|
||||
}
|
||||
Tcl_DecrRefCount(pEval);
|
||||
}
|
||||
|
||||
static void doTestWindowFinalize(int bValue, sqlite3_context *ctx){
|
||||
TestWindow *p = (TestWindow*)sqlite3_user_data(ctx);
|
||||
Tcl_Obj *pEval = Tcl_DuplicateObj(bValue ? p->xValue : p->xFinal);
|
||||
TestWindowCtx *pCtx = sqlite3_aggregate_context(ctx, sizeof(TestWindowCtx));
|
||||
|
||||
Tcl_IncrRefCount(pEval);
|
||||
if( pCtx ){
|
||||
const char *zResult;
|
||||
int rc;
|
||||
if( pCtx->pVal ){
|
||||
Tcl_ListObjAppendElement(p->interp, pEval, Tcl_DuplicateObj(pCtx->pVal));
|
||||
}else{
|
||||
Tcl_ListObjAppendElement(p->interp, pEval, Tcl_NewStringObj("", -1));
|
||||
}
|
||||
|
||||
rc = Tcl_EvalObjEx(p->interp, pEval, TCL_EVAL_GLOBAL);
|
||||
zResult = Tcl_GetStringResult(p->interp);
|
||||
if( rc!=TCL_OK ){
|
||||
sqlite3_result_error(ctx, zResult, -1);
|
||||
}else{
|
||||
sqlite3_result_text(ctx, zResult, -1, SQLITE_TRANSIENT);
|
||||
}
|
||||
|
||||
if( bValue==0 ){
|
||||
if( pCtx->pVal ) Tcl_DecrRefCount(pCtx->pVal);
|
||||
pCtx->pVal = 0;
|
||||
}
|
||||
}
|
||||
Tcl_DecrRefCount(pEval);
|
||||
}
|
||||
|
||||
static void testWindowStep(
|
||||
sqlite3_context *ctx,
|
||||
int nArg,
|
||||
sqlite3_value **apArg
|
||||
){
|
||||
doTestWindowStep(0, ctx, nArg, apArg);
|
||||
}
|
||||
static void testWindowInverse(
|
||||
sqlite3_context *ctx,
|
||||
int nArg,
|
||||
sqlite3_value **apArg
|
||||
){
|
||||
doTestWindowStep(1, ctx, nArg, apArg);
|
||||
}
|
||||
|
||||
static void testWindowFinal(sqlite3_context *ctx){
|
||||
doTestWindowFinalize(0, ctx);
|
||||
}
|
||||
static void testWindowValue(sqlite3_context *ctx){
|
||||
doTestWindowFinalize(1, ctx);
|
||||
}
|
||||
|
||||
static void testWindowDestroy(void *pCtx){
|
||||
ckfree(pCtx);
|
||||
}
|
||||
|
||||
/*
|
||||
** Usage: sqlite3_create_window_function DB NAME XSTEP XFINAL XVALUE XINVERSE
|
||||
*/
|
||||
static int SQLITE_TCLAPI test_create_window(
|
||||
void * clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
TestWindow *pNew;
|
||||
sqlite3 *db;
|
||||
const char *zName;
|
||||
int rc;
|
||||
|
||||
if( objc!=7 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "DB NAME XSTEP XFINAL XVALUE XINVERSE");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
|
||||
zName = Tcl_GetString(objv[2]);
|
||||
pNew = ckalloc(sizeof(TestWindow));
|
||||
memset(pNew, 0, sizeof(TestWindow));
|
||||
pNew->xStep = Tcl_DuplicateObj(objv[3]);
|
||||
pNew->xFinal = Tcl_DuplicateObj(objv[4]);
|
||||
pNew->xValue = Tcl_DuplicateObj(objv[5]);
|
||||
pNew->xInverse = Tcl_DuplicateObj(objv[6]);
|
||||
pNew->interp = interp;
|
||||
|
||||
Tcl_IncrRefCount(pNew->xStep);
|
||||
Tcl_IncrRefCount(pNew->xFinal);
|
||||
Tcl_IncrRefCount(pNew->xValue);
|
||||
Tcl_IncrRefCount(pNew->xInverse);
|
||||
|
||||
rc = sqlite3_create_window_function(db, zName, -1, SQLITE_UTF8, (void*)pNew,
|
||||
testWindowStep, testWindowFinal, testWindowValue, testWindowInverse,
|
||||
testWindowDestroy
|
||||
);
|
||||
if( rc!=SQLITE_OK ){
|
||||
Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1));
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
int Sqlitetest_window_Init(Tcl_Interp *interp){
|
||||
static struct {
|
||||
char *zName;
|
||||
Tcl_ObjCmdProc *xProc;
|
||||
int clientData;
|
||||
} aObjCmd[] = {
|
||||
{ "sqlite3_create_window_function", test_create_window, 0 },
|
||||
};
|
||||
int i;
|
||||
for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){
|
||||
ClientData c = (ClientData)SQLITE_INT_TO_PTR(aObjCmd[i].clientData);
|
||||
Tcl_CreateObjCommand(interp, aObjCmd[i].zName, aObjCmd[i].xProc, c, 0);
|
||||
}
|
||||
return TCL_OK;
|
||||
}
|
||||
#endif
|
@@ -6414,6 +6414,7 @@ case OP_AggFinal: {
|
||||
assert( (pMem->flags & ~(MEM_Null|MEM_Agg))==0 );
|
||||
if( pOp->p3 ){
|
||||
rc = sqlite3VdbeMemAggValue(pMem, &aMem[pOp->p3], pOp->p4.pFunc);
|
||||
pMem = &aMem[pOp->p3];
|
||||
}else{
|
||||
rc = sqlite3VdbeMemFinalize(pMem, pOp->p4.pFunc);
|
||||
}
|
||||
|
19
src/window.c
19
src/window.c
@@ -300,7 +300,7 @@ static void cume_distInvFunc(
|
||||
static void cume_distValueFunc(sqlite3_context *pCtx){
|
||||
struct CallCount *p;
|
||||
p = (struct CallCount*)sqlite3_aggregate_context(pCtx, sizeof(*p));
|
||||
if( p ){
|
||||
if( p && p->nTotal ){
|
||||
double r = (double)(p->nStep) / (double)(p->nTotal);
|
||||
sqlite3_result_double(pCtx, r);
|
||||
}
|
||||
@@ -684,7 +684,6 @@ int sqlite3WindowRewrite(Parse *pParse, Select *p){
|
||||
int rc = SQLITE_OK;
|
||||
if( p->pWin ){
|
||||
Vdbe *v = sqlite3GetVdbe(pParse);
|
||||
int i;
|
||||
sqlite3 *db = pParse->db;
|
||||
Select *pSub = 0; /* The subquery */
|
||||
SrcList *pSrc = p->pSrc;
|
||||
@@ -743,8 +742,6 @@ int sqlite3WindowRewrite(Parse *pParse, Select *p){
|
||||
p->pSrc = sqlite3SrcListAppend(db, 0, 0, 0);
|
||||
assert( p->pSrc || db->mallocFailed );
|
||||
if( p->pSrc ){
|
||||
int iTab;
|
||||
ExprList *pList = 0;
|
||||
p->pSrc->a[0].pSelect = pSub;
|
||||
sqlite3SrcListAssignCursors(pParse, p->pSrc);
|
||||
if( sqlite3ExpandSubquery(pParse, &p->pSrc->a[0]) ){
|
||||
@@ -1088,7 +1085,6 @@ static void windowPartitionCache(
|
||||
){
|
||||
Window *pMWin = p->pWin;
|
||||
Vdbe *v = sqlite3GetVdbe(pParse);
|
||||
Window *pWin;
|
||||
int iSubCsr = p->pSrc->a[0].iCursor;
|
||||
int nSub = p->pSrc->a[0].pTab->nCol;
|
||||
int k;
|
||||
@@ -1410,30 +1406,20 @@ static void windowCodeRowExprStep(
|
||||
){
|
||||
Window *pMWin = p->pWin;
|
||||
Vdbe *v = sqlite3GetVdbe(pParse);
|
||||
Window *pWin;
|
||||
int k;
|
||||
int nSub = p->pSrc->a[0].pTab->nCol;
|
||||
int regFlushPart; /* Register for "Gosub flush_partition" */
|
||||
int lblFlushPart; /* Label for "Gosub flush_partition" */
|
||||
int lblFlushDone; /* Label for "Gosub flush_partition_done" */
|
||||
|
||||
int regArg;
|
||||
int nArg;
|
||||
int addr;
|
||||
int csrStart = pParse->nTab++;
|
||||
int csrEnd = pParse->nTab++;
|
||||
int regStart; /* Value of <expr> PRECEDING */
|
||||
int regEnd; /* Value of <expr> FOLLOWING */
|
||||
int addrNext;
|
||||
int addrGoto;
|
||||
int addrTop;
|
||||
int addrIfPos1;
|
||||
int addrIfPos2;
|
||||
|
||||
int regPeer = 0; /* Number of peers in current group */
|
||||
int regPeerVal = 0; /* Array of values identifying peer group */
|
||||
int iPeer = 0; /* Column offset in eph-table of peer vals */
|
||||
int nPeerVal; /* Number of peer values */
|
||||
int regSize = 0;
|
||||
|
||||
assert( pMWin->eStart==TK_PRECEDING
|
||||
@@ -1679,7 +1665,6 @@ static void windowCodeCacheStep(
|
||||
){
|
||||
Window *pMWin = p->pWin;
|
||||
Vdbe *v = sqlite3GetVdbe(pParse);
|
||||
Window *pWin;
|
||||
int k;
|
||||
int addr;
|
||||
ExprList *pPart = pMWin->pPartition;
|
||||
@@ -1695,7 +1680,6 @@ static void windowCodeCacheStep(
|
||||
int regCtr;
|
||||
int regArg; /* Register array to martial function args */
|
||||
int regSize;
|
||||
int nArg;
|
||||
int lblEmpty;
|
||||
int bReverse = pMWin->pOrderBy && pMWin->eStart==TK_CURRENT
|
||||
&& pMWin->eEnd==TK_UNBOUNDED;
|
||||
@@ -1822,7 +1806,6 @@ static void windowCodeDefaultStep(
|
||||
){
|
||||
Window *pMWin = p->pWin;
|
||||
Vdbe *v = sqlite3GetVdbe(pParse);
|
||||
Window *pWin;
|
||||
int k;
|
||||
int iSubCsr = p->pSrc->a[0].iCursor;
|
||||
int nSub = p->pSrc->a[0].pTab->nCol;
|
||||
|
@@ -269,6 +269,13 @@ do_execsql_test 7.3 {
|
||||
SELECT row_number() OVER (ORDER BY x) FROM t1
|
||||
} {1 2 3 4 5}
|
||||
|
||||
do_execsql_test 7.4 {
|
||||
SELECT
|
||||
row_number() OVER win,
|
||||
lead(x) OVER win
|
||||
FROM t1
|
||||
WINDOW win AS (ORDER BY x ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)
|
||||
} {1 3 2 5 3 7 4 9 5 {}}
|
||||
|
||||
finish_test
|
||||
|
||||
|
68
test/window5.test
Normal file
68
test/window5.test
Normal file
@@ -0,0 +1,68 @@
|
||||
# 2018 May 8
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
#***********************************************************************
|
||||
# This file implements regression tests for SQLite library. Specifically,
|
||||
# it tests the sqlite3_create_window_function() API.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix window1
|
||||
|
||||
proc m_step {ctx val} {
|
||||
lappend ctx $val
|
||||
return $ctx
|
||||
}
|
||||
proc m_value {ctx} {
|
||||
set lSort [lsort $ctx]
|
||||
|
||||
set nVal [llength $lSort]
|
||||
set n [expr $nVal/2]
|
||||
|
||||
if {($nVal % 2)==0 && $nVal>0} {
|
||||
set a [lindex $lSort $n]
|
||||
set b [lindex $lSort $n-1]
|
||||
if {($a+$b) % 2} {
|
||||
set ret [expr ($a+$b)/2.0]
|
||||
} else {
|
||||
set ret [expr ($a+$b)/2]
|
||||
}
|
||||
} else {
|
||||
set ret [lindex $lSort $n]
|
||||
}
|
||||
return $ret
|
||||
}
|
||||
proc m_inverse {ctx val} {
|
||||
set ctx [lrange $ctx 1 end]
|
||||
return $ctx
|
||||
}
|
||||
proc w_value {ctx} {
|
||||
lsort $ctx
|
||||
}
|
||||
|
||||
sqlite3_create_window_function db median m_step m_value m_value m_inverse
|
||||
sqlite3_create_window_function db win m_step w_value w_value m_inverse
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE TABLE t1(a, b);
|
||||
INSERT INTO t1 VALUES(4, 'a');
|
||||
INSERT INTO t1 VALUES(6, 'b');
|
||||
INSERT INTO t1 VALUES(1, 'c');
|
||||
INSERT INTO t1 VALUES(5, 'd');
|
||||
INSERT INTO t1 VALUES(2, 'e');
|
||||
INSERT INTO t1 VALUES(3, 'f');
|
||||
}
|
||||
|
||||
do_execsql_test 1.1 {
|
||||
SELECT win(a) OVER (ORDER BY b), median(a) OVER (ORDER BY b) FROM t1;
|
||||
} {4 4 {4 6} 5 {1 4 6} 4 {1 4 5 6} 4.5 {1 2 4 5 6} 4 {1 2 3 4 5 6} 3.5}
|
||||
|
||||
finish_test
|
||||
|
Reference in New Issue
Block a user