4 ** The author disclaims copyright to this source code. In place of
5 ** a legal notice, here is a blessing:
7 ** May you do good and not evil.
8 ** May you find forgiveness for yourself and forgive others.
9 ** May you share freely, never taking more than you give.
11 *************************************************************************
18 #include "sqliteInt.h"
21 extern int getDbPointer(Tcl_Interp
*interp
, const char *zA
, sqlite3
**ppDb
);
22 extern const char *sqlite3ErrName(int);
24 typedef struct TestWindow TestWindow
;
33 typedef struct TestWindowCtx TestWindowCtx
;
34 struct TestWindowCtx
{
38 static void doTestWindowStep(
45 TestWindow
*p
= (TestWindow
*)sqlite3_user_data(ctx
);
46 Tcl_Obj
*pEval
= Tcl_DuplicateObj(bInverse
? p
->xInverse
: p
->xStep
);
47 TestWindowCtx
*pCtx
= sqlite3_aggregate_context(ctx
, sizeof(TestWindowCtx
));
49 Tcl_IncrRefCount(pEval
);
54 Tcl_ListObjAppendElement(p
->interp
, pEval
, Tcl_DuplicateObj(pCtx
->pVal
));
56 Tcl_ListObjAppendElement(p
->interp
, pEval
, Tcl_NewStringObj("", -1));
58 for(i
=0; i
<nArg
; i
++){
60 pArg
= Tcl_NewStringObj((const char*)sqlite3_value_text(apArg
[i
]), -1);
61 Tcl_ListObjAppendElement(p
->interp
, pEval
, pArg
);
63 rc
= Tcl_EvalObjEx(p
->interp
, pEval
, TCL_EVAL_GLOBAL
);
65 zResult
= Tcl_GetStringResult(p
->interp
);
66 sqlite3_result_error(ctx
, zResult
, -1);
68 if( pCtx
->pVal
) Tcl_DecrRefCount(pCtx
->pVal
);
69 pCtx
->pVal
= Tcl_DuplicateObj(Tcl_GetObjResult(p
->interp
));
70 Tcl_IncrRefCount(pCtx
->pVal
);
73 Tcl_DecrRefCount(pEval
);
76 static void doTestWindowFinalize(int bValue
, sqlite3_context
*ctx
){
77 TestWindow
*p
= (TestWindow
*)sqlite3_user_data(ctx
);
78 Tcl_Obj
*pEval
= Tcl_DuplicateObj(bValue
? p
->xValue
: p
->xFinal
);
79 TestWindowCtx
*pCtx
= sqlite3_aggregate_context(ctx
, sizeof(TestWindowCtx
));
81 Tcl_IncrRefCount(pEval
);
86 Tcl_ListObjAppendElement(p
->interp
, pEval
, Tcl_DuplicateObj(pCtx
->pVal
));
88 Tcl_ListObjAppendElement(p
->interp
, pEval
, Tcl_NewStringObj("", -1));
91 rc
= Tcl_EvalObjEx(p
->interp
, pEval
, TCL_EVAL_GLOBAL
);
92 zResult
= Tcl_GetStringResult(p
->interp
);
94 sqlite3_result_error(ctx
, zResult
, -1);
96 sqlite3_result_text(ctx
, zResult
, -1, SQLITE_TRANSIENT
);
100 if( pCtx
->pVal
) Tcl_DecrRefCount(pCtx
->pVal
);
104 Tcl_DecrRefCount(pEval
);
107 static void testWindowStep(
108 sqlite3_context
*ctx
,
110 sqlite3_value
**apArg
112 doTestWindowStep(0, ctx
, nArg
, apArg
);
114 static void testWindowInverse(
115 sqlite3_context
*ctx
,
117 sqlite3_value
**apArg
119 doTestWindowStep(1, ctx
, nArg
, apArg
);
122 static void testWindowFinal(sqlite3_context
*ctx
){
123 doTestWindowFinalize(0, ctx
);
125 static void testWindowValue(sqlite3_context
*ctx
){
126 doTestWindowFinalize(1, ctx
);
129 static void testWindowDestroy(void *pCtx
){
134 ** Usage: sqlite3_create_window_function DB NAME XSTEP XFINAL XVALUE XINVERSE
136 static int SQLITE_TCLAPI
test_create_window(
140 Tcl_Obj
*CONST objv
[]
148 Tcl_WrongNumArgs(interp
, 1, objv
, "DB NAME XSTEP XFINAL XVALUE XINVERSE");
152 if( getDbPointer(interp
, Tcl_GetString(objv
[1]), &db
) ) return TCL_ERROR
;
153 zName
= Tcl_GetString(objv
[2]);
154 pNew
= (TestWindow
*)ckalloc(sizeof(TestWindow
));
155 memset(pNew
, 0, sizeof(TestWindow
));
156 pNew
->xStep
= Tcl_DuplicateObj(objv
[3]);
157 pNew
->xFinal
= Tcl_DuplicateObj(objv
[4]);
158 pNew
->xValue
= Tcl_DuplicateObj(objv
[5]);
159 pNew
->xInverse
= Tcl_DuplicateObj(objv
[6]);
160 pNew
->interp
= interp
;
162 Tcl_IncrRefCount(pNew
->xStep
);
163 Tcl_IncrRefCount(pNew
->xFinal
);
164 Tcl_IncrRefCount(pNew
->xValue
);
165 Tcl_IncrRefCount(pNew
->xInverse
);
167 rc
= sqlite3_create_window_function(db
, zName
, -1, SQLITE_UTF8
, (void*)pNew
,
168 testWindowStep
, testWindowFinal
, testWindowValue
, testWindowInverse
,
172 Tcl_SetObjResult(interp
, Tcl_NewStringObj(sqlite3ErrName(rc
), -1));
179 static int SQLITE_TCLAPI
test_create_window_misuse(
183 Tcl_Obj
*CONST objv
[]
189 Tcl_WrongNumArgs(interp
, 1, objv
, "DB");
192 if( getDbPointer(interp
, Tcl_GetString(objv
[1]), &db
) ) return TCL_ERROR
;
194 rc
= sqlite3_create_window_function(db
, "fff", -1, SQLITE_UTF8
, 0,
195 0, testWindowFinal
, testWindowValue
, testWindowInverse
,
198 if( rc
!=SQLITE_MISUSE
) goto error
;
199 rc
= sqlite3_create_window_function(db
, "fff", -1, SQLITE_UTF8
, 0,
200 testWindowStep
, 0, testWindowValue
, testWindowInverse
,
203 if( rc
!=SQLITE_MISUSE
) goto error
;
204 rc
= sqlite3_create_window_function(db
, "fff", -1, SQLITE_UTF8
, 0,
205 testWindowStep
, testWindowFinal
, 0, testWindowInverse
,
208 if( rc
!=SQLITE_MISUSE
) goto error
;
209 rc
= sqlite3_create_window_function(db
, "fff", -1, SQLITE_UTF8
, 0,
210 testWindowStep
, testWindowFinal
, testWindowValue
, 0,
213 if( rc
!=SQLITE_MISUSE
) goto error
;
218 Tcl_SetObjResult(interp
, Tcl_NewStringObj("misuse test error", -1));
223 ** xStep for sumint().
225 static void sumintStep(
226 sqlite3_context
*ctx
,
228 sqlite3_value
*apArg
[]
233 if( sqlite3_value_type(apArg
[0])!=SQLITE_INTEGER
){
234 sqlite3_result_error(ctx
, "invalid argument", -1);
237 pInt
= (sqlite3_int64
*)sqlite3_aggregate_context(ctx
, sizeof(sqlite3_int64
));
239 *pInt
+= sqlite3_value_int64(apArg
[0]);
244 ** xInverse for sumint().
246 static void sumintInverse(
247 sqlite3_context
*ctx
,
249 sqlite3_value
*apArg
[]
252 pInt
= (sqlite3_int64
*)sqlite3_aggregate_context(ctx
, sizeof(sqlite3_int64
));
253 *pInt
-= sqlite3_value_int64(apArg
[0]);
257 ** xFinal for sumint().
259 static void sumintFinal(sqlite3_context
*ctx
){
260 sqlite3_int64 res
= 0;
262 pInt
= (sqlite3_int64
*)sqlite3_aggregate_context(ctx
, 0);
263 if( pInt
) res
= *pInt
;
264 sqlite3_result_int64(ctx
, res
);
268 ** xValue for sumint().
270 static void sumintValue(sqlite3_context
*ctx
){
271 sqlite3_int64 res
= 0;
273 pInt
= (sqlite3_int64
*)sqlite3_aggregate_context(ctx
, 0);
274 if( pInt
) res
= *pInt
;
275 sqlite3_result_int64(ctx
, res
);
278 static int SQLITE_TCLAPI
test_create_sumint(
282 Tcl_Obj
*CONST objv
[]
288 Tcl_WrongNumArgs(interp
, 1, objv
, "DB");
291 if( getDbPointer(interp
, Tcl_GetString(objv
[1]), &db
) ) return TCL_ERROR
;
293 rc
= sqlite3_create_window_function(db
, "sumint", 1, SQLITE_UTF8
, 0,
294 sumintStep
, sumintFinal
, sumintValue
, sumintInverse
,
299 Tcl_SetObjResult(interp
, Tcl_NewStringObj(sqlite3ErrName(rc
), -1));
305 static int SQLITE_TCLAPI
test_override_sum(
309 Tcl_Obj
*CONST objv
[]
315 Tcl_WrongNumArgs(interp
, 1, objv
, "DB");
318 if( getDbPointer(interp
, Tcl_GetString(objv
[1]), &db
) ) return TCL_ERROR
;
320 rc
= sqlite3_create_function(db
, "sum", -1, SQLITE_UTF8
, 0,
321 0, sumintStep
, sumintFinal
325 Tcl_SetObjResult(interp
, Tcl_NewStringObj(sqlite3ErrName(rc
), -1));
331 int Sqlitetest_window_Init(Tcl_Interp
*interp
){
334 Tcl_ObjCmdProc
*xProc
;
337 { "sqlite3_create_window_function", test_create_window
, 0 },
338 { "test_create_window_function_misuse", test_create_window_misuse
, 0 },
339 { "test_create_sumint", test_create_sumint
, 0 },
340 { "test_override_sum", test_override_sum
, 0 },
343 for(i
=0; i
<sizeof(aObjCmd
)/sizeof(aObjCmd
[0]); i
++){
344 ClientData c
= (ClientData
)SQLITE_INT_TO_PTR(aObjCmd
[i
].clientData
);
345 Tcl_CreateObjCommand(interp
, aObjCmd
[i
].zName
, aObjCmd
[i
].xProc
, c
, 0);