📄 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 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.130 2005/02/17 00:03:07 drh Exp $*/#include "sqliteInt.h"#include "tcl.h"#include "os.h"#include <stdlib.h>#include <string.h>static const char * errorName(int rc){ const char *zName = 0; switch( rc ){ case SQLITE_OK: zName = "SQLITE_OK"; break; case SQLITE_ERROR: zName = "SQLITE_ERROR"; break; case SQLITE_INTERNAL: zName = "SQLITE_INTERNAL"; 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_NOTFOUND: zName = "SQLITE_NOTFOUND"; 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_TOOBIG: zName = "SQLITE_TOOBIG"; 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;}/*** 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**)(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)", errorName(rc), rc, errorName(r2), r2); Tcl_ResetResult(interp); Tcl_AppendResult(interp, zBuf, 0); return 1; } return 0;}/*** Decode a pointer to an sqlite3 object.*/static int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb){ *ppDb = (sqlite3*)sqlite3TextToPtr(zA); return TCL_OK;}/*** 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.*/static int makePointerStr(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;}/*** 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 ) free(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 mprintf(). 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_get_table_printf DB FORMAT STRING**** Invoke the sqlite3_get_table_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_get_table_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; int nRow, nCol; char **aResult; int i; char zBuf[30]; char *zSql; 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_get_table(db, zSql, &aResult, &nRow, &nCol, &zErr); sqlite3_free(zSql); sprintf(zBuf, "%d", rc); Tcl_AppendElement(interp, zBuf); if( rc==SQLITE_OK ){ sprintf(zBuf, "%d", nRow); Tcl_AppendElement(interp, zBuf); sprintf(zBuf, "%d", nCol); Tcl_AppendElement(interp, zBuf); for(i=0; i<(nRow+1)*nCol; i++){ Tcl_AppendElement(interp, aResult[i] ? aResult[i] : "NULL"); } }else{ Tcl_AppendElement(interp, zErr); } sqlite3_free_table(aResult); if( zErr ) free(zErr); if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR; return TCL_OK;}/*** Usage: sqlite3_last_insert_rowid DB**** Returns the integer ROWID of the most recent insert.*/static int test_last_rowid( 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; char zBuf[30]; if( argc!=2 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " DB\"", 0); return TCL_ERROR; } if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; sprintf(zBuf, "%lld", sqlite3_last_insert_rowid(db)); Tcl_AppendResult(interp, zBuf, 0); return SQLITE_OK;}/*** Usage: sqlite3_key DB KEY**** Set the codec key.*/static int test_key( 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; const char *zKey; int nKey; if( argc!=3 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " FILENAME\"", 0); return TCL_ERROR; } if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; zKey = argv[2]; nKey = strlen(zKey);#ifdef SQLITE_HAS_CODEC sqlite3_key(db, zKey, nKey);#endif return TCL_OK;}/*** Usage: sqlite3_rekey DB KEY**** Change the codec key.*/static int test_rekey( 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; const char *zKey; int nKey; if( argc!=3 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " FILENAME\"", 0); return TCL_ERROR; } if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; zKey = argv[2]; nKey = strlen(zKey);#ifdef SQLITE_HAS_CODEC sqlite3_rekey(db, zKey, nKey);#endif return TCL_OK;}/*** Usage: sqlite3_close DB**** Closes the database opened by sqlite3_open.*/static int sqlite_test_close( 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; if( argc!=2 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " FILENAME\"", 0); return TCL_ERROR; } if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; rc = sqlite3_close(db); Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC); return TCL_OK;}/*** Implementation of the x_coalesce() function.** Return the first argument non-NULL argument.*/static void ifnullFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ int i; for(i=0; i<argc; i++){ if( SQLITE_NULL!=sqlite3_value_type(argv[i]) ){ sqlite3_result_text(context, sqlite3_value_text(argv[i]), -1, SQLITE_TRANSIENT); break; } }}/*** A structure into which to accumulate text.*/struct dstr { int nAlloc; /* Space allocated */ int nUsed; /* Space used */ char *z; /* The space */};/*** Append text to a dstr*/static void dstrAppend(struct dstr *p, const char *z, int divider){ int n = strlen(z); if( p->nUsed + n + 2 > p->nAlloc ){ char *zNew; p->nAlloc = p->nAlloc*2 + n + 200; zNew = sqliteRealloc(p->z, p->nAlloc); if( zNew==0 ){ sqliteFree(p->z); memset(p, 0, sizeof(*p)); return; } p->z = zNew; } if( divider && p->nUsed>0 ){ p->z[p->nUsed++] = divider; } memcpy(&p->z[p->nUsed], z, n+1); p->nUsed += n;}/*** Invoked for each callback from sqlite3ExecFunc*/static int execFuncCallback(void *pData, int argc, char **argv, char **NotUsed){ struct dstr *p = (struct dstr*)pData; int i; for(i=0; i<argc; i++){ if( argv[i]==0 ){ dstrAppend(p, "NULL", ' '); }else{ dstrAppend(p, argv[i], ' '); } } return 0;}/*** Implementation of the x_sqlite_exec() function. This function takes** a single argument and attempts to execute that argument as SQL code.** This is illegal and should set the SQLITE_MISUSE flag on the database.**** 2004-Jan-07: We have changed this to make it legal to call sqlite3_exec()** from within a function call. ** ** This routine simulates the effect of having two threads attempt to** use the same database at the same time.*/static void sqlite3ExecFunc( sqlite3_context *context, int argc, sqlite3_value **argv){ struct dstr x; memset(&x, 0, sizeof(x)); sqlite3_exec((sqlite3*)sqlite3_user_data(context), sqlite3_value_text(argv[0]), execFuncCallback, &x, 0); sqlite3_result_text(context, x.z, x.nUsed, SQLITE_TRANSIENT); sqliteFree(x.z);}/*** Usage: sqlite_test_create_function DB**** Call the sqlite3_create_function API on the given database in order** to create a function named "x_coalesce". This function does the same thing** as the "coalesce" function. This function also registers an SQL function** named "x_sqlite_exec" that invokes sqlite3_exec(). Invoking sqlite3_exec()** in this way is illegal recursion and should raise an SQLITE_MISUSE error.** The effect is similar to trying to use the same database connection from** two threads at the same time.**
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -