blob: b976f84e39cf0486e1a4656e8f82f4da12afb19b [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**
danielk19777e6ebfb2006-06-12 11:24:37 +000016** $Id: test8.c,v 1.3 2006/06/12 11:24:37 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
danielk197778efaba2006-06-12 06:09:17 +000024/*
25** Global Tcl variable $echo_module is a list. This routine appends
26** the string element zArg to that list in interpreter interp.
27*/
28static void appendToEchoModule(const sqlite3_module *pModule, const char *zArg){
29 int flags = (TCL_APPEND_VALUE | TCL_LIST_ELEMENT | TCL_GLOBAL_ONLY);
30 Tcl_SetVar((Tcl_Interp *)(pModule->pAux), "echo_module", zArg, flags);
31}
32
danielk19777e6ebfb2006-06-12 11:24:37 +000033/*
34** This function is called from within the echo-modules xCreate and
35** xConnect methods. The argc and argv arguments are copies of those
36** passed to the calling method. This function is responsible for
37** calling sqlite3_declare_vtab() to declare the schema of the virtual
38** table being created or connected.
39**
40** If the constructor was passed just one argument, i.e.:
41**
42** CREATE TABLE t1 AS echo(t2);
43**
44** Then t2 is assumed to be the name of a *real* database table. The
45** schema of the virtual table is declared by passing a copy of the
46** CREATE TABLE statement for the real table to sqlite3_declare_vtab().
47** Hence, the virtual table should have exactly the same column names and
48** types as the real table.
49*/
50static int echoDeclareVtab(sqlite3 *db, int argc, char **argv){
51 int rc = SQLITE_OK;
52
53 if( argc==2 ){
54 sqlite3_stmt *pStmt = 0;
55 sqlite3_prepare(db,
56 "SELECT sql FROM sqlite_master WHERE type = 'table' AND name = ?",
57 -1, &pStmt, 0);
58 sqlite3_bind_text(pStmt, 1, argv[1], -1, 0);
59 if( sqlite3_step(pStmt)==SQLITE_ROW ){
60 const char *zCreateTable = sqlite3_column_text(pStmt, 0);
61 sqlite3_declare_vtab(db, zCreateTable);
62 } else {
63 rc = SQLITE_ERROR;
64 }
65 sqlite3_finalize(pStmt);
66 }
67
68 return rc;
69}
70
drhb9bb7c12006-06-11 23:41:55 +000071/* Methods for the echo module */
72static int echoCreate(
73 sqlite3 *db,
74 const sqlite3_module *pModule,
75 int argc, char **argv,
76 sqlite3_vtab **ppVtab
77){
78 int i;
drhb9bb7c12006-06-11 23:41:55 +000079 *ppVtab = pModule->pAux;
80
danielk197778efaba2006-06-12 06:09:17 +000081 appendToEchoModule(pModule, "xCreate");
drhb9bb7c12006-06-11 23:41:55 +000082 for(i=0; i<argc; i++){
danielk197778efaba2006-06-12 06:09:17 +000083 appendToEchoModule(pModule, argv[i]);
drhb9bb7c12006-06-11 23:41:55 +000084 }
danielk197778efaba2006-06-12 06:09:17 +000085
danielk19777e6ebfb2006-06-12 11:24:37 +000086 echoDeclareVtab(db, argc, argv);
drhb9bb7c12006-06-11 23:41:55 +000087 return 0;
88}
89static int echoConnect(
90 sqlite3 *db,
91 const sqlite3_module *pModule,
92 int argc, char **argv,
93 sqlite3_vtab **ppVtab
94){
95 int i;
96 Tcl_Interp *interp = pModule->pAux;
97 *ppVtab = pModule->pAux;
98
99 Tcl_SetVar(interp, "echo_module", "xConnect", TCL_GLOBAL_ONLY);
100 for(i=0; i<argc; i++){
101 Tcl_SetVar(interp, "echo_module", argv[i],
102 TCL_APPEND_VALUE | TCL_LIST_ELEMENT | TCL_GLOBAL_ONLY);
103 }
danielk19777e6ebfb2006-06-12 11:24:37 +0000104
105 echoDeclareVtab(db, argc, argv);
drhb9bb7c12006-06-11 23:41:55 +0000106 return 0;
107}
108static int echoDisconnect(sqlite3_vtab *pVtab){
109 Tcl_Interp *interp = (Tcl_Interp*)pVtab;
110 Tcl_SetVar(interp, "echo_module", "xDisconnect",
111 TCL_APPEND_VALUE | TCL_LIST_ELEMENT | TCL_GLOBAL_ONLY);
112 return 0;
113}
114static int echoDestroy(sqlite3_vtab *pVtab){
115 Tcl_Interp *interp = (Tcl_Interp*)pVtab;
116 Tcl_SetVar(interp, "echo_module", "xDestroy",
117 TCL_APPEND_VALUE | TCL_LIST_ELEMENT | TCL_GLOBAL_ONLY);
118 return 0;
119}
120
121/*
122** A virtual table module that merely echos method calls into TCL
123** variables.
124*/
125static sqlite3_module echoModule = {
danielk197778efaba2006-06-12 06:09:17 +0000126 0, /* iVersion */
127 "echo", /* zName */
128 0, /* pAux */
drhb9bb7c12006-06-11 23:41:55 +0000129 echoCreate,
130 echoConnect,
danielk197778efaba2006-06-12 06:09:17 +0000131 0, /* xBestIndex */
drhb9bb7c12006-06-11 23:41:55 +0000132 echoDisconnect,
133 echoDestroy,
134};
135
136/*
137** Decode a pointer to an sqlite3 object.
138*/
139static int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb){
140 *ppDb = (sqlite3*)sqlite3TextToPtr(zA);
141 return TCL_OK;
142}
143
144
145/*
146** Register the echo virtual table module.
147*/
148static int register_echo_module(
149 ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
150 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
151 int objc, /* Number of arguments */
152 Tcl_Obj *CONST objv[] /* Command arguments */
153){
154 sqlite3 *db;
155 if( objc!=2 ){
156 Tcl_WrongNumArgs(interp, 1, objv, "DB");
157 return TCL_ERROR;
158 }
159 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
160 echoModule.pAux = interp;
161#ifndef SQLITE_OMIT_VIRTUALTABLE
162 sqlite3_create_module(db, "echo", &echoModule);
163#endif
164 return TCL_OK;
165}
166
167
168/*
169** Register commands with the TCL interpreter.
170*/
171int Sqlitetest8_Init(Tcl_Interp *interp){
172 static struct {
173 char *zName;
174 Tcl_ObjCmdProc *xProc;
175 void *clientData;
176 } aObjCmd[] = {
177 { "register_echo_module", register_echo_module, 0 },
178 };
179 int i;
180 for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){
181 Tcl_CreateObjCommand(interp, aObjCmd[i].zName,
182 aObjCmd[i].xProc, aObjCmd[i].clientData, 0);
183 }
184 return TCL_OK;
185}