/ Check-in [bbeb93b5]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Add first cut of sqlite3_declare_vtab(). Not at all well tested yet. (CVS 3213)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:bbeb93b5bb26ba83ee7b7ae439ca5ceebebac9a0
User & Date: danielk1977 2006-06-12 11:24:37
Context
2006-06-12
12:08
Add a simple test case (and corresponding bugfix) for the virtual table xConnect and xDisconnect methods. (CVS 3214) check-in: b63dbc79 user: danielk1977 tags: trunk
11:24
Add first cut of sqlite3_declare_vtab(). Not at all well tested yet. (CVS 3213) check-in: bbeb93b5 user: danielk1977 tags: trunk
06:09
Incremental work on parsing/storing and invoking the xCreate callback for virtual tables. (CVS 3212) check-in: 8ffbab79 user: danielk1977 tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/build.c.

18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
...
778
779
780
781
782
783
784
785



786

787
788
789
790
791
792
793
794
795
796
797
798
799
800


801
802
803
804
805
806
807
....
1645
1646
1647
1648
1649
1650
1651



1652
1653
1654
1655
1656
1657
1658
**     CREATE INDEX
**     DROP INDEX
**     creating ID lists
**     BEGIN TRANSACTION
**     COMMIT
**     ROLLBACK
**
** $Id: build.c,v 1.396 2006/06/11 23:41:55 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>

/*
** This routine is called when a new SQL statement is beginning to
** be parsed.  Initialize the pParse structure as needed.
................................................................................
      goto begin_table_error;
    }
  }
#endif

  /* Make sure the new table name does not collide with an existing
  ** index or table name in the same database.  Issue an error message if
  ** it does.



  */

  if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){
    goto begin_table_error;
  }
  pTable = sqlite3FindTable(db, zName, db->aDb[iDb].zName);
  if( pTable ){
    if( !noErr ){
      sqlite3ErrorMsg(pParse, "table %T already exists", pName);
    }
    goto begin_table_error;
  }
  if( sqlite3FindIndex(db, zName, 0)!=0 && (iDb==0 || !db->init.busy) ){
    sqlite3ErrorMsg(pParse, "there is already an index named %s", zName);
    goto begin_table_error;
  }


  pTable = sqliteMalloc( sizeof(Table) );
  if( pTable==0 ){
    pParse->rc = SQLITE_NOMEM;
    pParse->nErr++;
    goto begin_table_error;
  }
  pTable->zName = zName;
................................................................................

  assert( pTable );

  /* A positive nCol means the columns names for this view are
  ** already known.
  */
  if( pTable->nCol>0 ) return 0;




  /* A negative nCol is a special marker meaning that we are currently
  ** trying to compute the column names.  If we enter this routine with
  ** a negative nCol, it means two or more views form a loop, like this:
  **
  **     CREATE VIEW one AS SELECT * FROM two;
  **     CREATE VIEW two AS SELECT * FROM one;







|







 







|
>
>
>

>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
>
>







 







>
>
>







18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
...
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
....
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
**     CREATE INDEX
**     DROP INDEX
**     creating ID lists
**     BEGIN TRANSACTION
**     COMMIT
**     ROLLBACK
**
** $Id: build.c,v 1.397 2006/06/12 11:24:37 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>

/*
** This routine is called when a new SQL statement is beginning to
** be parsed.  Initialize the pParse structure as needed.
................................................................................
      goto begin_table_error;
    }
  }
#endif

  /* Make sure the new table name does not collide with an existing
  ** index or table name in the same database.  Issue an error message if
  ** it does. The exception is if the statement being parsed was passed
  ** to an sqlite3_declare_vtab() call. In that case only the column names
  ** and types will be used, so there is no need to test for namespace
  ** collisions.
  */
  if( !IN_DECLARE_VTAB ){
    if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){
      goto begin_table_error;
    }
    pTable = sqlite3FindTable(db, zName, db->aDb[iDb].zName);
    if( pTable ){
      if( !noErr ){
        sqlite3ErrorMsg(pParse, "table %T already exists", pName);
      }
      goto begin_table_error;
    }
    if( sqlite3FindIndex(db, zName, 0)!=0 && (iDb==0 || !db->init.busy) ){
      sqlite3ErrorMsg(pParse, "there is already an index named %s", zName);
      goto begin_table_error;
    }
  }

  pTable = sqliteMalloc( sizeof(Table) );
  if( pTable==0 ){
    pParse->rc = SQLITE_NOMEM;
    pParse->nErr++;
    goto begin_table_error;
  }
  pTable->zName = zName;
