SQLite

Check-in [230983e86a]
Login

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

Overview
Comment:Add support for IF NOT EXISTS on CREATE VIRTUAL TABLE.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 230983e86a897caa91a487ef2d4c1c7fb7c79f10
User & Date: drh 2012-01-28 19:41:53.964
Context
2012-01-28
19:44
Remove a couple of unnecessary nonterminals from the grammar. (check-in: 2b2a7d8d73 user: drh tags: trunk)
19:41
Add support for IF NOT EXISTS on CREATE VIRTUAL TABLE. (check-in: 230983e86a user: drh tags: trunk)
15:26
Update the version number to 3.7.11 and rerun autoconf. (check-in: 6f9b265dd0 user: drh tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/parse.y.
1386
1387
1388
1389
1390
1391
1392
1393

1394
1395
1396
1397
1398
1399
1400
1401
kwcolumn_opt ::= COLUMNKW.
%endif  SQLITE_OMIT_ALTERTABLE

//////////////////////// CREATE VIRTUAL TABLE ... /////////////////////////////
%ifndef SQLITE_OMIT_VIRTUALTABLE
cmd ::= create_vtab.                       {sqlite3VtabFinishParse(pParse,0);}
cmd ::= create_vtab LP vtabarglist RP(X).  {sqlite3VtabFinishParse(pParse,&X);}
create_vtab ::= createkw VIRTUAL TABLE nm(X) dbnm(Y) USING nm(Z). {

    sqlite3VtabBeginParse(pParse, &X, &Y, &Z);
}
vtabarglist ::= vtabarg.
vtabarglist ::= vtabarglist COMMA vtabarg.
vtabarg ::= .                       {sqlite3VtabArgInit(pParse);}
vtabarg ::= vtabarg vtabargtoken.
vtabargtoken ::= ANY(X).            {sqlite3VtabArgExtend(pParse,&X);}
vtabargtoken ::= lp anylist RP(X).  {sqlite3VtabArgExtend(pParse,&X);}







|
>
|







1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
kwcolumn_opt ::= COLUMNKW.
%endif  SQLITE_OMIT_ALTERTABLE

//////////////////////// CREATE VIRTUAL TABLE ... /////////////////////////////
%ifndef SQLITE_OMIT_VIRTUALTABLE
cmd ::= create_vtab.                       {sqlite3VtabFinishParse(pParse,0);}
cmd ::= create_vtab LP vtabarglist RP(X).  {sqlite3VtabFinishParse(pParse,&X);}
create_vtab ::= createkw VIRTUAL TABLE ifnotexists(E)
                nm(X) dbnm(Y) USING nm(Z). {
    sqlite3VtabBeginParse(pParse, &X, &Y, &Z, E);
}
vtabarglist ::= vtabarg.
vtabarglist ::= vtabarglist COMMA vtabarg.
vtabarg ::= .                       {sqlite3VtabArgInit(pParse);}
vtabarg ::= vtabarg vtabargtoken.
vtabargtoken ::= ANY(X).            {sqlite3VtabArgExtend(pParse,&X);}
vtabargtoken ::= lp anylist RP(X).  {sqlite3VtabArgExtend(pParse,&X);}
Changes to src/sqliteInt.h.
3123
3124
3125
3126
3127
3128
3129
3130
3131
3132
3133
3134
3135
3136
3137
   void sqlite3VtabUnlock(VTable *);
   void sqlite3VtabUnlockList(sqlite3*);
   int sqlite3VtabSavepoint(sqlite3 *, int, int);
   VTable *sqlite3GetVTable(sqlite3*, Table*);
#  define sqlite3VtabInSync(db) ((db)->nVTrans>0 && (db)->aVTrans==0)
#endif
void sqlite3VtabMakeWritable(Parse*,Table*);
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*);
int sqlite3VtabCallDestroy(sqlite3*, int, const char *);
int sqlite3VtabBegin(sqlite3 *, VTable *);







|







3123
3124
3125
3126
3127
3128
3129
3130
3131
3132
3133
3134
3135
3136
3137
   void sqlite3VtabUnlock(VTable *);
   void sqlite3VtabUnlockList(sqlite3*);
   int sqlite3VtabSavepoint(sqlite3 *, int, int);
   VTable *sqlite3GetVTable(sqlite3*, Table*);
#  define sqlite3VtabInSync(db) ((db)->nVTrans>0 && (db)->aVTrans==0)
#endif
void sqlite3VtabMakeWritable(Parse*,Table*);
void sqlite3VtabBeginParse(Parse*, Token*, Token*, Token*, int);
void sqlite3VtabFinishParse(Parse*, Token*);
void sqlite3VtabArgInit(Parse*);
void sqlite3VtabArgExtend(Parse*, Token*);
int sqlite3VtabCallCreate(sqlite3*, int, const char *, char **);
int sqlite3VtabCallConnect(Parse*, Table*);
int sqlite3VtabCallDestroy(sqlite3*, int, const char *);
int sqlite3VtabBegin(sqlite3 *, VTable *);
Changes to src/vtab.c.
274
275
276
277
278
279
280
281

