2N/A
2N/A#pragma ident "%Z%%M% %I% %E% SMI"
2N/A
2N/A/*
2N/A** 2001 September 15
2N/A**
2N/A** The author disclaims copyright to this source code. In place of
2N/A** a legal notice, here is a blessing:
2N/A**
2N/A** May you do good and not evil.
2N/A** May you find forgiveness for yourself and forgive others.
2N/A** May you share freely, never taking more than you give.
2N/A**
2N/A*************************************************************************
2N/A** Code for testing the printf() interface to SQLite. This code
2N/A** is not included in the SQLite library. It is used for automated
2N/A** testing of the SQLite library.
2N/A**
2N/A** $Id: test1.c,v 1.36.2.1 2004/05/07 00:57:06 drh Exp $
2N/A*/
2N/A#include "sqliteInt.h"
2N/A#include "tcl.h"
2N/A#include "os.h"
2N/A#include <stdlib.h>
2N/A#include <string.h>
2N/A
2N/A#if OS_WIN
2N/A# define PTR_FMT "%x"
2N/A#else
2N/A# define PTR_FMT "%p"
2N/A#endif
2N/A
2N/A/*
2N/A** Decode a pointer to an sqlite object.
2N/A*/
2N/Astatic int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite **ppDb){
2N/A if( sscanf(zA, PTR_FMT, (void**)ppDb)!=1 &&
2N/A (zA[0]!='0' || zA[1]!='x' || sscanf(&zA[2], PTR_FMT, (void**)ppDb)!=1)
2N/A ){
2N/A Tcl_AppendResult(interp, "\"", zA, "\" is not a valid pointer value", 0);
2N/A return TCL_ERROR;
2N/A }
2N/A return TCL_OK;
2N/A}
2N/A
2N/A/*
2N/A** Decode a pointer to an sqlite_vm object.
2N/A*/
2N/Astatic int getVmPointer(Tcl_Interp *interp, const char *zArg, sqlite_vm **ppVm){
2N/A if( sscanf(zArg, PTR_FMT, (void**)ppVm)!=1 ){
2N/A Tcl_AppendResult(interp, "\"", zArg, "\" is not a valid pointer value", 0);
2N/A return TCL_ERROR;
2N/A }
2N/A return TCL_OK;
2N/A}
2N/A
2N/A/*
2N/A** Generate a text representation of a pointer that can be understood
2N/A** by the getDbPointer and getVmPointer routines above.
2N/A**
2N/A** The problem is, on some machines (Solaris) if you do a printf with
2N/A** "%p" you cannot turn around and do a scanf with the same "%p" and
2N/A** get your pointer back. You have to prepend a "0x" before it will
2N/A** work. Or at least that is what is reported to me (drh). But this
2N/A** behavior varies from machine to machine. The solution used her is
2N/A** to test the string right after it is generated to see if it can be
2N/A** understood by scanf, and if not, try prepending an "0x" to see if
2N/A** that helps. If nothing works, a fatal error is generated.
2N/A*/
2N/Astatic int makePointerStr(Tcl_Interp *interp, char *zPtr, void *p){
2N/A void *p2;
2N/A sprintf(zPtr, PTR_FMT, p);
2N/A if( sscanf(zPtr, PTR_FMT, &p2)!=1 || p2!=p ){
2N/A sprintf(zPtr, "0x" PTR_FMT, p);
2N/A if( sscanf(zPtr, PTR_FMT, &p2)!=1 || p2!=p ){
2N/A Tcl_AppendResult(interp, "unable to convert a pointer to a string "
2N/A "in the file " __FILE__ " in function makePointerStr(). Please "
2N/A "report this problem to the SQLite mailing list or as a new but "
2N/A "report. Please provide detailed information about how you compiled "
2N/A "SQLite and what computer you are running on.", 0);
2N/A return TCL_ERROR;
2N/A }
2N/A }
2N/A return TCL_OK;
2N/A}
2N/A
2N/A/*
2N/A** Usage: sqlite_open filename
2N/A**
2N/A** Returns: The name of an open database.
2N/A*/
2N/Astatic int sqlite_test_open(
2N/A void *NotUsed,
2N/A Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
2N/A int argc, /* Number of arguments */
2N/A char **argv /* Text of each argument */
2N/A){
2N/A sqlite *db;
2N/A char *zErr = 0;
2N/A char zBuf[100];
2N/A if( argc!=2 ){
2N/A Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
2N/A " FILENAME\"", 0);
2N/A return TCL_ERROR;
2N/A }
2N/A db = sqlite_open(argv[1], 0666, &zErr);
2N/A if( db==0 ){
2N/A Tcl_AppendResult(interp, zErr, 0);
2N/A free(zErr);
2N/A return TCL_ERROR;
2N/A }
2N/A if( makePointerStr(interp, zBuf, db) ) return TCL_ERROR;
2N/A Tcl_AppendResult(interp, zBuf, 0);
2N/A return TCL_OK;
2N/A}
2N/A
2N/A/*
2N/A** The callback routine for sqlite_exec_printf().
2N/A*/
2N/Astatic int exec_printf_cb(void *pArg, int argc, char **argv, char **name){
2N/A Tcl_DString *str = (Tcl_DString*)pArg;
2N/A int i;
2N/A
2N/A if( Tcl_DStringLength(str)==0 ){
2N/A for(i=0; i<argc; i++){
2N/A Tcl_DStringAppendElement(str, name[i] ? name[i] : "NULL");
2N/A }
2N/A }
2N/A for(i=0; i<argc; i++){
2N/A Tcl_DStringAppendElement(str, argv[i] ? argv[i] : "NULL");
2N/A }
2N/A return 0;
2N/A}
2N/A
2N/A/*
2N/A** Usage: sqlite_exec_printf DB FORMAT STRING
2N/A**
2N/A** Invoke the sqlite_exec_printf() interface using the open database
2N/A** DB. The SQL is the string FORMAT. The format string should contain
2N/A** one %s or %q. STRING is the value inserted into %s or %q.
2N/A*/
2N/Astatic int test_exec_printf(
2N/A void *NotUsed,
2N/A Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
2N/A int argc, /* Number of arguments */
2N/A char **argv /* Text of each argument */
2N/A){
2N/A sqlite *db;
2N/A Tcl_DString str;
2N/A int rc;
2N/A char *zErr = 0;
2N/A char zBuf[30];
2N/A if( argc!=4 ){
2N/A Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
2N/A " DB FORMAT STRING", 0);
2N/A return TCL_ERROR;
2N/A }
2N/A if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
2N/A Tcl_DStringInit(&str);
2N/A rc = sqlite_exec_printf(db, argv[2], exec_printf_cb, &str, &zErr, argv[3]);
2N/A sprintf(zBuf, "%d", rc);
2N/A Tcl_AppendElement(interp, zBuf);
2N/A Tcl_AppendElement(interp, rc==SQLITE_OK ? Tcl_DStringValue(&str) : zErr);
2N/A Tcl_DStringFree(&str);
2N/A if( zErr ) free(zErr);
2N/A return TCL_OK;
2N/A}
2N/A
2N/A/*
2N/A** Usage: sqlite_mprintf_z_test SEPARATOR ARG0 ARG1 ...
2N/A**
2N/A** Test the %z format of mprintf(). Use multiple mprintf() calls to
2N/A** concatenate arg0 through argn using separator as the separator.
2N/A** Return the result.
2N/A*/
2N/Astatic int test_mprintf_z(
2N/A void *NotUsed,
2N/A Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
2N/A int argc, /* Number of arguments */
2N/A char **argv /* Text of each argument */
2N/A){
2N/A char *zResult = 0;
2N/A int i;
2N/A
2N/A for(i=2; i<argc; i++){
2N/A zResult = sqliteMPrintf("%z%s%s", zResult, argv[1], argv[i]);
2N/A }
2N/A Tcl_AppendResult(interp, zResult, 0);
2N/A sqliteFree(zResult);
2N/A return TCL_OK;
2N/A}
2N/A
2N/A/*
2N/A** Usage: sqlite_get_table_printf DB FORMAT STRING
2N/A**
2N/A** Invoke the sqlite_get_table_printf() interface using the open database
2N/A** DB. The SQL is the string FORMAT. The format string should contain
2N/A** one %s or %q. STRING is the value inserted into %s or %q.
2N/A*/
2N/Astatic int test_get_table_printf(
2N/A void *NotUsed,
2N/A Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
2N/A int argc, /* Number of arguments */
2N/A char **argv /* Text of each argument */
2N/A){
2N/A sqlite *db;
2N/A Tcl_DString str;
2N/A int rc;
2N/A char *zErr = 0;
2N/A int nRow, nCol;
2N/A char **aResult;
2N/A int i;
2N/A char zBuf[30];
2N/A if( argc!=4 ){
2N/A Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
2N/A " DB FORMAT STRING", 0);
2N/A return TCL_ERROR;
2N/A }
2N/A if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
2N/A Tcl_DStringInit(&str);
2N/A rc = sqlite_get_table_printf(db, argv[2], &aResult, &nRow, &nCol,
2N/A &zErr, argv[3]);
2N/A sprintf(zBuf, "%d", rc);
2N/A Tcl_AppendElement(interp, zBuf);
2N/A if( rc==SQLITE_OK ){
2N/A sprintf(zBuf, "%d", nRow);
2N/A Tcl_AppendElement(interp, zBuf);
2N/A sprintf(zBuf, "%d", nCol);
2N/A Tcl_AppendElement(interp, zBuf);
2N/A for(i=0; i<(nRow+1)*nCol; i++){
2N/A Tcl_AppendElement(interp, aResult[i] ? aResult[i] : "NULL");
2N/A }
2N/A }else{
2N/A Tcl_AppendElement(interp, zErr);
2N/A }
2N/A sqlite_free_table(aResult);
2N/A if( zErr ) free(zErr);
2N/A return TCL_OK;
2N/A}
2N/A
2N/A
2N/A/*
2N/A** Usage: sqlite_last_insert_rowid DB
2N/A**
2N/A** Returns the integer ROWID of the most recent insert.
2N/A*/
2N/Astatic int test_last_rowid(
2N/A void *NotUsed,
2N/A Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
2N/A int argc, /* Number of arguments */
2N/A char **argv /* Text of each argument */
2N/A){
2N/A sqlite *db;
2N/A char zBuf[30];
2N/A
2N/A if( argc!=2 ){
2N/A Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " DB\"", 0);
2N/A return TCL_ERROR;
2N/A }
2N/A if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
2N/A sprintf(zBuf, "%d", sqlite_last_insert_rowid(db));
2N/A Tcl_AppendResult(interp, zBuf, 0);
2N/A return SQLITE_OK;
2N/A}
2N/A
2N/A/*
2N/A** Usage: sqlite_close DB
2N/A**
2N/A** Closes the database opened by sqlite_open.
2N/A*/
2N/Astatic int sqlite_test_close(
2N/A void *NotUsed,
2N/A Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
2N/A int argc, /* Number of arguments */
2N/A char **argv /* Text of each argument */
2N/A){
2N/A sqlite *db;
2N/A if( argc!=2 ){
2N/A Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
2N/A " FILENAME\"", 0);
2N/A return TCL_ERROR;
2N/A }
2N/A if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
2N/A sqlite_close(db);
2N/A return TCL_OK;
2N/A}
2N/A
2N/A/*
2N/A** Implementation of the x_coalesce() function.
2N/A** Return the first argument non-NULL argument.
2N/A*/
2N/Astatic void ifnullFunc(sqlite_func *context, int argc, const char **argv){
2N/A int i;
2N/A for(i=0; i<argc; i++){
2N/A if( argv[i] ){
2N/A sqlite_set_result_string(context, argv[i], -1);
2N/A break;
2N/A }
2N/A }
2N/A}
2N/A
2N/A/*
2N/A** A structure into which to accumulate text.
2N/A*/
2N/Astruct dstr {
2N/A int nAlloc; /* Space allocated */
2N/A int nUsed; /* Space used */
2N/A char *z; /* The space */
2N/A};
2N/A
2N/A/*
2N/A** Append text to a dstr
2N/A*/
2N/Astatic void dstrAppend(struct dstr *p, const char *z, int divider){
2N/A int n = strlen(z);
2N/A if( p->nUsed + n + 2 > p->nAlloc ){
2N/A char *zNew;
2N/A p->nAlloc = p->nAlloc*2 + n + 200;
2N/A zNew = sqliteRealloc(p->z, p->nAlloc);
2N/A if( zNew==0 ){
2N/A sqliteFree(p->z);
2N/A memset(p, 0, sizeof(*p));
2N/A return;
2N/A }
2N/A p->z = zNew;
2N/A }
2N/A if( divider && p->nUsed>0 ){
2N/A p->z[p->nUsed++] = divider;
2N/A }
2N/A memcpy(&p->z[p->nUsed], z, n+1);
2N/A p->nUsed += n;
2N/A}
2N/A
2N/A/*
2N/A** Invoked for each callback from sqliteExecFunc
2N/A*/
2N/Astatic int execFuncCallback(void *pData, int argc, char **argv, char **NotUsed){
2N/A struct dstr *p = (struct dstr*)pData;
2N/A int i;
2N/A for(i=0; i<argc; i++){
2N/A if( argv[i]==0 ){
2N/A dstrAppend(p, "NULL", ' ');
2N/A }else{
2N/A dstrAppend(p, argv[i], ' ');
2N/A }
2N/A }
2N/A return 0;
2N/A}
2N/A
2N/A/*
2N/A** Implementation of the x_sqlite_exec() function. This function takes
2N/A** a single argument and attempts to execute that argument as SQL code.
2N/A** This is illegal and should set the SQLITE_MISUSE flag on the database.
2N/A**
2N/A** 2004-Jan-07: We have changed this to make it legal to call sqlite_exec()
2N/A** from within a function call.
2N/A**
2N/A** This routine simulates the effect of having two threads attempt to
2N/A** use the same database at the same time.
2N/A*/
2N/Astatic void sqliteExecFunc(sqlite_func *context, int argc, const char **argv){
2N/A struct dstr x;
2N/A memset(&x, 0, sizeof(x));
2N/A sqlite_exec((sqlite*)sqlite_user_data(context), argv[0],
2N/A execFuncCallback, &x, 0);
2N/A sqlite_set_result_string(context, x.z, x.nUsed);
2N/A sqliteFree(x.z);
2N/A}
2N/A
2N/A/*
2N/A** Usage: sqlite_test_create_function DB
2N/A**
2N/A** Call the sqlite_create_function API on the given database in order
2N/A** to create a function named "x_coalesce". This function does the same thing
2N/A** as the "coalesce" function. This function also registers an SQL function
2N/A** named "x_sqlite_exec" that invokes sqlite_exec(). Invoking sqlite_exec()
2N/A** in this way is illegal recursion and should raise an SQLITE_MISUSE error.
2N/A** The effect is similar to trying to use the same database connection from
2N/A** two threads at the same time.
2N/A**
2N/A** The original motivation for this routine was to be able to call the
2N/A** sqlite_create_function function while a query is in progress in order
2N/A** to test the SQLITE_MISUSE detection logic.
2N/A*/
2N/Astatic int test_create_function(
2N/A void *NotUsed,
2N/A Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
2N/A int argc, /* Number of arguments */
2N/A char **argv /* Text of each argument */
2N/A){
2N/A sqlite *db;
2N/A extern void Md5_Register(sqlite*);
2N/A if( argc!=2 ){
2N/A Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
2N/A " FILENAME\"", 0);
2N/A return TCL_ERROR;
2N/A }
2N/A if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
2N/A sqlite_create_function(db, "x_coalesce", -1, ifnullFunc, 0);
2N/A sqlite_create_function(db, "x_sqlite_exec", 1, sqliteExecFunc, db);
2N/A return TCL_OK;
2N/A}
2N/A
2N/A/*
2N/A** Routines to implement the x_count() aggregate function.
2N/A*/
2N/Atypedef struct CountCtx CountCtx;
2N/Astruct CountCtx {
2N/A int n;
2N/A};
2N/Astatic void countStep(sqlite_func *context, int argc, const char **argv){
2N/A CountCtx *p;
2N/A p = sqlite_aggregate_context(context, sizeof(*p));
2N/A if( (argc==0 || argv[0]) && p ){
2N/A p->n++;
2N/A }
2N/A}
2N/Astatic void countFinalize(sqlite_func *context){
2N/A CountCtx *p;
2N/A p = sqlite_aggregate_context(context, sizeof(*p));
2N/A sqlite_set_result_int(context, p ? p->n : 0);
2N/A}
2N/A
2N/A/*
2N/A** Usage: sqlite_test_create_aggregate DB
2N/A**
2N/A** Call the sqlite_create_function API on the given database in order
2N/A** to create a function named "x_count". This function does the same thing
2N/A** as the "md5sum" function.
2N/A**
2N/A** The original motivation for this routine was to be able to call the
2N/A** sqlite_create_aggregate function while a query is in progress in order
2N/A** to test the SQLITE_MISUSE detection logic.
2N/A*/
2N/Astatic int test_create_aggregate(
2N/A void *NotUsed,
2N/A Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
2N/A int argc, /* Number of arguments */
2N/A char **argv /* Text of each argument */
2N/A){
2N/A sqlite *db;
2N/A if( argc!=2 ){
2N/A Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
2N/A " FILENAME\"", 0);
2N/A return TCL_ERROR;
2N/A }
2N/A if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
2N/A sqlite_create_aggregate(db, "x_count", 0, countStep, countFinalize, 0);
2N/A sqlite_create_aggregate(db, "x_count", 1, countStep, countFinalize, 0);
2N/A return TCL_OK;
2N/A}
2N/A
2N/A
2N/A
2N/A/*
2N/A** Usage: sqlite_mprintf_int FORMAT INTEGER INTEGER INTEGER
2N/A**
2N/A** Call mprintf with three integer arguments
2N/A*/
2N/Astatic int sqlite_mprintf_int(
2N/A void *NotUsed,
2N/A Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
2N/A int argc, /* Number of arguments */
2N/A char **argv /* Text of each argument */
2N/A){
2N/A int a[3], i;
2N/A char *z;
2N/A if( argc!=5 ){
2N/A Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
2N/A " FORMAT INT INT INT\"", 0);
2N/A return TCL_ERROR;
2N/A }
2N/A for(i=2; i<5; i++){
2N/A if( Tcl_GetInt(interp, argv[i], &a[i-2]) ) return TCL_ERROR;
2N/A }
2N/A z = sqlite_mprintf(argv[1], a[0], a[1], a[2]);
2N/A Tcl_AppendResult(interp, z, 0);
2N/A sqlite_freemem(z);
2N/A return TCL_OK;
2N/A}
2N/A
2N/A/*
2N/A** Usage: sqlite_mprintf_str FORMAT INTEGER INTEGER STRING
2N/A**
2N/A** Call mprintf with two integer arguments and one string argument
2N/A*/
2N/Astatic int sqlite_mprintf_str(
2N/A void *NotUsed,
2N/A Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
2N/A int argc, /* Number of arguments */
2N/A char **argv /* Text of each argument */
2N/A){
2N/A int a[3], i;
2N/A char *z;
2N/A if( argc<4 || argc>5 ){
2N/A Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
2N/A " FORMAT INT INT ?STRING?\"", 0);
2N/A return TCL_ERROR;
2N/A }
2N/A for(i=2; i<4; i++){
2N/A if( Tcl_GetInt(interp, argv[i], &a[i-2]) ) return TCL_ERROR;
2N/A }
2N/A z = sqlite_mprintf(argv[1], a[0], a[1], argc>4 ? argv[4] : NULL);
2N/A Tcl_AppendResult(interp, z, 0);
2N/A sqlite_freemem(z);
2N/A return TCL_OK;
2N/A}
2N/A
2N/A/*
2N/A** Usage: sqlite_mprintf_str FORMAT INTEGER INTEGER DOUBLE
2N/A**
2N/A** Call mprintf with two integer arguments and one double argument
2N/A*/
2N/Astatic int sqlite_mprintf_double(
2N/A void *NotUsed,
2N/A Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
2N/A int argc, /* Number of arguments */
2N/A char **argv /* Text of each argument */
2N/A){
2N/A int a[3], i;
2N/A double r;
2N/A char *z;
2N/A if( argc!=5 ){
2N/A Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
2N/A " FORMAT INT INT STRING\"", 0);
2N/A return TCL_ERROR;
2N/A }
2N/A for(i=2; i<4; i++){
2N/A if( Tcl_GetInt(interp, argv[i], &a[i-2]) ) return TCL_ERROR;
2N/A }
2N/A if( Tcl_GetDouble(interp, argv[4], &r) ) return TCL_ERROR;
2N/A z = sqlite_mprintf(argv[1], a[0], a[1], r);
2N/A Tcl_AppendResult(interp, z, 0);
2N/A sqlite_freemem(z);
2N/A return TCL_OK;
2N/A}
2N/A
2N/A/*
2N/A** Usage: sqlite_mprintf_str FORMAT DOUBLE DOUBLE
2N/A**
2N/A** Call mprintf with a single double argument which is the product of the
2N/A** two arguments given above. This is used to generate overflow and underflow
2N/A** doubles to test that they are converted properly.
2N/A*/
2N/Astatic int sqlite_mprintf_scaled(
2N/A void *NotUsed,
2N/A Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
2N/A int argc, /* Number of arguments */
2N/A char **argv /* Text of each argument */
2N/A){
2N/A int i;
2N/A double r[2];
2N/A char *z;
2N/A if( argc!=4 ){
2N/A Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
2N/A " FORMAT DOUBLE DOUBLE\"", 0);
2N/A return TCL_ERROR;
2N/A }
2N/A for(i=2; i<4; i++){
2N/A if( Tcl_GetDouble(interp, argv[i], &r[i-2]) ) return TCL_ERROR;
2N/A }
2N/A z = sqlite_mprintf(argv[1], r[0]*r[1]);
2N/A Tcl_AppendResult(interp, z, 0);
2N/A sqlite_freemem(z);
2N/A return TCL_OK;
2N/A}
2N/A
2N/A/*
2N/A** Usage: sqlite_malloc_fail N
2N/A**
2N/A** Rig sqliteMalloc() to fail on the N-th call. Turn off this mechanism
2N/A** and reset the sqlite_malloc_failed variable is N==0.
2N/A*/
2N/A#ifdef MEMORY_DEBUG
2N/Astatic int sqlite_malloc_fail(
2N/A void *NotUsed,
2N/A Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
2N/A int argc, /* Number of arguments */
2N/A char **argv /* Text of each argument */
2N/A){
2N/A int n;
2N/A if( argc!=2 ){
2N/A Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " N\"", 0);
2N/A return TCL_ERROR;
2N/A }
2N/A if( Tcl_GetInt(interp, argv[1], &n) ) return TCL_ERROR;
2N/A sqlite_iMallocFail = n;
2N/A sqlite_malloc_failed = 0;
2N/A return TCL_OK;
2N/A}
2N/A#endif
2N/A
2N/A/*
2N/A** Usage: sqlite_malloc_stat
2N/A**
2N/A** Return the number of prior calls to sqliteMalloc() and sqliteFree().
2N/A*/
2N/A#ifdef MEMORY_DEBUG
2N/Astatic int sqlite_malloc_stat(
2N/A void *NotUsed,
2N/A Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
2N/A int argc, /* Number of arguments */
2N/A char **argv /* Text of each argument */
2N/A){
2N/A char zBuf[200];
2N/A sprintf(zBuf, "%d %d %d", sqlite_nMalloc, sqlite_nFree, sqlite_iMallocFail);
2N/A Tcl_AppendResult(interp, zBuf, 0);
2N/A return TCL_OK;
2N/A}
2N/A#endif
2N/A
2N/A/*
2N/A** Usage: sqlite_abort
2N/A**
2N/A** Shutdown the process immediately. This is not a clean shutdown.
2N/A** This command is used to test the recoverability of a database in
2N/A** the event of a program crash.
2N/A*/
2N/Astatic int sqlite_abort(
2N/A void *NotUsed,
2N/A Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
2N/A int argc, /* Number of arguments */
2N/A char **argv /* Text of each argument */
2N/A){
2N/A assert( interp==0 ); /* This will always fail */
2N/A return TCL_OK;
2N/A}
2N/A
2N/A/*
2N/A** The following routine is a user-defined SQL function whose purpose
2N/A** is to test the sqlite_set_result() API.
2N/A*/
2N/Astatic void testFunc(sqlite_func *context, int argc, const char **argv){
2N/A while( argc>=2 ){
2N/A if( argv[0]==0 ){
2N/A sqlite_set_result_error(context, "first argument to test function "
2N/A "may not be NULL", -1);
2N/A }else if( sqliteStrICmp(argv[0],"string")==0 ){
2N/A sqlite_set_result_string(context, argv[1], -1);
2N/A }else if( argv[1]==0 ){
2N/A sqlite_set_result_error(context, "2nd argument may not be NULL if the "
2N/A "first argument is not \"string\"", -1);
2N/A }else if( sqliteStrICmp(argv[0],"int")==0 ){
2N/A sqlite_set_result_int(context, atoi(argv[1]));
2N/A }else if( sqliteStrICmp(argv[0],"double")==0 ){
2N/A sqlite_set_result_double(context, sqliteAtoF(argv[1], 0));
2N/A }else{
2N/A sqlite_set_result_error(context,"first argument should be one of: "
2N/A "string int double", -1);
2N/A }
2N/A argc -= 2;
2N/A argv += 2;
2N/A }
2N/A}
2N/A
2N/A/*
2N/A** Usage: sqlite_register_test_function DB NAME
2N/A**
2N/A** Register the test SQL function on the database DB under the name NAME.
2N/A*/
2N/Astatic int test_register_func(
2N/A void *NotUsed,
2N/A Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
2N/A int argc, /* Number of arguments */
2N/A char **argv /* Text of each argument */
2N/A){
2N/A sqlite *db;
2N/A int rc;
2N/A if( argc!=3 ){
2N/A Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
2N/A " DB FUNCTION-NAME", 0);
2N/A return TCL_ERROR;
2N/A }
2N/A if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
2N/A rc = sqlite_create_function(db, argv[2], -1, testFunc, 0);
2N/A if( rc!=0 ){
2N/A Tcl_AppendResult(interp, sqlite_error_string(rc), 0);
2N/A return TCL_ERROR;
2N/A }
2N/A return TCL_OK;
2N/A}
2N/A
2N/A/*
2N/A** This SQLite callback records the datatype of all columns.
2N/A**
2N/A** The pArg argument is really a pointer to a TCL interpreter. The
2N/A** column names are inserted as the result of this interpreter.
2N/A**
2N/A** This routine returns non-zero which causes the query to abort.
2N/A*/
2N/Astatic int rememberDataTypes(void *pArg, int nCol, char **argv, char **colv){
2N/A int i;
2N/A Tcl_Interp *interp = (Tcl_Interp*)pArg;
2N/A Tcl_Obj *pList, *pElem;
2N/A if( colv[nCol+1]==0 ){
2N/A return 1;
2N/A }
2N/A pList = Tcl_NewObj();
2N/A for(i=0; i<nCol; i++){
2N/A pElem = Tcl_NewStringObj(colv[i+nCol] ? colv[i+nCol] : "NULL", -1);
2N/A Tcl_ListObjAppendElement(interp, pList, pElem);
2N/A }
2N/A Tcl_SetObjResult(interp, pList);
2N/A return 1;
2N/A}
2N/A
2N/A/*
2N/A** Invoke an SQL statement but ignore all the data in the result. Instead,
2N/A** return a list that consists of the datatypes of the various columns.
2N/A**
2N/A** This only works if "PRAGMA show_datatypes=on" has been executed against
2N/A** the database connection.
2N/A*/
2N/Astatic int sqlite_datatypes(
2N/A void *NotUsed,
2N/A Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
2N/A int argc, /* Number of arguments */
2N/A char **argv /* Text of each argument */
2N/A){
2N/A sqlite *db;
2N/A int rc;
2N/A if( argc!=3 ){
2N/A Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
2N/A " DB SQL", 0);
2N/A return TCL_ERROR;
2N/A }
2N/A if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
2N/A rc = sqlite_exec(db, argv[2], rememberDataTypes, interp, 0);
2N/A if( rc!=0 && rc!=SQLITE_ABORT ){
2N/A Tcl_AppendResult(interp, sqlite_error_string(rc), 0);
2N/A return TCL_ERROR;
2N/A }
2N/A return TCL_OK;
2N/A}
2N/A
2N/A/*
2N/A** Usage: sqlite_compile DB SQL ?TAILVAR?
2N/A**
2N/A** Attempt to compile an SQL statement. Return a pointer to the virtual
2N/A** machine used to execute that statement. Unprocessed SQL is written
2N/A** into TAILVAR.
2N/A*/
2N/Astatic int test_compile(
2N/A void *NotUsed,
2N/A Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
2N/A int argc, /* Number of arguments */
2N/A char **argv /* Text of each argument */
2N/A){
2N/A sqlite *db;
2N/A sqlite_vm *vm;
2N/A int rc;
2N/A char *zErr = 0;
2N/A const char *zTail;
2N/A char zBuf[50];
2N/A if( argc!=3 && argc!=4 ){
2N/A Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
2N/A " DB SQL TAILVAR", 0);
2N/A return TCL_ERROR;
2N/A }
2N/A if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
2N/A rc = sqlite_compile(db, argv[2], argc==4 ? &zTail : 0, &vm, &zErr);
2N/A if( argc==4 ) Tcl_SetVar(interp, argv[3], zTail, 0);
2N/A if( rc ){
2N/A assert( vm==0 );
2N/A sprintf(zBuf, "(%d) ", rc);
2N/A Tcl_AppendResult(interp, zBuf, zErr, 0);
2N/A sqlite_freemem(zErr);
2N/A return TCL_ERROR;
2N/A }
2N/A if( vm ){
2N/A if( makePointerStr(interp, zBuf, vm) ) return TCL_ERROR;
2N/A Tcl_AppendResult(interp, zBuf, 0);
2N/A }
2N/A return TCL_OK;
2N/A}
2N/A
2N/A/*
2N/A** Usage: sqlite_step VM ?NVAR? ?VALUEVAR? ?COLNAMEVAR?
2N/A**
2N/A** Step a virtual machine. Return a the result code as a string.
2N/A** Column results are written into three variables.
2N/A*/
2N/Astatic int test_step(
2N/A void *NotUsed,
2N/A Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
2N/A int argc, /* Number of arguments */
2N/A char **argv /* Text of each argument */
2N/A){
2N/A sqlite_vm *vm;
2N/A int rc, i;
2N/A const char **azValue = 0;
2N/A const char **azColName = 0;
2N/A int N = 0;
2N/A char *zRc;
2N/A char zBuf[50];
2N/A if( argc<2 || argc>5 ){
2N/A Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
2N/A " VM NVAR VALUEVAR COLNAMEVAR", 0);
2N/A return TCL_ERROR;
2N/A }
2N/A if( getVmPointer(interp, argv[1], &vm) ) return TCL_ERROR;
2N/A rc = sqlite_step(vm, argc>=3?&N:0, argc>=4?&azValue:0, argc==5?&azColName:0);
2N/A if( argc>=3 ){
2N/A sprintf(zBuf, "%d", N);
2N/A Tcl_SetVar(interp, argv[2], zBuf, 0);
2N/A }
2N/A if( argc>=4 ){
2N/A Tcl_SetVar(interp, argv[3], "", 0);
2N/A if( azValue ){
2N/A for(i=0; i<N; i++){
2N/A Tcl_SetVar(interp, argv[3], azValue[i] ? azValue[i] : "",
2N/A TCL_APPEND_VALUE | TCL_LIST_ELEMENT);
2N/A }
2N/A }
2N/A }
2N/A if( argc==5 ){
2N/A Tcl_SetVar(interp, argv[4], "", 0);
2N/A if( azColName ){
2N/A for(i=0; i<N*2; i++){
2N/A Tcl_SetVar(interp, argv[4], azColName[i] ? azColName[i] : "",
2N/A TCL_APPEND_VALUE | TCL_LIST_ELEMENT);
2N/A }
2N/A }
2N/A }
2N/A switch( rc ){
2N/A case SQLITE_DONE: zRc = "SQLITE_DONE"; break;
2N/A case SQLITE_BUSY: zRc = "SQLITE_BUSY"; break;
2N/A case SQLITE_ROW: zRc = "SQLITE_ROW"; break;
2N/A case SQLITE_ERROR: zRc = "SQLITE_ERROR"; break;
2N/A case SQLITE_MISUSE: zRc = "SQLITE_MISUSE"; break;
2N/A default: zRc = "unknown"; break;
2N/A }
2N/A Tcl_AppendResult(interp, zRc, 0);
2N/A return TCL_OK;
2N/A}
2N/A
2N/A/*
2N/A** Usage: sqlite_finalize VM
2N/A**
2N/A** Shutdown a virtual machine.
2N/A*/
2N/Astatic int test_finalize(
2N/A void *NotUsed,
2N/A Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
2N/A int argc, /* Number of arguments */
2N/A char **argv /* Text of each argument */
2N/A){
2N/A sqlite_vm *vm;
2N/A int rc;
2N/A char *zErrMsg = 0;
2N/A if( argc!=2 ){
2N/A Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
2N/A " VM\"", 0);
2N/A return TCL_ERROR;
2N/A }
2N/A if( getVmPointer(interp, argv[1], &vm) ) return TCL_ERROR;
2N/A rc = sqlite_finalize(vm, &zErrMsg);
2N/A if( rc ){
2N/A char zBuf[50];
2N/A sprintf(zBuf, "(%d) ", rc);
2N/A Tcl_AppendResult(interp, zBuf, zErrMsg, 0);
2N/A sqlite_freemem(zErrMsg);
2N/A return TCL_ERROR;
2N/A }
2N/A return TCL_OK;
2N/A}
2N/A
2N/A/*
2N/A** Usage: sqlite_reset VM
2N/A**
2N/A** Reset a virtual machine and prepare it to be run again.
2N/A*/
2N/Astatic int test_reset(
2N/A void *NotUsed,
2N/A Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
2N/A int argc, /* Number of arguments */
2N/A char **argv /* Text of each argument */
2N/A){
2N/A sqlite_vm *vm;
2N/A int rc;
2N/A char *zErrMsg = 0;
2N/A if( argc!=2 ){
2N/A Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
2N/A " VM\"", 0);
2N/A return TCL_ERROR;
2N/A }
2N/A if( getVmPointer(interp, argv[1], &vm) ) return TCL_ERROR;
2N/A rc = sqlite_reset(vm, &zErrMsg);
2N/A if( rc ){
2N/A char zBuf[50];
2N/A sprintf(zBuf, "(%d) ", rc);
2N/A Tcl_AppendResult(interp, zBuf, zErrMsg, 0);
2N/A sqlite_freemem(zErrMsg);
2N/A return TCL_ERROR;
2N/A }
2N/A return TCL_OK;
2N/A}
2N/A
2N/A/*
2N/A** This is the "static_bind_value" that variables are bound to when
2N/A** the FLAG option of sqlite_bind is "static"
2N/A*/
2N/Astatic char *sqlite_static_bind_value = 0;
2N/A
2N/A/*
2N/A** Usage: sqlite_bind VM IDX VALUE FLAGS
2N/A**
2N/A** Sets the value of the IDX-th occurance of "?" in the original SQL
2N/A** string. VALUE is the new value. If FLAGS=="null" then VALUE is
2N/A** ignored and the value is set to NULL. If FLAGS=="static" then
2N/A** the value is set to the value of a static variable named
2N/A** "sqlite_static_bind_value". If FLAGS=="normal" then a copy
2N/A** of the VALUE is made.
2N/A*/
2N/Astatic int test_bind(
2N/A void *NotUsed,
2N/A Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
2N/A int argc, /* Number of arguments */
2N/A char **argv /* Text of each argument */
2N/A){
2N/A sqlite_vm *vm;
2N/A int rc;
2N/A int idx;
2N/A if( argc!=5 ){
2N/A Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
2N/A " VM IDX VALUE (null|static|normal)\"", 0);
2N/A return TCL_ERROR;
2N/A }
2N/A if( getVmPointer(interp, argv[1], &vm) ) return TCL_ERROR;
2N/A if( Tcl_GetInt(interp, argv[2], &idx) ) return TCL_ERROR;
2N/A if( strcmp(argv[4],"null")==0 ){
2N/A rc = sqlite_bind(vm, idx, 0, 0, 0);
2N/A }else if( strcmp(argv[4],"static")==0 ){
2N/A rc = sqlite_bind(vm, idx, sqlite_static_bind_value, -1, 0);
2N/A }else if( strcmp(argv[4],"normal")==0 ){
2N/A rc = sqlite_bind(vm, idx, argv[3], -1, 1);
2N/A }else{
2N/A Tcl_AppendResult(interp, "4th argument should be "
2N/A "\"null\" or \"static\" or \"normal\"", 0);
2N/A return TCL_ERROR;
2N/A }
2N/A if( rc ){
2N/A char zBuf[50];
2N/A sprintf(zBuf, "(%d) ", rc);
2N/A Tcl_AppendResult(interp, zBuf, sqlite_error_string(rc), 0);
2N/A return TCL_ERROR;
2N/A }
2N/A return TCL_OK;
2N/A}
2N/A
2N/A/*
2N/A** Usage: breakpoint
2N/A**
2N/A** This routine exists for one purpose - to provide a place to put a
2N/A** breakpoint with GDB that can be triggered using TCL code. The use
2N/A** for this is when a particular test fails on (say) the 1485th iteration.
2N/A** In the TCL test script, we can add code like this:
2N/A**
2N/A** if {$i==1485} breakpoint
2N/A**
2N/A** Then run testfixture in the debugger and wait for the breakpoint to
2N/A** fire. Then additional breakpoints can be set to trace down the bug.
2N/A*/
2N/Astatic int test_breakpoint(
2N/A void *NotUsed,
2N/A Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
2N/A int argc, /* Number of arguments */
2N/A char **argv /* Text of each argument */
2N/A){
2N/A return TCL_OK; /* Do nothing */
2N/A}
2N/A
2N/A/*
2N/A** Register commands with the TCL interpreter.
2N/A*/
2N/Aint Sqlitetest1_Init(Tcl_Interp *interp){
2N/A extern int sqlite_search_count;
2N/A extern int sqlite_interrupt_count;
2N/A extern int sqlite_open_file_count;
2N/A extern int sqlite_current_time;
2N/A extern int sqlite_temp_directory;
2N/A static struct {
2N/A char *zName;
2N/A Tcl_CmdProc *xProc;
2N/A } aCmd[] = {
2N/A { "sqlite_mprintf_int", (Tcl_CmdProc*)sqlite_mprintf_int },
2N/A { "sqlite_mprintf_str", (Tcl_CmdProc*)sqlite_mprintf_str },
2N/A { "sqlite_mprintf_double", (Tcl_CmdProc*)sqlite_mprintf_double },
2N/A { "sqlite_mprintf_scaled", (Tcl_CmdProc*)sqlite_mprintf_scaled },
2N/A { "sqlite_mprintf_z_test", (Tcl_CmdProc*)test_mprintf_z },
2N/A { "sqlite_open", (Tcl_CmdProc*)sqlite_test_open },
2N/A { "sqlite_last_insert_rowid", (Tcl_CmdProc*)test_last_rowid },
2N/A { "sqlite_exec_printf", (Tcl_CmdProc*)test_exec_printf },
2N/A { "sqlite_get_table_printf", (Tcl_CmdProc*)test_get_table_printf },
2N/A { "sqlite_close", (Tcl_CmdProc*)sqlite_test_close },
2N/A { "sqlite_create_function", (Tcl_CmdProc*)test_create_function },
2N/A { "sqlite_create_aggregate", (Tcl_CmdProc*)test_create_aggregate },
2N/A { "sqlite_register_test_function", (Tcl_CmdProc*)test_register_func },
2N/A { "sqlite_abort", (Tcl_CmdProc*)sqlite_abort },
2N/A { "sqlite_datatypes", (Tcl_CmdProc*)sqlite_datatypes },
2N/A#ifdef MEMORY_DEBUG
2N/A { "sqlite_malloc_fail", (Tcl_CmdProc*)sqlite_malloc_fail },
2N/A { "sqlite_malloc_stat", (Tcl_CmdProc*)sqlite_malloc_stat },
2N/A#endif
2N/A { "sqlite_compile", (Tcl_CmdProc*)test_compile },
2N/A { "sqlite_step", (Tcl_CmdProc*)test_step },
2N/A { "sqlite_finalize", (Tcl_CmdProc*)test_finalize },
2N/A { "sqlite_bind", (Tcl_CmdProc*)test_bind },
2N/A { "sqlite_reset", (Tcl_CmdProc*)test_reset },
2N/A { "breakpoint", (Tcl_CmdProc*)test_breakpoint },
2N/A };
2N/A int i;
2N/A
2N/A for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){
2N/A Tcl_CreateCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0);
2N/A }
2N/A Tcl_LinkVar(interp, "sqlite_search_count",
2N/A (char*)&sqlite_search_count, TCL_LINK_INT);
2N/A Tcl_LinkVar(interp, "sqlite_interrupt_count",
2N/A (char*)&sqlite_interrupt_count, TCL_LINK_INT);
2N/A Tcl_LinkVar(interp, "sqlite_open_file_count",
2N/A (char*)&sqlite_open_file_count, TCL_LINK_INT);
2N/A Tcl_LinkVar(interp, "sqlite_current_time",
2N/A (char*)&sqlite_current_time, TCL_LINK_INT);
2N/A Tcl_LinkVar(interp, "sqlite_static_bind_value",
2N/A (char*)&sqlite_static_bind_value, TCL_LINK_STRING);
2N/A Tcl_LinkVar(interp, "sqlite_temp_directory",
2N/A (char*)&sqlite_temp_directory, TCL_LINK_STRING);
2N/A return TCL_OK;
2N/A}