................................................................................

  assert( pTable );

  /* A positive nCol means the columns names for this view are
  ** already known.
  */
  if( pTable->nCol>0 ) return 0;
#ifndef SQLITE_OMIT_VIRTUALTABLE
  if( pTable->isVirtual ) return 0;
#endif

  /* A negative nCol is a special marker meaning that we are currently
  ** trying to compute the column names.  If we enter this routine with
  ** a negative nCol, it means two or more views form a loop, like this:
  **
  **     CREATE VIEW one AS SELECT * FROM two;
  **     CREATE VIEW two AS SELECT * FROM one;

Changes to src/sqlite.h.in.

8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
....
1571
1572
1573
1574
1575
1576
1577

1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This header file defines the interface that the SQLite library
** presents to client programs.
**
** @(#) $Id: sqlite.h.in,v 1.168 2006/06/11 23:41:56 drh Exp $
*/
#ifndef _SQLITE3_H_
#define _SQLITE3_H_
#include <stdarg.h>     /* Needed for the definition of va_list */

/*
** Make sure we can call this stuff from C++.
................................................................................
#define SQLITE_INDEX_CONSTRAINT_MATCH 7
int sqlite3_create_module(
  sqlite3 *db, 
  const char *zName,
  const sqlite3_module *
);



/*
** Undo the hack that converts floating point types to integer for
** builds on processors without floating point support.
*/
#ifdef SQLITE_OMIT_FLOATING_POINT
# undef double
#endif

#ifdef __cplusplus
}  /* End of the 'extern "C"' block */
#endif
#endif







|







 







>













8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
....
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This header file defines the interface that the SQLite library
** presents to client programs.
**
** @(#) $Id: sqlite.h.in,v 1.169 2006/06/12 11:24:37 danielk1977 Exp $
*/
#ifndef _SQLITE3_H_
#define _SQLITE3_H_
#include <stdarg.h>     /* Needed for the definition of va_list */

/*
** Make sure we can call this stuff from C++.
................................................................................
#define SQLITE_INDEX_CONSTRAINT_MATCH 7
int sqlite3_create_module(
  sqlite3 *db, 
  const char *zName,
  const sqlite3_module *
);

int sqlite3_declare_vtab(sqlite3*, const char *zCreateTable);

/*
** Undo the hack that converts floating point types to integer for
** builds on processors without floating point support.
*/
#ifdef SQLITE_OMIT_FLOATING_POINT
# undef double
#endif

#ifdef __cplusplus
}  /* End of the 'extern "C"' block */
#endif
#endif

Changes to src/sqliteInt.h.

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
488
489
490
491
492
493
494

495
496
497
498
499
500
501
....
1279
1280
1281
1282
1283
1284
1285

1286
1287






1288
1289
1290
1291
1292
1293
1294
....
1787
1788
1789
1790
1791
1792
1793

1794
1795
1796
1797
1798
1799
**    May you do good and not evil.
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** Internal interface definitions for SQLite.
**
** @(#) $Id: sqliteInt.h,v 1.498 2006/06/12 06:09:18 danielk1977 Exp $
*/
#ifndef _SQLITEINT_H_
#define _SQLITEINT_H_

/*
** Extra interface definitions for those who need them
*/
................................................................................
#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
  int (*xProgress)(void *);     /* The progress callback */
  void *pProgressArg;           /* Argument to the progress callback */
  int nProgressOps;             /* Number of opcodes for progress callback */
#endif
#ifndef SQLITE_OMIT_VIRTUALTABLE
  Hash aModule;                 /* populated by sqlite3_create_module() */

#endif
  Hash aFunc;                   /* All functions that can be in SQL exprs */
  Hash aCollSeq;                /* All collating sequences */
  BusyHandler busyHandler;      /* Busy callback */
  int busyTimeout;              /* Busy handler timeout, in msec */
  Db aDbStatic[2];              /* Static space for the 2 default backends */
#ifdef SQLITE_SSE
................................................................................
  Trigger *pNewTrigger;     /* Trigger under construct by a CREATE TRIGGER */
  TriggerStack *trigStack;  /* Trigger actions being coded */
  const char *zAuthContext; /* The 6th parameter to db->xAuth callbacks */
#ifndef SQLITE_OMIT_VIRTUALTABLE
  int nArgAlloc;            /* Number of bytes allocated for zArg[] */
  int nArgUsed;             /* Number of bytes of zArg[] used so far */
  char *zArg;               /* Complete text of a module argument */

#endif
};