282
283
284
285
286
287
288
289
290
291
292
293
294
** statement.  The module name has been parsed, but the optional list
** of parameters that follow the module name are still pending.
*/
void sqlite3VtabBeginParse(
  Parse *pParse,        /* Parsing context */
  Token *pName1,        /* Name of new table, or database name */
  Token *pName2,        /* Name of new table or NULL */
  Token *pModuleName    /* Name of the module for the virtual table */

){
  int iDb;              /* The database the table is being created in */
  Table *pTable;        /* The new virtual table */
  sqlite3 *db;          /* Database connection */

  sqlite3StartTable(pParse, pName1, pName2, 0, 0, 1, 0);
  pTable = pParse->pNewTable;
  if( pTable==0 ) return;
  assert( 0==pTable->pIndex );

  db = pParse->db;
  iDb = sqlite3SchemaToIndex(db, pTable->pSchema);
  assert( iDb>=0 );







|
>





|







274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
** statement.  The module name has been parsed, but the optional list
** of parameters that follow the module name are still pending.
*/
void sqlite3VtabBeginParse(
  Parse *pParse,        /* Parsing context */
  Token *pName1,        /* Name of new table, or database name */
  Token *pName2,        /* Name of new table or NULL */
  Token *pModuleName,   /* Name of the module for the virtual table */
  int ifNotExists       /* No error if the table already exists */
){
  int iDb;              /* The database the table is being created in */
  Table *pTable;        /* The new virtual table */
  sqlite3 *db;          /* Database connection */

  sqlite3StartTable(pParse, pName1, pName2, 0, 0, 1, ifNotExists);
  pTable = pParse->pNewTable;
  if( pTable==0 ) return;
  assert( 0==pTable->pIndex );

  db = pParse->db;
  iDb = sqlite3SchemaToIndex(db, pTable->pSchema);
  assert( iDb>=0 );
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329

/*
** This routine takes the module argument that has been accumulating
** in pParse->zArg[] and appends it to the list of arguments on the
** virtual table currently under construction in pParse->pTable.
*/
static void addArgumentToVtab(Parse *pParse){
  if( pParse->sArg.z && ALWAYS(pParse->pNewTable) ){
    const char *z = (const char*)pParse->sArg.z;
    int n = pParse->sArg.n;
    sqlite3 *db = pParse->db;
    addModuleArgument(db, pParse->pNewTable, sqlite3DbStrNDup(db, z, n));
  }
}








|







316
317
318
319
320
321
322
323
324
325
326
327
328
329
330

/*
** This routine takes the module argument that has been accumulating
** in pParse->zArg[] and appends it to the list of arguments on the
** virtual table currently under construction in pParse->pTable.
*/
static void addArgumentToVtab(Parse *pParse){
  if( pParse->sArg.z && pParse->pNewTable ){
    const char *z = (const char*)pParse->sArg.z;
    int n = pParse->sArg.n;
    sqlite3 *db = pParse->db;
    addModuleArgument(db, pParse->pNewTable, sqlite3DbStrNDup(db, z, n));
  }
}

Changes to test/vtab1.test.
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

#----------------------------------------------------------------------
# Test cases vtab1.1.*
#

# We cannot create a virtual table if the module has not been registered.
#
do_test vtab1-1.1 {
  explain {
    CREATE VIRTUAL TABLE t1 USING echo;
  }
  catchsql {
    CREATE VIRTUAL TABLE t1 USING echo;
  }





} {1 {no such module: echo}}
do_test vtab1-1.2 {
  execsql {
    SELECT name FROM sqlite_master ORDER BY 1
  }
} {}

# Register the module
register_echo_module [sqlite3_connection_pointer db]

# Once a module has been registered, virtual tables using that module
# may be created. However if a module xCreate() fails to call
# sqlite3_declare_vtab() an error will be raised and the table not created.
#
# The "echo" module does not invoke sqlite3_declare_vtab() if it is
# passed zero arguments.
#
do_test vtab1-1.3 {
  catchsql {
    CREATE VIRTUAL TABLE t1 USING echo;





  }
} {1 {vtable constructor did not declare schema: t1}}
do_test vtab1-1.4 {
  execsql {
    SELECT name FROM sqlite_master ORDER BY 1
  }
} {}

# The "echo" module xCreate method returns an error and does not create
# the virtual table if it is passed an argument that does not correspond
# to an existing real table in the same database.
#
do_test vtab1-1.5 {
  catchsql {
    CREATE VIRTUAL TABLE t1 USING echo(no_such_table);
  }





} {1 {vtable constructor failed: t1}}
do_test vtab1-1.6 {
  execsql {
    SELECT name FROM sqlite_master ORDER BY 1
  }
} {}








|






>
>
>
>
>

















|


>
>
>
>
>












|



>
>
>
>
>







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

#----------------------------------------------------------------------
# Test cases vtab1.1.*
#

# We cannot create a virtual table if the module has not been registered.
#
do_test vtab1-1.1.1 {
  explain {
    CREATE VIRTUAL TABLE t1 USING echo;
  }
  catchsql {
    CREATE VIRTUAL TABLE t1 USING echo;
  }
} {1 {no such module: echo}}
do_test vtab1-1.1.2 {
  catchsql {
    CREATE VIRTUAL TABLE IF NOT EXISTS t1 USING echo;
  }
} {1 {no such module: echo}}
do_test vtab1-1.2 {
  execsql {
    SELECT name FROM sqlite_master ORDER BY 1
  }
} {}

# Register the module
register_echo_module [sqlite3_connection_pointer db]

# Once a module has been registered, virtual tables using that module
# may be created. However if a module xCreate() fails to call
# sqlite3_declare_vtab() an error will be raised and the table not created.
#
# The "echo" module does not invoke sqlite3_declare_vtab() if it is
# passed zero arguments.
#
do_test vtab1-1.3.1 {
  catchsql {
    CREATE VIRTUAL TABLE t1 USING echo;
  }
} {1 {vtable constructor did not declare schema: t1}}
do_test vtab1-1.3.2 {
  catchsql {
    CREATE VIRTUAL TABLE IF NOT EXISTS t1 USING echo;
  }
} {1 {vtable constructor did not declare schema: t1}}
do_test vtab1-1.4 {
  execsql {
    SELECT name FROM sqlite_master ORDER BY 1
  }
} {}

# The "echo" module xCreate method returns an error and does not create
# the virtual table if it is passed an argument that does not correspond
# to an existing real table in the same database.
#
do_test vtab1-1.5.1 {
  catchsql {
    CREATE VIRTUAL TABLE t1 USING echo(no_such_table);
  }
} {1 {vtable constructor failed: t1}}
do_test vtab1-1.5.2 {
  catchsql {
    CREATE VIRTUAL TABLE IF NOT EXISTS t1 USING echo(no_such_table);
  }
} {1 {vtable constructor failed: t1}}
do_test vtab1-1.6 {
  execsql {
    SELECT name FROM sqlite_master ORDER BY 1
  }
} {}

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
  db eval {DROP TABLE t2152a; DROP TABLE t2152b}
} {}

# Test to make sure nothing goes wrong and no memory is leaked if we 
# select an illegal table-name (i.e a reserved name or the name of a
# table that already exists).
#
do_test vtab1-1.7 {
  catchsql {
    CREATE VIRTUAL TABLE sqlite_master USING echo;
  }
} {1 {object name reserved for internal use: sqlite_master}}
do_test vtab1-1.8 {





  catchsql {
    CREATE TABLE treal(a, b, c);
    CREATE VIRTUAL TABLE treal USING echo(treal);
  }
} {1 {table treal already exists}}





do_test vtab1-1.9 {
  execsql {
    DROP TABLE treal;
    SELECT name FROM sqlite_master ORDER BY 1
  }
} {}








|




|
>
>
>
>
>





>
>
>
>
>







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
  db eval {DROP TABLE t2152a; DROP TABLE t2152b}
} {}

# Test to make sure nothing goes wrong and no memory is leaked if we 
# select an illegal table-name (i.e a reserved name or the name of a
# table that already exists).
#
do_test vtab1-1.7.1 {
  catchsql {
    CREATE VIRTUAL TABLE sqlite_master USING echo;
  }
} {1 {object name reserved for internal use: sqlite_master}}
do_test vtab1-1.7.2 {
  catchsql {
    CREATE VIRTUAL TABLE IF NOT EXISTS sqlite_master USING echo;
  }
} {1 {object name reserved for internal use: sqlite_master}}
do_test vtab1-1.8.1 {
  catchsql {
    CREATE TABLE treal(a, b, c);
    CREATE VIRTUAL TABLE treal USING echo(treal);
  }
} {1 {table treal already exists}}
do_test vtab1-1.8.2 {
  catchsql {
    CREATE VIRTUAL TABLE IF NOT EXISTS treal USING echo(treal);
  }
} {0 {}}
do_test vtab1-1.9 {
  execsql {
    DROP TABLE treal;
    SELECT name FROM sqlite_master ORDER BY 1
  }
} {}