/* ** 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. */ #include "sqlite4.h" #include "tcl.h" #include #include #include /* ** Allocate nByte bytes of space using sqlite4_malloc(). If the ** allocation fails, call sqlite4_result_error_nomem() to notify ** the database handle that malloc() has failed. */ static void *testContextMalloc(sqlite4_context *context, int nByte){ char *z = sqlite4_malloc(sqlite4_context_env(context), nByte); if( !z && nByte>0 ){ sqlite4_result_error_nomem(context); } return z; } /* ** This function generates a string of random characters. Used for ** generating test data. */ static void randStr(sqlite4_context *context, int argc, sqlite4_value **argv){ static const unsigned char zSrc[] = "abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "0123456789" ".-!,:*^+=_|?/<> "; int iMin, iMax, n, r, i; sqlite4_env *pEnv = sqlite4_context_env(context); 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 = sqlite4_value_int(argv[0]); if( iMin<0 ) iMin = 0; if( iMin>=sizeof(zBuf) ) iMin = sizeof(zBuf)-1; iMax = sqlite4_value_int(argv[1]); if( iMax=sizeof(zBuf) ) iMax = sizeof(zBuf)-1; n = iMin; if( iMax>iMin ){ sqlite4_randomness(pEnv, sizeof(r), &r); r &= 0x7fffffff; n += r%(iMax + 1 - iMin); } assert( npEnv, p); } /* ** Implementation of the counter(X) function. If X is an integer ** constant, then the first invocation will return X. The second X+1. ** and so forth. Can be used (for example) to provide a sequence number ** in a result set. */ static void counterFunc( sqlite4_context *pCtx, /* Function context */ int nArg, /* Number of function arguments */ sqlite4_value **argv /* Values for all function arguments */ ){ struct counterObject *pCounter; pCounter = (struct counterObject*)sqlite4_auxdata_fetch(pCtx, 0); if( pCounter==0 ){ pCounter = sqlite4_malloc(sqlite4_context_env(pCtx), sizeof(*pCounter) ); if( pCounter==0 ){ sqlite4_result_error_nomem(pCtx); return; } pCounter->cnt = sqlite4_value_int(argv[0]); pCounter->pEnv = sqlite4_context_env(pCtx); sqlite4_auxdata_store(pCtx, 0, pCounter, counterFree, 0); }else{ pCounter->cnt++; } sqlite4_result_int(pCtx, pCounter->cnt); } /* ** This function takes two arguments. It performance UTF-8/16 type ** conversions on the first argument then returns a copy of the second ** argument. ** ** This function is used in cases such as the following: ** ** SELECT test_isolation(x,x) FROM t1; ** ** We want to verify that the type conversions that occur on the ** first argument do not invalidate the second argument. */ static void test_isolation( sqlite4_context *pCtx, int nArg, sqlite4_value **argv ){ #ifndef SQLITE4_OMIT_UTF16 sqlite4_value_text16(argv[0], 0); sqlite4_value_text(argv[0], 0); sqlite4_value_text16(argv[0], 0); sqlite4_value_text(argv[0], 0); #endif sqlite4_result_value(pCtx, argv[1]); } /* ** Invoke an SQL statement recursively. The function result is the ** first column of the first row of the result set. */ static void test_eval( sqlite4_context *pCtx, int nArg, sqlite4_value **argv ){ sqlite4_stmt *pStmt; int rc; sqlite4 *db = sqlite4_context_db_handle(pCtx); const char *zSql; zSql = sqlite4_value_text(argv[0], 0); rc = sqlite4_prepare(db, zSql, -1, &pStmt, 0); if( rc==SQLITE4_OK ){ rc = sqlite4_step(pStmt); if( rc==SQLITE4_ROW ){ sqlite4_result_value(pCtx, sqlite4_column_value(pStmt, 0)); } rc = sqlite4_finalize(pStmt); } if( rc ){ char *zErr; sqlite4_env *pEnv = sqlite4_context_env(pCtx); assert( pStmt==0 ); zErr = sqlite4_mprintf(pEnv, "sqlite4_prepare() error: %s", sqlite4_errmsg(db)); sqlite4_result_text(pCtx, zErr, -1, SQLITE4_DYNAMIC, 0); sqlite4_result_error_code(pCtx, rc); } } /* ** convert one character from hex to binary */ static int testHexChar(char c){ if( c>='0' && c<='9' ){ return c - '0'; }else if( c>='a' && c<='f' ){ return c - 'a' + 10; }else if( c>='A' && c<='F' ){ return c - 'A' + 10; } return 0; } /* ** Convert hex to binary. */ static void testHexToBin(const char *zIn, char *zOut){ while( zIn[0] && zIn[1] ){ *(zOut++) = (testHexChar(zIn[0])<<4) + testHexChar(zIn[1]); zIn += 2; } } /* ** hex_to_utf16be(HEX) ** ** Convert the input string from HEX into binary. Then return the ** result using sqlite4_result_text16le(). */ #ifndef SQLITE4_OMIT_UTF16 static void testHexToUtf16be( sqlite4_context *pCtx, int nArg, sqlite4_value **argv ){ int n; const char *zIn; char *zOut; assert( nArg==1 ); zIn = sqlite4_value_text(argv[0], &n); zOut = sqlite4_malloc(sqlite4_context_env(pCtx), n/2 ); if( zOut==0 ){ sqlite4_result_error_nomem(pCtx); }else{ testHexToBin(zIn, zOut); sqlite4_result_text16be(pCtx, zOut, n/2, SQLITE4_DYNAMIC, 0); } } #endif /* ** hex_to_utf8(HEX) ** ** Convert the input string from HEX into binary. Then return the ** result using sqlite4_result_text16le(). */ static void testHexToUtf8( sqlite4_context *pCtx, int nArg, sqlite4_value **argv ){ int n; const char *zIn; char *zOut; assert( nArg==1 ); zIn = sqlite4_value_text(argv[0], &n); zOut = sqlite4_malloc(sqlite4_context_env(pCtx), n/2 ); if( zOut==0 ){ sqlite4_result_error_nomem(pCtx); }else{ testHexToBin(zIn, zOut); sqlite4_result_text(pCtx, zOut, n/2, SQLITE4_DYNAMIC, 0); } } /* ** hex_to_utf16le(HEX) ** ** Convert the input string from HEX into binary. Then return the ** result using sqlite4_result_text16le(). */ #ifndef SQLITE4_OMIT_UTF16 static void testHexToUtf16le( sqlite4_context *pCtx, int nArg, sqlite4_value **argv ){ int n; const char *zIn; char *zOut; assert( nArg==1 ); zIn = sqlite4_value_text(argv[0], &n); zOut = sqlite4_malloc(sqlite4_context_env(pCtx), n/2 ); if( zOut==0 ){ sqlite4_result_error_nomem(pCtx); }else{ testHexToBin(zIn, zOut); sqlite4_result_text16le(pCtx, zOut, n/2, SQLITE4_DYNAMIC, 0); } } #endif static int registerTestFunctions(sqlite4 *db){ static const struct { char *zName; signed char nArg; unsigned char eTextRep; /* 1: UTF-16. 0: UTF-8 */ void (*xFunc)(sqlite4_context*,int,sqlite4_value **); } aFuncs[] = { { "randstr", 2, SQLITE4_UTF8, randStr }, { "test_destructor", 1, SQLITE4_UTF8, test_destructor}, #ifndef SQLITE4_OMIT_UTF16 { "test_destructor16", 1, SQLITE4_UTF8, test_destructor16}, { "hex_to_utf16be", 1, SQLITE4_UTF8, testHexToUtf16be}, { "hex_to_utf16le", 1, SQLITE4_UTF8, testHexToUtf16le}, #endif { "hex_to_utf8", 1, SQLITE4_UTF8, testHexToUtf8}, { "test_destructor_count", 0, SQLITE4_UTF8, test_destructor_count}, { "test_auxdata", -1, SQLITE4_UTF8, test_auxdata}, { "test_error", 1, SQLITE4_UTF8, test_error}, { "test_error", 2, SQLITE4_UTF8, test_error}, { "test_eval", 1, SQLITE4_UTF8, test_eval}, { "test_isolation", 2, SQLITE4_UTF8, test_isolation}, { "test_counter", 1, SQLITE4_UTF8, counterFunc}, }; int i; for(i=0; i