/*
** An instance of the following structure can be declared on a stack and used
** to save the Parse.zAuthContext value so that it can be restored later.
*/
struct AuthContext {
  const char *zAuthContext;   /* Put saved Parse.zAuthContext here */
................................................................................
   void sqlite3VtabClear(Table*);
#endif
void sqlite3VtabBeginParse(Parse*, Token*, Token*, Token*);
void sqlite3VtabFinishParse(Parse*, Token*);
void sqlite3VtabArgInit(Parse*);
void sqlite3VtabArgExtend(Parse*, Token*);
int sqlite3VtabCallCreate(sqlite3*, int, const char *, char **);


#ifdef SQLITE_SSE
#include "sseInt.h"
#endif

#endif







|







 







>







 







>


>
>
>
>
>
>







 







>






7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
....
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
....
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
**    May you do good and not evil.
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** Internal interface definitions for SQLite.
**
** @(#) $Id: sqliteInt.h,v 1.499 2006/06/12 11:24:37 danielk1977 Exp $
*/
#ifndef _SQLITEINT_H_
#define _SQLITEINT_H_

/*
** Extra interface definitions for those who need them
*/
................................................................................
#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
  int (*xProgress)(void *);     /* The progress callback */
  void *pProgressArg;           /* Argument to the progress callback */
  int nProgressOps;             /* Number of opcodes for progress callback */
#endif
#ifndef SQLITE_OMIT_VIRTUALTABLE
  Hash aModule;                 /* populated by sqlite3_create_module() */
  Table *pVTab;                 /* vtab with active Connect/Create method */
#endif
  Hash aFunc;                   /* All functions that can be in SQL exprs */
  Hash aCollSeq;                /* All collating sequences */
  BusyHandler busyHandler;      /* Busy callback */
  int busyTimeout;              /* Busy handler timeout, in msec */
  Db aDbStatic[2];              /* Static space for the 2 default backends */
#ifdef SQLITE_SSE
................................................................................
  Trigger *pNewTrigger;     /* Trigger under construct by a CREATE TRIGGER */
  TriggerStack *trigStack;  /* Trigger actions being coded */
  const char *zAuthContext; /* The 6th parameter to db->xAuth callbacks */
#ifndef SQLITE_OMIT_VIRTUALTABLE
  int nArgAlloc;            /* Number of bytes allocated for zArg[] */
  int nArgUsed;             /* Number of bytes of zArg[] used so far */
  char *zArg;               /* Complete text of a module argument */
  u8 declareVtab;           /* True if inside sqlite3_declare_vtab() */
#endif
};

#ifdef SQLITE_OMIT_VIRTUALTABLE
  #define IN_DECLARE_VTAB 0
#else
  #define IN_DECLARE_VTAB (pParse->declareVtab)
#endif

/*
** An instance of the following structure can be declared on a stack and used
** to save the Parse.zAuthContext value so that it can be restored later.
*/
struct AuthContext {
  const char *zAuthContext;   /* Put saved Parse.zAuthContext here */
................................................................................
   void sqlite3VtabClear(Table*);
#endif
void sqlite3VtabBeginParse(Parse*, Token*, Token*, Token*);
void sqlite3VtabFinishParse(Parse*, Token*);
void sqlite3VtabArgInit(Parse*);
void sqlite3VtabArgExtend(Parse*, Token*);
int sqlite3VtabCallCreate(sqlite3*, int, const char *, char **);
int sqlite3VtabCallConnect(Parse*, Table*);

#ifdef SQLITE_SSE
#include "sseInt.h"
#endif

#endif

Changes to src/test8.c.

9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
..
25
26
27
28
29
30
31






































32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48

49
50
51
52
53
54
55
..
59
60
61
62
63
64
65


66
67
68
69
70
71
72
**    May you share freely, never taking more than you give.
**
*************************************************************************
** Code for testing the virtual table interfaces.  This code
** is not included in the SQLite library.  It is used for automated
** testing of the SQLite library.
**
** $Id: test8.c,v 1.2 2006/06/12 06:09:19 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "tcl.h"
#include "os.h"
#include <stdlib.h>
#include <string.h>

................................................................................
** Global Tcl variable $echo_module is a list. This routine appends
** the string element zArg to that list in interpreter interp.
*/
static void appendToEchoModule(const sqlite3_module *pModule, const char *zArg){
  int flags = (TCL_APPEND_VALUE | TCL_LIST_ELEMENT | TCL_GLOBAL_ONLY);
  Tcl_SetVar((Tcl_Interp *)(pModule->pAux), "echo_module", zArg, flags);
}







































/* Methods for the echo module */
static int echoCreate(
  sqlite3 *db,
  const sqlite3_module *pModule,
  int argc, char **argv,
  sqlite3_vtab **ppVtab
){
  int i;
  Tcl_Interp *interp = pModule->pAux;
  *ppVtab = pModule->pAux;

  appendToEchoModule(pModule, "xCreate");
  for(i=0; i<argc; i++){
    appendToEchoModule(pModule, argv[i]);
  }


  return 0;
}
static int echoConnect(
  sqlite3 *db,
  const sqlite3_module *pModule,
  int argc, char **argv,
  sqlite3_vtab **ppVtab
................................................................................
  *ppVtab = pModule->pAux;

  Tcl_SetVar(interp, "echo_module", "xConnect", TCL_GLOBAL_ONLY);
  for(i=0; i<argc; i++){
    Tcl_SetVar(interp, "echo_module", argv[i],
                TCL_APPEND_VALUE | TCL_LIST_ELEMENT | TCL_GLOBAL_ONLY);
  }


  return 0;
}
static int echoDisconnect(sqlite3_vtab *pVtab){
  Tcl_Interp *interp = (Tcl_Interp*)pVtab;
  Tcl_SetVar(interp, "echo_module", "xDisconnect",
                TCL_APPEND_VALUE | TCL_LIST_ELEMENT | TCL_GLOBAL_ONLY);
  return 0;







|







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>









<







>







 







>
>







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
..
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78

79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
..
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
**    May you share freely, never taking more than you give.
**
*************************************************************************
** Code for testing the virtual table interfaces.  This code
** is not included in the SQLite library.  It is used for automated
** testing of the SQLite library.
**
** $Id: test8.c,v 1.3 2006/06/12 11:24:37 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "tcl.h"
#include "os.h"
#include <stdlib.h>
#include <string.h>

................................................................................
** Global Tcl variable $echo_module is a list. This routine appends
** the string element zArg to that list in interpreter interp.
*/
static void appendToEchoModule(const sqlite3_module *pModule, const char *zArg){
  int flags = (TCL_APPEND_VALUE | TCL_LIST_ELEMENT | TCL_GLOBAL_ONLY);
  Tcl_SetVar((Tcl_Interp *)(pModule->pAux), "echo_module", zArg, flags);
}

/*
** This function is called from within the echo-modules xCreate and
** xConnect methods. The argc and argv arguments are copies of those 
** passed to the calling method. This function is responsible for
** calling sqlite3_declare_vtab() to declare the schema of the virtual
** table being created or connected.
**
** If the constructor was passed just one argument, i.e.:
**
**   CREATE TABLE t1 AS echo(t2);
**
** Then t2 is assumed to be the name of a *real* database table. The
** schema of the virtual table is declared by passing a copy of the 
** CREATE TABLE statement for the real table to sqlite3_declare_vtab().
** Hence, the virtual table should have exactly the same column names and 
** types as the real table.
*/
static int echoDeclareVtab(sqlite3 *db, int argc, char **argv){
  int rc = SQLITE_OK;

  if( argc==2 ){
    sqlite3_stmt *pStmt = 0;
    sqlite3_prepare(db, 
        "SELECT sql FROM sqlite_master WHERE type = 'table' AND name = ?",
        -1, &pStmt, 0);
    sqlite3_bind_text(pStmt, 1, argv[1], -1, 0);
    if( sqlite3_step(pStmt)==SQLITE_ROW ){
      const char *zCreateTable = sqlite3_column_text(pStmt, 0);
      sqlite3_declare_vtab(db, zCreateTable);
    } else {
      rc = SQLITE_ERROR;
    }
    sqlite3_finalize(pStmt);
  }

  return rc;
}

/* Methods for the echo module */
static int echoCreate(
  sqlite3 *db,
  const sqlite3_module *pModule,
  int argc, char **argv,
  sqlite3_vtab **ppVtab
){
  int i;

  *ppVtab = pModule->pAux;

  appendToEchoModule(pModule, "xCreate");
  for(i=0; i<argc; i++){
    appendToEchoModule(pModule, argv[i]);
  }

  echoDeclareVtab(db, argc, argv);
  return 0;
}
static int echoConnect(
  sqlite3 *db,
  const sqlite3_module *pModule,
  int argc, char **argv,
  sqlite3_vtab **ppVtab
................................................................................
  *ppVtab = pModule->pAux;

  Tcl_SetVar(interp, "echo_module", "xConnect", TCL_GLOBAL_ONLY);
  for(i=0; i<argc; i++){
    Tcl_SetVar(interp, "echo_module", argv[i],
                TCL_APPEND_VALUE | TCL_LIST_ELEMENT | TCL_GLOBAL_ONLY);
  }

  echoDeclareVtab(db, argc, argv);
  return 0;
}
static int echoDisconnect(sqlite3_vtab *pVtab){
  Tcl_Interp *interp = (Tcl_Interp*)pVtab;
  Tcl_SetVar(interp, "echo_module", "xDisconnect",
                TCL_APPEND_VALUE | TCL_LIST_ELEMENT | TCL_GLOBAL_ONLY);
  return 0;

Changes to src/tokenize.c.

11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
...
479
480
481
482
483
484
485

486
487
488






489


490
491
492
493
494
495
496
*************************************************************************
** An tokenizer for SQL
**
** This file contains C code that splits an SQL input string up into
** individual tokens and sends those tokens one-by-one over to the
** parser for analysis.
**
** $Id: tokenize.c,v 1.119 2006/06/11 23:41:56 drh Exp $
*/
#include "sqliteInt.h"
#include "os.h"
#include <ctype.h>
#include <stdlib.h>

/*
................................................................................
#ifndef SQLITE_OMIT_SHARED_CACHE
  if( pParse->nested==0 ){
    sqliteFree(pParse->aTableLock);
    pParse->aTableLock = 0;
    pParse->nTableLock = 0;
  }
#endif

#ifndef SQLITE_OMIT_VIRTUALTABLE
  sqliteFree(pParse->zArg);
#endif






  sqlite3DeleteTable(pParse->db, pParse->pNewTable);


  sqlite3DeleteTrigger(pParse->pNewTrigger);
  sqliteFree(pParse->apVarExpr);
  if( nErr>0 && (pParse->rc==SQLITE_OK || pParse->rc==SQLITE_DONE) ){
    pParse->rc = SQLITE_ERROR;
  }
  return nErr;
}







|







 







>



>
>
>
>
>
>
|
>
>







11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
...
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
*************************************************************************
** An tokenizer for SQL
**
** This file contains C code that splits an SQL input string up into
** individual tokens and sends those tokens one-by-one over to the
** parser for analysis.
**
** $Id: tokenize.c,v 1.120 2006/06/12 11:24:37 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "os.h"
#include <ctype.h>
#include <stdlib.h>

/*
................................................................................
#ifndef SQLITE_OMIT_SHARED_CACHE
  if( pParse->nested==0 ){
    sqliteFree(pParse->aTableLock);
    pParse->aTableLock = 0;
    pParse->nTableLock = 0;
  }
#endif

#ifndef SQLITE_OMIT_VIRTUALTABLE
  sqliteFree(pParse->zArg);
#endif

  if( !IN_DECLARE_VTAB ){
    /* If the pParse->declareVtab flag is set, do not delete any table 
    ** structure built up in pParse->pNewTable. The calling code (see vtab.c)
    ** will take responsibility for freeing the Table structure.
    */
    sqlite3DeleteTable(pParse->db, pParse->pNewTable);
  }

  sqlite3DeleteTrigger(pParse->pNewTrigger);
  sqliteFree(pParse->apVarExpr);
  if( nErr>0 && (pParse->rc==SQLITE_OK || pParse->rc==SQLITE_DONE) ){
    pParse->rc = SQLITE_ERROR;
  }
  return nErr;
}

Changes to src/vtab.c.

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
...
184
185
186
187
188
189
190
191

192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207

208
209
210
211
212
213
214
...
233
234
235
236
237
238
239














































































240
241
242
243
244
245
246
247
248
249
250
251
252

253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269




270







271
272
273
274
275
276
277
278
279
**    May you do good and not evil.
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains code used to help implement virtual tables.
**
** $Id: vtab.c,v 1.2 2006/06/12 06:09:19 danielk1977 Exp $
*/
#ifndef SQLITE_OMIT_VIRTUALTABLE
#include "sqliteInt.h"

/*
** External API function used to create a new virtual-table module.
*/
................................................................................
  pParse->nArgAlloc = 0;

