AryaWu/sqlite
0
1/*2** 2018 June 173**4** The author disclaims copyright to this source code. In place of5** a legal notice, here is a blessing:6**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.10**11*************************************************************************12*/13 14#include "sqlite3.h"15 16#ifdef SQLITE_TEST17 18#include "sqliteInt.h"19#include "tclsqlite.h"20 21extern int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb);22extern const char *sqlite3ErrName(int);23 24typedef struct TestWindow TestWindow;25struct TestWindow {26 Tcl_Obj *xStep;27 Tcl_Obj *xFinal;28 Tcl_Obj *xValue;29 Tcl_Obj *xInverse;30 Tcl_Interp *interp;31};32 33typedef struct TestWindowCtx TestWindowCtx;34struct TestWindowCtx {35 Tcl_Obj *pVal;36};37 38static void doTestWindowStep(39 int bInverse,40 sqlite3_context *ctx, 41 int nArg, 42 sqlite3_value **apArg43){44 int i;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));48 49 Tcl_IncrRefCount(pEval);50 if( pCtx ){51 const char *zResult;52 int rc;53 if( pCtx->pVal ){54 Tcl_ListObjAppendElement(p->interp, pEval, Tcl_DuplicateObj(pCtx->pVal));55 }else{56 Tcl_ListObjAppendElement(p->interp, pEval, Tcl_NewStringObj("", -1));57 }58 for(i=0; i<nArg; i++){59 Tcl_Obj *pArg;60 pArg = Tcl_NewStringObj((const char*)sqlite3_value_text(apArg[i]), -1);61 Tcl_ListObjAppendElement(p->interp, pEval, pArg);62 }63 rc = Tcl_EvalObjEx(p->interp, pEval, TCL_EVAL_GLOBAL);64 if( rc!=TCL_OK ){65 zResult = Tcl_GetStringResult(p->interp);66 sqlite3_result_error(ctx, zResult, -1);67 }else{68 if( pCtx->pVal ) Tcl_DecrRefCount(pCtx->pVal);69 pCtx->pVal = Tcl_DuplicateObj(Tcl_GetObjResult(p->interp));70 Tcl_IncrRefCount(pCtx->pVal);71 }72 }73 Tcl_DecrRefCount(pEval);74}75 76static 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));80 81 Tcl_IncrRefCount(pEval);82 if( pCtx ){83 const char *zResult;84 int rc;85 if( pCtx->pVal ){86 Tcl_ListObjAppendElement(p->interp, pEval, Tcl_DuplicateObj(pCtx->pVal));87 }else{88 Tcl_ListObjAppendElement(p->interp, pEval, Tcl_NewStringObj("", -1));89 }90 91 rc = Tcl_EvalObjEx(p->interp, pEval, TCL_EVAL_GLOBAL);92 zResult = Tcl_GetStringResult(p->interp);93 if( rc!=TCL_OK ){94 sqlite3_result_error(ctx, zResult, -1);95 }else{96 sqlite3_result_text(ctx, zResult, -1, SQLITE_TRANSIENT);97 }98 99 if( bValue==0 ){100 if( pCtx->pVal ) Tcl_DecrRefCount(pCtx->pVal);101 pCtx->pVal = 0;102 }103 }104 Tcl_DecrRefCount(pEval);105}106 107static void testWindowStep(108 sqlite3_context *ctx, 109 int nArg, 110 sqlite3_value **apArg111){112 doTestWindowStep(0, ctx, nArg, apArg);113}114static void testWindowInverse(115 sqlite3_context *ctx, 116 int nArg, 117 sqlite3_value **apArg118){119 doTestWindowStep(1, ctx, nArg, apArg);120}121 122static void testWindowFinal(sqlite3_context *ctx){123 doTestWindowFinalize(0, ctx);124}125static void testWindowValue(sqlite3_context *ctx){126 doTestWindowFinalize(1, ctx);127}128 129static void testWindowDestroy(void *pCtx){130 ckfree(pCtx);131}132 133/*134** Usage: sqlite3_create_window_function DB NAME XSTEP XFINAL XVALUE XINVERSE135*/136static int SQLITE_TCLAPI test_create_window(137 void * clientData,138 Tcl_Interp *interp,139 int objc,140 Tcl_Obj *CONST objv[]141){142 TestWindow *pNew;143 sqlite3 *db;144 const char *zName;145 int rc;146 147 if( objc!=7 ){148 Tcl_WrongNumArgs(interp, 1, objv, "DB NAME XSTEP XFINAL XVALUE XINVERSE");149 return TCL_ERROR;150 }151 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;161 162 Tcl_IncrRefCount(pNew->xStep);163 Tcl_IncrRefCount(pNew->xFinal);164 Tcl_IncrRefCount(pNew->xValue);165 Tcl_IncrRefCount(pNew->xInverse);166 167 rc = sqlite3_create_window_function(db, zName, -1, SQLITE_UTF8, (void*)pNew,168 testWindowStep, testWindowFinal, testWindowValue, testWindowInverse,169 testWindowDestroy170 );171 if( rc!=SQLITE_OK ){172 Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1));173 return TCL_ERROR;174 }175 176 return TCL_OK;177}178 179static int SQLITE_TCLAPI test_create_window_misuse(180 void * clientData,181 Tcl_Interp *interp,182 int objc,183 Tcl_Obj *CONST objv[]184){185 sqlite3 *db;186 int rc;187 188 if( objc!=2 ){189 Tcl_WrongNumArgs(interp, 1, objv, "DB");190 return TCL_ERROR;191 }192 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;193 194 rc = sqlite3_create_window_function(db, "fff", -1, SQLITE_UTF8, 0,195 0, testWindowFinal, testWindowValue, testWindowInverse,196 0197 );198 if( rc!=SQLITE_MISUSE ) goto error;199 rc = sqlite3_create_window_function(db, "fff", -1, SQLITE_UTF8, 0,200 testWindowStep, 0, testWindowValue, testWindowInverse,201 0202 );203 if( rc!=SQLITE_MISUSE ) goto error;204 rc = sqlite3_create_window_function(db, "fff", -1, SQLITE_UTF8, 0,205 testWindowStep, testWindowFinal, 0, testWindowInverse,206 0207 );208 if( rc!=SQLITE_MISUSE ) goto error;209 rc = sqlite3_create_window_function(db, "fff", -1, SQLITE_UTF8, 0,210 testWindowStep, testWindowFinal, testWindowValue, 0,211 0212 );213 if( rc!=SQLITE_MISUSE ) goto error;214 215 return TCL_OK;216 217 error:218 Tcl_SetObjResult(interp, Tcl_NewStringObj("misuse test error", -1));219 return TCL_ERROR;220}221 222/*223** xStep for sumint().224*/225static void sumintStep(226 sqlite3_context *ctx, 227 int nArg, 228 sqlite3_value *apArg[]229){230 sqlite3_int64 *pInt;231 232 assert( nArg==1 );233 if( sqlite3_value_type(apArg[0])!=SQLITE_INTEGER ){234 sqlite3_result_error(ctx, "invalid argument", -1);235 return;236 }237 pInt = (sqlite3_int64*)sqlite3_aggregate_context(ctx, sizeof(sqlite3_int64));238 if( pInt ){239 *pInt += sqlite3_value_int64(apArg[0]);240 }241}242 243/*244** xInverse for sumint().245*/246static void sumintInverse(247 sqlite3_context *ctx, 248 int nArg, 249 sqlite3_value *apArg[]250){251 sqlite3_int64 *pInt;252 pInt = (sqlite3_int64*)sqlite3_aggregate_context(ctx, sizeof(sqlite3_int64));253 *pInt -= sqlite3_value_int64(apArg[0]);254}255 256/*257** xFinal for sumint().258*/259static void sumintFinal(sqlite3_context *ctx){260 sqlite3_int64 res = 0;261 sqlite3_int64 *pInt;262 pInt = (sqlite3_int64*)sqlite3_aggregate_context(ctx, 0);263 if( pInt ) res = *pInt;264 sqlite3_result_int64(ctx, res);265}266 267/*268** xValue for sumint().269*/270static void sumintValue(sqlite3_context *ctx){271 sqlite3_int64 res = 0;272 sqlite3_int64 *pInt;273 pInt = (sqlite3_int64*)sqlite3_aggregate_context(ctx, 0);274 if( pInt ) res = *pInt;275 sqlite3_result_int64(ctx, res);276}277 278static int SQLITE_TCLAPI test_create_sumint(279 void * clientData,280 Tcl_Interp *interp,281 int objc,282 Tcl_Obj *CONST objv[]283){284 sqlite3 *db;285 int rc;286 287 if( objc!=2 ){288 Tcl_WrongNumArgs(interp, 1, objv, "DB");289 return TCL_ERROR;290 }291 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;292 293 rc = sqlite3_create_window_function(db, "sumint", 1, SQLITE_UTF8, 0,294 sumintStep, sumintFinal, sumintValue, sumintInverse,295 0296 );297 298 if( rc!=SQLITE_OK ){299 Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1));300 return TCL_ERROR;301 }302 return TCL_OK;303}304 305static int SQLITE_TCLAPI test_override_sum(306 void * clientData,307 Tcl_Interp *interp,308 int objc,309 Tcl_Obj *CONST objv[]310){311 sqlite3 *db;312 int rc;313 314 if( objc!=2 ){315 Tcl_WrongNumArgs(interp, 1, objv, "DB");316 return TCL_ERROR;317 }318 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;319 320 rc = sqlite3_create_function(db, "sum", -1, SQLITE_UTF8, 0,321 0, sumintStep, sumintFinal322 );323 324 if( rc!=SQLITE_OK ){325 Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1));326 return TCL_ERROR;327 }328 return TCL_OK;329}330 331int Sqlitetest_window_Init(Tcl_Interp *interp){332 static struct {333 char *zName;334 Tcl_ObjCmdProc *xProc;335 int clientData;336 } aObjCmd[] = {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 },341 };342 int i;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);346 }347 return TCL_OK;348}349#endif350 