/* ** 2001 September 15 ** ** 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 the printf() interface to SQLite. This code ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. ** ** $Id: test1.c,v 1.16 2003/01/13 23:27:33 drh Exp $ */ #include "sqliteInt.h" #include "tcl.h" #include #include /* ** Usage: sqlite_open filename ** ** Returns: The name of an open database. */ static int sqlite_test_open( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ char **argv /* Text of each argument */ ){ sqlite *db; char *zErr = 0; char zBuf[100]; if( argc!=2 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " FILENAME\"", 0); return TCL_ERROR; } db = sqlite_open(argv[1], 0666, &zErr); if( db==0 ){ Tcl_AppendResult(interp, zErr, 0); free(zErr); return TCL_ERROR; } sprintf(zBuf,"%d",(int)db); Tcl_AppendResult(interp, zBuf, 0); return TCL_OK; } /* ** The callback routine for sqlite_exec_printf(). */ static int exec_printf_cb(void *pArg, int argc, char **argv, char **name){ Tcl_DString *str = (Tcl_DString*)pArg; int i; if( Tcl_DStringLength(str)==0 ){ for(i=0; in++; } } static void countFinalize(sqlite_func *context){ CountCtx *p; p = sqlite_aggregate_context(context, sizeof(*p)); sqlite_set_result_int(context, p ? p->n : 0); } /* ** Usage: sqlite_test_create_aggregate DB ** ** Call the sqlite_create_function API on the given database in order ** to create a function named "x_count". This function does the same thing ** as the "md5sum" function. ** ** The original motivation for this routine was to be able to call the ** sqlite_create_aggregate function while a query is in progress in order ** to test the SQLITE_MISUSE detection logic. */ static int test_create_aggregate( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ char **argv /* Text of each argument */ ){ sqlite *db; if( argc!=2 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " FILENAME\"", 0); return TCL_ERROR; } db = (sqlite*)strtol(argv[1], 0, 0); sqlite_create_aggregate(db, "x_count", 0, countStep, countFinalize, 0); sqlite_create_aggregate(db, "x_count", 1, countStep, countFinalize, 0); return TCL_OK; } /* ** Usage: sqlite_mprintf_int FORMAT INTEGER INTEGER INTEGER ** ** Call mprintf with three integer arguments */ static int sqlite_mprintf_int( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ char **argv /* Text of each argument */ ){ int a[3], i; char *z; if( argc!=5 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " FORMAT INT INT INT\"", 0); return TCL_ERROR; } for(i=2; i<5; i++){ if( Tcl_GetInt(interp, argv[i], &a[i-2]) ) return TCL_ERROR; } z = sqlite_mprintf(argv[1], a[0], a[1], a[2]); Tcl_AppendResult(interp, z, 0); sqlite_freemem(z); return TCL_OK; } /* ** Usage: sqlite_mprintf_str FORMAT INTEGER INTEGER STRING ** ** Call mprintf with two integer arguments and one string argument */ static int sqlite_mprintf_str( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ char **argv /* Text of each argument */ ){ int a[3], i; char *z; if( argc<4 || argc>5 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " FORMAT INT INT ?STRING?\"", 0); return TCL_ERROR; } for(i=2; i<4; i++){ if( Tcl_GetInt(interp, argv[i], &a[i-2]) ) return TCL_ERROR; } z = sqlite_mprintf(argv[1], a[0], a[1], argc>4 ? argv[4] : NULL); Tcl_AppendResult(interp, z, 0); sqlite_freemem(z); return TCL_OK; } /* ** Usage: sqlite_mprintf_str FORMAT INTEGER INTEGER DOUBLE ** ** Call mprintf with two integer arguments and one double argument */ static int sqlite_mprintf_double( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ char **argv /* Text of each argument */ ){ int a[3], i; double r; char *z; if( argc!=5 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " FORMAT INT INT STRING\"", 0); return TCL_ERROR; } for(i=2; i<4; i++){ if( Tcl_GetInt(interp, argv[i], &a[i-2]) ) return TCL_ERROR; } if( Tcl_GetDouble(interp, argv[4], &r) ) return TCL_ERROR; z = sqlite_mprintf(argv[1], a[0], a[1], r); Tcl_AppendResult(interp, z, 0); sqlite_freemem(z); return TCL_OK; } /* ** Usage: sqlite_malloc_fail N ** ** Rig sqliteMalloc() to fail on the N-th call. Turn off this mechanism ** and reset the sqlite_malloc_failed variable is N==0. */ #ifdef MEMORY_DEBUG static int sqlite_malloc_fail( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ char **argv /* Text of each argument */ ){ int n; if( argc!=2 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " N\"", 0); return TCL_ERROR; } if( Tcl_GetInt(interp, argv[1], &n) ) return TCL_ERROR; sqlite_iMallocFail = n; sqlite_malloc_failed = 0; return TCL_OK; } #endif /* ** Usage: sqlite_malloc_stat ** ** Return the number of prior calls to sqliteMalloc() and sqliteFree(). */ #ifdef MEMORY_DEBUG static int sqlite_malloc_stat( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ char **argv /* Text of each argument */ ){ char zBuf[200]; sprintf(zBuf, "%d %d %d", sqlite_nMalloc, sqlite_nFree, sqlite_iMallocFail); Tcl_AppendResult(interp, zBuf, 0); return TCL_OK; } #endif /* ** Usage: sqlite_abort ** ** Shutdown the process immediately. This is not a clean shutdown. ** This command is used to test the recoverability of a database in ** the event of a program crash. */ static int sqlite_abort( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ char **argv /* Text of each argument */ ){ assert( interp==0 ); /* This will always fail */ return TCL_OK; } /* ** The following routine is a user-defined SQL function whose purpose ** is to test the sqlite_set_result() API. */ static void testFunc(sqlite_func *context, int argc, const char **argv){ while( argc>=2 ){ if( argv[0]==0 ){ sqlite_set_result_error(context, "first argument to test function " "may not be NULL", -1); }else if( sqliteStrICmp(argv[0],"string")==0 ){ sqlite_set_result_string(context, argv[1], -1); }else if( argv[1]==0 ){ sqlite_set_result_error(context, "2nd argument may not be NULL if the " "first argument is not \"string\"", -1); }else if( sqliteStrICmp(argv[0],"int")==0 ){ sqlite_set_result_int(context, atoi(argv[1])); }else if( sqliteStrICmp(argv[0],"double")==0 ){ sqlite_set_result_double(context, atof(argv[1])); }else{ sqlite_set_result_error(context,"first argument should be one of: " "string int double", -1); } argc -= 2; argv += 2; } } /* ** Usage: sqlite_register_test_function DB NAME ** ** Register the test SQL function on the database DB under the name NAME. */ static int test_register_func( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ char **argv /* Text of each argument */ ){ sqlite *db; int rc; if( argc!=3 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " DB FUNCTION-NAME", 0); return TCL_ERROR; } db = (sqlite*)strtol(argv[1], 0, 0); rc = sqlite_create_function(db, argv[2], -1, testFunc, 0); if( rc!=0 ){ Tcl_AppendResult(interp, sqlite_error_string(rc), 0); return TCL_ERROR; } return TCL_OK; } /* ** This SQLite callback records the datatype of all columns. ** ** The pArg argument is really a pointer to a TCL interpreter. The ** column names are inserted as the result of this interpreter. ** ** This routine returns non-zero which causes the query to abort. */ static int rememberDataTypes(void *pArg, int nCol, char **argv, char **colv){ int i; Tcl_Interp *interp = (Tcl_Interp*)pArg; Tcl_Obj *pList, *pElem; if( colv[nCol+1]==0 ){ return 1; } pList = Tcl_NewObj(); for(i=0; isizeof(authInfo.zCmd) ){ Tcl_AppendResult(interp, "command too big", 0); return TCL_ERROR; } authInfo.interp = interp; authInfo.nCmd = strlen(zCmd); strcpy(authInfo.zCmd, zCmd); sqlite_set_authorizer(db, auth_callback, 0); return TCL_OK; } #endif /* SQLITE_OMIT_AUTHORIZATION */ /* ** Register commands with the TCL interpreter. */ int Sqlitetest1_Init(Tcl_Interp *interp){ extern int sqlite_search_count; static struct { char *zName; Tcl_CmdProc *xProc; } aCmd[] = { { "sqlite_mprintf_int", (Tcl_CmdProc*)sqlite_mprintf_int }, { "sqlite_mprintf_str", (Tcl_CmdProc*)sqlite_mprintf_str }, { "sqlite_mprintf_double", (Tcl_CmdProc*)sqlite_mprintf_double }, { "sqlite_open", (Tcl_CmdProc*)sqlite_test_open }, { "sqlite_last_insert_rowid", (Tcl_CmdProc*)test_last_rowid }, { "sqlite_exec_printf", (Tcl_CmdProc*)test_exec_printf }, { "sqlite_get_table_printf", (Tcl_CmdProc*)test_get_table_printf }, { "sqlite_close", (Tcl_CmdProc*)sqlite_test_close }, { "sqlite_create_function", (Tcl_CmdProc*)test_create_function }, { "sqlite_create_aggregate", (Tcl_CmdProc*)test_create_aggregate }, { "sqlite_register_test_function", (Tcl_CmdProc*)test_register_func }, { "sqlite_abort", (Tcl_CmdProc*)sqlite_abort }, { "sqlite_datatypes", (Tcl_CmdProc*)sqlite_datatypes }, #ifndef SQLITE_OMIT_AUTHORIZATION { "sqlite_set_authorizer", (Tcl_CmdProc*)test_set_authorizer }, #endif #ifdef MEMORY_DEBUG { "sqlite_malloc_fail", (Tcl_CmdProc*)sqlite_malloc_fail }, { "sqlite_malloc_stat", (Tcl_CmdProc*)sqlite_malloc_stat }, #endif }; int i; for(i=0; i