  /* Lookup the module name. */
  pTab = pParse->pNewTable;
  if( pTab==0 ) return;
  db = pParse->db;
  if( pTab->nModuleArg<1 ) return;
  pParse->pNewTable = 0;
  zModule = pTab->azModuleArg[0];
  pTab->pModule = (sqlite3_module*)sqlite3HashFind(&db->aModule, 
                     zModule, strlen(zModule));
  
  /* If the CREATE VIRTUAL TABLE statement is being entered for the
  ** first time (in other words if the virtual table is actually being
  ** created now instead of just being read out of sqlite_master) then
................................................................................
  }

  /* If we are rereading the sqlite_master table create the in-memory
  ** record of the table. 
  **
  ** TODO: If the module is already registered, should we call xConnect()
  ** here, or should it wait until the table is first referenced. Maybe
  ** it's better to be lazy here, in case xConnect() is expensive to call.

  */
  else {
#if 0
    sqlite3_module *pMod = pTab->pModule;
    assert( pMod->xConnect );
    pMod->xConnect(db, pMod, pTab->nModuleArg, pTab->azModuleArg, &pTab->pVtab);
#endif
    Table *pOld;
    Schema *pSchema = pTab->pSchema;
    const char *zName = pTab->zName;
    int nName = strlen(zName) + 1;
    pOld = sqlite3HashInsert(&pSchema->tblHash, zName, nName, pTab);
    if( pOld ){
      assert( pTab==pOld );  /* Malloc must have failed inside HashInsert() */
      return;
    }

  }
}

/*
** The parser calls this routine when it sees the first token
** of an argument to the module name in a CREATE VIRTUAL TABLE statement.
*/
................................................................................
  if( pParse->nArgUsed ){
    pParse->zArg[pParse->nArgUsed++] = ' ';
  }
  memcpy(&pParse->zArg[pParse->nArgUsed], p->z, p->n);
  pParse->nArgUsed += p->n;
  pParse->zArg[pParse->nArgUsed] = 0;
}















































































