blob: 9d2450da27f0fcde3a5235cfc335f1940bfc68c6 [file] [log] [blame] [edit]
/*
** 2008 March 19
**
** 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.
**
*************************************************************************
** Code for testing all sorts of SQLite interfaces. This code
** implements new SQL functions used by the test scripts.
*/
#include "sqlite3.h"
#include "tcl.h"
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "sqliteInt.h"
#include "vdbeInt.h"
struct CursorHintGlobal {
Tcl_Interp *interp;
Tcl_Obj *pScript;
} cursorhintglobal;
static char *exprToString(Mem *aMem, Expr *pExpr){
char *zRet = 0;
char *zBinOp = 0;
switch( pExpr->op ){
case TK_STRING:
zRet = sqlite3_mprintf("%Q", pExpr->u.zToken);
break;
case TK_INTEGER:
zRet = sqlite3_mprintf("%d", pExpr->u.iValue);
break;
case TK_NULL:
zRet = sqlite3_mprintf("%s", "NULL");
break;
case TK_REGISTER: {
Mem *pMem = &aMem[pExpr->iTable];
if( pMem->flags & MEM_Int ){
zRet = sqlite3_mprintf("%lld", pMem->u.i);
}
else if( pMem->flags & MEM_Real ){
zRet = sqlite3_mprintf("%f", pMem->r);
}
else if( pMem->flags & MEM_Str ){
zRet = sqlite3_mprintf("%.*Q", pMem->n, pMem->z);
}
else if( pMem->flags & MEM_Blob ){
}
else{
zRet = sqlite3_mprintf("%s", "NULL");
}
break;
}
case TK_COLUMN: {
zRet = sqlite3_mprintf("col(%d)", (int)pExpr->iColumn);
break;
}
case TK_LT: zBinOp = "<"; break;
case TK_LE: zBinOp = "<="; break;
case TK_GT: zBinOp = ">"; break;
case TK_GE: zBinOp = ">="; break;
case TK_NE: zBinOp = "!="; break;
case TK_EQ: zBinOp = "=="; break;
case TK_IS: zBinOp = "IS"; break;
case TK_ISNOT: zBinOp = "IS NOT"; break;
case TK_AND: zBinOp = "AND"; break;
case TK_OR: zBinOp = "OR"; break;
case TK_PLUS: zBinOp = "+"; break;
case TK_STAR: zBinOp = "*"; break;
case TK_MINUS: zBinOp = "-"; break;
case TK_REM: zBinOp = "%"; break;
case TK_BITAND: zBinOp = "&"; break;
case TK_BITOR: zBinOp = "|"; break;
case TK_SLASH: zBinOp = "/"; break;
case TK_LSHIFT: zBinOp = "<<"; break;
case TK_RSHIFT: zBinOp = ">>"; break;
case TK_CONCAT: zBinOp = "||"; break;
default:
zRet = sqlite3_mprintf("%s", "expr");
break;
}
if( zBinOp ){
zRet = sqlite3_mprintf("(%z %s %z)",
exprToString(aMem, pExpr->pLeft),
zBinOp,
exprToString(aMem, pExpr->pRight)
);
}
return zRet;
}
void sqlite3BtreeCursorHintTest(Mem *aMem, Expr *pExpr){
if( cursorhintglobal.pScript ){
Tcl_Obj *pEval = Tcl_DuplicateObj(cursorhintglobal.pScript);
char *zExpr;
Tcl_Obj *pObj;
Tcl_IncrRefCount(pEval);
zExpr = exprToString(aMem, pExpr);
pObj = Tcl_NewStringObj(zExpr, -1);
sqlite3_free(zExpr);
Tcl_ListObjAppendElement(cursorhintglobal.interp, pEval, pObj);
Tcl_EvalObjEx(cursorhintglobal.interp, pEval, TCL_GLOBAL_ONLY);
Tcl_DecrRefCount(pEval);
}
}
/*
** Usage: cursorhint_hook SCRIPT
*/
static int install_cursorhint_hook(
ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int objc, /* Number of arguments */
Tcl_Obj *CONST objv[] /* Command arguments */
){
if( objc!=1 && objc!=2 ){
Tcl_WrongNumArgs(interp, 1, objv, "?SCRIPT?");
return TCL_ERROR;
}
if( cursorhintglobal.pScript ){
Tcl_DecrRefCount(cursorhintglobal.pScript);
memset(&cursorhintglobal, 0, sizeof(cursorhintglobal));
}
if( objc==2 ){
cursorhintglobal.interp = interp;
cursorhintglobal.pScript = Tcl_DuplicateObj(objv[1]);
}
return TCL_OK;
}
/*
** Register commands with the TCL interpreter.
*/
int Sqlitetest_cursorhint_Init(Tcl_Interp *interp){
static struct {
char *zName;
Tcl_ObjCmdProc *xProc;
} aObjCmd[] = {
{ "cursorhint_hook", install_cursorhint_hook },
};
int i;
for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){
Tcl_CreateObjCommand(interp, aObjCmd[i].zName, aObjCmd[i].xProc, 0, 0);
}
sqlite3_initialize();
return TCL_OK;
}