When processing an "ORDER BY ... LIMIT" that does not use an index, check
[sqlite.git] / ext / expert / test_expert.c
blob064c1908a960b07c167f4decd74967dfa53b6158
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.
11 *************************************************************************
14 #if defined(SQLITE_TEST)
16 #include "sqlite3expert.h"
17 #include <assert.h>
18 #include <string.h>
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
29 #ifndef SQLITE_OMIT_VIRTUALTABLE
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.
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;
43 *pDb = *(sqlite3 **)info.objClientData;
44 return TCL_OK;
49 ** Tclcmd: $expert sql SQL
50 ** $expert analyze
51 ** $expert count
52 ** $expert report STMT EREPORT
53 ** $expert destroy
55 static int SQLITE_TCLAPI testExpertCmd(
56 void *clientData,
57 Tcl_Interp *interp,
58 int objc,
59 Tcl_Obj *CONST objv[]
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 }
74 int iSub;
75 int rc = TCL_OK;
76 char *zErr = 0;
78 if( objc<2 ){
79 Tcl_WrongNumArgs(interp, 1, objv, "SUBCOMMAND ...");
80 return TCL_ERROR;
82 rc = Tcl_GetIndexFromObjStruct(interp,
83 objv[1], aSub, sizeof(aSub[0]), "sub-command", 0, &iSub
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;
91 switch( iSub ){
92 case 0: { /* sql */
93 char *zArg = Tcl_GetString(objv[2]);
94 rc = sqlite3_expert_sql(pExpert, zArg, &zErr);
95 break;
98 case 1: { /* analyze */
99 rc = sqlite3_expert_analyze(pExpert, &zErr);
100 break;
103 case 2: { /* count */
104 int n = sqlite3_expert_count(pExpert);
105 Tcl_SetObjResult(interp, Tcl_NewIntObj(n));
106 break;
109 case 3: { /* report */
110 const char *aEnum[] = {
111 "sql", "indexes", "plan", "candidates", 0
113 int iEnum;
114 int iStmt;
115 const char *zReport;
117 if( Tcl_GetIntFromObj(interp, objv[2], &iStmt)
118 || Tcl_GetIndexFromObj(interp, objv[3], aEnum, "report", 0, &iEnum)
120 return TCL_ERROR;
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;
132 default: /* destroy */
133 assert( iSub==4 );
134 Tcl_DeleteCommand(interp, Tcl_GetString(objv[0]));
135 break;
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));
146 sqlite3_free(zErr);
147 return rc;
150 static void SQLITE_TCLAPI testExpertDel(void *clientData){
151 sqlite3expert *pExpert = (sqlite3expert*)clientData;
152 sqlite3_expert_destroy(pExpert);
156 ** sqlite3_expert_new DB
158 static int SQLITE_TCLAPI test_sqlite3_expert_new(
159 void * clientData,
160 Tcl_Interp *interp,
161 int objc,
162 Tcl_Obj *CONST objv[]
164 static int iCmd = 0;
165 sqlite3 *db;
166 char *zCmd = 0;
167 char *zErr = 0;
168 sqlite3expert *pExpert;
169 int rc = TCL_OK;
171 if( objc!=2 ){
172 Tcl_WrongNumArgs(interp, 1, objv, "DB");
173 return TCL_ERROR;
175 if( dbHandleFromObj(interp, objv[1], &db) ){
176 return TCL_ERROR;
179 zCmd = sqlite3_mprintf("sqlite3expert%d", ++iCmd);
180 if( zCmd==0 ){
181 Tcl_AppendResult(interp, "out of memory", (char*)0);
182 return TCL_ERROR;
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));
195 sqlite3_free(zCmd);
196 sqlite3_free(zErr);
197 return rc;
200 #endif /* ifndef SQLITE_OMIT_VIRTUALTABLE */
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 },
210 int i;
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);
216 #endif
217 return TCL_OK;
220 #endif