/*
** This function is invoked by the vdbe to call the xCreate method
** of the virtual table named zTab in database iDb. 
**
** If an error occurs, *pzErr is set to point an an English language
** description of the error and an SQLITE_XXX error code is returned.
** In this case the caller must call sqliteFree() on *pzErr.
*/
int sqlite3VtabCallCreate(sqlite3 *db, int iDb, const char *zTab, char **pzErr){
  int rc = SQLITE_OK;
  Table *pTab;
  sqlite3_module *pModule;


  pTab = sqlite3FindTable(db, zTab, db->aDb[iDb].zName);
  assert(pTab && pTab->isVirtual);
  pModule = pTab->pModule;
  const char *zModule = pTab->azModuleArg[0];

  /* If the module has been registered and includes a Create method, 
  ** invoke it now. If the module has not been registered, return an 
  ** error. Otherwise, do nothing.
  */
  if( !pModule ){
    *pzErr = sqlite3MPrintf("unknown module: %s", zModule);
    rc = SQLITE_ERROR;
  }else if( pModule->xCreate ){
    /* TODO: Maybe the above condition should refer to pTable->needCreate. */
    char **azArg = pTab->azModuleArg;
    int nArg = pTab->nModuleArg;




    rc = pModule->xCreate(db, pModule, nArg, azArg, &pTab->pVtab);







  }

  if( SQLITE_OK==rc ){
    pTab->needCreate = 0;
  }
  return rc;
}

