mirror of
https://github.com/status-im/sqlcipher.git
synced 2025-02-24 17:58:23 +00:00
350 lines
8.7 KiB
C
350 lines
8.7 KiB
C
/*
|
|
** 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 = (TestWindow*)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;
|
|
}
|
|
|
|
static int SQLITE_TCLAPI test_create_window_misuse(
|
|
void * clientData,
|
|
Tcl_Interp *interp,
|
|
int objc,
|
|
Tcl_Obj *CONST objv[]
|
|
){
|
|
sqlite3 *db;
|
|
int rc;
|
|
|
|
if( objc!=2 ){
|
|
Tcl_WrongNumArgs(interp, 1, objv, "DB");
|
|
return TCL_ERROR;
|
|
}
|
|
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
|
|
|
|
rc = sqlite3_create_window_function(db, "fff", -1, SQLITE_UTF8, 0,
|
|
0, testWindowFinal, testWindowValue, testWindowInverse,
|
|
0
|
|
);
|
|
if( rc!=SQLITE_MISUSE ) goto error;
|
|
rc = sqlite3_create_window_function(db, "fff", -1, SQLITE_UTF8, 0,
|
|
testWindowStep, 0, testWindowValue, testWindowInverse,
|
|
0
|
|
);
|
|
if( rc!=SQLITE_MISUSE ) goto error;
|
|
rc = sqlite3_create_window_function(db, "fff", -1, SQLITE_UTF8, 0,
|
|
testWindowStep, testWindowFinal, 0, testWindowInverse,
|
|
0
|
|
);
|
|
if( rc!=SQLITE_MISUSE ) goto error;
|
|
rc = sqlite3_create_window_function(db, "fff", -1, SQLITE_UTF8, 0,
|
|
testWindowStep, testWindowFinal, testWindowValue, 0,
|
|
0
|
|
);
|
|
if( rc!=SQLITE_MISUSE ) goto error;
|
|
|
|
return TCL_OK;
|
|
|
|
error:
|
|
Tcl_SetObjResult(interp, Tcl_NewStringObj("misuse test error", -1));
|
|
return TCL_ERROR;
|
|
}
|
|
|
|
/*
|
|
** xStep for sumint().
|
|
*/
|
|
static void sumintStep(
|
|
sqlite3_context *ctx,
|
|
int nArg,
|
|
sqlite3_value *apArg[]
|
|
){
|
|
sqlite3_int64 *pInt;
|
|
|
|
assert( nArg==1 );
|
|
if( sqlite3_value_type(apArg[0])!=SQLITE_INTEGER ){
|
|
sqlite3_result_error(ctx, "invalid argument", -1);
|
|
return;
|
|
}
|
|
pInt = (sqlite3_int64*)sqlite3_aggregate_context(ctx, sizeof(sqlite3_int64));
|
|
if( pInt ){
|
|
*pInt += sqlite3_value_int64(apArg[0]);
|
|
}
|
|
}
|
|
|
|
/*
|
|
** xInverse for sumint().
|
|
*/
|
|
static void sumintInverse(
|
|
sqlite3_context *ctx,
|
|
int nArg,
|
|
sqlite3_value *apArg[]
|
|
){
|
|
sqlite3_int64 *pInt;
|
|
pInt = (sqlite3_int64*)sqlite3_aggregate_context(ctx, sizeof(sqlite3_int64));
|
|
*pInt -= sqlite3_value_int64(apArg[0]);
|
|
}
|
|
|
|
/*
|
|
** xFinal for sumint().
|
|
*/
|
|
static void sumintFinal(sqlite3_context *ctx){
|
|
sqlite3_int64 res = 0;
|
|
sqlite3_int64 *pInt;
|
|
pInt = (sqlite3_int64*)sqlite3_aggregate_context(ctx, 0);
|
|
if( pInt ) res = *pInt;
|
|
sqlite3_result_int64(ctx, res);
|
|
}
|
|
|
|
/*
|
|
** xValue for sumint().
|
|
*/
|
|
static void sumintValue(sqlite3_context *ctx){
|
|
sqlite3_int64 res = 0;
|
|
sqlite3_int64 *pInt;
|
|
pInt = (sqlite3_int64*)sqlite3_aggregate_context(ctx, 0);
|
|
if( pInt ) res = *pInt;
|
|
sqlite3_result_int64(ctx, res);
|
|
}
|
|
|
|
static int SQLITE_TCLAPI test_create_sumint(
|
|
void * clientData,
|
|
Tcl_Interp *interp,
|
|
int objc,
|
|
Tcl_Obj *CONST objv[]
|
|
){
|
|
sqlite3 *db;
|
|
int rc;
|
|
|
|
if( objc!=2 ){
|
|
Tcl_WrongNumArgs(interp, 1, objv, "DB");
|
|
return TCL_ERROR;
|
|
}
|
|
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
|
|
|
|
rc = sqlite3_create_window_function(db, "sumint", 1, SQLITE_UTF8, 0,
|
|
sumintStep, sumintFinal, sumintValue, sumintInverse,
|
|
0
|
|
);
|
|
|
|
if( rc!=SQLITE_OK ){
|
|
Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1));
|
|
return TCL_ERROR;
|
|
}
|
|
return TCL_OK;
|
|
}
|
|
|
|
static int SQLITE_TCLAPI test_override_sum(
|
|
void * clientData,
|
|
Tcl_Interp *interp,
|
|
int objc,
|
|
Tcl_Obj *CONST objv[]
|
|
){
|
|
sqlite3 *db;
|
|
int rc;
|
|
|
|
if( objc!=2 ){
|
|
Tcl_WrongNumArgs(interp, 1, objv, "DB");
|
|
return TCL_ERROR;
|
|
}
|
|
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
|
|
|
|
rc = sqlite3_create_function(db, "sum", -1, SQLITE_UTF8, 0,
|
|
0, sumintStep, sumintFinal
|
|
);
|
|
|
|
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 },
|
|
{ "test_create_window_function_misuse", test_create_window_misuse, 0 },
|
|
{ "test_create_sumint", test_create_sumint, 0 },
|
|
{ "test_override_sum", test_override_sum, 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
|