xref: /sqlite-3.40.0/ext/expert/test_expert.c (revision f87ae41f)
1 /*
2 ** 2017 April 07
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.
10 **
11 *************************************************************************
12 */
13 
14 #if defined(SQLITE_TEST)
15 
16 #include "sqlite3expert.h"
17 #include <assert.h>
18 #include <string.h>
19 
20 #if defined(INCLUDE_SQLITE_TCL_H)
21 #  include "sqlite_tcl.h"
22 #else
23 #  include "tcl.h"
24 #  ifndef SQLITE_TCLAPI
25 #    define SQLITE_TCLAPI
26 #  endif
27 #endif
28 
29 #ifndef SQLITE_OMIT_VIRTUALTABLE
30 
31 /*
32 ** Extract an sqlite3* db handle from the object passed as the second
33 ** argument. If successful, set *pDb to point to the db handle and return
34 ** TCL_OK. Otherwise, return TCL_ERROR.
35 */
dbHandleFromObj(Tcl_Interp * interp,Tcl_Obj * pObj,sqlite3 ** pDb)36 static int dbHandleFromObj(Tcl_Interp *interp, Tcl_Obj *pObj, sqlite3 **pDb){
37   Tcl_CmdInfo info;
38   if( 0==Tcl_GetCommandInfo(interp, Tcl_GetString(pObj), &info) ){
39     Tcl_AppendResult(interp, "no such handle: ", Tcl_GetString(pObj), 0);
40     return TCL_ERROR;
41   }
42 
43   *pDb = *(sqlite3 **)info.objClientData;
44   return TCL_OK;
45 }
46 
47 
48 /*
49 ** Tclcmd:  $expert sql SQL
50 **          $expert analyze
51 **          $expert count
52 **          $expert report STMT EREPORT
53 **          $expert destroy
54 */
testExpertCmd(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])55 static int SQLITE_TCLAPI testExpertCmd(
56   void *clientData,
57   Tcl_Interp *interp,
58   int objc,
59   Tcl_Obj *CONST objv[]
60 ){
61   sqlite3expert *pExpert = (sqlite3expert*)clientData;
62   struct Subcmd {
63     const char *zSub;
64     int nArg;
65     const char *zMsg;
66   } aSub[] = {
67     { "sql",       1, "TABLE",        }, /* 0 */
68     { "analyze",   0, "",             }, /* 1 */
69     { "count",     0, "",             }, /* 2 */
70     { "report",    2, "STMT EREPORT", }, /* 3 */
71     { "destroy",   0, "",             }, /* 4 */
72     { 0 }
73   };
74   int iSub;
75   int rc = TCL_OK;
76   char *zErr = 0;
77 
78   if( objc<2 ){
79     Tcl_WrongNumArgs(interp, 1, objv, "SUBCOMMAND ...");
80     return TCL_ERROR;
81   }
82   rc = Tcl_GetIndexFromObjStruct(interp,
83       objv[1], aSub, sizeof(aSub[0]), "sub-command", 0, &iSub
84   );
85   if( rc!=TCL_OK ) return rc;
86   if( objc!=2+aSub[iSub].nArg ){
87     Tcl_WrongNumArgs(interp, 2, objv, aSub[iSub].zMsg);
88     return TCL_ERROR;
89   }
90 
91   switch( iSub ){
92     case 0: {      /* sql */
93       char *zArg = Tcl_GetString(objv[2]);
94       rc = sqlite3_expert_sql(pExpert, zArg, &zErr);
95       break;
96     }
97 
98     case 1: {      /* analyze */
99       rc = sqlite3_expert_analyze(pExpert, &zErr);
100       break;
101     }
102 
103     case 2: {      /* count */
104       int n = sqlite3_expert_count(pExpert);
105       Tcl_SetObjResult(interp, Tcl_NewIntObj(n));
106       break;
107     }
108 
109     case 3: {      /* report */
110       const char *aEnum[] = {
111         "sql", "indexes", "plan", "candidates", 0
112       };
113       int iEnum;
114       int iStmt;
115       const char *zReport;
116 
117       if( Tcl_GetIntFromObj(interp, objv[2], &iStmt)
118        || Tcl_GetIndexFromObj(interp, objv[3], aEnum, "report", 0, &iEnum)
119       ){
120         return TCL_ERROR;
121       }
122 
123       assert( EXPERT_REPORT_SQL==1 );
124       assert( EXPERT_REPORT_INDEXES==2 );
125       assert( EXPERT_REPORT_PLAN==3 );
126       assert( EXPERT_REPORT_CANDIDATES==4 );
127       zReport = sqlite3_expert_report(pExpert, iStmt, 1+iEnum);
128       Tcl_SetObjResult(interp, Tcl_NewStringObj(zReport, -1));
129       break;
130     }
131 
132     default:       /* destroy */
133       assert( iSub==4 );
134       Tcl_DeleteCommand(interp, Tcl_GetString(objv[0]));
135       break;
136   }
137 
138   if( rc!=TCL_OK ){
139     if( zErr ){
140       Tcl_SetObjResult(interp, Tcl_NewStringObj(zErr, -1));
141     }else{
142       extern const char *sqlite3ErrName(int);
143       Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1));
144     }
145   }
146   sqlite3_free(zErr);
147   return rc;
148 }
149 
testExpertDel(void * clientData)150 static void SQLITE_TCLAPI testExpertDel(void *clientData){
151   sqlite3expert *pExpert = (sqlite3expert*)clientData;
152   sqlite3_expert_destroy(pExpert);
153 }
154 
155 /*
156 ** sqlite3_expert_new DB
157 */
test_sqlite3_expert_new(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])158 static int SQLITE_TCLAPI test_sqlite3_expert_new(
159   void * clientData,
160   Tcl_Interp *interp,
161   int objc,
162   Tcl_Obj *CONST objv[]
163 ){
164   static int iCmd = 0;
165   sqlite3 *db;
166   char *zCmd = 0;
167   char *zErr = 0;
168   sqlite3expert *pExpert;
169   int rc = TCL_OK;
170 
171   if( objc!=2 ){
172     Tcl_WrongNumArgs(interp, 1, objv, "DB");
173     return TCL_ERROR;
174   }
175   if( dbHandleFromObj(interp, objv[1], &db) ){
176     return TCL_ERROR;
177   }
178 
179   zCmd = sqlite3_mprintf("sqlite3expert%d", ++iCmd);
180   if( zCmd==0 ){
181     Tcl_AppendResult(interp, "out of memory", (char*)0);
182     return TCL_ERROR;
183   }
184 
185   pExpert = sqlite3_expert_new(db, &zErr);
186   if( pExpert==0 ){
187     Tcl_AppendResult(interp, zErr, (char*)0);
188     rc = TCL_ERROR;
189   }else{
190     void *p = (void*)pExpert;
191     Tcl_CreateObjCommand(interp, zCmd, testExpertCmd, p, testExpertDel);
192     Tcl_SetObjResult(interp, Tcl_NewStringObj(zCmd, -1));
193   }
194 
195   sqlite3_free(zCmd);
196   sqlite3_free(zErr);
197   return rc;
198 }
199 
200 #endif  /* ifndef SQLITE_OMIT_VIRTUALTABLE */
201 
TestExpert_Init(Tcl_Interp * interp)202 int TestExpert_Init(Tcl_Interp *interp){
203 #ifndef SQLITE_OMIT_VIRTUALTABLE
204   struct Cmd {
205     const char *zCmd;
206     Tcl_ObjCmdProc *xProc;
207   } aCmd[] = {
208     { "sqlite3_expert_new", test_sqlite3_expert_new },
209   };
210   int i;
211 
212   for(i=0; i<sizeof(aCmd)/sizeof(struct Cmd); i++){
213     struct Cmd *p = &aCmd[i];
214     Tcl_CreateObjCommand(interp, p->zCmd, p->xProc, 0, 0);
215   }
216 #endif
217   return TCL_OK;
218 }
219 
220 #endif
221