#endif /* SQLITE_OMIT_VIRTUALTABLE */







|







 







<







 







|
>


<
<
<
<
<









>







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>













>


|

|









<


>
>
>
>

>
>
>
>
>
>
>









7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
124
125
126
127
128
129
130

131
132
133
134
135
136
137
...
183
184
185
186
187
188
189
190
191
192
193





194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
...
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341

342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
**    May you do good and not evil.
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains code used to help implement virtual tables.
**
** $Id: vtab.c,v 1.3 2006/06/12 11:24:37 danielk1977 Exp $
*/
#ifndef SQLITE_OMIT_VIRTUALTABLE
#include "sqliteInt.h"

/*
** External API function used to create a new virtual-table module.
*/
................................................................................
  pParse->nArgAlloc = 0;

  /* Lookup the module name. */
  pTab = pParse->pNewTable;
  if( pTab==0 ) return;
  db = pParse->db;
  if( pTab->nModuleArg<1 ) return;

  zModule = pTab->azModuleArg[0];
  pTab->pModule = (sqlite3_module*)sqlite3HashFind(&db->aModule, 
                     zModule, strlen(zModule));
  
  /* If the CREATE VIRTUAL TABLE statement is being entered for the
  ** first time (in other words if the virtual table is actually being
  ** created now instead of just being read out of sqlite_master) then
................................................................................
  }

  /* If we are rereading the sqlite_master table create the in-memory
  ** record of the table. 
  **
  ** TODO: If the module is already registered, should we call xConnect()
  ** here, or should it wait until the table is first referenced. Maybe
  ** it's better to be lazy here, in case xConnect() is expensive to call
  ** and the schema is reparsed a number of times.
  */
  else {





    Table *pOld;
    Schema *pSchema = pTab->pSchema;
    const char *zName = pTab->zName;
    int nName = strlen(zName) + 1;
    pOld = sqlite3HashInsert(&pSchema->tblHash, zName, nName, pTab);
    if( pOld ){
      assert( pTab==pOld );  /* Malloc must have failed inside HashInsert() */
      return;
    }
    pParse->pNewTable = 0;
  }
}

