Fix the TCL interface so that SQL functions implemented in TCL honor the

"nullvalue" setting.  Also remove from the TCL interface some unused 
legacy UTF8 translation code left over from SQLite2.

FossilOrigin-Name: c1f10a2643179ec58f3879764e9e89676d4b5f91
This commit is contained in:
drh 2012-10-03 11:02:33 +00:00
parent e7c54168fa
commit c45e67162d
4 changed files with 33 additions and 48 deletions

View File

@ -1,5 +1,5 @@
C Work\saround\san\soptimization\sissue\swith\sthe\sMSVC\scompiler\sfor\sARM.
D 2012-10-02T22:54:27.390
C Fix\sthe\sTCL\sinterface\sso\sthat\sSQL\sfunctions\simplemented\sin\sTCL\shonor\sthe\n"nullvalue"\ssetting.\s\sAlso\sremove\sfrom\sthe\sTCL\sinterface\ssome\sunused\s\nlegacy\sUTF8\stranslation\scode\sleft\sover\sfrom\sSQLite2.
D 2012-10-03T11:02:33.741
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in 5f4f26109f9d80829122e0e09f9cda008fa065fb
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@ -183,7 +183,7 @@ F src/sqliteInt.h c29395d6e68cfbcb2661787ae4820e5e256c916a
F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
F src/status.c 35939e7e03abf1b7577ce311f48f682c40de3208
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
F src/tclsqlite.c 22de426c579d01c7bd2c24fb9229fbd774613b42
F src/tclsqlite.c fc9027118d5fa1b3d16a7b22c63684a54adeeb42
F src/test1.c 936afc02766403e5debca49a1817a780e116df7e
F src/test2.c 4178056dd1e7d70f954ad8a1e3edb71a2a784daf
F src/test3.c 3c3c2407fa6ec7a19e24ae23f7cb439d0275a60d
@ -737,7 +737,7 @@ F test/syscall.test bea9bf329bff733c791310244617c2a76974e64a
F test/sysfault.test c79441d88d23696fbec7b147dba98d42a04f523f
F test/table.test a59d985ca366e39b17b175f387f9d5db5a18d4e2
F test/tableapi.test 2674633fa95d80da917571ebdd759a14d9819126
F test/tclsqlite.test a3d2df21ee98957f5de4f9dc1db0eab68047ab5d
F test/tclsqlite.test 37a61c2da7e3bfe3b8c1a2867199f6b860df5d43
F test/tempdb.test 19d0f66e2e3eeffd68661a11c83ba5e6ace9128c
F test/temptable.test 51edd31c65ed1560dd600b1796e8325df96318e2
F test/temptrigger.test 26670ed7a39cf2296a7f0a9e0a1d7bdb7abe936d
@ -1018,7 +1018,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381
F tool/win/sqlite.vsix 67d8a99aceb56384a81b3f30d6c71743146d2cc9
P abcf6a5d054559ee5a093ba39180c47b4958d9cd
R e2af9a84c8984f66075b1b5542126d99
U mistachkin
Z 2e5e5eca8b24072e2977c29980c9c33a
P 7d301fdfeec540e4a58f43bff04d219e9f769dc4
R 6327212080c41cdbc10c1e2eb094be0d
U drh
Z 25d327c4e46a0608f83a0eb5d2f156c2

View File

@ -1 +1 @@
7d301fdfeec540e4a58f43bff04d219e9f769dc4
c1f10a2643179ec58f3879764e9e89676d4b5f91

View File

