$(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 \
$(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 \
$(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.
-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
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
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
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
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
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
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
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
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
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
-ac251f72608c27c1512a0b3457524f5378a0b13d93d829cf0ed8bc178bc54a73
\ No newline at end of file
+da03fb4318fd2613ec5c5b109a3974ac1120c19ed16bed4ca85bbdc4b35c998c
\ No newline at end of file
}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);
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;
}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;
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(
- 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(
+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 (*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;
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);
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,
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);
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
#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*);
extern int Zipvfs_Init(Tcl_Interp*);
#endif
extern int TestExpert_Init(Tcl_Interp*);
+ extern int Sqlitetest_window_Init(Tcl_Interp *);
Tcl_CmdInfo cmdInfo;
Sqlitetestfts3_Init(interp);
#endif
TestExpert_Init(interp);
+ Sqlitetest_window_Init(interp);
Tcl_CreateObjCommand(
interp, "load_testfixture_extensions", load_testfixture_extensions,0,0
--- /dev/null
+/*
+** 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
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);
}
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);
}
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;
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]) ){
){
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;
){
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
){
Window *pMWin = p->pWin;
Vdbe *v = sqlite3GetVdbe(pParse);
- Window *pWin;
int k;
int addr;
ExprList *pPart = pMWin->pPartition;
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;
){
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;
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
--- /dev/null
+# 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
+