/*
** The parser calls this routine when it sees the first token
** of an argument to the module name in a CREATE VIRTUAL TABLE statement.
*/
................................................................................
  if( pParse->nArgUsed ){
    pParse->zArg[pParse->nArgUsed++] = ' ';
  }
  memcpy(&pParse->zArg[pParse->nArgUsed], p->z, p->n);
  pParse->nArgUsed += p->n;
  pParse->zArg[pParse->nArgUsed] = 0;
}

/*
** This function is invoked by the parser to call the xConnect() method
** of table pTab. If an error occurs, an error code is returned and an error
** left in pParse.
*/
int sqlite3VtabCallConnect(Parse *pParse, Table *pTab){
  sqlite3_module *pModule;
  const char *zModule;
  int rc = SQLITE_OK;

  assert(pTab && pTab->isVirtual);
  if( pTab->pVtab ){
    return SQLITE_OK;
  }

  pModule = pTab->pModule;
  zModule = pTab->azModuleArg[0];
  if( !pModule || !pModule->xConnect ){
    const char *zModule = pTab->azModuleArg[0];
    sqlite3ErrorMsg(pParse, "unknown module: %s", zModule);
    rc = SQLITE_ERROR;
  } else {
    char **azArg = pTab->azModuleArg;
    int nArg = pTab->nModuleArg;
    assert( !pParse->db->pVTab );
    pParse->db->pVTab = pTab;
    rc = pModule->xConnect(pParse->db, pModule, nArg, azArg, &pTab->pVtab);
    pParse->db->pVTab = 0;
    if( rc ){
      sqlite3ErrorMsg(pParse, "module connect failed: %s", zModule);
    }
  }

  return rc;
}

int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
  Parse sParse;

  int rc = SQLITE_OK;
  Table *pTab = db->pVTab;
  char *zErr = 0;

  if( !pTab ){
    sqlite3Error(db, SQLITE_MISUSE, 0);
    return SQLITE_MISUSE;
  }
  assert(pTab->isVirtual && pTab->nCol==0 && pTab->aCol==0);

  memset(&sParse, 0, sizeof(Parse));
  sParse.declareVtab = 1;
  sParse.db = db;

  if( 
      SQLITE_OK == sqlite3RunParser(&sParse, zCreateTable, &zErr) && 
      sParse.pNewTable && 
      !sParse.pNewTable->pSelect && 
      !sParse.pNewTable->isVirtual 
  ){
    pTab->aCol = sParse.pNewTable->aCol;
    pTab->nCol = sParse.pNewTable->nCol;
    sParse.pNewTable->nCol = 0;
    sParse.pNewTable->aCol = 0;
  } else {
    sqlite3Error(db, SQLITE_ERROR, zErr);
    sqliteFree(zErr);
    rc = SQLITE_ERROR;
  }
  sParse.declareVtab = 0;

  sqlite3_finalize((sqlite3_stmt*)sParse.pVdbe);
  sqlite3DeleteTable(0, sParse.pNewTable);
  sParse.pNewTable = 0;
  db->pVTab = 0;

  return rc;
}

