| /* |
| ** 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; |
| } |