Use more efficient SQL to verify that indexes contain entries that match their tables.
[sqlite.git] / ext / intck / test_intck.c
blob75bcfa298abb7e5f989b0f3e4ab44efe46be9e1e
1 /*
2 ** 2010 August 28
3 **
4 ** The author disclaims copyright to this source code. In place of
5 ** a legal notice, here is a blessing:
6 **
7 ** May you do good and not evil.
8 ** May you find forgiveness for yourself and forgive others.
9 ** May you share freely, never taking more than you give.
11 *************************************************************************
12 ** Code for testing all sorts of SQLite interfaces. This code
13 ** is not included in the SQLite library.
16 #include "sqlite3.h"
17 #include "sqlite3intck.h"
19 #if defined(INCLUDE_SQLITE_TCL_H)
20 # include "sqlite_tcl.h"
21 #else
22 # include "tcl.h"
23 #endif
25 #include <string.h>
26 #include <assert.h>
28 /* In test1.c */
29 int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb);
30 const char *sqlite3ErrName(int);
32 typedef struct TestIntck TestIntck;
33 struct TestIntck {
34 sqlite3_intck *intck;
37 static int testIntckCmd(
38 void * clientData,
39 Tcl_Interp *interp,
40 int objc,
41 Tcl_Obj *CONST objv[]
43 struct Subcmd {
44 const char *zName;
45 int nArg;
46 const char *zExpect;
47 } aCmd[] = {
48 {"close", 0, ""}, /* 0 */
49 {"step", 0, ""}, /* 1 */
50 {"message", 0, ""}, /* 2 */
51 {"error", 0, ""}, /* 3 */
52 {"suspend", 0, ""}, /* 4 */
53 {"test_sql", 1, ""}, /* 5 */
54 {0 , 0}
56 int rc = TCL_OK;
57 int iIdx = -1;
58 TestIntck *p = (TestIntck*)clientData;
60 if( objc<2 ){
61 Tcl_WrongNumArgs(interp, 1, objv, "SUB-COMMAND ...");
62 return TCL_ERROR;
65 rc = Tcl_GetIndexFromObjStruct(
66 interp, objv[1], aCmd, sizeof(aCmd[0]), "SUB-COMMAND", 0, &iIdx
68 if( rc ) return rc;
70 if( objc!=2+aCmd[iIdx].nArg ){
71 Tcl_WrongNumArgs(interp, 2, objv, aCmd[iIdx].zExpect);
72 return TCL_ERROR;
75 switch( iIdx ){
76 case 0: assert( 0==strcmp("close", aCmd[iIdx].zName) ); {
77 Tcl_DeleteCommand(interp, Tcl_GetStringFromObj(objv[0], 0));
78 break;
81 case 1: assert( 0==strcmp("step", aCmd[iIdx].zName) ); {
82 int rc = sqlite3_intck_step(p->intck);
83 Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1));
84 break;
87 case 2: assert( 0==strcmp("message", aCmd[iIdx].zName) ); {
88 const char *z = sqlite3_intck_message(p->intck);
89 Tcl_SetObjResult(interp, Tcl_NewStringObj(z ? z : "", -1));
90 break;
93 case 3: assert( 0==strcmp("error", aCmd[iIdx].zName) ); {
94 const char *zErr = 0;
95 int rc = sqlite3_intck_error(p->intck, &zErr);
96 Tcl_Obj *pRes = Tcl_NewObj();
98 Tcl_ListObjAppendElement(
99 interp, pRes, Tcl_NewStringObj(sqlite3ErrName(rc), -1)
101 Tcl_ListObjAppendElement(
102 interp, pRes, Tcl_NewStringObj(zErr ? zErr : 0, -1)
104 Tcl_SetObjResult(interp, pRes);
105 break;
108 case 4: assert( 0==strcmp("suspend", aCmd[iIdx].zName) ); {
109 int rc = sqlite3_intck_suspend(p->intck);
110 Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1));
111 break;
114 case 5: assert( 0==strcmp("test_sql", aCmd[iIdx].zName) ); {
115 const char *zObj = Tcl_GetString(objv[2]);
116 const char *zSql = sqlite3_intck_test_sql(p->intck, zObj[0] ? zObj : 0);
117 Tcl_SetObjResult(interp, Tcl_NewStringObj(zSql, -1));
118 break;
122 return TCL_OK;
126 ** Destructor for commands created by test_sqlite3_intck().
128 static void testIntckFree(void *clientData){
129 TestIntck *p = (TestIntck*)clientData;
130 sqlite3_intck_close(p->intck);
131 ckfree(p);
135 ** tclcmd: sqlite3_intck DB DBNAME PATH
137 static int test_sqlite3_intck(
138 void * clientData,
139 Tcl_Interp *interp,
140 int objc,
141 Tcl_Obj *CONST objv[]
143 char zName[64];
144 int iName = 0;
145 Tcl_CmdInfo info;
146 TestIntck *p = 0;
147 sqlite3 *db = 0;
148 const char *zDb = 0;
149 const char *zFile = 0;
150 int rc = SQLITE_OK;
152 if( objc!=4 ){
153 Tcl_WrongNumArgs(interp, 1, objv, "DB DBNAME PATH");
154 return TCL_ERROR;
157 p = (TestIntck*)ckalloc(sizeof(TestIntck));
158 memset(p, 0, sizeof(TestIntck));
160 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){
161 return TCL_ERROR;
163 zDb = Tcl_GetString(objv[2]);
164 zFile = Tcl_GetString(objv[3]);
166 rc = sqlite3_intck_open(db, zDb, zFile, &p->intck);
167 if( rc!=SQLITE_OK ){
168 ckfree(p);
169 Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3_errstr(rc), -1));
170 return TCL_ERROR;
173 do {
174 sprintf(zName, "intck%d", iName);
175 }while( Tcl_GetCommandInfo(interp, zName, &info)!=0 );
176 Tcl_CreateObjCommand(interp, zName, testIntckCmd, (void*)p, testIntckFree);
177 Tcl_SetObjResult(interp, Tcl_NewStringObj(zName, -1));
179 return TCL_OK;
183 ** tclcmd: test_do_intck DB DBNAME
185 static int test_do_intck(
186 void * clientData,
187 Tcl_Interp *interp,
188 int objc,
189 Tcl_Obj *CONST objv[]
191 sqlite3 *db = 0;
192 const char *zDb = 0;
193 int rc = SQLITE_OK;
194 sqlite3_intck *pCk = 0;
195 Tcl_Obj *pRet = 0;
196 const char *zErr = 0;
198 if( objc!=3 ){
199 Tcl_WrongNumArgs(interp, 1, objv, "DB DBNAME");
200 return TCL_ERROR;
202 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){
203 return TCL_ERROR;
205 zDb = Tcl_GetString(objv[2]);
207 pRet = Tcl_NewObj();
208 Tcl_IncrRefCount(pRet);
210 rc = sqlite3_intck_open(db, zDb, 0, &pCk);
211 if( rc==SQLITE_OK ){
212 while( sqlite3_intck_step(pCk)==SQLITE_OK ){
213 const char *zMsg = sqlite3_intck_message(pCk);
214 if( zMsg ){
215 Tcl_ListObjAppendElement(interp, pRet, Tcl_NewStringObj(zMsg, -1));
218 rc = sqlite3_intck_error(pCk, &zErr);
220 if( rc!=SQLITE_OK ){
221 if( zErr ){
222 Tcl_SetObjResult(interp, Tcl_NewStringObj(zErr, -1));
223 }else{
224 Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1));
226 }else{
227 Tcl_SetObjResult(interp, pRet);
229 Tcl_DecrRefCount(pRet);
230 sqlite3_intck_close(pCk);
231 return rc ? TCL_ERROR : TCL_OK;
234 int Sqlitetestintck_Init(Tcl_Interp *interp){
235 Tcl_CreateObjCommand(interp, "sqlite3_intck", test_sqlite3_intck, 0, 0);
236 Tcl_CreateObjCommand(interp, "test_do_intck", test_do_intck, 0, 0);
237 return TCL_OK;