-C Make\sthe\s.exit\sand\s.quit\scommands\swork\sagain\sin\sthe\sshell.\s\sTicket\s#2056.\s(CVS\s3505)
-D 2006-11-08T12:25:43
+C First\scut\sat\sadding\sthe\ssqlite3_prepare_v2()\sAPI.\s\sTest\scases\sadded,\sbut\nmore\stesting\swould\sbe\suseful.\s\sStill\sneed\sto\supdate\sthe\sdocumentation.\s(CVS\s3506)
+D 2006-11-09T00:24:54
F Makefile.in 8e14898d41a53033ecb687d93c9cd5d109fb9ae3
F Makefile.linux-gcc 2d8574d1ba75f129aba2019f0b959db380a90935
F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028
F src/pager.h 2e6d42f4ae004ae748a037b8468112b851c447a7
F src/parse.y 8c79a1debbd92a4f5609511e9bf0222de78f5ecb
F src/pragma.c 2ef4353448e202961a22312f34695128bbb6d69a
-F src/prepare.c 3d9a1bb0644e8bccb3b78cb0833d269719237f4e
+F src/prepare.c f4f45b4560defbb566cf8255763625d2c09a8023
F src/printf.c b179b6ed12f793e028dd169e2e2e2b2a37eedc63
F src/random.c d40f8d356cecbd351ccfab6eaedd7ec1b54f5261
F src/select.c 6ba6d8ead43d0575ce1f8b418cc039f8f301389a
F src/server.c 087b92a39d883e3fa113cae259d64e4c7438bc96
F src/shell.c 41513f31dce4252198944c712b79ea4c92df2592
-F src/sqlite.h.in bf935004029631fd93d119bcf2f7259b9cb9ad5e
+F src/sqlite.h.in 2931f7ee2415e7a49fd12f386c23575046f0f540
F src/sqlite3ext.h 2c2156cc32a158e2b7bd9042d42accf94bff2e40
-F src/sqliteInt.h 637ef229c3d8e0f98096ab31c496efdf5361d678
+F src/sqliteInt.h f6bac44ee7b8ee2614b046974551c22999ec674f
F src/table.c 6d0da66dde26ee75614ed8f584a1996467088d06
F src/tclsqlite.c e029f739bed90071789fe81a226d53e97a80a4d8
-F src/test1.c 20ca02cba62082b58a5e59f1278632dbd32024a1
+F src/test1.c 3d0cb8837eb13e6cd5fe2b76a37ba8d9c0ad77fc
F src/test2.c ca74a1d8aeb7d9606e8f6b762c5daf85c1a3f92b
F src/test3.c 85135c09560c48bdb0a23c9b890ab405486b8ec9
F src/test4.c 8b784cd82de158a2317cb4ac4bc86f91ad315e25
F src/util.c 91d4cb189476906639ae611927d939691d1365f6
F src/vacuum.c f6a7943f1f1002cb82ef2ea026cb1975a5b687cb
F src/vdbe.c 3e31f2e49423955afb2ac905ceacf54c679b1f28
-F src/vdbe.h 258b5d1c0aaa72192f09ff0568ce42b383f156fa
-F src/vdbeInt.h e3eaab262b67b84474625cfc38aec1125c32834b
-F src/vdbeapi.c f1858a5edc3a5e32d038514dd9e7e9091400a782
-F src/vdbeaux.c 78c744f127df03ea63098ebb7dd7fe3eb303e284
+F src/vdbe.h 9720cae673359dc2bdcb106285ecf686b7d3ef24
+F src/vdbeInt.h 1ca07f2d7446c90230346aed7fbf990c032460bc
+F src/vdbeapi.c 2d1e6843af8705a1172e54a418d2a3d5febd1dd7
+F src/vdbeaux.c 05cc6f0f82b86dfb4c356e06ab07ec8cc83a2eda
F src/vdbefifo.c 9efb94c8c3f4c979ebd0028219483f88e57584f5
F src/vdbemem.c 26623176bf1c616aa478da958fac49502491a921
F src/vtab.c aa30e940058ea56a1b7a9a7019ec21d307316fb4
F test/capi2.test cb478885b8b1a6a9f703a9da1c8d7d101c0970d6
F test/capi3.test 5f54824e8356ad25ee40a101b36452e74d68a945
F test/capi3b.test 5f0bc94b104e11086b1103b20277e1910f59c7f4
+F test/capi3c.test d45ecc2e06879967a6a0786dff1caa2195f08ac1
F test/cast.test f88e7b6946e9a467cf4bb142d92bb65a83747fc2
F test/check.test e5ea0c1a06c10e81e3434ca029e2c4a562f2b673
F test/collate1.test add9454cef160677bb8b34148b8f277ce7f9f1c4
F test/pragma.test b81f483cac7b8fe519988a102303799cc72d25a2
F test/printf.test cdd8e20dd901382a385afcbaa777b9377815c2ad
F test/progress.test 8b22b4974b0a95272566385f8cb8c341c7130df8 x
-F test/quick.test 4eabf0fd67dc6e116cbebe3f8d899608239eae50
+F test/quick.test 71ed89a1a516fe1594b178e0001342eafcd2f32a
F test/quote.test 5891f2338980916cf7415484b4ce785294044adb
F test/reindex.test 38b138abe36bf9a08c791ed44d9f76cd6b97b78b
F test/rollback.test 673cd8c44c685ad54987fe7f0eeba84efa09685d
F test/rowid.test 040a3bef06f970c45f5fcd14b2355f7f4d62f0cf
F test/safety.test 4a06934e45d03b8b50ebcd8d174eb0367d2fd851
F test/schema.test 8a2ae440fb15f5798a68059e8746402f3137be46
+F test/schema2.test d815923e57e90b8c60ddf5e0d8fd65075e94f57f
F test/select1.test fa4e941da0a38961635d903530bd292dc149a8e8
F test/select2.test f3c2678c3a9f3cf08ec4988a3845bda64be6d9e3
F test/select3.test 33c78663e6b1b41220dcec4eb6affb1a05001ffe
F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b
F www/whentouse.tcl 97e2b5cd296f7d8057e11f44427dea8a4c2db513
-P d309680ec7a806d181b601e0105aebf1e33bfb81
-R e590c00bb49173f4e5a5df7e97598d24
+P f39978ef13e986a16ee322ee84ab9bd38ffc5a8b
+R dc22d9f5d0aa421e42db62c318429739
U drh
-Z 928b8f12ac488a19e769eda3ed1d6f5a
+Z d20637c076532a0c72ad06c1b6f375c3
-f39978ef13e986a16ee322ee84ab9bd38ffc5a8b
\ No newline at end of file
+f1efae9224170c9155afcf17ab3ee769a557b874
\ No newline at end of file
** interface, and routines that contribute to loading the database schema
** from disk.
**
-** $Id: prepare.c,v 1.40 2006/09/23 20:36:02 drh Exp $
+** $Id: prepare.c,v 1.41 2006/11/09 00:24:54 drh Exp $
*/
#include "sqliteInt.h"
#include "os.h"
/*
** Compile the UTF-8 encoded SQL statement zSql into a statement handle.
*/
-int sqlite3_prepare(
+int sqlite3Prepare(
sqlite3 *db, /* Database handle. */
const char *zSql, /* UTF-8 encoded SQL statement. */
int nBytes, /* Length of zSql in bytes. */
+ int saveSqlFlag, /* True to copy SQL text into the sqlite3_stmt */
sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */
- const char** pzTail /* OUT: End of parsed string */
+ const char **pzTail /* OUT: End of parsed string */
){
Parse sParse;
char *zErrMsg = 0;
if( sqlite3MallocFailed() ){
sParse.rc = SQLITE_NOMEM;
}
- if( pzTail ) *pzTail = sParse.zTail;
+ if( pzTail ){
+ *pzTail = sParse.zTail;
+ }
rc = sParse.rc;
#ifndef SQLITE_OMIT_EXPLAIN
sqlite3VdbeSetColName(sParse.pVdbe, 3, COLNAME_NAME, "p2", P3_STATIC);
sqlite3VdbeSetColName(sParse.pVdbe, 4, COLNAME_NAME, "p3", P3_STATIC);
}
- }
+ }
#endif
if( sqlite3SafetyOff(db) ){
rc = SQLITE_MISUSE;
}
if( rc==SQLITE_OK ){
+ if( saveSqlFlag ){
+ sqlite3VdbeSetSql(sParse.pVdbe, zSql, sParse.zTail - zSql);
+ }
*ppStmt = (sqlite3_stmt*)sParse.pVdbe;
}else if( sParse.pVdbe ){
sqlite3_finalize((sqlite3_stmt*)sParse.pVdbe);
return rc;
}
+/*
+** Rerun the compilation of a statement after a schema change.
+** Return true if the statement was recompiled successfully.
+** Return false if there is an error of some kind.
+*/
+int sqlite3Reprepare(Vdbe *p){
+ int rc;
+ Vdbe *pNew;
+ const char *zSql;
+ sqlite3 *db;
+
+ zSql = sqlite3VdbeGetSql(p);
+ if( zSql==0 ){
+ return 0;
+ }
+ db = sqlite3VdbeDb(p);
+ rc = sqlite3Prepare(db, zSql, -1, 0, (sqlite3_stmt**)&pNew, 0);
+ if( rc ){
+ assert( pNew==0 );
+ return 0;
+ }else{
+ assert( pNew!=0 );
+ }
+ sqlite3VdbeSwapOps(pNew, p);
+ sqlite3_finalize((sqlite3_stmt*)pNew);
+ return 1;
+}
+
+
+/*
+** Two versions of the official API. Legacy and new use. In the legacy
+** version, the original SQL text is not saved in the prepared statement
+** and so if a schema change occurs, SQLITE_SCHEMA is returned by
+** sqlite3_step(). In the new version, the original SQL text is retained
+** and the statement is automatically recompiled if an schema change
+** occurs.
+*/
+int sqlite3_prepare(
+ sqlite3 *db, /* Database handle. */
+ const char *zSql, /* UTF-8 encoded SQL statement. */
+ int nBytes, /* Length of zSql in bytes. */
+ sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */
+ const char **pzTail /* OUT: End of parsed string */
+){
+ return sqlite3Prepare(db,zSql,nBytes,0,ppStmt,pzTail);
+}
+int sqlite3_prepare_v2(
+ sqlite3 *db, /* Database handle. */
+ const char *zSql, /* UTF-8 encoded SQL statement. */
+ int nBytes, /* Length of zSql in bytes. */
+ sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */
+ const char **pzTail /* OUT: End of parsed string */
+){
+ return sqlite3Prepare(db,zSql,nBytes,1,ppStmt,pzTail);
+}
+
+
#ifndef SQLITE_OMIT_UTF16
/*
** Compile the UTF-16 encoded SQL statement zSql into a statement handle.
*/
-int sqlite3_prepare16(
+static int sqlite3Prepare16(
sqlite3 *db, /* Database handle. */
const void *zSql, /* UTF-8 encoded SQL statement. */
int nBytes, /* Length of zSql in bytes. */
+ int saveSqlFlag, /* True to save SQL text into the sqlite3_stmt */
sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */
const void **pzTail /* OUT: End of parsed string */
){
}
zSql8 = sqlite3utf16to8(zSql, nBytes);
if( zSql8 ){
- rc = sqlite3_prepare(db, zSql8, -1, ppStmt, &zTail8);
+ rc = sqlite3Prepare(db, zSql8, -1, saveSqlFlag, ppStmt, &zTail8);
}
if( zTail8 && pzTail ){
sqliteFree(zSql8);
return sqlite3ApiExit(db, rc);
}
+
+/*
+** Two versions of the official API. Legacy and new use. In the legacy
+** version, the original SQL text is not saved in the prepared statement
+** and so if a schema change occurs, SQLITE_SCHEMA is returned by
+** sqlite3_step(). In the new version, the original SQL text is retained
+** and the statement is automatically recompiled if an schema change
+** occurs.
+*/
+int sqlite3_prepare16(
+ sqlite3 *db, /* Database handle. */
+ const void *zSql, /* UTF-8 encoded SQL statement. */
+ int nBytes, /* Length of zSql in bytes. */
+ sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */
+ const void **pzTail /* OUT: End of parsed string */
+){
+ return sqlite3Prepare16(db,zSql,nBytes,0,ppStmt,pzTail);
+}
+int sqlite3_prepare16_v2(
+ sqlite3 *db, /* Database handle. */
+ const void *zSql, /* UTF-8 encoded SQL statement. */
+ int nBytes, /* Length of zSql in bytes. */
+ sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */
+ const void **pzTail /* OUT: End of parsed string */
+){
+ return sqlite3Prepare16(db,zSql,nBytes,1,ppStmt,pzTail);
+}
+
#endif /* SQLITE_OMIT_UTF16 */
** This header file defines the interface that the SQLite library
** presents to client programs.
**
-** @(#) $Id: sqlite.h.in,v 1.194 2006/09/16 21:45:14 drh Exp $
+** @(#) $Id: sqlite.h.in,v 1.195 2006/11/09 00:24:54 drh Exp $
*/
#ifndef _SQLITE3_H_
#define _SQLITE3_H_
const void **pzTail /* OUT: Pointer to unused portion of zSql */
);
+/*
+** Newer versions of the prepare API work just like the legacy versions
+** but with one exception: The a copy of the SQL text is saved in the
+** sqlite3_stmt structure that is returned. If this copy exists, it
+** modifieds the behavior of sqlite3_step() slightly. First, sqlite3_step()
+** will no longer return an SQLITE_SCHEMA error but will instead automatically
+** rerun the compiler to rebuild the prepared statement. Secondly,
+** sqlite3_step() now turns a full result code - the result code that
+** use used to have to call sqlite3_reset() to get.
+*/
+int sqlite3_prepare_v2(
+ sqlite3 *db, /* Database handle */
+ const char *zSql, /* SQL statement, UTF-8 encoded */
+ int nBytes, /* Length of zSql in bytes. */
+ sqlite3_stmt **ppStmt, /* OUT: Statement handle */
+ const char **pzTail /* OUT: Pointer to unused portion of zSql */
+);
+int sqlite3_prepare16_v2(
+ sqlite3 *db, /* Database handle */
+ const void *zSql, /* SQL statement, UTF-16 encoded */
+ int nBytes, /* Length of zSql in bytes. */
+ sqlite3_stmt **ppStmt, /* OUT: Statement handle */
+ const void **pzTail /* OUT: Pointer to unused portion of zSql */
+);
+
/*
** Pointers to the following two opaque structures are used to communicate
** with the implementations of user-defined functions.
*************************************************************************
** Internal interface definitions for SQLite.
**
-** @(#) $Id: sqliteInt.h,v 1.529 2006/09/23 20:36:02 drh Exp $
+** @(#) $Id: sqliteInt.h,v 1.530 2006/11/09 00:24:54 drh Exp $
*/
#ifndef _SQLITEINT_H_
#define _SQLITEINT_H_
int sqlite3VtabBegin(sqlite3 *, sqlite3_vtab *);
FuncDef *sqlite3VtabOverloadFunction(FuncDef*, int nArg, Expr*);
void sqlite3InvalidFunction(sqlite3_context*,int,sqlite3_value**);
+int sqlite3Reprepare(Vdbe*);
#ifdef SQLITE_SSE
#include "sseInt.h"
** is not included in the SQLite library. It is used for automated
** testing of the SQLite library.
**
-** $Id: test1.c,v 1.223 2006/10/19 20:27:59 shess Exp $
+** $Id: test1.c,v 1.224 2006/11/09 00:24:54 drh Exp $
*/
#include "sqliteInt.h"
#include "tcl.h"
}
/*
-** Usage: sqlite3_prepare DB sql bytes tailvar
+** Usage: sqlite3_prepare_v2 DB sql bytes tailvar
+**
+** Compile up to <bytes> bytes of the supplied SQL string <sql> using
+** database handle <DB>. The parameter <tailval> is the name of a global
+** variable that is set to the unused portion of <sql> (if any). A
+** STMT handle is returned.
+*/
+static int test_prepare_v2(
+ void * clientData,
+ Tcl_Interp *interp,
+ int objc,
+ Tcl_Obj *CONST objv[]
+){
+ sqlite3 *db;
+ const char *zSql;
+ int bytes;
+ const char *zTail = 0;
+ sqlite3_stmt *pStmt = 0;
+ char zBuf[50];
+ int rc;
+
+ if( objc!=5 ){
+ Tcl_AppendResult(interp, "wrong # args: should be \"",
+ Tcl_GetString(objv[0]), " DB sql bytes tailvar", 0);
+ return TCL_ERROR;
+ }
+ if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
+ zSql = Tcl_GetString(objv[2]);
+ if( Tcl_GetIntFromObj(interp, objv[3], &bytes) ) return TCL_ERROR;
+
+ rc = sqlite3_prepare_v2(db, zSql, bytes, &pStmt, &zTail);
+ if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR;
+ if( zTail ){
+ if( bytes>=0 ){
+ bytes = bytes - (zTail-zSql);
+ }
+ Tcl_ObjSetVar2(interp, objv[4], 0, Tcl_NewStringObj(zTail, bytes), 0);
+ }
+ if( rc!=SQLITE_OK ){
+ assert( pStmt==0 );
+ sprintf(zBuf, "(%d) ", rc);
+ Tcl_AppendResult(interp, zBuf, sqlite3_errmsg(db), 0);
+ return TCL_ERROR;
+ }
+
+ if( pStmt ){
+ if( sqlite3TestMakePointerStr(interp, zBuf, pStmt) ) return TCL_ERROR;
+ Tcl_AppendResult(interp, zBuf, 0);
+ }
+ return TCL_OK;
+}
+
+/*
+** Usage: sqlite3_prepare16 DB sql bytes tailvar
**
** Compile up to <bytes> bytes of the supplied SQL string <sql> using
** database handle <DB>. The parameter <tailval> is the name of a global
return TCL_OK;
}
+/*
+** Usage: sqlite3_prepare16_v2 DB sql bytes tailvar
+**
+** Compile up to <bytes> bytes of the supplied SQL string <sql> using
+** database handle <DB>. The parameter <tailval> is the name of a global
+** variable that is set to the unused portion of <sql> (if any). A
+** STMT handle is returned.
+*/
+static int test_prepare16_v2(
+ void * clientData,
+ Tcl_Interp *interp,
+ int objc,
+ Tcl_Obj *CONST objv[]
+){
+#ifndef SQLITE_OMIT_UTF16
+ sqlite3 *db;
+ const void *zSql;
+ const void *zTail = 0;
+ Tcl_Obj *pTail = 0;
+ sqlite3_stmt *pStmt = 0;
+ char zBuf[50];
+ int rc;
+ int bytes; /* The integer specified as arg 3 */
+ int objlen; /* The byte-array length of arg 2 */
+
+ if( objc!=5 ){
+ Tcl_AppendResult(interp, "wrong # args: should be \"",
+ Tcl_GetString(objv[0]), " DB sql bytes tailvar", 0);
+ return TCL_ERROR;
+ }
+ if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
+ zSql = Tcl_GetByteArrayFromObj(objv[2], &objlen);
+ if( Tcl_GetIntFromObj(interp, objv[3], &bytes) ) return TCL_ERROR;
+
+ rc = sqlite3_prepare16_v2(db, zSql, bytes, &pStmt, &zTail);
+ if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR;
+ if( rc ){
+ return TCL_ERROR;
+ }
+
+ if( zTail ){
+ objlen = objlen - ((u8 *)zTail-(u8 *)zSql);
+ }else{
+ objlen = 0;
+ }
+ pTail = Tcl_NewByteArrayObj((u8 *)zTail, objlen);
+ Tcl_IncrRefCount(pTail);
+ Tcl_ObjSetVar2(interp, objv[4], 0, pTail, 0);
+ Tcl_DecrRefCount(pTail);
+
+ if( pStmt ){
+ if( sqlite3TestMakePointerStr(interp, zBuf, pStmt) ) return TCL_ERROR;
+ }
+ Tcl_AppendResult(interp, zBuf, 0);
+#endif /* SQLITE_OMIT_UTF16 */
+ return TCL_OK;
+}
+
/*
** Usage: sqlite3_open filename ?options-list?
*/
{ "sqlite3_prepare", test_prepare ,0 },
{ "sqlite3_prepare16", test_prepare16 ,0 },
+ { "sqlite3_prepare_v2", test_prepare_v2 ,0 },
+ { "sqlite3_prepare16_v2", test_prepare16_v2 ,0 },
{ "sqlite3_finalize", test_finalize ,0 },
{ "sqlite3_reset", test_reset ,0 },
{ "sqlite3_expired", test_expired ,0 },
** or VDBE. The VDBE implements an abstract machine that runs a
** simple program to access and modify the underlying database.
**
-** $Id: vdbe.h,v 1.105 2006/06/13 23:51:35 drh Exp $
+** $Id: vdbe.h,v 1.106 2006/11/09 00:24:54 drh Exp $
*/
#ifndef _SQLITE_VDBE_H_
#define _SQLITE_VDBE_H_
int sqlite3VdbeSetColName(Vdbe*, int, int, const char *, int);
void sqlite3VdbeCountChanges(Vdbe*);
sqlite3 *sqlite3VdbeDb(Vdbe*);
+void sqlite3VdbeSetSql(Vdbe*, const char *z, int n);
+const char *sqlite3VdbeGetSql(Vdbe*);
+void sqlite3VdbeSwapOps(Vdbe*,Vdbe*);
#ifndef NDEBUG
void sqlite3VdbeComment(Vdbe*, const char*, ...);
u8 inVtabMethod; /* See comments above */
int nChange; /* Number of db changes made since last reset */
i64 startTime; /* Time when query started - used for profiling */
+ int nSql; /* Number of bytes in zSql */
+ char *zSql; /* Text of the SQL statement that generated this */
#ifdef SQLITE_SSE
int fetchId; /* Statement number used by sqlite3_fetch_statement */
int lru; /* Counter used for LRU cache replacement */
/*
** Execute the statement pStmt, either until a row of data is ready, the
** statement is completely executed or an error occurs.
+**
+** This routine implements the bulk of the logic behind the sqlite_step()
+** API. The only thing omitted is the automatic recompile if a
+** schema change has occurred. That detail is handled by the
+** outer sqlite3_step() wrapper procedure.
*/
-int sqlite3_step(sqlite3_stmt *pStmt){
- Vdbe *p = (Vdbe*)pStmt;
+static int sqlite3Step(Vdbe *p){
sqlite3 *db;
int rc;
if( p->rc==SQLITE_OK ){
p->rc = SQLITE_SCHEMA;
}
- return SQLITE_ERROR;
+ rc = SQLITE_ERROR;
+ goto end_of_step;
}
db = p->db;
if( sqlite3SafetyOn(db) ){
sqlite3Error(p->db, rc, 0);
p->rc = sqlite3ApiExit(p->db, p->rc);
+end_of_step:
assert( (rc&0xff)==rc );
+ if( p->zSql && (rc&0xff)<SQLITE_ROW ){
+ /* This behavior occurs if sqlite3_prepare_v2() was used to build
+ ** the prepared statement. Return error codes directly */
+ return p->rc;
+ }else{
+ /* This is for legacy sqlite3_prepare() builds and when the code
+ ** is SQLITE_ROW or SQLITE_DONE */
+ return rc;
+ }
+}
+
+/*
+** This is the top-level implementation of sqlite3_step(). Call
+** sqlite3Step() to do most of the work. If a schema error occurs,
+** call sqlite3Reprepare() and try again.
+*/
+#ifdef SQLITE_OMIT_PARSER
+int sqlite3_step(sqlite3_stmt *pStmt){
+ return sqlite3Step((Vdbe*)pStmt);
+}
+#else
+int sqlite3_step(sqlite3_stmt *pStmt){
+ int cnt = 0;
+ int rc;
+ Vdbe *v = (Vdbe*)pStmt;
+ while( (rc = sqlite3Step(v))==SQLITE_SCHEMA
+ && cnt++ < 5
+ && sqlite3Reprepare(v) ){
+ sqlite3_reset(pStmt);
+ v->expired = 0;
+ }
return rc;
}
+#endif
/*
** Extract the user data from a sqlite3_context structure and return a
return p;
}
+/*
+** Remember the SQL string for a prepared statement.
+*/
+void sqlite3VdbeSetSql(Vdbe *p, const char *z, int n){
+ if( p==0 ) return;
+ assert( p->zSql==0 );
+ p->zSql = sqlite3StrNDup(z, n);
+}
+
+/*
+** Return the SQL associated with a prepared statement
+*/
+const char *sqlite3VdbeGetSql(Vdbe *p){
+ return p->zSql;
+}
+
+/*
+** Swap the set of Opcodes between to Vdbe structures. No
+** other parts of either Vdbe structure are changed.
+*/
+void sqlite3VdbeSwapOps(Vdbe *pA, Vdbe *pB){
+ Op *aOp;
+ int nOp;
+
+ aOp = pA->aOp;
+ nOp = pA->nOp;
+ pA->aOp = pB->aOp;
+ pA->nOp = pB->nOp;
+ pB->aOp = aOp;
+ pB->nOp = nOp;
+}
+
/*
** Turn tracing on or off
*/
sqliteFree(p->aStack);
releaseMemArray(p->aColName, p->nResColumn*COLNAME_N);
sqliteFree(p->aColName);
+ sqliteFree(p->zSql);
p->magic = VDBE_MAGIC_DEAD;
sqliteFree(p);
}
--- /dev/null
+# 2006 November 08
+#
+# 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.
+#
+#***********************************************************************
+# This file implements regression tests for SQLite library.
+#
+# This is a copy of the capi3.test file that has been adapted to
+# test the new sqlite3_prepare_v2 interface.
+#
+# $Id: capi3c.test,v 1.1 2006/11/09 00:24:55 drh Exp $
+#
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+
+# Return the UTF-16 representation of the supplied UTF-8 string $str.
+# If $nt is true, append two 0x00 bytes as a nul terminator.
+proc utf16 {str {nt 1}} {
+ set r [encoding convertto unicode $str]
+ if {$nt} {
+ append r "\x00\x00"
+ }
+ return $r
+}
+
+# Return the UTF-8 representation of the supplied UTF-16 string $str.
+proc utf8 {str} {
+ # If $str ends in two 0x00 0x00 bytes, knock these off before
+ # converting to UTF-8 using TCL.
+ binary scan $str \c* vals
+ if {[lindex $vals end]==0 && [lindex $vals end-1]==0} {
+ set str [binary format \c* [lrange $vals 0 end-2]]
+ }
+
+ set r [encoding convertfrom unicode $str]
+ return $r
+}
+
+# These tests complement those in capi2.test. They are organized
+# as follows:
+#
+# capi3-1.*: Test sqlite3_prepare_v2
+# capi3-2.*: Test sqlite3_prepare16_v2
+# capi3-3.*: Test sqlite3_open
+# capi3-4.*: Test sqlite3_open16
+# capi3-5.*: Test the various sqlite3_result_* APIs
+# capi3-6.*: Test that sqlite3_close fails if there are outstanding VMs.
+#
+
+set DB [sqlite3_connection_pointer db]
+
+do_test capi3-1.0 {
+ sqlite3_get_autocommit $DB
+} 1
+do_test capi3-1.1 {
+ set STMT [sqlite3_prepare_v2 $DB {SELECT name FROM sqlite_master} -1 TAIL]
+ sqlite3_finalize $STMT
+ set TAIL
+} {}
+do_test capi3-1.2 {
+ sqlite3_errcode $DB
+} {SQLITE_OK}
+do_test capi3-1.3 {
+ sqlite3_errmsg $DB
+} {not an error}
+do_test capi3-1.4 {
+ set sql {SELECT name FROM sqlite_master;SELECT 10}
+ set STMT [sqlite3_prepare_v2 $DB $sql -1 TAIL]
+ sqlite3_finalize $STMT
+ set TAIL
+} {SELECT 10}
+do_test capi3-1.5 {
+ set sql {SELECT namex FROM sqlite_master}
+ catch {
+ set STMT [sqlite3_prepare_v2 $DB $sql -1 TAIL]
+ }
+} {1}
+do_test capi3-1.6 {
+ sqlite3_errcode $DB
+} {SQLITE_ERROR}
+do_test capi3-1.7 {
+ sqlite3_errmsg $DB
+} {no such column: namex}
+
+ifcapable {utf16} {
+ do_test capi3-2.1 {
+ set sql16 [utf16 {SELECT name FROM sqlite_master}]
+ set STMT [sqlite3_prepare16_v2 $DB $sql16 -1 ::TAIL]
+ sqlite3_finalize $STMT
+ utf8 $::TAIL
+ } {}
+ do_test capi3-2.2 {
+ set sql [utf16 {SELECT name FROM sqlite_master;SELECT 10}]
+ set STMT [sqlite3_prepare16_v2 $DB $sql -1 TAIL]
+ sqlite3_finalize $STMT
+ utf8 $TAIL
+ } {SELECT 10}
+ do_test capi3-2.3 {
+ set sql [utf16 {SELECT namex FROM sqlite_master}]
+ catch {
+ set STMT [sqlite3_prepare16_v2 $DB $sql -1 TAIL]
+ }
+ } {1}
+ do_test capi3-2.4 {
+ sqlite3_errcode $DB
+ } {SQLITE_ERROR}
+ do_test capi3-2.5 {
+ sqlite3_errmsg $DB
+ } {no such column: namex}
+
+ ifcapable schema_pragmas {
+ do_test capi3-2.6 {
+ execsql {CREATE TABLE tablename(x)}
+ set sql16 [utf16 {PRAGMA table_info("TableName")}]
+ set STMT [sqlite3_prepare16_v2 $DB $sql16 -1 TAIL]
+ sqlite3_step $STMT
+ } SQLITE_ROW
+ do_test capi3-2.7 {
+ sqlite3_step $STMT
+ } SQLITE_DONE
+ do_test capi3-2.8 {
+ sqlite3_finalize $STMT
+ } SQLITE_OK
+ }
+
+} ;# endif utf16
+
+# rename sqlite3_open sqlite3_open_old
+# proc sqlite3_open {fname options} {sqlite3_open_new $fname $options}
+
+do_test capi3-3.1 {
+ set db2 [sqlite3_open test.db {}]
+ sqlite3_errcode $db2
+} {SQLITE_OK}
+# FIX ME: Should test the db handle works.
+do_test capi3-3.2 {
+ sqlite3_close $db2
+} {SQLITE_OK}
+do_test capi3-3.3 {
+ catch {
+ set db2 [sqlite3_open /bogus/path/test.db {}]
+ }
+ sqlite3_errcode $db2
+} {SQLITE_CANTOPEN}
+do_test capi3-3.4 {
+ sqlite3_errmsg $db2
+} {unable to open database file}
+do_test capi3-3.5 {
+ sqlite3_close $db2
+} {SQLITE_OK}
+do_test capi3-3.6.1 {
+ sqlite3_close $db2
+} {SQLITE_MISUSE}
+do_test capi3-3.6.2 {
+ sqlite3_errmsg $db2
+} {library routine called out of sequence}
+ifcapable {utf16} {
+ do_test capi3-3.6.3 {
+ utf8 [sqlite3_errmsg16 $db2]
+ } {library routine called out of sequence}
+}
+
+# rename sqlite3_open ""
+# rename sqlite3_open_old sqlite3_open
+
+ifcapable {utf16} {
+do_test capi3-4.1 {
+ set db2 [sqlite3_open16 [utf16 test.db] {}]
+ sqlite3_errcode $db2
+} {SQLITE_OK}
+# FIX ME: Should test the db handle works.
+do_test capi3-4.2 {
+ sqlite3_close $db2
+} {SQLITE_OK}
+do_test capi3-4.3 {
+ catch {
+ set db2 [sqlite3_open16 [utf16 /bogus/path/test.db] {}]
+ }
+ sqlite3_errcode $db2
+} {SQLITE_CANTOPEN}
+do_test capi3-4.4 {
+ utf8 [sqlite3_errmsg16 $db2]
+} {unable to open database file}
+do_test capi3-4.5 {
+ sqlite3_close $db2
+} {SQLITE_OK}
+} ;# utf16
+
+# This proc is used to test the following API calls:
+#
+# sqlite3_column_count
+# sqlite3_column_name
+# sqlite3_column_name16
+# sqlite3_column_decltype
+# sqlite3_column_decltype16
+#
+# $STMT is a compiled SQL statement. $test is a prefix
+# to use for test names within this proc. $names is a list
+# of the column names that should be returned by $STMT.
+# $decltypes is a list of column declaration types for $STMT.
+#
+# Example:
+#
+# set STMT [sqlite3_prepare_v2 "SELECT 1, 2, 2;" -1 DUMMY]
+# check_header test1.1 {1 2 3} {"" "" ""}
+#
+proc check_header {STMT test names decltypes} {
+
+ # Use the return value of sqlite3_column_count() to build
+ # a list of column indexes. i.e. If sqlite3_column_count
+ # is 3, build the list {0 1 2}.
+ set ::idxlist [list]
+ set ::numcols [sqlite3_column_count $STMT]
+ for {set i 0} {$i < $::numcols} {incr i} {lappend ::idxlist $i}
+
+ # Column names in UTF-8
+ do_test $test.1 {
+ set cnamelist [list]
+ foreach i $idxlist {lappend cnamelist [sqlite3_column_name $STMT $i]}
+ set cnamelist
+ } $names
+
+ # Column names in UTF-16
+ ifcapable {utf16} {
+ do_test $test.2 {
+ set cnamelist [list]
+ foreach i $idxlist {
+ lappend cnamelist [utf8 [sqlite3_column_name16 $STMT $i]]
+ }
+ set cnamelist
+ } $names
+ }
+
+ # Column names in UTF-8
+ do_test $test.3 {
+ set cnamelist [list]
+ foreach i $idxlist {lappend cnamelist [sqlite3_column_name $STMT $i]}
+ set cnamelist
+ } $names
+
+ # Column names in UTF-16
+ ifcapable {utf16} {
+ do_test $test.4 {
+ set cnamelist [list]
+ foreach i $idxlist {
+ lappend cnamelist [utf8 [sqlite3_column_name16 $STMT $i]]
+ }
+ set cnamelist
+ } $names
+ }
+
+ # Column names in UTF-8
+ do_test $test.5 {
+ set cnamelist [list]
+ foreach i $idxlist {lappend cnamelist [sqlite3_column_decltype $STMT $i]}
+ set cnamelist
+ } $decltypes
+
+ # Column declaration types in UTF-16
+ ifcapable {utf16} {
+ do_test $test.6 {
+ set cnamelist [list]
+ foreach i $idxlist {
+ lappend cnamelist [utf8 [sqlite3_column_decltype16 $STMT $i]]
+ }
+ set cnamelist
+ } $decltypes
+ }
+
+
+ # Test some out of range conditions:
+ ifcapable {utf16} {
+ do_test $test.7 {
+ list \
+ [sqlite3_column_name $STMT -1] \
+ [sqlite3_column_name16 $STMT -1] \
+ [sqlite3_column_decltype $STMT -1] \
+ [sqlite3_column_decltype16 $STMT -1] \
+ [sqlite3_column_name $STMT $numcols] \
+ [sqlite3_column_name16 $STMT $numcols] \
+ [sqlite3_column_decltype $STMT $numcols] \
+ [sqlite3_column_decltype16 $STMT $numcols]
+ } {{} {} {} {} {} {} {} {}}
+ }
+}
+
+# This proc is used to test the following API calls:
+#
+# sqlite3_column_origin_name
+# sqlite3_column_origin_name16
+# sqlite3_column_table_name
+# sqlite3_column_table_name16
+# sqlite3_column_database_name
+# sqlite3_column_database_name16
+#
+# $STMT is a compiled SQL statement. $test is a prefix
+# to use for test names within this proc. $names is a list
+# of the column names that should be returned by $STMT.
+# $decltypes is a list of column declaration types for $STMT.
+#
+# Example:
+#
+# set STMT [sqlite3_prepare_v2 "SELECT 1, 2, 2;" -1 DUMMY]
+# check_header test1.1 {1 2 3} {"" "" ""}
+#
+proc check_origin_header {STMT test dbs tables cols} {
+ # If sqlite3_column_origin_name() and friends are not compiled into
+ # this build, this proc is a no-op.
+ifcapable columnmetadata {
+
+ # Use the return value of sqlite3_column_count() to build
+ # a list of column indexes. i.e. If sqlite3_column_count
+ # is 3, build the list {0 1 2}.
+ set ::idxlist [list]
+ set ::numcols [sqlite3_column_count $STMT]
+ for {set i 0} {$i < $::numcols} {incr i} {lappend ::idxlist $i}
+
+ # Database names in UTF-8
+ do_test $test.8 {
+ set cnamelist [list]
+ foreach i $idxlist {
+ lappend cnamelist [sqlite3_column_database_name $STMT $i]
+ }
+ set cnamelist
+ } $dbs
+
+ # Database names in UTF-16
+ ifcapable {utf16} {
+ do_test $test.9 {
+ set cnamelist [list]
+ foreach i $idxlist {
+ lappend cnamelist [utf8 [sqlite3_column_database_name16 $STMT $i]]
+ }
+ set cnamelist
+ } $dbs
+ }
+
+ # Table names in UTF-8
+ do_test $test.10 {
+ set cnamelist [list]
+ foreach i $idxlist {
+ lappend cnamelist [sqlite3_column_table_name $STMT $i]
+ }
+ set cnamelist
+ } $tables
+
+ # Table names in UTF-16
+ ifcapable {utf16} {
+ do_test $test.11 {
+ set cnamelist [list]
+ foreach i $idxlist {
+ lappend cnamelist [utf8 [sqlite3_column_table_name16 $STMT $i]]
+ }
+ set cnamelist
+ } $tables
+ }
+
+ # Origin names in UTF-8
+ do_test $test.12 {
+ set cnamelist [list]
+ foreach i $idxlist {
+ lappend cnamelist [sqlite3_column_origin_name $STMT $i]
+ }
+ set cnamelist
+ } $cols
+
+ # Origin declaration types in UTF-16
+ ifcapable {utf16} {
+ do_test $test.13 {
+ set cnamelist [list]
+ foreach i $idxlist {
+ lappend cnamelist [utf8 [sqlite3_column_origin_name16 $STMT $i]]
+ }
+ set cnamelist
+ } $cols
+ }
+ }
+}
+
+# This proc is used to test the following APIs:
+#
+# sqlite3_data_count
+# sqlite3_column_type
+# sqlite3_column_int
+# sqlite3_column_text
+# sqlite3_column_text16
+# sqlite3_column_double
+#
+# $STMT is a compiled SQL statement for which the previous call
+# to sqlite3_step returned SQLITE_ROW. $test is a prefix to use
+# for test names within this proc. $types is a list of the
+# manifest types for the current row. $ints, $doubles and $strings
+# are lists of the integer, real and string representations of
+# the values in the current row.
+#
+# Example:
+#
+# set STMT [sqlite3_prepare_v2 "SELECT 'hello', 1.1, NULL" -1 DUMMY]
+# sqlite3_step $STMT
+# check_data test1.2 {TEXT REAL NULL} {0 1 0} {0 1.1 0} {hello 1.1 {}}
+#
+proc check_data {STMT test types ints doubles strings} {
+
+ # Use the return value of sqlite3_column_count() to build
+ # a list of column indexes. i.e. If sqlite3_column_count
+ # is 3, build the list {0 1 2}.
+ set ::idxlist [list]
+ set numcols [sqlite3_data_count $STMT]
+ for {set i 0} {$i < $numcols} {incr i} {lappend ::idxlist $i}
+
+# types
+do_test $test.1 {
+ set types [list]
+ foreach i $idxlist {lappend types [sqlite3_column_type $STMT $i]}
+ set types
+} $types
+
+# Integers
+do_test $test.2 {
+ set ints [list]
+ foreach i $idxlist {lappend ints [sqlite3_column_int64 $STMT $i]}
+ set ints
+} $ints
+
+# bytes
+set lens [list]
+foreach i $::idxlist {
+ lappend lens [string length [lindex $strings $i]]
+}
+do_test $test.3 {
+ set bytes [list]
+ set lens [list]
+ foreach i $idxlist {
+ lappend bytes [sqlite3_column_bytes $STMT $i]
+ }
+ set bytes
+} $lens
+
+# bytes16
+ifcapable {utf16} {
+ set lens [list]
+ foreach i $::idxlist {
+ lappend lens [expr 2 * [string length [lindex $strings $i]]]
+ }
+ do_test $test.4 {
+ set bytes [list]
+ set lens [list]
+ foreach i $idxlist {
+ lappend bytes [sqlite3_column_bytes16 $STMT $i]
+ }
+ set bytes
+ } $lens
+}
+
+# Blob
+do_test $test.5 {
+ set utf8 [list]
+ foreach i $idxlist {lappend utf8 [sqlite3_column_blob $STMT $i]}
+ set utf8
+} $strings
+
+# UTF-8
+do_test $test.6 {
+ set utf8 [list]
+ foreach i $idxlist {lappend utf8 [sqlite3_column_text $STMT $i]}
+ set utf8
+} $strings
+
+# Floats
+do_test $test.7 {
+ set utf8 [list]
+ foreach i $idxlist {lappend utf8 [sqlite3_column_double $STMT $i]}
+ set utf8
+} $doubles
+
+# UTF-16
+ifcapable {utf16} {
+ do_test $test.8 {
+ set utf8 [list]
+ foreach i $idxlist {lappend utf8 [utf8 [sqlite3_column_text16 $STMT $i]]}
+ set utf8
+ } $strings
+}
+
+# Integers
+do_test $test.9 {
+ set ints [list]
+ foreach i $idxlist {lappend ints [sqlite3_column_int $STMT $i]}
+ set ints
+} $ints
+
+# Floats
+do_test $test.10 {
+ set utf8 [list]
+ foreach i $idxlist {lappend utf8 [sqlite3_column_double $STMT $i]}
+ set utf8
+} $doubles
+
+# UTF-8
+do_test $test.11 {
+ set utf8 [list]
+ foreach i $idxlist {lappend utf8 [sqlite3_column_text $STMT $i]}
+ set utf8
+} $strings
+
+# Types
+do_test $test.12 {
+ set types [list]
+ foreach i $idxlist {lappend types [sqlite3_column_type $STMT $i]}
+ set types
+} $types
+
+# Test that an out of range request returns the equivalent of NULL
+do_test $test.13 {
+ sqlite3_column_int $STMT -1
+} {0}
+do_test $test.13 {
+ sqlite3_column_text $STMT -1
+} {}
+
+}
+
+ifcapable !floatingpoint {
+ finish_test
+ return
+}
+
+do_test capi3-5.0 {
+ execsql {
+ CREATE TABLE t1(a VARINT, b BLOB, c VARCHAR(16));
+ INSERT INTO t1 VALUES(1, 2, 3);
+ INSERT INTO t1 VALUES('one', 'two', NULL);
+ INSERT INTO t1 VALUES(1.2, 1.3, 1.4);
+ }
+ set sql "SELECT * FROM t1"
+ set STMT [sqlite3_prepare_v2 $DB $sql -1 TAIL]
+ sqlite3_column_count $STMT
+} 3
+
+check_header $STMT capi3-5.1 {a b c} {VARINT BLOB VARCHAR(16)}
+check_origin_header $STMT capi3-5.1 {main main main} {t1 t1 t1} {a b c}
+do_test capi3-5.2 {
+ sqlite3_step $STMT
+} SQLITE_ROW
+
+check_header $STMT capi3-5.3 {a b c} {VARINT BLOB VARCHAR(16)}
+check_origin_header $STMT capi3-5.3 {main main main} {t1 t1 t1} {a b c}
+check_data $STMT capi3-5.4 {INTEGER INTEGER TEXT} {1 2 3} {1.0 2.0 3.0} {1 2 3}
+
+do_test capi3-5.5 {
+ sqlite3_step $STMT
+} SQLITE_ROW
+
+check_header $STMT capi3-5.6 {a b c} {VARINT BLOB VARCHAR(16)}
+check_origin_header $STMT capi3-5.6 {main main main} {t1 t1 t1} {a b c}
+check_data $STMT capi3-5.7 {TEXT TEXT NULL} {0 0 0} {0.0 0.0 0.0} {one two {}}
+
+do_test capi3-5.8 {
+ sqlite3_step $STMT
+} SQLITE_ROW
+
+check_header $STMT capi3-5.9 {a b c} {VARINT BLOB VARCHAR(16)}
+check_origin_header $STMT capi3-5.9 {main main main} {t1 t1 t1} {a b c}
+check_data $STMT capi3-5.10 {FLOAT FLOAT TEXT} {1 1 1} {1.2 1.3 1.4} {1.2 1.3 1.4}
+
+do_test capi3-5.11 {
+ sqlite3_step $STMT
+} SQLITE_DONE
+
+do_test capi3-5.12 {
+ sqlite3_finalize $STMT
+} SQLITE_OK
+
+do_test capi3-5.20 {
+ set sql "SELECT a, sum(b), max(c) FROM t1 GROUP BY a"
+ set STMT [sqlite3_prepare_v2 $DB $sql -1 TAIL]
+ sqlite3_column_count $STMT
+} 3
+
+check_header $STMT capi3-5.21 {a sum(b) max(c)} {VARINT {} {}}
+check_origin_header $STMT capi3-5.22 {main {} {}} {t1 {} {}} {a {} {}}
+do_test capi3-5.23 {
+ sqlite3_finalize $STMT
+} SQLITE_OK
+
+
+set ::ENC [execsql {pragma encoding}]
+db close
+
+do_test capi3-6.0 {
+btree_breakpoint
+ sqlite3 db test.db
+ set DB [sqlite3_connection_pointer db]
+btree_breakpoint
+ sqlite3_key $DB xyzzy
+ set sql {SELECT a FROM t1 order by rowid}
+ set STMT [sqlite3_prepare_v2 $DB $sql -1 TAIL]
+ expr 0
+} {0}
+do_test capi3-6.1 {
+ db cache flush
+ sqlite3_close $DB
+} {SQLITE_BUSY}
+do_test capi3-6.2 {
+ sqlite3_step $STMT
+} {SQLITE_ROW}
+check_data $STMT capi3-6.3 {INTEGER} {1} {1.0} {1}
+do_test capi3-6.3 {
+ sqlite3_finalize $STMT
+} {SQLITE_OK}
+do_test capi3-6.4 {
+ db cache flush
+ sqlite3_close $DB
+} {SQLITE_OK}
+db close
+
+if {![sqlite3 -has-codec]} {
+ # Test what happens when the library encounters a newer file format.
+ # Do this by updating the file format via the btree layer.
+ do_test capi3-7.1 {
+ set ::bt [btree_open test.db 10 0]
+ btree_begin_transaction $::bt
+ set meta [btree_get_meta $::bt]
+ lset meta 2 5
+ eval [concat btree_update_meta $::bt [lrange $meta 0 end]]
+ btree_commit $::bt
+ btree_close $::bt
+ } {}
+ do_test capi3-7.2 {
+ sqlite3 db test.db
+ catchsql {
+ SELECT * FROM sqlite_master;
+ }
+ } {1 {unsupported file format}}
+ db close
+}
+
+if {![sqlite3 -has-codec]} {
+ # Now test that the library correctly handles bogus entries in the
+ # sqlite_master table (schema corruption).
+ do_test capi3-8.1 {
+ file delete -force test.db
+ file delete -force test.db-journal
+ sqlite3 db test.db
+ execsql {
+ CREATE TABLE t1(a);
+ }
+ db close
+ } {}
+ do_test capi3-8.2 {
+ set ::bt [btree_open test.db 10 0]
+ btree_begin_transaction $::bt
+ set ::bc [btree_cursor $::bt 1 1]
+
+ # Build a 5-field row record consisting of 5 null records. This is
+ # officially black magic.
+ catch {unset data}
+ set data [binary format c6 {6 0 0 0 0 0}]
+ btree_insert $::bc 5 $data
+
+ btree_close_cursor $::bc
+ btree_commit $::bt
+ btree_close $::bt
+ } {}
+ do_test capi3-8.3 {
+ sqlite3 db test.db
+ catchsql {
+ SELECT * FROM sqlite_master;
+ }
+ } {1 {malformed database schema}}
+ do_test capi3-8.4 {
+ set ::bt [btree_open test.db 10 0]
+ btree_begin_transaction $::bt
+ set ::bc [btree_cursor $::bt 1 1]
+
+ # Build a 5-field row record. The first field is a string 'table', and
+ # subsequent fields are all NULL. Replace the other broken record with
+ # this one and try to read the schema again. The broken record uses
+ # either UTF-8 or native UTF-16 (if this file is being run by
+ # utf16.test).
+ if { [string match UTF-16* $::ENC] } {
+ set data [binary format c6a10 {6 33 0 0 0 0} [utf16 table]]
+ } else {
+ set data [binary format c6a5 {6 23 0 0 0 0} table]
+ }
+ btree_insert $::bc 5 $data
+
+ btree_close_cursor $::bc
+ btree_commit $::bt
+ btree_close $::bt
+ } {};
+ do_test capi3-8.5 {
+ db close
+ sqlite3 db test.db
+ catchsql {
+ SELECT * FROM sqlite_master;
+ }
+ } {1 {malformed database schema}}
+ db close
+}
+file delete -force test.db
+file delete -force test.db-journal
+
+
+# Test the english language string equivalents for sqlite error codes
+set code2english [list \
+SQLITE_OK {not an error} \
+SQLITE_ERROR {SQL logic error or missing database} \
+SQLITE_PERM {access permission denied} \
+SQLITE_ABORT {callback requested query abort} \
+SQLITE_BUSY {database is locked} \
+SQLITE_LOCKED {database table is locked} \
+SQLITE_NOMEM {out of memory} \
+SQLITE_READONLY {attempt to write a readonly database} \
+SQLITE_INTERRUPT {interrupted} \
+SQLITE_IOERR {disk I/O error} \
+SQLITE_CORRUPT {database disk image is malformed} \
+SQLITE_FULL {database or disk is full} \
+SQLITE_CANTOPEN {unable to open database file} \
+SQLITE_PROTOCOL {database locking protocol failure} \
+SQLITE_EMPTY {table contains no data} \
+SQLITE_SCHEMA {database schema has changed} \
+SQLITE_CONSTRAINT {constraint failed} \
+SQLITE_MISMATCH {datatype mismatch} \
+SQLITE_MISUSE {library routine called out of sequence} \
+SQLITE_NOLFS {kernel lacks large file support} \
+SQLITE_AUTH {authorization denied} \
+SQLITE_FORMAT {auxiliary database format error} \
+SQLITE_RANGE {bind or column index out of range} \
+SQLITE_NOTADB {file is encrypted or is not a database} \
+unknownerror {unknown error} \
+]
+
+set test_number 1
+foreach {code english} $code2english {
+ do_test capi3-9.$test_number "sqlite3_test_errstr $code" $english
+ incr test_number
+}
+
+# Test the error message when a "real" out of memory occurs.
+if {[info command sqlite_malloc_stat]!=""} {
+set sqlite_malloc_fail 1
+do_test capi3-10-1 {
+ sqlite3 db test.db
+ set DB [sqlite3_connection_pointer db]
+ sqlite_malloc_fail 1
+ catchsql {
+ select * from sqlite_master;
+ }
+} {1 {out of memory}}
+do_test capi3-10-2 {
+ sqlite3_errmsg $::DB
+} {out of memory}
+ifcapable {utf16} {
+ do_test capi3-10-3 {
+ utf8 [sqlite3_errmsg16 $::DB]
+ } {out of memory}
+}
+db close
+sqlite_malloc_fail 0
+}
+
+# The following tests - capi3-11.* - test that a COMMIT or ROLLBACK
+# statement issued while there are still outstanding VMs that are part of
+# the transaction fails.
+sqlite3 db test.db
+set DB [sqlite3_connection_pointer db]
+sqlite_register_test_function $DB func
+do_test capi3-11.1 {
+ execsql {
+ BEGIN;
+ CREATE TABLE t1(a, b);
+ INSERT INTO t1 VALUES(1, 'int');
+ INSERT INTO t1 VALUES(2, 'notatype');
+ }
+} {}
+do_test capi3-11.1.1 {
+ sqlite3_get_autocommit $DB
+} 0
+do_test capi3-11.2 {
+ set STMT [sqlite3_prepare_v2 $DB "SELECT func(b, a) FROM t1" -1 TAIL]
+ sqlite3_step $STMT
+} {SQLITE_ROW}
+do_test capi3-11.3 {
+ catchsql {
+ COMMIT;
+ }
+} {1 {cannot commit transaction - SQL statements in progress}}
+do_test capi3-11.3.1 {
+ sqlite3_get_autocommit $DB
+} 0
+do_test capi3-11.4 {
+ sqlite3_step $STMT
+} {SQLITE_ERROR}
+do_test capi3-11.5 {
+ sqlite3_finalize $STMT
+} {SQLITE_ERROR}
+do_test capi3-11.6 {
+ catchsql {
+ SELECT * FROM t1;
+ }
+} {0 {1 int 2 notatype}}
+do_test capi3-11.6.1 {
+ sqlite3_get_autocommit $DB
+} 0
+do_test capi3-11.7 {
+ catchsql {
+ COMMIT;
+ }
+} {0 {}}
+do_test capi3-11.7.1 {
+ sqlite3_get_autocommit $DB
+} 1
+do_test capi3-11.8 {
+ execsql {
+ CREATE TABLE t2(a);
+ INSERT INTO t2 VALUES(1);
+ INSERT INTO t2 VALUES(2);
+ BEGIN;
+ INSERT INTO t2 VALUES(3);
+ }
+} {}
+do_test capi3-11.8.1 {
+ sqlite3_get_autocommit $DB
+} 0
+do_test capi3-11.9 {
+ set STMT [sqlite3_prepare_v2 $DB "SELECT a FROM t2" -1 TAIL]
+ sqlite3_step $STMT
+} {SQLITE_ROW}
+do_test capi3-11.9.1 {
+ sqlite3_get_autocommit $DB
+} 0
+do_test capi3-11.9.2 {
+ catchsql {
+ ROLLBACK;
+ }
+} {1 {cannot rollback transaction - SQL statements in progress}}
+do_test capi3-11.9.3 {
+ sqlite3_get_autocommit $DB
+} 0
+do_test capi3-11.10 {
+ sqlite3_step $STMT
+} {SQLITE_ROW}
+do_test capi3-11.11 {
+ sqlite3_step $STMT
+} {SQLITE_ROW}
+do_test capi3-11.12 {
+ sqlite3_step $STMT
+} {SQLITE_DONE}
+do_test capi3-11.13 {
+ sqlite3_finalize $STMT
+} {SQLITE_OK}
+do_test capi3-11.14 {
+ execsql {
+ SELECT a FROM t2;
+ }
+} {1 2 3}
+do_test capi3-11.14.1 {
+ sqlite3_get_autocommit $DB
+} 0
+do_test capi3-11.15 {
+ catchsql {
+ ROLLBACK;
+ }
+} {0 {}}
+do_test capi3-11.15.1 {
+ sqlite3_get_autocommit $DB
+} 1
+do_test capi3-11.16 {
+ execsql {
+ SELECT a FROM t2;
+ }
+} {1 2}
+
+# Sanity check on the definition of 'outstanding VM'. This means any VM
+# that has had sqlite3_step() called more recently than sqlite3_finalize() or
+# sqlite3_reset(). So a VM that has just been prepared or reset does not
+# count as an active VM.
+do_test capi3-11.17 {
+ execsql {
+ BEGIN;
+ }
+} {}
+do_test capi3-11.18 {
+ set STMT [sqlite3_prepare_v2 $DB "SELECT a FROM t1" -1 TAIL]
+ catchsql {
+ COMMIT;
+ }
+} {0 {}}
+do_test capi3-11.19 {
+ sqlite3_step $STMT
+} {SQLITE_ROW}
+do_test capi3-11.20 {
+ catchsql {
+ BEGIN;
+ COMMIT;
+ }
+} {1 {cannot commit transaction - SQL statements in progress}}
+do_test capi3-11.20 {
+ sqlite3_reset $STMT
+ catchsql {
+ COMMIT;
+ }
+} {0 {}}
+do_test capi3-11.21 {
+ sqlite3_finalize $STMT
+} {SQLITE_OK}
+
+# The following tests - capi3-12.* - check that it's Ok to start a
+# transaction while other VMs are active, and that it's Ok to execute
+# atomic updates in the same situation
+#
+do_test capi3-12.1 {
+ set STMT [sqlite3_prepare_v2 $DB "SELECT a FROM t2" -1 TAIL]
+ sqlite3_step $STMT
+} {SQLITE_ROW}
+do_test capi3-12.2 {
+ catchsql {
+ INSERT INTO t1 VALUES(3, NULL);
+ }
+} {0 {}}
+do_test capi3-12.3 {
+ catchsql {
+ INSERT INTO t2 VALUES(4);
+ }
+} {0 {}}
+do_test capi3-12.4 {
+ catchsql {
+ BEGIN;
+ INSERT INTO t1 VALUES(4, NULL);
+ }
+} {0 {}}
+do_test capi3-12.5 {
+ sqlite3_step $STMT
+} {SQLITE_ROW}
+do_test capi3-12.5.1 {
+ sqlite3_step $STMT
+} {SQLITE_ROW}
+do_test capi3-12.6 {
+ sqlite3_step $STMT
+} {SQLITE_DONE}
+do_test capi3-12.7 {
+ sqlite3_finalize $STMT
+} {SQLITE_OK}
+do_test capi3-12.8 {
+ execsql {
+ COMMIT;
+ SELECT a FROM t1;
+ }
+} {1 2 3 4}
+
+# Test cases capi3-13.* test the sqlite3_clear_bindings() and
+# sqlite3_sleep APIs.
+#
+if {[llength [info commands sqlite3_clear_bindings]]>0} {
+ do_test capi3-13.1 {
+ execsql {
+ DELETE FROM t1;
+ }
+ set STMT [sqlite3_prepare_v2 $DB "INSERT INTO t1 VALUES(?, ?)" -1 TAIL]
+ sqlite3_step $STMT
+ } {SQLITE_DONE}
+ do_test capi3-13.2 {
+ sqlite3_reset $STMT
+ sqlite3_bind_text $STMT 1 hello 5
+ sqlite3_bind_text $STMT 2 world 5
+ sqlite3_step $STMT
+ } {SQLITE_DONE}
+ do_test capi3-13.3 {
+ sqlite3_reset $STMT
+ sqlite3_clear_bindings $STMT
+ sqlite3_step $STMT
+ } {SQLITE_DONE}
+ do_test capi3-13-4 {
+ sqlite3_finalize $STMT
+ execsql {
+ SELECT * FROM t1;
+ }
+ } {{} {} hello world {} {}}
+}
+if {[llength [info commands sqlite3_sleep]]>0} {
+ do_test capi3-13-5 {
+ set ms [sqlite3_sleep 80]
+ expr {$ms==80 || $ms==1000}
+ } {1}
+}
+
+# Ticket #1219: Make sure binding APIs can handle a NULL pointer.
+#
+do_test capi3-14.1 {
+ set rc [catch {sqlite3_bind_text 0 1 hello 5} msg]
+ lappend rc $msg
+} {1 SQLITE_MISUSE}
+
+# Ticket #1650: Honor the nBytes parameter to sqlite3_prepare.
+#
+do_test capi3-15.1 {
+ set sql {SELECT * FROM t2}
+ set nbytes [string length $sql]
+ append sql { WHERE a==1}
+ set STMT [sqlite3_prepare_v2 $DB $sql $nbytes TAIL]
+ sqlite3_step $STMT
+ sqlite3_column_int $STMT 0
+} {1}
+do_test capi3-15.2 {
+ sqlite3_step $STMT
+ sqlite3_column_int $STMT 0
+} {2}
+do_test capi3-15.3 {
+ sqlite3_finalize $STMT
+} {SQLITE_OK}
+
+# Make sure code is always generated even if an IF EXISTS or
+# IF NOT EXISTS clause is present that the table does not or
+# does exists. That way we will always have a prepared statement
+# to expire when the schema changes.
+#
+do_test capi3-16.1 {
+ set sql {DROP TABLE IF EXISTS t3}
+ set STMT [sqlite3_prepare_v2 $DB $sql -1 TAIL]
+ sqlite3_finalize $STMT
+ expr {$STMT!=""}
+} {1}
+do_test capi3-16.2 {
+ set sql {CREATE TABLE IF NOT EXISTS t1(x,y)}
+ set STMT [sqlite3_prepare_v2 $DB $sql -1 TAIL]
+ sqlite3_finalize $STMT
+ expr {$STMT!=""}
+} {1}
+
+# But still we do not generate code if there is no SQL
+#
+do_test capi3-16.3 {
+ set STMT [sqlite3_prepare_v2 $DB {} -1 TAIL]
+ sqlite3_finalize $STMT
+ expr {$STMT==""}
+} {1}
+do_test capi3-16.4 {
+ set STMT [sqlite3_prepare_v2 $DB {;} -1 TAIL]
+ sqlite3_finalize $STMT
+ expr {$STMT==""}
+} {1}
+
+
+
+finish_test
#***********************************************************************
# This file runs all tests.
#
-# $Id: quick.test,v 1.45 2006/06/23 08:05:38 danielk1977 Exp $
+# $Id: quick.test,v 1.46 2006/11/09 00:24:55 drh Exp $
proc lshift {lvar} {
upvar $lvar l
# conflict.test
}
+
+# Files to include in the test. If this list is empty then everything
+# that is not in the EXCLUDE list is run.
+#
+set INCLUDE {
+}
+
foreach testfile [lsort -dictionary [glob $testdir/*.test]] {
set tail [file tail $testfile]
if {[lsearch -exact $EXCLUDE $tail]>=0} continue
+ if {[llength $INCLUDE]>0 && [lsearch -exact $INCLUDE $tail]<0} continue
source $testfile
catch {db close}
if {$sqlite_open_file_count>0} {
--- /dev/null
+# 2006 November 08
+#
+# 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.
+#
+#***********************************************************************
+# This file implements regression tests for SQLite library.
+#
+# This file tests the various conditions under which an SQLITE_SCHEMA
+# error should be returned. This is a copy of schema.test that
+# has been altered to use sqlite3_prepare_v2 instead of sqlite3_prepare
+#
+# $Id: schema2.test,v 1.1 2006/11/09 00:24:55 drh Exp $
+
+#---------------------------------------------------------------------
+# When any of the following types of SQL statements or actions are
+# executed, all pre-compiled statements are invalidated. An attempt
+# to execute an invalidated statement always returns SQLITE_SCHEMA.
+#
+# CREATE/DROP TABLE...................................schema2-1.*
+# CREATE/DROP VIEW....................................schema2-2.*
+# CREATE/DROP TRIGGER.................................schema2-3.*
+# CREATE/DROP INDEX...................................schema2-4.*
+# DETACH..............................................schema2-5.*
+# Deleting a user-function............................schema2-6.*
+# Deleting a collation sequence.......................schema2-7.*
+# Setting or changing the authorization function......schema2-8.*
+#
+# Test cases schema2-9.* and schema2-10.* test some specific bugs
+# that came up during development.
+#
+# Test cases schema2-11.* test that it is impossible to delete or
+# change a collation sequence or user-function while SQL statements
+# are executing. Adding new collations or functions is allowed.
+#
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+
+do_test schema2-1.1 {
+ set ::STMT [sqlite3_prepare_v2 $::DB {SELECT * FROM sqlite_master} -1 TAIL]
+ execsql {
+ CREATE TABLE abc(a, b, c);
+ }
+ sqlite3_step $::STMT
+} {SQLITE_ROW}
+do_test schema2-1.2 {
+ sqlite3_finalize $::STMT
+} {SQLITE_OK}
+do_test schema2-1.3 {
+ set ::STMT [sqlite3_prepare_v2 $::DB {SELECT * FROM sqlite_master} -1 TAIL]
+ execsql {
+ DROP TABLE abc;
+ }
+ sqlite3_step $::STMT
+} {SQLITE_DONE}
+do_test schema2-1.4 {
+ sqlite3_finalize $::STMT
+} {SQLITE_OK}
+
+
+ifcapable view {
+ do_test schema2-2.1 {
+ set ::STMT [sqlite3_prepare_v2 $::DB {SELECT * FROM sqlite_master} -1 TAIL]
+ execsql {
+ CREATE VIEW v1 AS SELECT * FROM sqlite_master;
+ }
+ sqlite3_step $::STMT
+ } {SQLITE_ROW}
+ do_test schema2-2.2 {
+ sqlite3_finalize $::STMT
+ } {SQLITE_OK}
+ do_test schema2-2.3 {
+ set ::STMT [sqlite3_prepare_v2 $::DB {SELECT * FROM sqlite_master} -1 TAIL]
+ execsql {
+ DROP VIEW v1;
+ }
+ sqlite3_step $::STMT
+ } {SQLITE_DONE}
+ do_test schema2-2.4 {
+ sqlite3_finalize $::STMT
+ } {SQLITE_OK}
+}
+
+ifcapable trigger {
+ do_test schema2-3.1 {
+ execsql {
+ CREATE TABLE abc(a, b, c);
+ }
+ set ::STMT [sqlite3_prepare_v2 $::DB {SELECT * FROM sqlite_master} -1 TAIL]
+ execsql {
+ CREATE TRIGGER abc_trig AFTER INSERT ON abc BEGIN
+ SELECT 1, 2, 3;
+ END;
+ }
+ sqlite3_step $::STMT
+ } {SQLITE_ROW}
+ do_test schema2-3.2 {
+ sqlite3_finalize $::STMT
+ } {SQLITE_OK}
+ do_test schema2-3.3 {
+ set ::STMT [sqlite3_prepare_v2 $::DB {SELECT * FROM sqlite_master} -1 TAIL]
+ execsql {
+ DROP TRIGGER abc_trig;
+ }
+ sqlite3_step $::STMT
+ } {SQLITE_ROW}
+ do_test schema2-3.4 {
+ sqlite3_finalize $::STMT
+ } {SQLITE_OK}
+}
+
+do_test schema2-4.1 {
+ catchsql {
+ CREATE TABLE abc(a, b, c);
+ }
+ set ::STMT [sqlite3_prepare_v2 $::DB {SELECT * FROM sqlite_master} -1 TAIL]
+ execsql {
+ CREATE INDEX abc_index ON abc(a);
+ }
+ sqlite3_step $::STMT
+} {SQLITE_ROW}
+do_test schema2-4.2 {
+ sqlite3_finalize $::STMT
+} {SQLITE_OK}
+do_test schema2-4.3 {
+ set ::STMT [sqlite3_prepare_v2 $::DB {SELECT * FROM sqlite_master} -1 TAIL]
+ execsql {
+ DROP INDEX abc_index;
+ }
+ sqlite3_step $::STMT
+} {SQLITE_ROW}
+do_test schema2-4.4 {
+ sqlite3_finalize $::STMT
+} {SQLITE_OK}
+
+#---------------------------------------------------------------------
+# Tests 5.1 to 5.4 check that prepared statements are invalidated when
+# a database is DETACHed (but not when one is ATTACHed).
+#
+do_test schema2-5.1 {
+ set sql {SELECT * FROM abc;}
+ set ::STMT [sqlite3_prepare_v2 $::DB $sql -1 TAIL]
+ execsql {
+ ATTACH 'test2.db' AS aux;
+ }
+ sqlite3_step $::STMT
+} {SQLITE_DONE}
+do_test schema2-5.2 {
+ sqlite3_reset $::STMT
+} {SQLITE_OK}
+do_test schema2-5.3 {
+ execsql {
+ DETACH aux;
+ }
+ sqlite3_step $::STMT
+} {SQLITE_DONE}
+do_test schema2-5.4 {
+ sqlite3_finalize $::STMT
+} {SQLITE_OK}
+
+#---------------------------------------------------------------------
+# Tests 6.* check that prepared statements are invalidated when
+# a user-function is deleted (but not when one is added).
+do_test schema2-6.1 {
+ set sql {SELECT * FROM abc;}
+ set ::STMT [sqlite3_prepare_v2 $::DB $sql -1 TAIL]
+ db function hello_function {}
+ sqlite3_step $::STMT
+} {SQLITE_DONE}
+do_test schema2-6.2 {
+ sqlite3_reset $::STMT
+} {SQLITE_OK}
+do_test schema2-6.3 {
+ sqlite_delete_function $::DB hello_function
+ sqlite3_step $::STMT
+} {SQLITE_DONE}
+do_test schema2-6.4 {
+ sqlite3_finalize $::STMT
+} {SQLITE_OK}
+
+#---------------------------------------------------------------------
+# Tests 7.* check that prepared statements are invalidated when
+# a collation sequence is deleted (but not when one is added).
+#
+ifcapable utf16 {
+ do_test schema2-7.1 {
+ set sql {SELECT * FROM abc;}
+ set ::STMT [sqlite3_prepare_v2 $::DB $sql -1 TAIL]
+ add_test_collate $::DB 1 1 1
+ sqlite3_step $::STMT
+ } {SQLITE_DONE}
+ do_test schema2-7.2 {
+ sqlite3_reset $::STMT
+ } {SQLITE_OK}
+ do_test schema2-7.3 {
+ add_test_collate $::DB 0 0 0
+ sqlite3_step $::STMT
+ } {SQLITE_DONE}
+ do_test schema2-7.4 {
+ sqlite3_finalize $::STMT
+ } {SQLITE_OK}
+}
+
+#---------------------------------------------------------------------
+# Tests 8.1 and 8.2 check that prepared statements are invalidated when
+# the authorization function is set.
+#
+ifcapable auth {
+ do_test schema2-8.1 {
+ set ::STMT [sqlite3_prepare_v2 $::DB {SELECT * FROM sqlite_master} -1 TAIL]
+ db auth {}
+ sqlite3_step $::STMT
+ } {SQLITE_ROW}
+ do_test schema2-8.3 {
+ sqlite3_finalize $::STMT
+ } {SQLITE_OK}
+}
+
+#---------------------------------------------------------------------
+# schema2-9.1: Test that if a table is dropped by one database connection,
+# other database connections are aware of the schema change.
+# schema2-9.2: Test that if a view is dropped by one database connection,
+# other database connections are aware of the schema change.
+#
+do_test schema2-9.1 {
+ sqlite3 db2 test.db
+ execsql {
+ DROP TABLE abc;
+ } db2
+ db2 close
+ catchsql {
+ SELECT * FROM abc;
+ }
+} {1 {no such table: abc}}
+execsql {
+ CREATE TABLE abc(a, b, c);
+}
+ifcapable view {
+ do_test schema2-9.2 {
+ execsql {
+ CREATE VIEW abcview AS SELECT * FROM abc;
+ }
+ sqlite3 db2 test.db
+ execsql {
+ DROP VIEW abcview;
+ } db2
+ db2 close
+ catchsql {
+ SELECT * FROM abcview;
+ }
+ } {1 {no such table: abcview}}
+}
+
+#---------------------------------------------------------------------
+# Test that if a CREATE TABLE statement fails because there are other
+# btree cursors open on the same database file it does not corrupt
+# the sqlite_master table.
+#
+do_test schema2-10.1 {
+ execsql {
+ INSERT INTO abc VALUES(1, 2, 3);
+ }
+ set sql {SELECT * FROM abc}
+ set ::STMT [sqlite3_prepare_v2 $::DB $sql -1 TAIL]
+ sqlite3_step $::STMT
+} {SQLITE_ROW}
+do_test schema2-10.2 {
+ catchsql {
+ CREATE TABLE t2(a, b, c);
+ }
+} {1 {database table is locked}}
+do_test schema2-10.3 {
+ sqlite3_finalize $::STMT
+} {SQLITE_OK}
+do_test schema2-10.4 {
+ sqlite3 db2 test.db
+ execsql {
+ SELECT * FROM abc
+ } db2
+} {1 2 3}
+do_test schema2-10.5 {
+ db2 close
+} {}
+
+#---------------------------------------------------------------------
+# Attempting to delete or replace a user-function or collation sequence
+# while there are active statements returns an SQLITE_BUSY error.
+#
+# schema2-11.1 - 11.4: User function.
+# schema2-11.5 - 11.8: Collation sequence.
+#
+do_test schema2-11.1 {
+ db function tstfunc {}
+ set sql {SELECT * FROM abc}
+ set ::STMT [sqlite3_prepare_v2 $::DB $sql -1 TAIL]
+ sqlite3_step $::STMT
+} {SQLITE_ROW}
+do_test schema2-11.2 {
+ sqlite_delete_function $::DB tstfunc
+} {SQLITE_BUSY}
+do_test schema2-11.3 {
+ set rc [catch {
+ db function tstfunc {}
+ } msg]
+ list $rc $msg
+} {1 {Unable to delete/modify user-function due to active statements}}
+do_test schema2-11.4 {
+ sqlite3_finalize $::STMT
+} {SQLITE_OK}
+do_test schema2-11.5 {
+ db collate tstcollate {}
+ set sql {SELECT * FROM abc}
+ set ::STMT [sqlite3_prepare_v2 $::DB $sql -1 TAIL]
+ sqlite3_step $::STMT
+} {SQLITE_ROW}
+do_test schema2-11.6 {
+ sqlite_delete_collation $::DB tstcollate
+} {SQLITE_BUSY}
+do_test schema2-11.7 {
+ set rc [catch {
+ db collate tstcollate {}
+ } msg]
+ list $rc $msg
+} {1 {Unable to delete/modify collation sequence due to active statements}}
+do_test schema2-11.8 {
+ sqlite3_finalize $::STMT
+} {SQLITE_OK}
+
+finish_test