@ -53,15 +53,8 @@
#define NUM_PREPARED_STMTS 10
#define MAX_PREPARED_STMTS 100
/*
** If TCL uses UTF-8 and SQLite is configured to use iso8859, then we
** have to do a translation when going between the two. Set the
** UTF_TRANSLATION_NEEDED macro to indicate that we need to do
** this translation.
*/
#if defined(TCL_UTF_MAX) && !defined(SQLITE_UTF8)
# define UTF_TRANSLATION_NEEDED 1
#endif
/* Forward declaration */
typedef struct SqliteDb SqliteDb;
/*
** New SQL functions can be created as TCL scripts. Each such function
@ -71,6 +64,7 @@ typedef struct SqlFunc SqlFunc;
struct SqlFunc {
Tcl_Interp *interp; /* The TCL interpret to execute the function */
Tcl_Obj *pScript; /* The Tcl_Obj representation of the script */
SqliteDb *pDb; /* Database connection that owns this function */
int useEvalObjv; /* True if it is safe to use Tcl_EvalObjv */
char *zName; /* Name of this function */
SqlFunc *pNext; /* Next function on the list of them all */
@ -113,7 +107,6 @@ typedef struct IncrblobChannel IncrblobChannel;
** sqlite3_prepare_v2() or sqlite3_prepare() to prepare SQL statements.
** If SqliteDb.bLegacyPrepare is true, sqlite3_prepare() is used.
*/
typedef struct SqliteDb SqliteDb;
struct SqliteDb {
sqlite3 *db; /* The "real" database structure. MUST BE FIRST */
Tcl_Interp *interp; /* The interpreter used for this database */
@ -431,6 +424,7 @@ static SqlFunc *findSqlFunc(SqliteDb *pDb, const char *zName){
}
}
pNew->interp = pDb->interp;
pNew->pDb = pDb;
pNew->pScript = 0;
pNew->pNext = pDb->pFunc;
pDb->pFunc = pNew;
@ -478,6 +472,7 @@ static void DbDeleteCmd(void *db){
while( pDb->pFunc ){
SqlFunc *pFunc = pDb->pFunc;
pDb->pFunc = pFunc->pNext;
assert( pFunc->pDb==pDb );
Tcl_DecrRefCount(pFunc->pScript);
Tcl_Free((char*)pFunc);
}
@ -794,7 +789,7 @@ static void tclSqlFunc(sqlite3_context *context, int argc, sqlite3_value**argv){
break;
}
case SQLITE_NULL: {
pVal = Tcl_NewStringObj("", 0);
pVal = Tcl_NewStringObj(p->pDb->zNull, -1);
break;
}
default: {
@ -933,26 +928,6 @@ static int auth_callback(
}
#endif /* SQLITE_OMIT_AUTHORIZATION */
/*
** zText is a pointer to text obtained via an sqlite3_result_text()
** or similar interface. This routine returns a Tcl string object,
** reference count set to 0, containing the text. If a translation
** between iso8859 and UTF-8 is required, it is preformed.
*/
static Tcl_Obj *dbTextToObj(char const *zText){
Tcl_Obj *pVal;
#ifdef UTF_TRANSLATION_NEEDED
Tcl_DString dCol;
Tcl_DStringInit(&dCol);
Tcl_ExternalToUtfDString(NULL, zText, -1, &dCol);
pVal = Tcl_NewStringObj(Tcl_DStringValue(&dCol), -1);
Tcl_DStringFree(&dCol);
#else
pVal = Tcl_NewStringObj(zText, -1);
#endif
return pVal;
}
/*
** This routine reads a line of text from FILE in, stores
** the text in memory obtained from malloc() and returns a pointer
@ -1140,13 +1115,13 @@ static int dbPrepareAndBind(
int nByte;
if( SQLITE_OK!=dbPrepare(pDb, zSql, &pStmt, pzOut) ){
Tcl_SetObjResult(interp, dbTextToObj(sqlite3_errmsg(pDb->db)));
Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3_errmsg(pDb->db), -1));
return TCL_ERROR;
}
if( pStmt==0 ){
if( SQLITE_OK!=sqlite3_errcode(pDb->db) ){
/* A compile-time error in the statement. */
Tcl_SetObjResult(interp, dbTextToObj(sqlite3_errmsg(pDb->db)));
Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3_errmsg(pDb->db), -1));
return TCL_ERROR;
}else{
/* The statement was a no-op. Continue to the next statement
@ -1365,7 +1340,7 @@ static void dbEvalRowInfo(
if( nCol>0 && (papColName || p->pArray) ){
apColName = (Tcl_Obj**)Tcl_Alloc( sizeof(Tcl_Obj*)*nCol );
for(i=0; i<nCol; i++){
apColName[i] = dbTextToObj(sqlite3_column_name(pStmt,i));
apColName[i] = Tcl_NewStringObj(sqlite3_column_name(pStmt,i), -1);
Tcl_IncrRefCount(apColName[i]);
}
p->apColName = apColName;
@ -1452,7 +1427,8 @@ static int dbEvalStep(DbEvalContext *p){
continue;
}
#endif
Tcl_SetObjResult(pDb->interp, dbTextToObj(sqlite3_errmsg(pDb->db)));
Tcl_SetObjResult(pDb->interp,
Tcl_NewStringObj(sqlite3_errmsg(pDb->db), -1));
return TCL_ERROR;
}else{
dbReleaseStmt(pDb, pPreStmt, 0);
@ -1509,11 +1485,11 @@ static Tcl_Obj *dbEvalColumnValue(DbEvalContext *p, int iCol){
return Tcl_NewDoubleObj(sqlite3_column_double(pStmt, iCol));
}
case SQLITE_NULL: {
return dbTextToObj(p->pDb->zNull);
return Tcl_NewStringObj(p->pDb->zNull, -1);
}
}
return dbTextToObj((char *)sqlite3_column_text(pStmt, iCol));
return Tcl_NewStringObj(sqlite3_column_text(pStmt, iCol), -1);
}
/*
@ -2433,7 +2409,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
pDb->zNull = 0;
}
}
Tcl_SetObjResult(interp, dbTextToObj(pDb->zNull));
Tcl_SetObjResult(interp, Tcl_NewStringObj(pDb->zNull, -1));
break;
}

View File

@ -319,14 +319,23 @@ do_test tcl-8.1 {
execsql {INSERT INTO t1 VALUES(30,NULL)}
db eval {SELECT * FROM t1 WHERE b IS NULL}
} {30 NaN}
proc concatFunc args {return [join $args {}]}
do_test tcl-8.2 {
db function concat concatFunc
db eval {SELECT concat('a', b, 'z') FROM t1 WHERE b is NULL}
} {aNaNz}
do_test tcl-8.3 {
db nullvalue NULL
db nullvalue
} {NULL}
do_test tcl-8.3 {
do_test tcl-8.4 {
db nullvalue {}
db eval {SELECT * FROM t1 WHERE b IS NULL}
} {30 {}}
do_test tcl-8.5 {
db function concat concatFunc
db eval {SELECT concat('a', b, 'z') FROM t1 WHERE b is NULL}
} {az}
# Test the return type of user-defined functions
#