📄 test1.c
字号:
/*** 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 all sorts of SQLite interfaces. This code** is not included in the SQLite library. It is used for automated** testing of the SQLite library.**** $Id: test1.c,v 1.258 2007/06/26 00:37:28 drh Exp $*/#include "sqliteInt.h"#include "tcl.h"#include "os.h"#include <stdlib.h>#include <string.h>/*** This is a copy of the first part of the SqliteDb structure in ** tclsqlite.c. We need it here so that the get_sqlite_pointer routine** can extract the sqlite3* pointer from an existing Tcl SQLite** connection.*/struct SqliteDb { sqlite3 *db;};/*** Convert text generated by the "%p" conversion format back into** a pointer.*/static int testHexToInt(int h){ if( h>='0' && h<='9' ){ return h - '0'; }else if( h>='a' && h<='f' ){ return h - 'a' + 10; }else{ assert( h>='A' && h<='F' ); return h - 'A' + 10; }}void *sqlite3TextToPtr(const char *z){ void *p; u64 v; u32 v2; if( z[0]=='0' && z[1]=='x' ){ z += 2; } v = 0; while( *z ){ v = (v<<4) + testHexToInt(*z); z++; } if( sizeof(p)==sizeof(v) ){ memcpy(&p, &v, sizeof(p)); }else{ assert( sizeof(p)==sizeof(v2) ); v2 = (u32)v; memcpy(&p, &v2, sizeof(p)); } return p;}/*** A TCL command that returns the address of the sqlite* pointer** for an sqlite connection instance. Bad things happen if the** input is not an sqlite connection.*/static int get_sqlite_pointer( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]){ struct SqliteDb *p; Tcl_CmdInfo cmdInfo; char zBuf[100]; if( objc!=2 ){ Tcl_WrongNumArgs(interp, 1, objv, "SQLITE-CONNECTION"); return TCL_ERROR; } if( !Tcl_GetCommandInfo(interp, Tcl_GetString(objv[1]), &cmdInfo) ){ Tcl_AppendResult(interp, "command not found: ", Tcl_GetString(objv[1]), (char*)0); return TCL_ERROR; } p = (struct SqliteDb*)cmdInfo.objClientData; sprintf(zBuf, "%p", p->db); if( strncmp(zBuf,"0x",2) ){ sprintf(zBuf, "0x%p", p->db); } Tcl_AppendResult(interp, zBuf, 0); return TCL_OK;}/*** Decode a pointer to an sqlite3 object.*/static int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb){ struct SqliteDb *p; Tcl_CmdInfo cmdInfo; if( Tcl_GetCommandInfo(interp, zA, &cmdInfo) ){ p = (struct SqliteDb*)cmdInfo.objClientData; *ppDb = p->db; }else{ *ppDb = (sqlite3*)sqlite3TextToPtr(zA); } return TCL_OK;}const char *sqlite3TestErrorName(int rc){ const char *zName = 0; switch( rc & 0xff ){ case SQLITE_OK: zName = "SQLITE_OK"; break; case SQLITE_ERROR: zName = "SQLITE_ERROR"; break; case SQLITE_PERM: zName = "SQLITE_PERM"; break; case SQLITE_ABORT: zName = "SQLITE_ABORT"; break; case SQLITE_BUSY: zName = "SQLITE_BUSY"; break; case SQLITE_LOCKED: zName = "SQLITE_LOCKED"; break; case SQLITE_NOMEM: zName = "SQLITE_NOMEM"; break; case SQLITE_READONLY: zName = "SQLITE_READONLY"; break; case SQLITE_INTERRUPT: zName = "SQLITE_INTERRUPT"; break; case SQLITE_IOERR: zName = "SQLITE_IOERR"; break; case SQLITE_CORRUPT: zName = "SQLITE_CORRUPT"; break; case SQLITE_FULL: zName = "SQLITE_FULL"; break; case SQLITE_CANTOPEN: zName = "SQLITE_CANTOPEN"; break; case SQLITE_PROTOCOL: zName = "SQLITE_PROTOCOL"; break; case SQLITE_EMPTY: zName = "SQLITE_EMPTY"; break; case SQLITE_SCHEMA: zName = "SQLITE_SCHEMA"; break; case SQLITE_CONSTRAINT: zName = "SQLITE_CONSTRAINT"; break; case SQLITE_MISMATCH: zName = "SQLITE_MISMATCH"; break; case SQLITE_MISUSE: zName = "SQLITE_MISUSE"; break; case SQLITE_NOLFS: zName = "SQLITE_NOLFS"; break; case SQLITE_AUTH: zName = "SQLITE_AUTH"; break; case SQLITE_FORMAT: zName = "SQLITE_FORMAT"; break; case SQLITE_RANGE: zName = "SQLITE_RANGE"; break; case SQLITE_ROW: zName = "SQLITE_ROW"; break; case SQLITE_DONE: zName = "SQLITE_DONE"; break; case SQLITE_NOTADB: zName = "SQLITE_NOTADB"; break; default: zName = "SQLITE_Unknown"; break; } return zName;}#define t1ErrorName sqlite3TestErrorName/*** Convert an sqlite3_stmt* into an sqlite3*. This depends on the** fact that the sqlite3* is the first field in the Vdbe structure.*/#define StmtToDb(X) sqlite3_db_handle(X)/*** Check a return value to make sure it agrees with the results** from sqlite3_errcode.*/int sqlite3TestErrCode(Tcl_Interp *interp, sqlite3 *db, int rc){ if( rc!=SQLITE_MISUSE && rc!=SQLITE_OK && sqlite3_errcode(db)!=rc ){ char zBuf[200]; int r2 = sqlite3_errcode(db); sprintf(zBuf, "error code %s (%d) does not match sqlite3_errcode %s (%d)", t1ErrorName(rc), rc, t1ErrorName(r2), r2); Tcl_ResetResult(interp); Tcl_AppendResult(interp, zBuf, 0); return 1; } return 0;}/*** Decode a pointer to an sqlite3_stmt object.*/static int getStmtPointer( Tcl_Interp *interp, const char *zArg, sqlite3_stmt **ppStmt){ *ppStmt = (sqlite3_stmt*)sqlite3TextToPtr(zArg); return TCL_OK;}/*** Decode a pointer to an sqlite3_stmt object.*/static int getFilePointer( Tcl_Interp *interp, const char *zArg, OsFile **ppFile){ *ppFile = (OsFile*)sqlite3TextToPtr(zArg); return TCL_OK;}/*** Generate a text representation of a pointer that can be understood** by the getDbPointer and getVmPointer routines above.**** The problem is, on some machines (Solaris) if you do a printf with** "%p" you cannot turn around and do a scanf with the same "%p" and** get your pointer back. You have to prepend a "0x" before it will** work. Or at least that is what is reported to me (drh). But this** behavior varies from machine to machine. The solution used her is** to test the string right after it is generated to see if it can be** understood by scanf, and if not, try prepending an "0x" to see if** that helps. If nothing works, a fatal error is generated.*/int sqlite3TestMakePointerStr(Tcl_Interp *interp, char *zPtr, void *p){ sqlite3_snprintf(100, zPtr, "%p", p); return TCL_OK;}/*** The callback routine for sqlite3_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; i<argc; i++){ Tcl_DStringAppendElement(str, name[i] ? name[i] : "NULL"); } } for(i=0; i<argc; i++){ Tcl_DStringAppendElement(str, argv[i] ? argv[i] : "NULL"); } return 0;}/*** The I/O tracing callback.*/static FILE *iotrace_file = 0;static void io_trace_callback(const char *zFormat, ...){ va_list ap; va_start(ap, zFormat); vfprintf(iotrace_file, zFormat, ap); va_end(ap); fflush(iotrace_file);}/*** Usage: io_trace FILENAME**** Turn I/O tracing on or off. If FILENAME is not an empty string,** I/O tracing begins going into FILENAME. If FILENAME is an empty** string, I/O tracing is turned off.*/static int test_io_trace( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ char **argv /* Text of each argument */){ if( argc!=2 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " FILENAME\"", 0); return TCL_ERROR; } if( iotrace_file ){ if( iotrace_file!=stdout && iotrace_file!=stderr ){ fclose(iotrace_file); } iotrace_file = 0; sqlite3_io_trace = 0; } if( argv[1][0] ){ if( strcmp(argv[1],"stdout")==0 ){ iotrace_file = stdout; }else if( strcmp(argv[1],"stderr")==0 ){ iotrace_file = stderr; }else{ iotrace_file = fopen(argv[1], "w"); } sqlite3_io_trace = io_trace_callback; } return SQLITE_OK;}/*** Usage: sqlite3_exec_printf DB FORMAT STRING**** Invoke the sqlite3_exec_printf() interface using the open database** DB. The SQL is the string FORMAT. The format string should contain** one %s or %q. STRING is the value inserted into %s or %q.*/static int test_exec_printf( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ char **argv /* Text of each argument */){ sqlite3 *db; Tcl_DString str; int rc; char *zErr = 0; char *zSql; char zBuf[30]; if( argc!=4 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " DB FORMAT STRING", 0); return TCL_ERROR; } if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; Tcl_DStringInit(&str); zSql = sqlite3_mprintf(argv[2], argv[3]); rc = sqlite3_exec(db, zSql, exec_printf_cb, &str, &zErr); sqlite3_free(zSql); sprintf(zBuf, "%d", rc); Tcl_AppendElement(interp, zBuf); Tcl_AppendElement(interp, rc==SQLITE_OK ? Tcl_DStringValue(&str) : zErr); Tcl_DStringFree(&str); if( zErr ) sqlite3_free(zErr); if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR; return TCL_OK;}/*** Usage: sqlite3_exec DB SQL**** Invoke the sqlite3_exec interface using the open database DB*/static int test_exec( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ char **argv /* Text of each argument */){ sqlite3 *db; Tcl_DString str; int rc; char *zErr = 0; char *zSql; int i, j; char zBuf[30]; if( argc!=3 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " DB SQL", 0); return TCL_ERROR; } if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; Tcl_DStringInit(&str); zSql = sqlite3_mprintf("%s", argv[2]); for(i=j=0; zSql[i];){ if( zSql[i]=='%' ){ zSql[j++] = (testHexToInt(zSql[i+1])<<4) + testHexToInt(zSql[i+2]); i += 3; }else{ zSql[j++] = zSql[i++]; } } zSql[j] = 0; rc = sqlite3_exec(db, zSql, exec_printf_cb, &str, &zErr); sqlite3_free(zSql); sprintf(zBuf, "%d", rc); Tcl_AppendElement(interp, zBuf); Tcl_AppendElement(interp, rc==SQLITE_OK ? Tcl_DStringValue(&str) : zErr); Tcl_DStringFree(&str); if( zErr ) sqlite3_free(zErr); if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR; return TCL_OK;}/*** Usage: sqlite3_exec_nr DB SQL**** Invoke the sqlite3_exec interface using the open database DB. Discard** all results*/static int test_exec_nr( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ char **argv /* Text of each argument */){ sqlite3 *db; int rc; char *zErr = 0; if( argc!=3 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " DB SQL", 0); return TCL_ERROR; } if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; rc = sqlite3_exec(db, argv[2], 0, 0, &zErr); if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR; return TCL_OK;}/*** Usage: sqlite3_mprintf_z_test SEPARATOR ARG0 ARG1 ...**** Test the %z format of sqliteMPrintf(). Use multiple mprintf() calls to ** concatenate arg0 through argn using separator as the separator.** Return the result.*/static int test_mprintf_z( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ char **argv /* Text of each argument */){ char *zResult = 0; int i; for(i=2; i<argc; i++){ zResult = sqlite3MPrintf("%z%s%s", zResult, argv[1], argv[i]); } Tcl_AppendResult(interp, zResult, 0); sqliteFree(zResult); return TCL_OK;}/*** Usage: sqlite3_mprintf_n_test STRING**** Test the %n format of sqliteMPrintf(). Return the length of the** input string.*/static int test_mprintf_n( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ char **argv /* Text of each argument */){ char *zStr; int n = 0; zStr = sqlite3MPrintf("%s%n", argv[1], &n); sqliteFree(zStr); Tcl_SetObjResult(interp, Tcl_NewIntObj(n)); return TCL_OK;}/*** Usage: sqlite3_snprintf_int SIZE FORMAT INT**** Test the of sqlite3_snprintf() routine. SIZE is the size of the** output buffer in bytes. The maximum size is 100. FORMAT is the** format string. INT is a single integer argument. The FORMAT** string must require no more than this one integer argument. If** You pass in a format string that requires more than one argument,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -