SQLite

Check-in [1f20e1832b]
Login

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

Overview
Comment:Add implementations for opcodes required for linear scans of virtual tables. (CVS 3223)
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 1f20e1832b38c76d2b0dde5fd720670c2ad0438b
User & Date: danielk1977 2006-06-13 10:24:43.000
Context
2006-06-13
11:15
Minor changes to lempar.c to reduce warnings on some compilers. (CVS 3224) (check-in: dae71de10d user: drh tags: trunk)
10:24
Add implementations for opcodes required for linear scans of virtual tables. (CVS 3223) (check-in: 1f20e1832b user: danielk1977 tags: trunk)
04:11
Bugfixes: Fix a segfault introduced as part of the new vtab code, deallocate memory in the Destroy() method of the echo module. (CVS 3222) (check-in: 00f3c249bc user: danielk1977 tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/sqliteInt.h.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/*
** 2001 September 15
**
** The author disclaims copyright to this source code.  In place of
** a legal notice, here is a blessing:
**
**    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.502 2006/06/12 21:59:14 drh Exp $
*/
#ifndef _SQLITEINT_H_
#define _SQLITEINT_H_

/*
** Extra interface definitions for those who need them
*/













|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/*
** 2001 September 15
**
** The author disclaims copyright to this source code.  In place of
** a legal notice, here is a blessing:
**
**    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.503 2006/06/13 10:24:43 danielk1977 Exp $
*/
#ifndef _SQLITEINT_H_
#define _SQLITEINT_H_

/*
** Extra interface definitions for those who need them
*/
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
  int addColOffset;  /* Offset in CREATE TABLE statement to add a new column */
#endif
#ifndef SQLITE_OMIT_VIRTUALTABLE
  sqlite3_module *pModule;  /* Pointer to the implementation of the module */
  sqlite3_vtab *pVtab;      /* Pointer to the module instance */
  int nModuleArg;           /* Number of arguments to the module */
  char **azModuleArg;       /* Text of all module args. [0] is module name */
  u8 needCreate;            /* Need to call pMod->xCreate() */
  u8 isVirtual;             /* True if this is a virtual table */
#endif
  Schema *pSchema;
};

/*
** Each foreign key constraint is an instance of the following structure.







<







705
706
707
708
709
710
711

712
713
714
715
716
717
718
  int addColOffset;  /* Offset in CREATE TABLE statement to add a new column */
#endif
#ifndef SQLITE_OMIT_VIRTUALTABLE
  sqlite3_module *pModule;  /* Pointer to the implementation of the module */
  sqlite3_vtab *pVtab;      /* Pointer to the module instance */
  int nModuleArg;           /* Number of arguments to the module */
  char **azModuleArg;       /* Text of all module args. [0] is module name */

  u8 isVirtual;             /* True if this is a virtual table */
#endif
  Schema *pSchema;
};

/*
** Each foreign key constraint is an instance of the following structure.
Changes to src/test8.c.
9
10
11
12
13
14
15
16
17
18
19
20
21
22


















23
24
25
26
27
28
29
**    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.7 2006/06/13 04:11:44 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(Tcl_Interp *interp, const char *zArg){
  int flags = (TCL_APPEND_VALUE | TCL_LIST_ELEMENT | TCL_GLOBAL_ONLY);







|






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







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
**    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.8 2006/06/13 10:24:43 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "tcl.h"
#include "os.h"
#include <stdlib.h>
#include <string.h>

typedef struct echo_vtab echo_vtab;
typedef struct echo_cursor echo_cursor;

/* An echo vtab object */
struct echo_vtab {
  sqlite3_vtab base;
  Tcl_Interp *interp;
  sqlite3 *db;
  char *zStmt;
};

/* An echo cursor object */
struct echo_cursor {
  sqlite3_vtab_cursor base;
  sqlite3_stmt *pStmt;
  int errcode;                 /* Error code */
};

/*
** Global Tcl variable $echo_module is a list. This routine appends
** the string element zArg to that list in interpreter interp.
*/
static void appendToEchoModule(Tcl_Interp *interp, const char *zArg){
  int flags = (TCL_APPEND_VALUE | TCL_LIST_ELEMENT | TCL_GLOBAL_ONLY);
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
94
95
96
97
98
99
100
101











102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127

128
129
130
131
132
133

134
135

































































































136
137
138
139
140
141
142
**
** 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);
#ifndef SQLITE_OMIT_VIRTUALTABLE
      sqlite3_declare_vtab(db, zCreateTable);
