diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/func.c | 169 | ||||
-rw-r--r-- | src/loadext.c | 13 | ||||
-rw-r--r-- | src/main.c | 49 | ||||
-rw-r--r-- | src/tclsqlite.c | 4 | ||||
-rw-r--r-- | src/test_autoext.c | 4 | ||||
-rw-r--r-- | src/test_func.c | 238 |
6 files changed, 302 insertions, 175 deletions
diff --git a/src/func.c b/src/func.c index 828e764fc..d91b36a3a 100644 --- a/src/func.c +++ b/src/func.c @@ -16,7 +16,7 @@ ** sqliteRegisterBuildinFunctions() found at the bottom of the file. ** All other code has file scope. ** -** $Id: func.c,v 1.187 2008/03/19 14:15:34 drh Exp $ +** $Id: func.c,v 1.188 2008/03/19 16:08:54 drh Exp $ */ #include "sqliteInt.h" #include <ctype.h> @@ -1020,166 +1020,6 @@ static void loadExt(sqlite3_context *context, int argc, sqlite3_value **argv){ } #endif -#ifdef SQLITE_TEST -/* -** This function generates a string of random characters. Used for -** generating test data. -*/ -static void randStr(sqlite3_context *context, int argc, sqlite3_value **argv){ - static const unsigned char zSrc[] = - "abcdefghijklmnopqrstuvwxyz" - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "0123456789" - ".-!,:*^+=_|?/<> "; - int iMin, iMax, n, r, i; - unsigned char zBuf[1000]; - - /* It used to be possible to call randstr() with any number of arguments, - ** but now it is registered with SQLite as requiring exactly 2. - */ - assert(argc==2); - - iMin = sqlite3_value_int(argv[0]); - if( iMin<0 ) iMin = 0; - if( iMin>=sizeof(zBuf) ) iMin = sizeof(zBuf)-1; - iMax = sqlite3_value_int(argv[1]); - if( iMax<iMin ) iMax = iMin; - if( iMax>=sizeof(zBuf) ) iMax = sizeof(zBuf)-1; - n = iMin; - if( iMax>iMin ){ - sqlite3_randomness(sizeof(r), &r); - r &= 0x7fffffff; - n += r%(iMax + 1 - iMin); - } - assert( n<sizeof(zBuf) ); - sqlite3_randomness(n, zBuf); - for(i=0; i<n; i++){ - zBuf[i] = zSrc[zBuf[i]%(sizeof(zSrc)-1)]; - } - zBuf[n] = 0; - sqlite3_result_text(context, (char*)zBuf, n, SQLITE_TRANSIENT); -} -#endif /* SQLITE_TEST */ - -#ifdef SQLITE_TEST -/* -** The following two SQL functions are used to test returning a text -** result with a destructor. Function 'test_destructor' takes one argument -** and returns the same argument interpreted as TEXT. A destructor is -** passed with the sqlite3_result_text() call. -** -** SQL function 'test_destructor_count' returns the number of outstanding -** allocations made by 'test_destructor'; -** -** WARNING: Not threadsafe. -*/ -static int test_destructor_count_var = 0; -static void destructor(void *p){ - char *zVal = (char *)p; - assert(zVal); - zVal--; - sqlite3_free(zVal); - test_destructor_count_var--; -} -static void test_destructor( - sqlite3_context *pCtx, - int nArg, - sqlite3_value **argv -){ - char *zVal; - int len; - sqlite3 *db = sqlite3_user_data(pCtx); - - test_destructor_count_var++; - assert( nArg==1 ); - if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return; - len = sqlite3ValueBytes(argv[0], ENC(db)); - zVal = contextMalloc(pCtx, len+3); - if( !zVal ){ - return; - } - zVal[len+1] = 0; - zVal[len+2] = 0; - zVal++; - memcpy(zVal, sqlite3ValueText(argv[0], ENC(db)), len); - if( ENC(db)==SQLITE_UTF8 ){ - sqlite3_result_text(pCtx, zVal, -1, destructor); -#ifndef SQLITE_OMIT_UTF16 - }else if( ENC(db)==SQLITE_UTF16LE ){ - sqlite3_result_text16le(pCtx, zVal, -1, destructor); - }else{ - sqlite3_result_text16be(pCtx, zVal, -1, destructor); -#endif /* SQLITE_OMIT_UTF16 */ - } -} -static void test_destructor_count( - sqlite3_context *pCtx, - int nArg, - sqlite3_value **argv -){ - sqlite3_result_int(pCtx, test_destructor_count_var); -} -#endif /* SQLITE_TEST */ - -#ifdef SQLITE_TEST -/* -** Routines for testing the sqlite3_get_auxdata() and sqlite3_set_auxdata() -** interface. -** -** The test_auxdata() SQL function attempts to register each of its arguments -** as auxiliary data. If there are no prior registrations of aux data for -** that argument (meaning the argument is not a constant or this is its first -** call) then the result for that argument is 0. If there is a prior -** registration, the result for that argument is 1. The overall result -** is the individual argument results separated by spaces. -*/ -static void free_test_auxdata(void *p) {sqlite3_free(p);} -static void test_auxdata( - sqlite3_context *pCtx, - int nArg, - sqlite3_value **argv -){ - int i; - char *zRet = contextMalloc(pCtx, nArg*2); - if( !zRet ) return; - memset(zRet, 0, nArg*2); - for(i=0; i<nArg; i++){ - char const *z = (char*)sqlite3_value_text(argv[i]); - if( z ){ - int n; - char *zAux = sqlite3_get_auxdata(pCtx, i); - if( zAux ){ - zRet[i*2] = '1'; - assert( strcmp(zAux,z)==0 ); - }else { - zRet[i*2] = '0'; - } - n = strlen(z) + 1; - zAux = contextMalloc(pCtx, n); - if( zAux ){ - memcpy(zAux, z, n); - sqlite3_set_auxdata(pCtx, i, zAux, free_test_auxdata); - } - zRet[i*2+1] = ' '; - } - } - sqlite3_result_text(pCtx, zRet, 2*nArg-1, free_test_auxdata); -} -#endif /* SQLITE_TEST */ - -#ifdef SQLITE_TEST -/* -** A function to test error reporting from user functions. This function -** returns a copy of its first argument as an error. -*/ -static void test_error( - sqlite3_context *pCtx, - int nArg, - sqlite3_value **argv -){ - sqlite3_result_error(pCtx, (char*)sqlite3_value_text(argv[0]), 0); -} -#endif /* SQLITE_TEST */ /* ** An instance of the following structure holds the context of a @@ -1425,13 +1265,6 @@ void sqlite3RegisterBuiltinFunctions(sqlite3 *db){ { "load_extension", 1, 0xff, SQLITE_UTF8, 0, loadExt }, { "load_extension", 2, 0xff, SQLITE_UTF8, 0, loadExt }, #endif -#ifdef SQLITE_TEST - { "randstr", 2, 0, SQLITE_UTF8, 0, randStr }, - { "test_destructor", 1, 0xff, SQLITE_UTF8, 0, test_destructor}, - { "test_destructor_count", 0, 0, SQLITE_UTF8, 0, test_destructor_count}, - { "test_auxdata", -1, 0, SQLITE_UTF8, 0, test_auxdata}, - { "test_error", 1, 0, SQLITE_UTF8, 0, test_error}, -#endif }; static const struct { char *zName; diff --git a/src/loadext.c b/src/loadext.c index 3638e926c..5e910d274 100644 --- a/src/loadext.c +++ b/src/loadext.c @@ -430,6 +430,17 @@ int sqlite3_enable_load_extension(sqlite3 *db, int onoff){ return SQLITE_OK; } +#endif /* SQLITE_OMIT_LOADEXTENSION */ + +/* +** The following code is added regardless of whether or not extension +** loading is supported. +*/ +#ifdef SQLITE_OMIT_LOAD_EXTENSTION +const sqlite3_api_routines sqlite3Apis = { 0 }; +#endif + + /* ** The following object holds the list of automatically loaded ** extensions. @@ -519,5 +530,3 @@ int sqlite3AutoLoadExtensions(sqlite3 *db){ } return rc; } - -#endif /* SQLITE_OMIT_LOAD_EXTENSION */ diff --git a/src/main.c b/src/main.c index a9a61742c..dd9999e53 100644 --- a/src/main.c +++ b/src/main.c @@ -14,7 +14,7 @@ ** other files are for internal use by SQLite and should not be ** accessed by users of the library. ** -** $Id: main.c,v 1.423 2008/03/19 14:15:34 drh Exp $ +** $Id: main.c,v 1.424 2008/03/19 16:08:54 drh Exp $ */ #include "sqliteInt.h" #include <ctype.h> @@ -541,7 +541,6 @@ int sqlite3_create_function( ){ int rc; sqlite3_mutex_enter(db->mutex); - assert( !db->mallocFailed ); rc = sqlite3CreateFunc(db, zFunctionName, nArg, enc, p, xFunc, xStep, xFinal); rc = sqlite3ApiExit(db, rc); sqlite3_mutex_leave(db->mutex); @@ -1495,6 +1494,14 @@ int sqlite3_test_control(int op, ...){ va_list ap; va_start(ap, op); switch( op ){ + /* + ** sqlite3_test_control(FAULT_CONFIG, fault_id, nDelay, nRepeat) + ** + ** Configure a fault injector. The specific fault injector is + ** identified by the fault_id argument. (ex: SQLITE_FAULTINJECTOR_MALLOC) + ** The fault will occur after a delay of nDelay calls. The fault + ** will repeat nRepeat times. + */ case SQLITE_TESTCTRL_FAULT_CONFIG: { int id = va_arg(ap, int); int nDelay = va_arg(ap, int); @@ -1502,29 +1509,67 @@ int sqlite3_test_control(int op, ...){ sqlite3FaultConfig(id, nDelay, nRepeat); break; } + + /* + ** sqlite3_test_control(FAULT_FAILURES, fault_id) + ** + ** Return the number of faults (both hard and benign faults) that have + ** occurred since the injector identified by fault_id) was last configured. + */ case SQLITE_TESTCTRL_FAULT_FAILURES: { int id = va_arg(ap, int); rc = sqlite3FaultFailures(id); break; } + + /* + ** sqlite3_test_control(FAULT_BENIGN_FAILURES, fault_id) + ** + ** Return the number of benign faults that have occurred since the + ** injector identified by fault_id was last configured. + */ case SQLITE_TESTCTRL_FAULT_BENIGN_FAILURES: { int id = va_arg(ap, int); rc = sqlite3FaultBenignFailures(id); break; } + + /* + ** sqlite3_test_control(FAULT_PENDING, fault_id) + ** + ** Return the number of successes that will occur before the next + ** scheduled failure on fault injector fault_id. + ** If no failures are scheduled, return -1. + */ case SQLITE_TESTCTRL_FAULT_PENDING: { int id = va_arg(ap, int); rc = sqlite3FaultPending(id); break; } + + /* + ** Save the current state of the PRNG. + */ case SQLITE_TESTCTRL_PRNG_SAVE: { sqlite3PrngSaveState(); break; } + + /* + ** Restore the state of the PRNG to the last state saved using + ** PRNG_SAVE. If PRNG_SAVE has never before been called, then + ** this verb acts like PRNG_RESET. + */ case SQLITE_TESTCTRL_PRNG_RESTORE: { sqlite3PrngRestoreState(); break; } + + /* + ** Reset the PRNG back to its uninitialized state. The next call + ** to sqlite3_randomness() will reseed the PRNG using a single call + ** to the xRandomness method of the default VFS. + */ case SQLITE_TESTCTRL_PRNG_RESET: { sqlite3PrngResetState(); break; diff --git a/src/tclsqlite.c b/src/tclsqlite.c index 4f1a6c928..a637aa233 100644 --- a/src/tclsqlite.c +++ b/src/tclsqlite.c @@ -12,7 +12,7 @@ ** A TCL Interface to SQLite. Append this file to sqlite3.c and ** compile the whole thing to build a TCL-enabled version of SQLite. ** -** $Id: tclsqlite.c,v 1.209 2008/02/18 22:24:58 drh Exp $ +** $Id: tclsqlite.c,v 1.210 2008/03/19 16:08:54 drh Exp $ */ #include "tcl.h" #include <errno.h> @@ -2534,6 +2534,7 @@ int TCLSH_MAIN(int argc, char **argv){ extern int Sqlitetest9_Init(Tcl_Interp*); extern int Sqlitetestasync_Init(Tcl_Interp*); extern int Sqlitetest_autoext_Init(Tcl_Interp*); + extern int Sqlitetest_func_Init(Tcl_Interp*); extern int Sqlitetest_hexio_Init(Tcl_Interp*); extern int Sqlitetest_malloc_Init(Tcl_Interp*); extern int Sqlitetestschema_Init(Tcl_Interp*); @@ -2555,6 +2556,7 @@ int TCLSH_MAIN(int argc, char **argv){ Sqlitetest9_Init(interp); Sqlitetestasync_Init(interp); Sqlitetest_autoext_Init(interp); + Sqlitetest_func_Init(interp); Sqlitetest_hexio_Init(interp); Sqlitetest_malloc_Init(interp); Sqlitetestschema_Init(interp); diff --git a/src/test_autoext.c b/src/test_autoext.c index 0eaeda057..d6ff10d61 100644 --- a/src/test_autoext.c +++ b/src/test_autoext.c @@ -11,7 +11,7 @@ ************************************************************************* ** Test extension for testing the sqlite3_auto_extension() function. ** -** $Id: test_autoext.c,v 1.2 2006/12/19 18:57:11 drh Exp $ +** $Id: test_autoext.c,v 1.3 2008/03/19 16:08:54 drh Exp $ */ #include "tcl.h" #ifndef SQLITE_OMIT_LOAD_EXTENSION @@ -157,8 +157,8 @@ int Sqlitetest_autoext_Init(Tcl_Interp *interp){ autoExtCubeObjCmd, 0, 0); Tcl_CreateObjCommand(interp, "sqlite3_auto_extension_broken", autoExtBrokenObjCmd, 0, 0); +#endif Tcl_CreateObjCommand(interp, "sqlite3_reset_auto_extension", resetAutoExtObjCmd, 0, 0); -#endif return TCL_OK; } diff --git a/src/test_func.c b/src/test_func.c new file mode 100644 index 000000000..3c1dedd8e --- /dev/null +++ b/src/test_func.c @@ -0,0 +1,238 @@ +/* +** 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. +** +** $Id: test_func.c,v 1.1 2008/03/19 16:08:54 drh Exp $ +*/ +#include "sqlite3.h" +#include "tcl.h" +#include <stdlib.h> +#include <string.h> +#include <assert.h> + + +/* +** Allocate nByte bytes of space using sqlite3_malloc(). If the +** allocation fails, call sqlite3_result_error_nomem() to notify +** the database handle that malloc() has failed. +*/ +static void *testContextMalloc(sqlite3_context *context, int nByte){ + char *z = sqlite3_malloc(nByte); + if( !z && nByte>0 ){ + sqlite3_result_error_nomem(context); + } + return z; +} + +/* +** This function generates a string of random characters. Used for +** generating test data. +*/ +static void randStr(sqlite3_context *context, int argc, sqlite3_value **argv){ + static const unsigned char zSrc[] = + "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "0123456789" + ".-!,:*^+=_|?/<> "; + int iMin, iMax, n, r, i; + unsigned char zBuf[1000]; + + /* It used to be possible to call randstr() with any number of arguments, + ** but now it is registered with SQLite as requiring exactly 2. + */ + assert(argc==2); + + iMin = sqlite3_value_int(argv[0]); + if( iMin<0 ) iMin = 0; + if( iMin>=sizeof(zBuf) ) iMin = sizeof(zBuf)-1; + iMax = sqlite3_value_int(argv[1]); + if( iMax<iMin ) iMax = iMin; + if( iMax>=sizeof(zBuf) ) iMax = sizeof(zBuf)-1; + n = iMin; + if( iMax>iMin ){ + sqlite3_randomness(sizeof(r), &r); + r &= 0x7fffffff; + n += r%(iMax + 1 - iMin); + } + assert( n<sizeof(zBuf) ); + sqlite3_randomness(n, zBuf); + for(i=0; i<n; i++){ + zBuf[i] = zSrc[zBuf[i]%(sizeof(zSrc)-1)]; + } + zBuf[n] = 0; + sqlite3_result_text(context, (char*)zBuf, n, SQLITE_TRANSIENT); +} + +/* +** The following two SQL functions are used to test returning a text +** result with a destructor. Function 'test_destructor' takes one argument +** and returns the same argument interpreted as TEXT. A destructor is +** passed with the sqlite3_result_text() call. +** +** SQL function 'test_destructor_count' returns the number of outstanding +** allocations made by 'test_destructor'; +** +** WARNING: Not threadsafe. +*/ +static int test_destructor_count_var = 0; +static void destructor(void *p){ + char *zVal = (char *)p; + assert(zVal); + zVal--; + sqlite3_free(zVal); + test_destructor_count_var--; +} +static void test_destructor( + sqlite3_context *pCtx, + int nArg, + sqlite3_value **argv +){ + char *zVal; + int len; + + test_destructor_count_var++; + assert( nArg==1 ); + if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return; + len = sqlite3_value_bytes(argv[0]); + zVal = testContextMalloc(pCtx, len+3); + if( !zVal ){ + return; + } + zVal[len+1] = 0; + zVal[len+2] = 0; + zVal++; + memcpy(zVal, sqlite3_value_text(argv[0]), len); + sqlite3_result_text(pCtx, zVal, -1, destructor); +} +static void test_destructor_count( + sqlite3_context *pCtx, + int nArg, + sqlite3_value **argv +){ + sqlite3_result_int(pCtx, test_destructor_count_var); +} + +/* +** Routines for testing the sqlite3_get_auxdata() and sqlite3_set_auxdata() +** interface. +** +** The test_auxdata() SQL function attempts to register each of its arguments +** as auxiliary data. If there are no prior registrations of aux data for +** that argument (meaning the argument is not a constant or this is its first +** call) then the result for that argument is 0. If there is a prior +** registration, the result for that argument is 1. The overall result +** is the individual argument results separated by spaces. +*/ +static void free_test_auxdata(void *p) {sqlite3_free(p);} +static void test_auxdata( + sqlite3_context *pCtx, + int nArg, + sqlite3_value **argv +){ + int i; + char *zRet = testContextMalloc(pCtx, nArg*2); + if( !zRet ) return; + memset(zRet, 0, nArg*2); + for(i=0; i<nArg; i++){ + char const *z = (char*)sqlite3_value_text(argv[i]); + if( z ){ + int n; + char *zAux = sqlite3_get_auxdata(pCtx, i); + if( zAux ){ + zRet[i*2] = '1'; + assert( strcmp(zAux,z)==0 ); + }else { + zRet[i*2] = '0'; + } + n = strlen(z) + 1; + zAux = testContextMalloc(pCtx, n); + if( zAux ){ + memcpy(zAux, z, n); + sqlite3_set_auxdata(pCtx, i, zAux, free_test_auxdata); + } + zRet[i*2+1] = ' '; + } + } + sqlite3_result_text(pCtx, zRet, 2*nArg-1, free_test_auxdata); +} + +/* +** A function to test error reporting from user functions. This function +** returns a copy of its first argument as an error. +*/ +static void test_error( + sqlite3_context *pCtx, + int nArg, + sqlite3_value **argv +){ + sqlite3_result_error(pCtx, (char*)sqlite3_value_text(argv[0]), 0); +} + +static int registerTestFunctions(sqlite3 *db){ + static const struct { + char *zName; + signed char nArg; + unsigned char eTextRep; /* 1: UTF-16. 0: UTF-8 */ + void (*xFunc)(sqlite3_context*,int,sqlite3_value **); + } aFuncs[] = { + { "randstr", 2, SQLITE_UTF8, randStr }, + { "test_destructor", 1, SQLITE_UTF8, test_destructor}, + { "test_destructor_count", 0, SQLITE_UTF8, test_destructor_count}, + { "test_auxdata", -1, SQLITE_UTF8, test_auxdata}, + { "test_error", 1, SQLITE_UTF8, test_error}, + }; + int i; + + for(i=0; i<sizeof(aFuncs)/sizeof(aFuncs[0]); i++){ + sqlite3_create_function(db, aFuncs[i].zName, aFuncs[i].nArg, + aFuncs[i].eTextRep, 0, aFuncs[i].xFunc, 0, 0); + } + return SQLITE_OK; +} + +/* +** TCLCMD: autoinstall_test_functions +** +** Invoke this TCL command to use sqlite3_auto_extension() to cause +** the standard set of test functions to be loaded into each new +** database connection. +*/ +static int autoinstall_test_funcs( + void * clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *CONST objv[] +){ + sqlite3_auto_extension((void*)registerTestFunctions); + return TCL_OK; +} + + + +/* +** Register commands with the TCL interpreter. +*/ +int Sqlitetest_func_Init(Tcl_Interp *interp){ + static struct { + char *zName; + Tcl_ObjCmdProc *xProc; + } aObjCmd[] = { + { "autoinstall_test_functions", autoinstall_test_funcs }, + }; + int i; + for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){ + Tcl_CreateObjCommand(interp, aObjCmd[i].zName, aObjCmd[i].xProc, 0, 0); + } + sqlite3_auto_extension((void*)registerTestFunctions); + return TCL_OK; +} |