/*
** This function is invoked by the vdbe to call the xCreate method
** of the virtual table named zTab in database iDb. 
**
** If an error occurs, *pzErr is set to point an an English language
** description of the error and an SQLITE_XXX error code is returned.
** In this case the caller must call sqliteFree() on *pzErr.
*/
int sqlite3VtabCallCreate(sqlite3 *db, int iDb, const char *zTab, char **pzErr){
  int rc = SQLITE_OK;
  Table *pTab;
  sqlite3_module *pModule;
  const char *zModule;

  pTab = sqlite3FindTable(db, zTab, db->aDb[iDb].zName);
  assert(pTab && pTab->isVirtual && !pTab->pVtab);
  pModule = pTab->pModule;
  zModule = pTab->azModuleArg[0];

  /* If the module has been registered and includes a Create method, 
  ** invoke it now. If the module has not been registered, return an 
  ** error. Otherwise, do nothing.
  */
  if( !pModule ){
    *pzErr = sqlite3MPrintf("unknown module: %s", zModule);
    rc = SQLITE_ERROR;
  }else if( pModule->xCreate ){

    char **azArg = pTab->azModuleArg;
    int nArg = pTab->nModuleArg;
    assert( !db->pVTab );
    db->pVTab = pTab;
    rc = sqlite3SafetyOff(db);
    assert( rc==SQLITE_OK );
    rc = pModule->xCreate(db, pModule, nArg, azArg, &pTab->pVtab);
    db->pVTab = 0;
    if( rc ){
      *pzErr = sqlite3MPrintf("module create failed: %s", zModule);
      sqlite3SafetyOn(db);
    } else {
      rc = sqlite3SafetyOn(db);
    }
  }

  if( SQLITE_OK==rc ){
    pTab->needCreate = 0;
  }
  return rc;
}

#endif /* SQLITE_OMIT_VIRTUALTABLE */

Changes to test/vtab1.test.

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
..
43
44
45
46
47
48
49
50


























51

#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this file is creating and dropping virtual tables.
#
# $Id: vtab1.test,v 1.2 2006/06/12 06:09:19 danielk1977 Exp $

set testdir [file dirname $argv0]
source $testdir/tester.tcl

# We cannot create a virtual table if the module has not
# been registered.
#
................................................................................
  set echo_module
} {xCreate echo}
do_test vtab1-1.5 {
  execsql {
    SELECT name, sql FROM sqlite_master ORDER BY 1
  }
} {t1 {CREATE VIRTUAL TABLE t1 USING echo}}



























finish_test








|







 








>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

>
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
..
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this file is creating and dropping virtual tables.
#
# $Id: vtab1.test,v 1.3 2006/06/12 11:24:38 danielk1977 Exp $

set testdir [file dirname $argv0]
source $testdir/tester.tcl

# We cannot create a virtual table if the module has not
# been registered.
#
................................................................................
  set echo_module
} {xCreate echo}
do_test vtab1-1.5 {
  execsql {
    SELECT name, sql FROM sqlite_master ORDER BY 1
  }
} {t1 {CREATE VIRTUAL TABLE t1 USING echo}}

# If a single argument is passed to the echo module during table
# creation, it is assumed to be the name of a table in the same
# database. The echo module attempts to set the schema of the
# new virtual table to be the same as the existing database table.
#
do_test vtab1-2.1 {
  execsql {
    CREATE TABLE template(a, b, c);
  }
  execsql { PRAGMA table_info(template); }
} [list         \
  0 a {} 0 {} 0 \
  1 b {} 0 {} 0 \
  2 c {} 0 {} 0 \
]
do_test vtab1-2.2 {
  execsql {
    CREATE VIRTUAL TABLE t2 USING echo(template);
  }
  execsql { PRAGMA table_info(t2); }
} [list         \
  0 a {} 0 {} 0 \
  1 b {} 0 {} 0 \
  2 c {} 0 {} 0 \
]

finish_test