blob: 0176d7b2e5f4f6b12bb2403b5260a1046560fbc9 [file] [log] [blame]
drhb9bb7c12006-06-11 23:41:55 +00001/*
2** 2006 June 10
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** Code for testing the virtual table interfaces. This code
13** is not included in the SQLite library. It is used for automated
14** testing of the SQLite library.
15**
danielk1977b7a7b9a2006-06-13 10:24:42 +000016** $Id: test8.c,v 1.8 2006/06/13 10:24:43 danielk1977 Exp $
drhb9bb7c12006-06-11 23:41:55 +000017*/
18#include "sqliteInt.h"
19#include "tcl.h"
20#include "os.h"
21#include <stdlib.h>
22#include <string.h>
23
danielk1977b7a7b9a2006-06-13 10:24:42 +000024typedef struct echo_vtab echo_vtab;
25typedef struct echo_cursor echo_cursor;
26
27/* An echo vtab object */
28struct echo_vtab {
29 sqlite3_vtab base;
30 Tcl_Interp *interp;
31 sqlite3 *db;
32 char *zStmt;
33};
34
35/* An echo cursor object */
36struct echo_cursor {
37 sqlite3_vtab_cursor base;
38 sqlite3_stmt *pStmt;
39 int errcode; /* Error code */
40};
41
danielk197778efaba2006-06-12 06:09:17 +000042/*
43** Global Tcl variable $echo_module is a list. This routine appends
44** the string element zArg to that list in interpreter interp.
45*/
drha967e882006-06-13 01:04:52 +000046static void appendToEchoModule(Tcl_Interp *interp, const char *zArg){
danielk197778efaba2006-06-12 06:09:17 +000047 int flags = (TCL_APPEND_VALUE | TCL_LIST_ELEMENT | TCL_GLOBAL_ONLY);
drha967e882006-06-13 01:04:52 +000048 Tcl_SetVar(interp, "echo_module", zArg, flags);
danielk197778efaba2006-06-12 06:09:17 +000049}
50
danielk19777e6ebfb2006-06-12 11:24:37 +000051/*
52** This function is called from within the echo-modules xCreate and
53** xConnect methods. The argc and argv arguments are copies of those
54** passed to the calling method. This function is responsible for
55** calling sqlite3_declare_vtab() to declare the schema of the virtual
56** table being created or connected.
57**
58** If the constructor was passed just one argument, i.e.:
59**
60** CREATE TABLE t1 AS echo(t2);
61**
62** Then t2 is assumed to be the name of a *real* database table. The
63** schema of the virtual table is declared by passing a copy of the
64** CREATE TABLE statement for the real table to sqlite3_declare_vtab().
65** Hence, the virtual table should have exactly the same column names and
66** types as the real table.
67*/
danielk1977b7a7b9a2006-06-13 10:24:42 +000068static int echoDeclareVtab(
69 echo_vtab *pVtab,
70 sqlite3 *db,
71 int argc,
72 char **argv
73){
danielk19777e6ebfb2006-06-12 11:24:37 +000074 int rc = SQLITE_OK;
75
76 if( argc==2 ){
77 sqlite3_stmt *pStmt = 0;
78 sqlite3_prepare(db,
79 "SELECT sql FROM sqlite_master WHERE type = 'table' AND name = ?",
80 -1, &pStmt, 0);
81 sqlite3_bind_text(pStmt, 1, argv[1], -1, 0);
82 if( sqlite3_step(pStmt)==SQLITE_ROW ){
83 const char *zCreateTable = sqlite3_column_text(pStmt, 0);
drha75803d2006-06-12 12:50:23 +000084#ifndef SQLITE_OMIT_VIRTUALTABLE
danielk19777e6ebfb2006-06-12 11:24:37 +000085 sqlite3_declare_vtab(db, zCreateTable);
drha75803d2006-06-12 12:50:23 +000086#endif
danielk19777e6ebfb2006-06-12 11:24:37 +000087 } else {
88 rc = SQLITE_ERROR;
89 }
90 sqlite3_finalize(pStmt);
danielk1977b7a7b9a2006-06-13 10:24:42 +000091 pVtab->zStmt = sqlite3MPrintf("SELECT rowid, * FROM %s ", argv[1]);
danielk19777e6ebfb2006-06-12 11:24:37 +000092 }
93
94 return rc;
95}
96
danielk1977b7a7b9a2006-06-13 10:24:42 +000097static int echoConstructor(
98 sqlite3 *db,
99 const sqlite3_module *pModule,
100 int argc, char **argv,
101 sqlite3_vtab **ppVtab
102){
103 int i;
104 echo_vtab *pVtab;
105
106 pVtab = sqliteMalloc( sizeof(*pVtab) );
107
108 *ppVtab = &pVtab->base;
109 pVtab->base.pModule = pModule;
110 pVtab->interp = pModule->pAux;
111 pVtab->db = db;
112 for(i=0; i<argc; i++){
113 appendToEchoModule(pVtab->interp, argv[i]);
114 }
115
116 echoDeclareVtab(pVtab, db, argc, argv);
117 return 0;
118}
drha967e882006-06-13 01:04:52 +0000119
drhb9bb7c12006-06-11 23:41:55 +0000120/* Methods for the echo module */
121static int echoCreate(
122 sqlite3 *db,
123 const sqlite3_module *pModule,
124 int argc, char **argv,
125 sqlite3_vtab **ppVtab
126){
danielk1977b7a7b9a2006-06-13 10:24:42 +0000127 appendToEchoModule((Tcl_Interp *)(pModule->pAux), "xCreate");
128 return echoConstructor(db, pModule, argc, argv, ppVtab);
drhb9bb7c12006-06-11 23:41:55 +0000129}
130static int echoConnect(
131 sqlite3 *db,
132 const sqlite3_module *pModule,
133 int argc, char **argv,
134 sqlite3_vtab **ppVtab
135){
danielk1977b7a7b9a2006-06-13 10:24:42 +0000136 appendToEchoModule((Tcl_Interp *)(pModule->pAux), "xConnect");
137 return echoConstructor(db, pModule, argc, argv, ppVtab);
drhb9bb7c12006-06-11 23:41:55 +0000138}
danielk1977b7a7b9a2006-06-13 10:24:42 +0000139
drhb9bb7c12006-06-11 23:41:55 +0000140static int echoDisconnect(sqlite3_vtab *pVtab){
drha967e882006-06-13 01:04:52 +0000141 echo_vtab *p = (echo_vtab*)pVtab;
danielk19777dabaa12006-06-13 04:11:43 +0000142 appendToEchoModule(p->interp, "xDisconnect");
danielk1977b7a7b9a2006-06-13 10:24:42 +0000143 sqliteFree(p->zStmt);
144 sqliteFree(p);
drhb9bb7c12006-06-11 23:41:55 +0000145 return 0;
146}
147static int echoDestroy(sqlite3_vtab *pVtab){
drha967e882006-06-13 01:04:52 +0000148 echo_vtab *p = (echo_vtab*)pVtab;
danielk19777dabaa12006-06-13 04:11:43 +0000149 appendToEchoModule(p->interp, "xDestroy");
danielk1977b7a7b9a2006-06-13 10:24:42 +0000150 sqliteFree(p->zStmt);
151 sqliteFree(p);
drhb9bb7c12006-06-11 23:41:55 +0000152 return 0;
153}
154
danielk1977b7a7b9a2006-06-13 10:24:42 +0000155static int echoOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor)
156{
157 echo_cursor *pCur;
158 pCur = sqliteMalloc(sizeof(echo_cursor));
159 *ppCursor = (sqlite3_vtab_cursor *)pCur;
160 return SQLITE_OK;
161}
162
163static int echoClose(sqlite3_vtab_cursor *cur)
164{
165 echo_cursor *pCur = (echo_cursor *)cur;
166 sqlite3_finalize(pCur->pStmt);
167 sqliteFree(pCur);
168 return SQLITE_OK;
169}
170
171static int echoNext(sqlite3_vtab_cursor *cur)
172{
173 int rc;
174 echo_cursor *pCur = (echo_cursor *)cur;
175
176 rc = sqlite3_step(pCur->pStmt);
177
178 if( rc==SQLITE_ROW ){
179 rc = 1;
180 } else {
181 pCur->errcode = sqlite3_finalize(pCur->pStmt);
182 pCur->pStmt = 0;
183 rc = 0;
184 }
185
186 return rc;
187}
188
189static int echoFilter(
190 sqlite3_vtab_cursor *pVtabCursor,
191 int idx,
192 int argc,
193 sqlite3_value **argv
194){
195 int rc;
196
197 echo_cursor *pCur = (echo_cursor *)pVtabCursor;
198 echo_vtab *pVtab = (echo_vtab *)pVtabCursor->pVtab;
199 sqlite3 *db = pVtab->db;
200
201 sqlite3_finalize(pCur->pStmt);
202 pCur->pStmt = 0;
203 rc = sqlite3_prepare(db, pVtab->zStmt, -1, &pCur->pStmt, 0);
204
205 if( rc==SQLITE_OK ){
206 rc = echoNext(pVtabCursor);
207 }
208
209 return rc;
210}
211
212static int echoColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i)
213{
214 int iCol = i + 1;
215 sqlite3_stmt *pStmt = ((echo_cursor *)cur)->pStmt;
216
217 assert( sqlite3_data_count(pStmt)>iCol );
218 switch( sqlite3_column_type(pStmt, iCol) ){
219 case SQLITE_INTEGER:
220 sqlite3_result_int64(ctx, sqlite3_column_int64(pStmt, iCol));
221 break;
222 case SQLITE_FLOAT:
223 sqlite3_result_double(ctx, sqlite3_column_double(pStmt, iCol));
224 break;
225 case SQLITE_TEXT:
226 sqlite3_result_text(ctx,
227 sqlite3_column_text(pStmt, iCol),
228 sqlite3_column_bytes(pStmt, iCol),
229 SQLITE_TRANSIENT
230 );
231 break;
232 case SQLITE_BLOB:
233 sqlite3_result_blob(ctx,
234 sqlite3_column_blob(pStmt, iCol),
235 sqlite3_column_bytes(pStmt, iCol),
236 SQLITE_TRANSIENT
237 );
238 break;
239 }
240 return SQLITE_OK;
241}
242
243static int echoRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid)
244{
245 sqlite3_stmt *pStmt = ((echo_cursor *)cur)->pStmt;
246 *pRowid = sqlite3_column_int64(pStmt, 0);
247 return SQLITE_OK;
248}
249
250
251
drhb9bb7c12006-06-11 23:41:55 +0000252/*
drha967e882006-06-13 01:04:52 +0000253** The xBestIndex method for the echo module always returns
254** an index of 123.
255*/
256static int echoBestIndex(sqlite3_vtab *pVtab, sqlite3_index_info *pIdxInfo){
257 pIdxInfo->idxNum = 123;
258 return SQLITE_OK;
259}
260
261/*
drhb9bb7c12006-06-11 23:41:55 +0000262** A virtual table module that merely echos method calls into TCL
263** variables.
264*/
265static sqlite3_module echoModule = {
danielk197778efaba2006-06-12 06:09:17 +0000266 0, /* iVersion */
267 "echo", /* zName */
268 0, /* pAux */
drhb9bb7c12006-06-11 23:41:55 +0000269 echoCreate,
270 echoConnect,
drha967e882006-06-13 01:04:52 +0000271 echoBestIndex,
drhb9bb7c12006-06-11 23:41:55 +0000272 echoDisconnect,
273 echoDestroy,
danielk1977b7a7b9a2006-06-13 10:24:42 +0000274 echoOpen, /* xOpen - open a cursor */
275 echoClose, /* xClose - close a cursor */
276 echoFilter, /* xFilter - configure scan constraints */
277 echoNext, /* xNext - advance a cursor */
278 echoColumn, /* xColumn - read data */
279 echoRowid /* xRowid - read data */
drhb9bb7c12006-06-11 23:41:55 +0000280};
281
282/*
283** Decode a pointer to an sqlite3 object.
284*/
285static int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb){
286 *ppDb = (sqlite3*)sqlite3TextToPtr(zA);
287 return TCL_OK;
288}
289
290
291/*
292** Register the echo virtual table module.
293*/
294static int register_echo_module(
295 ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
296 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
297 int objc, /* Number of arguments */
298 Tcl_Obj *CONST objv[] /* Command arguments */
299){
300 sqlite3 *db;
301 if( objc!=2 ){
302 Tcl_WrongNumArgs(interp, 1, objv, "DB");
303 return TCL_ERROR;
304 }
305 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
306 echoModule.pAux = interp;
307#ifndef SQLITE_OMIT_VIRTUALTABLE
308 sqlite3_create_module(db, "echo", &echoModule);
309#endif
310 return TCL_OK;
311}
312
313
314/*
315** Register commands with the TCL interpreter.
316*/
317int Sqlitetest8_Init(Tcl_Interp *interp){
318 static struct {
319 char *zName;
320 Tcl_ObjCmdProc *xProc;
321 void *clientData;
322 } aObjCmd[] = {
323 { "register_echo_module", register_echo_module, 0 },
324 };
325 int i;
326 for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){
327 Tcl_CreateObjCommand(interp, aObjCmd[i].zName,
328 aObjCmd[i].xProc, aObjCmd[i].clientData, 0);
329 }
330 return TCL_OK;
331}