#endif
    } else {
      rc = SQLITE_ERROR;
    }
    sqlite3_finalize(pStmt);

  }

  return rc;
}

/* An echo vtab object */
typedef struct echo_vtab echo_vtab;
struct echo_vtab {
  sqlite3_vtab base;
  Tcl_Interp *interp;
};

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

  pVtab = sqliteMalloc( sizeof(*pVtab) );

  *ppVtab = &pVtab->base;
  pVtab->base.pModule = pModule;
  pVtab->interp = pModule->pAux;
  appendToEchoModule(pVtab->interp, "xCreate");
  for(i=0; i<argc; i++){
    appendToEchoModule(pVtab->interp, argv[i]);
  }

  echoDeclareVtab(db, argc, argv);
  return 0;
}











static int echoConnect(
  sqlite3 *db,
  const sqlite3_module *pModule,
  int argc, char **argv,
  sqlite3_vtab **ppVtab
){
  int i;
  Tcl_Interp *interp = pModule->pAux;
  echo_vtab *pVtab;

  pVtab = sqliteMalloc( sizeof(*pVtab) );
  *ppVtab = &pVtab->base;
  pVtab->base.pModule = pModule;
  pVtab->interp = pModule->pAux;
  appendToEchoModule(pVtab->interp, "xConnect");
  for(i=0; i<argc; i++){
    appendToEchoModule(pVtab->interp, argv[i]);
  }

  echoDeclareVtab(db, argc, argv);
  return 0;
}
static int echoDisconnect(sqlite3_vtab *pVtab){
  echo_vtab *p = (echo_vtab*)pVtab;
  appendToEchoModule(p->interp, "xDisconnect");
  sqliteFree(pVtab);

  return 0;
}
static int echoDestroy(sqlite3_vtab *pVtab){
  echo_vtab *p = (echo_vtab*)pVtab;
  appendToEchoModule(p->interp, "xDestroy");
  sqliteFree(pVtab);

  return 0;
}


































































































/*
** The xBestIndex method for the echo module always returns
** an index of 123.
*/
static int echoBestIndex(sqlite3_vtab *pVtab, sqlite3_index_info *pIdxInfo){
  pIdxInfo->idxNum = 123;







|
>
>
>
>
>

















>





<
<
<
<
<
<
<
<
|









>



|




|


>
>
>
>
>
>
>
>
>
>
>






<
|
<
|
<
<
<
<
<
<
<
|

<
<
<



|
>





|
>


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







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
94
95
96








97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135

136

137







138
139



140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
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
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
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
**
** 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(
  echo_vtab *pVtab, 
  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);
#ifndef SQLITE_OMIT_VIRTUALTABLE
      sqlite3_declare_vtab(db, zCreateTable);
#endif
    } else {
      rc = SQLITE_ERROR;
    }
    sqlite3_finalize(pStmt);
    pVtab->zStmt = sqlite3MPrintf("SELECT rowid, * FROM %s ", argv[1]);
  }

  return rc;
}









static int echoConstructor(
  sqlite3 *db,
  const sqlite3_module *pModule,
  int argc, char **argv,
  sqlite3_vtab **ppVtab
){
  int i;
  echo_vtab *pVtab;

  pVtab = sqliteMalloc( sizeof(*pVtab) );

  *ppVtab = &pVtab->base;
  pVtab->base.pModule = pModule;
  pVtab->interp = pModule->pAux;
  pVtab->db = db;
  for(i=0; i<argc; i++){
    appendToEchoModule(pVtab->interp, argv[i]);
  }

  echoDeclareVtab(pVtab, db, argc, argv);
  return 0;
}

/* Methods for the echo module */
static int echoCreate(
  sqlite3 *db,
  const sqlite3_module *pModule,
  int argc, char **argv,
  sqlite3_vtab **ppVtab
){
  appendToEchoModule((Tcl_Interp *)(pModule->pAux), "xCreate");
  return echoConstructor(db, pModule, argc, argv, ppVtab);
}
static int echoConnect(
  sqlite3 *db,
  const sqlite3_module *pModule,
  int argc, char **argv,
  sqlite3_vtab **ppVtab
){

  appendToEchoModule((Tcl_Interp *)(pModule->pAux), "xConnect");

  return echoConstructor(db, pModule, argc, argv, ppVtab);







}




static int echoDisconnect(sqlite3_vtab *pVtab){
  echo_vtab *p = (echo_vtab*)pVtab;
  appendToEchoModule(p->interp, "xDisconnect");
  sqliteFree(p->zStmt);
  sqliteFree(p);
  return 0;
}
static int echoDestroy(sqlite3_vtab *pVtab){
  echo_vtab *p = (echo_vtab*)pVtab;
  appendToEchoModule(p->interp, "xDestroy");
  sqliteFree(p->zStmt);
  sqliteFree(p);
  return 0;
}

static int echoOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor)
{
  echo_cursor *pCur;
  pCur = sqliteMalloc(sizeof(echo_cursor));
  *ppCursor = (sqlite3_vtab_cursor *)pCur;
  return SQLITE_OK;
}

static int echoClose(sqlite3_vtab_cursor *cur)
{
  echo_cursor *pCur = (echo_cursor *)cur;
  sqlite3_finalize(pCur->pStmt);
  sqliteFree(pCur);
  return SQLITE_OK;
}

static int echoNext(sqlite3_vtab_cursor *cur)
{
  int rc;
  echo_cursor *pCur = (echo_cursor *)cur;

  rc = sqlite3_step(pCur->pStmt);

  if( rc==SQLITE_ROW ){
    rc = 1;
  } else {
    pCur->errcode = sqlite3_finalize(pCur->pStmt);
    pCur->pStmt = 0;
    rc = 0;
  }

  return rc;
}

static int echoFilter(
  sqlite3_vtab_cursor *pVtabCursor, 
  int idx,
  int argc, 
  sqlite3_value **argv
){
  int rc;

  echo_cursor *pCur = (echo_cursor *)pVtabCursor;
  echo_vtab *pVtab = (echo_vtab *)pVtabCursor->pVtab;
  sqlite3 *db = pVtab->db;

  sqlite3_finalize(pCur->pStmt);
  pCur->pStmt = 0;
  rc = sqlite3_prepare(db, pVtab->zStmt, -1, &pCur->pStmt, 0);

  if( rc==SQLITE_OK ){
    rc = echoNext(pVtabCursor);
  }

  return rc;
}

static int echoColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i)
{
  int iCol = i + 1;
  sqlite3_stmt *pStmt = ((echo_cursor *)cur)->pStmt;

  assert( sqlite3_data_count(pStmt)>iCol );
  switch( sqlite3_column_type(pStmt, iCol) ){
    case SQLITE_INTEGER:
      sqlite3_result_int64(ctx, sqlite3_column_int64(pStmt, iCol));
      break;
    case SQLITE_FLOAT:
      sqlite3_result_double(ctx, sqlite3_column_double(pStmt, iCol));
      break;
    case SQLITE_TEXT:
      sqlite3_result_text(ctx, 
          sqlite3_column_text(pStmt, iCol),
          sqlite3_column_bytes(pStmt, iCol),
          SQLITE_TRANSIENT
      );
      break;
    case SQLITE_BLOB:
      sqlite3_result_blob(ctx, 
          sqlite3_column_blob(pStmt, iCol),
          sqlite3_column_bytes(pStmt, iCol),
          SQLITE_TRANSIENT
      );
      break;
  }
  return SQLITE_OK;
}

static int echoRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid)
{
  sqlite3_stmt *pStmt = ((echo_cursor *)cur)->pStmt;
  *pRowid = sqlite3_column_int64(pStmt, 0);
  return SQLITE_OK;
}



/*
** The xBestIndex method for the echo module always returns
** an index of 123.
*/
static int echoBestIndex(sqlite3_vtab *pVtab, sqlite3_index_info *pIdxInfo){
  pIdxInfo->idxNum = 123;
152
153
154
155
156
157
158






159
160
161
162
163
164
165
  "echo",                    /* zName */
  0,                         /* pAux */
  echoCreate,
  echoConnect,
  echoBestIndex,
  echoDisconnect, 
  echoDestroy,






};

/*
** Decode a pointer to an sqlite3 object.
*/
static int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb){
  *ppDb = (sqlite3*)sqlite3TextToPtr(zA);







>
>
>
>
>
>







267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
  "echo",                    /* zName */
  0,                         /* pAux */
  echoCreate,
  echoConnect,
  echoBestIndex,
  echoDisconnect, 
  echoDestroy,
  echoOpen,                  /* xOpen - open a cursor */
  echoClose,                 /* xClose - close a cursor */
  echoFilter,                /* xFilter - configure scan constraints */
  echoNext,                  /* xNext - advance a cursor */
  echoColumn,                /* xColumn - read data */
  echoRowid                  /* xRowid - read data */
};

/*
** Decode a pointer to an sqlite3 object.
*/
static int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb){
  *ppDb = (sqlite3*)sqlite3TextToPtr(zA);
Changes to src/vdbe.c.
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
**
** Various scripts scan this source file in order to generate HTML
** documentation, headers files, or other derived files.  The formatting
** of the code in this file is, therefore, important.  See other comments
** in this file for details.  If in doubt, do not deviate from existing
** commenting and indentation practices when changing or adding code.
**
** $Id: vdbe.c,v 1.554 2006/06/12 21:59:14 drh Exp $
*/
#include "sqliteInt.h"
#include "os.h"
#include <ctype.h>
#include "vdbeInt.h"

/*







|







39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
**
** Various scripts scan this source file in order to generate HTML
** documentation, headers files, or other derived files.  The formatting
** of the code in this file is, therefore, important.  See other comments
** in this file for details.  If in doubt, do not deviate from existing
** commenting and indentation practices when changing or adding code.
**
** $Id: vdbe.c,v 1.555 2006/06/13 10:24:43 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "os.h"
#include <ctype.h>
#include "vdbeInt.h"

/*
4561
4562
4563
4564
4565
4566
4567


















4568
4569
4570
4571
4572
4573
4574
4575
4576
4577
4578
4579
4580
4581



4582
4583
4584
4585
4586
4587
4588
































4589
4590
4591
4592
4593
4594
4595
4596
4597
4598
4599




















4600
4601
4602
4603
4604
4605
4606
4607
4608
4609
4610



























4611
4612
4613
4614
4615
4616
4617
4618
4619
4620
4621
4622


























4623
4624
4625
4626
4627
4628
4629
/* Opcode: VOpen P1 * P3
**
** P3 is a pointer to a virtual table object, an sqlite3_vtab structure.
** P1 is a cursor number.  This opcode opens a cursor to the virtual
** table and stores that cursor in P1.
*/
case OP_VOpen: {


















  break;
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */

#ifndef SQLITE_OMIT_VIRTUALTABLE
/* Opcode: VFilter P1 P2 *
**
** P1 is a cursor opened using VOpen.  P2 is an address to jump to if
** the filtered result set is empty.
**
** This opcode invokes the xFilter method on the virtual table specified
** by P1.  The index number parameter to xFilter is the top of the stack.
** Next down on the stack is the argc parameter.  Beneath the
** next of stack are argc additional parameters which are passed to



** xFilter as argv.  The index number, argc, and all argv stack values
** are popped from the stack before this instruction completes.
**
** A jump is made to P2 if the result set after filtering would be 
** empty.
*/
case OP_VFilter: {
































  break;
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */

#ifndef SQLITE_OMIT_VIRTUALTABLE
/* Opcode: VRowid P1 * *
**
** Push an integer onto the stack which is the rowid of
** the virtual-table that the P1 cursor is pointing to.
*/
case OP_VRowid: {




















  break;
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */

#ifndef SQLITE_OMIT_VIRTUALTABLE
/* Opcode: VColumn P1 P2 *
**
** Push onto the stack the value of the P2-th column of
** the row of the virtual-table that the P1 cursor is pointing to.
*/
case OP_VColumn: {



























  break;
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */

#ifndef SQLITE_OMIT_VIRTUALTABLE
/* Opcode: VNext P1 P2 *
**
** Advance virtual table P1 to the next row in its result set and
** jump to instruction P2.  Or, if the virtual table has reached
** the end of its result set, then fall through to the next instruction.
*/
case OP_VNext: {


























  break;
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */

/* An other opcode is illegal...
*/
default: {







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














>
>
>
|
|





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











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











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












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







4561
4562
4563
4564
4565
4566
4567
4568
4569
4570
4571
4572
4573
4574
4575
4576
4577
4578
4579
4580
4581
4582
4583
4584
4585
4586
4587
4588
4589
4590
4591
4592
4593
4594
4595
4596
4597
4598
4599
4600
4601
4602
4603
4604
4605
4606
4607
4608
4609
4610
4611
4612
4613
4614
4615
4616
4617
4618
4619
4620
4621
4622
4623
4624
4625
4626
4627
4628
4629
4630
4631
4632
4633
4634
4635
4636
4637
4638
4639
4640
4641
4642
4643
4644
4645
4646
4647
4648
4649
4650
4651
4652
4653
4654
4655
4656
4657
4658
4659
4660
4661
4662
4663
4664
4665
4666
4667
4668
4669
4670
4671
4672
4673
4674
4675
4676
4677
4678
4679
4680
4681
4682
4683
4684
4685
4686
4687
4688
4689
4690
4691
4692
4693
4694
4695
4696
4697
4698
4699
4700
4701
4702
4703
4704
4705
4706
4707
4708
4709
4710
4711
4712
4713
4714
4715
4716
4717
4718
4719
4720
4721
4722
4723
4724
4725
4726
4727
4728
4729
4730
4731
4732
4733
4734
4735
4736
4737
4738
4739
4740
4741
4742
4743
4744
4745
4746
4747
4748
4749
4750
4751
4752
4753
4754
4755
/* Opcode: VOpen P1 * P3
**
** P3 is a pointer to a virtual table object, an sqlite3_vtab structure.
** P1 is a cursor number.  This opcode opens a cursor to the virtual
** table and stores that cursor in P1.
*/
case OP_VOpen: {
  Cursor *pCur = 0;
  sqlite3_vtab_cursor *pVtabCursor = 0;

  sqlite3_vtab *pVtab = (sqlite3_vtab *)(pOp->p3);
  sqlite3_module *pModule = (sqlite3_module *)pVtab->pModule;

  assert(pVtab && pModule);
  if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
  rc = pModule->xOpen(pVtab, &pVtabCursor);
  if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse;
  if( SQLITE_OK==rc ){
    /* Initialise sqlite3_vtab_cursor base class */
    pVtabCursor->pVtab = pVtab;

    /* Initialise vdbe cursor object */
    pCur = allocateCursor(p, pOp->p1, -1);
    pCur->pVtabCursor = pVtabCursor;
  }
  break;
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */

#ifndef SQLITE_OMIT_VIRTUALTABLE
/* Opcode: VFilter P1 P2 *
**
** P1 is a cursor opened using VOpen.  P2 is an address to jump to if
** the filtered result set is empty.
**
** This opcode invokes the xFilter method on the virtual table specified
** by P1.  The index number parameter to xFilter is the top of the stack.
** Next down on the stack is the argc parameter.  Beneath the
** next of stack are argc additional parameters which are passed to
** xFilter as argv. The topmost parameter (i.e. 3rd element popped from
** the stack) becomes argv[argc-1] when passed to xFilter.
**
** The index number, argc, and all argv stack values are popped from the
** stack before this instruction completes.
**
** A jump is made to P2 if the result set after filtering would be 
** empty.
*/
case OP_VFilter: {
  int iIndex;
  int nArg;

  const sqlite3_module *pModule;

  Cursor *pCur = p->apCsr[pOp->p1];
  assert( pCur->pVtabCursor );
  pModule = pCur->pVtabCursor->pVtab->pModule;

  /* Grab the index number and argc parameters off the top of the stack. */
  assert( (&pTos[-1])>=p->aStack );
  assert( pTos[0].flags==MEM_Int && pTos[-1].flags==MEM_Int );
  iIndex = pTos[0].i;
  nArg = pTos[-1].i;

  /* Invoke the xFilter method if one is defined. */
  if( pModule->xFilter ){
    int res;
    Mem *apArg;
    apArg = &pTos[1-2-nArg];

    if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
    res = pModule->xFilter(pCur->pVtabCursor, iIndex, nArg, &apArg);
    if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse;

    if( res==0 ){
      pc = pOp->p2 - 1;
    }
  }

  /* Pop the index number, argc value and parameters off the stack */
  popStack(&pTos, 2+nArg);
  break;
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */

#ifndef SQLITE_OMIT_VIRTUALTABLE
/* Opcode: VRowid P1 * *
**
** Push an integer onto the stack which is the rowid of
** the virtual-table that the P1 cursor is pointing to.
*/
case OP_VRowid: {
  const sqlite3_module *pModule;

  Cursor *pCur = p->apCsr[pOp->p1];
  assert( pCur->pVtabCursor );
  pModule = pCur->pVtabCursor->pVtab->pModule;
  if( pModule->xRowid==0 ){
    sqlite3SetString(&p->zErrMsg, "Unsupported module operation: xRowid", 0);
    rc = SQLITE_ERROR;
  } else {
    sqlite_int64 iRow;

    if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
    rc = pModule->xRowid(pCur->pVtabCursor, &iRow);
    if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse;

    pTos++;
    pTos->flags = MEM_Int;
    pTos->i = iRow;
  }

  break;
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */

#ifndef SQLITE_OMIT_VIRTUALTABLE
/* Opcode: VColumn P1 P2 *
**
** Push onto the stack the value of the P2-th column of
** the row of the virtual-table that the P1 cursor is pointing to.
*/
case OP_VColumn: {
  const sqlite3_module *pModule;

  Cursor *pCur = p->apCsr[pOp->p1];
  assert( pCur->pVtabCursor );
  pModule = pCur->pVtabCursor->pVtab->pModule;
  if( pModule->xColumn==0 ){
    sqlite3SetString(&p->zErrMsg, "Unsupported module operation: xColumn", 0);
    rc = SQLITE_ERROR;
  } else {
    sqlite3_context sContext;
    memset(&sContext, 0, sizeof(sContext));
    sContext.s.flags = MEM_Null;
    if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
    rc = pModule->xColumn(pCur->pVtabCursor, &sContext, pOp->p2);

    /* Copy the result of the function to the top of the stack. We
    ** do this regardless of whether or not an error occured to ensure any
    ** dynamic allocation in sContext.s (a Mem struct) is  released.
    */
    sqlite3VdbeChangeEncoding(&sContext.s, encoding);
    pTos++;
    pTos->flags = 0;
    sqlite3VdbeMemMove(pTos, &sContext.s);

    if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse;
  }
  
  break;
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */

#ifndef SQLITE_OMIT_VIRTUALTABLE
/* Opcode: VNext P1 P2 *
**
** Advance virtual table P1 to the next row in its result set and
** jump to instruction P2.  Or, if the virtual table has reached
** the end of its result set, then fall through to the next instruction.
*/
case OP_VNext: {
  const sqlite3_module *pModule;
  int res = 0;

  Cursor *pCur = p->apCsr[pOp->p1];
  assert( pCur->pVtabCursor );
  pModule = pCur->pVtabCursor->pVtab->pModule;
  if( pModule->xNext==0 ){
    sqlite3SetString(&p->zErrMsg, "Unsupported module operation: xNext", 0);
    rc = SQLITE_ERROR;
  } else {
    /* Invoke the xNext() method of the module. There is no way for the
    ** underlying implementation to return an error if one occurs during
    ** xNext(). Instead, if an error occurs, true is returned (indicating that 
    ** data is available) and the error code returned when xColumn or
    ** some other method is next invoked on the save virtual table cursor.
    */
    if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
    res = pModule->xNext(pCur->pVtabCursor);
    if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse;

    if( res ){
      /* If there is data (or an error), jump to P2 */
      pc = pOp->p2 - 1;
    }
  }

  break;
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */

/* An other opcode is illegal...
*/
default: {
Changes to src/vdbeaux.c.
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
  if( pCx->pBt ){
    sqlite3BtreeClose(pCx->pBt);
  }
#ifndef SQLITE_OMIT_VIRTUALTABLE
  if( pCx->pVtabCursor ){
    sqlite3_vtab_cursor *pVtabCursor = pCx->pVtabCursor;
    sqlite3_vtab *pVtab = pVtabCursor->pVtab;
    sqlite3_module *pModule = pVtab->pModule;
    pModule->xClose(pVtabCursor);
  }
#endif
  sqliteFree(pCx->pData);
  sqliteFree(pCx->aType);
  sqliteFree(pCx);
}







|







835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
  if( pCx->pBt ){
    sqlite3BtreeClose(pCx->pBt);
  }
#ifndef SQLITE_OMIT_VIRTUALTABLE
  if( pCx->pVtabCursor ){
    sqlite3_vtab_cursor *pVtabCursor = pCx->pVtabCursor;
    sqlite3_vtab *pVtab = pVtabCursor->pVtab;
    const sqlite3_module *pModule = pVtab->pModule;
    pModule->xClose(pVtabCursor);
  }
#endif
  sqliteFree(pCx->pData);
  sqliteFree(pCx->aType);
  sqliteFree(pCx);
}
Changes to src/vtab.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/*
** 2006 June 10
**
** The author disclaims copyright to this source code.  In place of
** a legal notice, here is a blessing:
**
**    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.5 2006/06/12 16:01:22 danielk1977 Exp $
*/
#ifndef SQLITE_OMIT_VIRTUALTABLE
#include "sqliteInt.h"

/*
** External API function used to create a new virtual-table module.
*/













|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/*
** 2006 June 10
**
** The author disclaims copyright to this source code.  In place of
** a legal notice, here is a blessing:
**
**    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.6 2006/06/13 10:24:43 danielk1977 Exp $
*/
#ifndef SQLITE_OMIT_VIRTUALTABLE
#include "sqliteInt.h"

/*
** External API function used to create a new virtual-table module.
*/
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
      *pzErr = sqlite3MPrintf("module create failed: %s", zModule);
      sqlite3SafetyOn(db);
    } else {
      rc = sqlite3SafetyOn(db);
    }
  }

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

/*
** This function is invoked by the vdbe to call the xDestroy method
** of the virtual table named zTab in database iDb. This occurs
** when a DROP TABLE is mentioned.







<
<
<







363
364
365
366
367
368
369



370
371
372
373
374
375
376
      *pzErr = sqlite3MPrintf("module create failed: %s", zModule);
      sqlite3SafetyOn(db);
    } else {
      rc = sqlite3SafetyOn(db);
    }
  }




  return rc;
}

/*
** This function is invoked by the vdbe to call the xDestroy method
** of the virtual table named zTab in database iDb. This occurs
** when a DROP TABLE is mentioned.
Changes to test/vtab1.test.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 2006 June 10
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    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 implements regression tests for SQLite library.  The
# focus of this file is creating and dropping virtual tables.
#
# $Id: vtab1.test,v 1.7 2006/06/13 04:11:44 danielk1977 Exp $

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

ifcapable !vtab {
  finish_test
  return













|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 2006 June 10
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    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 implements regression tests for SQLite library.  The
# focus of this file is creating and dropping virtual tables.
#
# $Id: vtab1.test,v 1.8 2006/06/13 10:24:44 danielk1977 Exp $

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

ifcapable !vtab {
  finish_test
  return
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
  set echo_module [list]
  execsql { 
    DROP TABLE t2;
  }
  set echo_module
} [list xDestroy]

finish_test

do_test vtab1-2.6 {
  execsql { 
    PRAGMA table_info(t2); 
  }
} {}
do_test vtab1-2.7 {
  execsql {







<
<







106
107
108
109
110
111
112


113
114
115
116
117
118
119
  set echo_module [list]
  execsql { 
    DROP TABLE t2;
  }
  set echo_module
} [list xDestroy]



do_test vtab1-2.6 {
  execsql { 
    PRAGMA table_info(t2); 
  }
} {}
do_test vtab1-2.7 {
  execsql {
133
134
135
136
137
138
139
140





































141

  set echo_module
} [list]
do_test vtab1-2.9 {
  execsql {
    SELECT sql FROM sqlite_master;
  }
} [list]






































finish_test









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

>
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
  set echo_module
} [list]
do_test vtab1-2.9 {
  execsql {
    SELECT sql FROM sqlite_master;
  }
} [list]

#----------------------------------------------------------------------
# Test case vtab1-3 tests simple linear scans (no filter conditions) of 
# virtual table modules.
do_test vtab1-3.1 {
  set echo_module ""
  execsql {
    CREATE TABLE treal(a INTEGER, b VARCHAR(32), c); 
    CREATE VIRTUAL TABLE t1 USING echo(treal);
  }
  set echo_module
} [list xCreate echo treal]
do_test vtab1-3.2 {
  # Test that a SELECT on t2 doesn't crash. No rows are returned
  # because the underlying real table, is currently empty.
  execsql {
    SELECT a, b, c FROM t1;
  }
} {}
do_test vtab1-3.3 {
  # Put some data into the table treal. Then try a select on t1.
  execsql {
    INSERT INTO treal VALUES(1, 2, 3);
    INSERT INTO treal VALUES(4, 5, 6);
    SELECT * FROM t1;
  }
} {1 2 3 4 5 6}
do_test vtab1-3.4 {
  execsql {
    SELECT a FROM t1;
  }
} {1 4}
do_test vtab1-3.5 {
  execsql {
    SELECT rowid FROM t1;
  }
} {1 2}

finish_test