mirror of
https://github.com/sqlite/sqlite.git
synced 2025-11-11 01:42:22 +03:00
Allow CREATE TABLE and CREATE INDEX on attached databases. (CVS 1483)
FossilOrigin-Name: 4984a130ccf3b8e486941a5d0d0cc70a691f0dac
This commit is contained in:
226
src/build.c
226
src/build.c
@@ -23,7 +23,7 @@
|
||||
** ROLLBACK
|
||||
** PRAGMA
|
||||
**
|
||||
** $Id: build.c,v 1.193 2004/05/22 08:09:11 danielk1977 Exp $
|
||||
** $Id: build.c,v 1.194 2004/05/28 11:37:27 danielk1977 Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <ctype.h>
|
||||
@@ -399,17 +399,58 @@ char *sqlite3TableNameFromToken(Token *pName){
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate code to open the appropriate master table. The table
|
||||
** opened will be SQLITE_MASTER for persistent tables and
|
||||
** SQLITE_TEMP_MASTER for temporary tables. The table is opened
|
||||
** on cursor 0.
|
||||
** Open the sqlite_master table stored in database number iDb for
|
||||
** writing. The table is opened using cursor 0.
|
||||
*/
|
||||
void sqlite3OpenMasterTable(Vdbe *v, int isTemp){
|
||||
sqlite3VdbeAddOp(v, OP_Integer, isTemp, 0);
|
||||
void sqlite3OpenMasterTable(Vdbe *v, int iDb){
|
||||
sqlite3VdbeAddOp(v, OP_Integer, iDb, 0);
|
||||
sqlite3VdbeAddOp(v, OP_OpenWrite, 0, MASTER_ROOT);
|
||||
sqlite3VdbeAddOp(v, OP_SetNumColumns, 0, 5); /* sqlite_master has 5 columns */
|
||||
}
|
||||
|
||||
/*
|
||||
** The token *pName contains the name of a database (either "main" or
|
||||
** "temp" or the name of an attached db). This routine returns the
|
||||
** index of the named database in db->aDb[], or -1 if the named db
|
||||
** does not exist.
|
||||
*/
|
||||
int findDb(sqlite3 *db, Token *pName){
|
||||
int i;
|
||||
for(i=0; i<db->nDb; i++){
|
||||
if( pName->n==strlen(db->aDb[i].zName) &&
|
||||
0==sqlite3StrNICmp(db->aDb[i].zName, pName->z, pName->n) ){
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int resolveSchemaName(
|
||||
Parse *pParse,
|
||||
Token *pName1,
|
||||
Token *pName2,
|
||||
Token **pUnqual
|
||||
){
|
||||
int iDb;
|
||||
sqlite3 *db = pParse->db;
|
||||
|
||||
if( pName2 && pName2->n>0 ){
|
||||
assert( !db->init.busy );
|
||||
*pUnqual = pName2;
|
||||
iDb = findDb(db, pName1);
|
||||
if( iDb<0 ){
|
||||
sqlite3ErrorMsg(pParse, "unknown database %T", pName1);
|
||||
pParse->nErr++;
|
||||
return -1;
|
||||
}
|
||||
}else{
|
||||
assert( db->init.iDb==0 || db->init.busy );
|
||||
iDb = db->init.iDb;
|
||||
*pUnqual = pName1;
|
||||
}
|
||||
return iDb;
|
||||
}
|
||||
|
||||
/*
|
||||
** Begin constructing a new table representation in memory. This is
|
||||
** the first of several action routines that get called in response
|
||||
@@ -430,7 +471,8 @@ void sqlite3OpenMasterTable(Vdbe *v, int isTemp){
|
||||
void sqlite3StartTable(
|
||||
Parse *pParse, /* Parser context */
|
||||
Token *pStart, /* The "CREATE" token */
|
||||
Token *pName, /* Name of table or view to create */
|
||||
Token *pName1, /* First part of the name of the table or view */
|
||||
Token *pName2, /* Second part of the name of the table or view */
|
||||
int isTemp, /* True if this is a TEMP table */
|
||||
int isView /* True if this is a VIEW */
|
||||
){
|
||||
@@ -439,9 +481,37 @@ void sqlite3StartTable(
|
||||
char *zName;
|
||||
sqlite *db = pParse->db;
|
||||
Vdbe *v;
|
||||
int iDb;
|
||||
int iDb; /* Database number to create the table in */
|
||||
Token *pName; /* Unqualified name of the table to create */
|
||||
|
||||
pParse->sFirstToken = *pStart;
|
||||
/* The table or view name to create is passed to this routine via tokens
|
||||
** pName1 and pName2. If the table name was fully qualified, for example:
|
||||
**
|
||||
** CREATE TABLE xxx.yyy (...);
|
||||
**
|
||||
** Then pName1 is set to "xxx" and pName2 "yyy". On the other hand if
|
||||
** the table name is not fully qualified, i.e.:
|
||||
**
|
||||
** CREATE TABLE yyy(...);
|
||||
**
|
||||
** Then pName1 is set to "yyy" and pName2 is "".
|
||||
**
|
||||
** The call below sets the pName pointer to point at the token (pName1 or
|
||||
** pName2) that stores the unqualified table name. The variable iDb is
|
||||
** set to the index of the database that the table or view is to be
|
||||
** created in.
|
||||
*/
|
||||
iDb = resolveSchemaName(pParse, pName1, pName2, &pName);
|
||||
if( iDb<0 ) return;
|
||||
if( isTemp && iDb>1 ){
|
||||
/* If creating a temp table, the name may not be qualified */
|
||||
sqlite3ErrorMsg(pParse, "temporary table name must be unqualified");
|
||||
pParse->nErr++;
|
||||
return;
|
||||
}
|
||||
if( isTemp ) iDb = 1;
|
||||
|
||||
pParse->sNameToken = *pName;
|
||||
zName = sqlite3TableNameFromToken(pName);
|
||||
if( zName==0 ) return;
|
||||
if( db->init.iDb==1 ) isTemp = 1;
|
||||
@@ -449,7 +519,7 @@ void sqlite3StartTable(
|
||||
assert( (isTemp & 1)==isTemp );
|
||||
{
|
||||
int code;
|
||||
char *zDb = isTemp ? "temp" : "main";
|
||||
char *zDb = db->aDb[iDb].zName;
|
||||
if( sqlite3AuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(isTemp), 0, zDb) ){
|
||||
sqliteFree(zName);
|
||||
return;
|
||||
@@ -473,7 +543,6 @@ void sqlite3StartTable(
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* Before trying to create a temporary table, make sure the Btree for
|
||||
** holding temporary tables is open.
|
||||
@@ -504,7 +573,6 @@ void sqlite3StartTable(
|
||||
** an existing temporary table, that is not an error.
|
||||
*/
|
||||
pTable = sqlite3FindTable(db, zName, 0);
|
||||
iDb = isTemp ? 1 : db->init.iDb;
|
||||
if( pTable!=0 && (pTable->iDb==iDb || !db->init.busy) ){
|
||||
sqlite3ErrorMsg(pParse, "table %T already exists", pName);
|
||||
sqliteFree(zName);
|
||||
@@ -539,14 +607,18 @@ void sqlite3StartTable(
|
||||
** now.
|
||||
*/
|
||||
if( !db->init.busy && (v = sqlite3GetVdbe(pParse))!=0 ){
|
||||
sqlite3BeginWriteOperation(pParse, 0, isTemp);
|
||||
sqlite3BeginWriteOperation(pParse, 0, iDb);
|
||||
if( !isTemp ){
|
||||
/* Every time a new table is created the file-format
|
||||
** and encoding meta-values are set in the database, in
|
||||
** case this is the first table created.
|
||||
*/
|
||||
sqlite3VdbeAddOp(v, OP_Integer, db->file_format, 0);
|
||||
sqlite3VdbeAddOp(v, OP_SetCookie, 0, 1);
|
||||
sqlite3VdbeAddOp(v, OP_SetCookie, iDb, 1);
|
||||
sqlite3VdbeAddOp(v, OP_Integer, db->enc, 0);
|
||||
sqlite3VdbeAddOp(v, OP_SetCookie, 0, 4);
|
||||
sqlite3VdbeAddOp(v, OP_SetCookie, iDb, 4);
|
||||
}
|
||||
sqlite3OpenMasterTable(v, isTemp);
|
||||
sqlite3OpenMasterTable(v, iDb);
|
||||
sqlite3VdbeAddOp(v, OP_NewRecno, 0, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
|
||||
sqlite3VdbeAddOp(v, OP_String, 0, 0);
|
||||
@@ -721,7 +793,7 @@ void sqlite3AddPrimaryKey(Parse *pParse, IdList *pList, int onError){
|
||||
pTab->iPKey = iCol;
|
||||
pTab->keyConf = onError;
|
||||
}else{
|
||||
sqlite3CreateIndex(pParse, 0, 0, pList, onError, 0, 0);
|
||||
sqlite3CreateIndex(pParse, 0, 0, 0, pList, onError, 0, 0);
|
||||
pList = 0;
|
||||
}
|
||||
|
||||
@@ -850,14 +922,14 @@ char sqlite3AffinityType(const char *zType, int nType){
|
||||
** and the probability of hitting the same cookie value is only
|
||||
** 1 chance in 2^32. So we're safe enough.
|
||||
*/
|
||||
void sqlite3ChangeCookie(sqlite *db, Vdbe *v){
|
||||
void sqlite3ChangeCookie(sqlite *db, Vdbe *v, int iDb){
|
||||
if( db->next_cookie==db->aDb[0].schema_cookie ){
|
||||
unsigned char r;
|
||||
sqlite3Randomness(1, &r);
|
||||
db->next_cookie = db->aDb[0].schema_cookie + r + 1;
|
||||
db->flags |= SQLITE_InternChanges;
|
||||
sqlite3VdbeAddOp(v, OP_Integer, db->next_cookie, 0);
|
||||
sqlite3VdbeAddOp(v, OP_SetCookie, 0, 0);
|
||||
sqlite3VdbeAddOp(v, OP_SetCookie, iDb, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1015,21 +1087,28 @@ void sqlite3EndTable(Parse *pParse, Token *pEnd, Select *pSelect){
|
||||
sqlite3VdbeOp3(v, OP_String, 0, 0, p->zName, 0);
|
||||
sqlite3VdbeOp3(v, OP_String, 0, 0, p->zName, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Dup, 4, 0);
|
||||
sqlite3VdbeAddOp(v, OP_String, 0, 0);
|
||||
if( pSelect ){
|
||||
char *z = createTableStmt(p);
|
||||
n = z ? strlen(z) : 0;
|
||||
sqlite3VdbeAddOp(v, OP_String, 0, 0);
|
||||
sqlite3VdbeChangeP3(v, -1, z, n);
|
||||
sqliteFree(z);
|
||||
}else{
|
||||
if( p->pSelect ){
|
||||
sqlite3VdbeOp3(v, OP_String, 0, 0, "CREATE VIEW ", P3_STATIC);
|
||||
}else{
|
||||
sqlite3VdbeOp3(v, OP_String, 0, 0, "CREATE TABLE ", P3_STATIC);
|
||||
}
|
||||
assert( pEnd!=0 );
|
||||
n = Addr(pEnd->z) - Addr(pParse->sFirstToken.z) + 1;
|
||||
sqlite3VdbeChangeP3(v, -1, pParse->sFirstToken.z, n);
|
||||
n = Addr(pEnd->z) - Addr(pParse->sNameToken.z) + 1;
|
||||
sqlite3VdbeAddOp(v, OP_String, 0, 0);
|
||||
sqlite3VdbeChangeP3(v, -1, pParse->sNameToken.z, n);
|
||||
sqlite3VdbeAddOp(v, OP_Concat, 2, 0);
|
||||
}
|
||||
sqlite3VdbeOp3(v, OP_MakeRecord, 5, 0, "tttit", P3_STATIC);
|
||||
sqlite3VdbeAddOp(v, OP_PutIntKey, 0, 0);
|
||||
if( !p->iDb ){
|
||||
sqlite3ChangeCookie(db, v);
|
||||
sqlite3ChangeCookie(db, v, p->iDb);
|
||||
}
|
||||
sqlite3VdbeAddOp(v, OP_Close, 0, 0);
|
||||
if( pSelect ){
|
||||
@@ -1079,7 +1158,7 @@ void sqlite3CreateView(
|
||||
Token sEnd;
|
||||
DbFixer sFix;
|
||||
|
||||
sqlite3StartTable(pParse, pBegin, pName, isTemp, 1);
|
||||
sqlite3StartTable(pParse, pBegin, pName, 0, isTemp, 1);
|
||||
p = pParse->pNewTable;
|
||||
if( p==0 || pParse->nErr ){
|
||||
sqlite3SelectDelete(pSelect);
|
||||
@@ -1349,8 +1428,8 @@ void sqlite3DropTable(Parse *pParse, Token *pName, int isView){
|
||||
sqlite3VdbeChangeP3(v, base+1, pTable->zName, 0);
|
||||
}
|
||||
|
||||
if( pTable->iDb==0 ){
|
||||
sqlite3ChangeCookie(db, v);
|
||||
if( pTable->iDb!=1 ){ /* Temp database has no schema cookie */
|
||||
sqlite3ChangeCookie(db, v, pTable->iDb);
|
||||
}
|
||||
sqlite3VdbeAddOp(v, OP_Close, 0, 0);
|
||||
if( !isView ){
|
||||
@@ -1517,14 +1596,15 @@ void sqlite3DeferForeignKey(Parse *pParse, int isDeferred){
|
||||
*/
|
||||
void sqlite3CreateIndex(
|
||||
Parse *pParse, /* All information about this parse */
|
||||
Token *pName, /* Name of the index. May be NULL */
|
||||
SrcList *pTable, /* Name of the table to index. Use pParse->pNewTable if 0 */
|
||||
Token *pName1, /* First part of index name. May be NULL */
|
||||
Token *pName2, /* Second part of index name. May be NULL */
|
||||
Token *pTblName, /* Name of the table to index. Use pParse->pNewTable if 0 */
|
||||
IdList *pList, /* A list of columns to be indexed */
|
||||
int onError, /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */
|
||||
Token *pStart, /* The CREATE token that begins a CREATE TABLE statement */
|
||||
Token *pEnd /* The ")" that closes the CREATE INDEX statement */
|
||||
){
|
||||
Table *pTab; /* Table to be indexed */
|
||||
Table *pTab = 0; /* Table to be indexed */
|
||||
Index *pIndex; /* The index to be created */
|
||||
char *zName = 0;
|
||||
int i, j;
|
||||
@@ -1533,6 +1613,10 @@ void sqlite3CreateIndex(
|
||||
int isTemp; /* True for a temporary index */
|
||||
sqlite *db = pParse->db;
|
||||
|
||||
int iDb; /* Index of the database that is being written */
|
||||
Token *pName = 0; /* Unqualified name of the index to create */
|
||||
|
||||
/*
|
||||
if( pParse->nErr || sqlite3_malloc_failed ) goto exit_create_index;
|
||||
if( db->init.busy
|
||||
&& sqlite3FixInit(&sFix, pParse, db->init.iDb, "index", pName)
|
||||
@@ -1540,27 +1624,59 @@ void sqlite3CreateIndex(
|
||||
){
|
||||
goto exit_create_index;
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
** Find the table that is to be indexed. Return early if not found.
|
||||
*/
|
||||
if( pTable!=0 ){
|
||||
assert( pName!=0 );
|
||||
assert( pTable->nSrc==1 );
|
||||
pTab = sqlite3SrcListLookup(pParse, pTable);
|
||||
if( pTblName!=0 ){
|
||||
char *zTblName;
|
||||
|
||||
/* Use the two-part index name to determine the database
|
||||
** to search for the table. If no database name is specified,
|
||||
** iDb is set to 0. In this case search both the temp and main
|
||||
** databases for the named table.
|
||||
*/
|
||||
assert( pName1 && pName2 );
|
||||
iDb = resolveSchemaName(pParse, pName1, pName2, &pName);
|
||||
if( iDb<0 ) goto exit_create_index;
|
||||
|
||||
/* Now search for the table in the database iDb. If iDb is
|
||||
** zero, then search both the "main" and "temp" databases.
|
||||
*/
|
||||
zTblName = sqlite3TableNameFromToken(pTblName);
|
||||
if( !zTblName ){
|
||||
pParse->nErr++;
|
||||
pParse->rc = SQLITE_NOMEM;
|
||||
goto exit_create_index;
|
||||
}
|
||||
assert( pName1!=0 );
|
||||
if( iDb==0 ){
|
||||
pTab = sqlite3FindTable(db, zTblName, "temp");
|
||||
}
|
||||
if( !pTab ){
|
||||
pTab = sqlite3LocateTable(pParse, zTblName, db->aDb[iDb].zName);
|
||||
}
|
||||
sqliteFree( zTblName );
|
||||
if( !pTab ) goto exit_create_index;
|
||||
iDb = pTab->iDb;
|
||||
}else{
|
||||
assert( pName==0 );
|
||||
pTab = pParse->pNewTable;
|
||||
iDb = pTab->iDb;
|
||||
}
|
||||
|
||||
if( pTab==0 || pParse->nErr ) goto exit_create_index;
|
||||
if( pTab->readOnly ){
|
||||
sqlite3ErrorMsg(pParse, "table %s may not be indexed", pTab->zName);
|
||||
goto exit_create_index;
|
||||
}
|
||||
/*
|
||||
if( pTab->iDb>=2 && db->init.busy==0 ){
|
||||
sqlite3ErrorMsg(pParse, "table %s may not have indices added", pTab->zName);
|
||||
goto exit_create_index;
|
||||
}
|
||||
*/
|
||||
if( pTab->pSelect ){
|
||||
sqlite3ErrorMsg(pParse, "views may not be indexed");
|
||||
goto exit_create_index;
|
||||
@@ -1611,8 +1727,6 @@ void sqlite3CreateIndex(
|
||||
#ifndef SQLITE_OMIT_AUTHORIZATION
|
||||
{
|
||||
const char *zDb = db->aDb[pTab->iDb].zName;
|
||||
|
||||
assert( pTab->iDb==db->init.iDb || isTemp );
|
||||
if( sqlite3AuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(isTemp), 0, zDb) ){
|
||||
goto exit_create_index;
|
||||
}
|
||||
@@ -1648,7 +1762,7 @@ void sqlite3CreateIndex(
|
||||
pIndex->nColumn = pList->nId;
|
||||
pIndex->onError = onError;
|
||||
pIndex->autoIndex = pName==0;
|
||||
pIndex->iDb = isTemp ? 1 : db->init.iDb;
|
||||
pIndex->iDb = iDb;
|
||||
|
||||
/* Scan the names of the columns of the table to be indexed and
|
||||
** load the column indices into the Index structure. Report an error
|
||||
@@ -1706,7 +1820,7 @@ void sqlite3CreateIndex(
|
||||
** "sqlite_master" table on the disk. So do not write to the disk
|
||||
** again. Extract the table number from the db->init.newTnum field.
|
||||
*/
|
||||
if( db->init.busy && pTable!=0 ){
|
||||
if( db->init.busy && pTblName!=0 ){
|
||||
pIndex->tnum = db->init.newTnum;
|
||||
}
|
||||
|
||||
@@ -1720,7 +1834,7 @@ void sqlite3CreateIndex(
|
||||
** the latter case the index already exists on disk, which is why
|
||||
** we don't want to recreate it.
|
||||
**
|
||||
** If pTable==0 it means this index is generated as a primary key
|
||||
** If pTblName==0 it means this index is generated as a primary key
|
||||
** or UNIQUE constraint of a CREATE TABLE statement. Since the table
|
||||
** has just been created, it contains no data and the index initialization
|
||||
** step can be skipped.
|
||||
@@ -1730,36 +1844,38 @@ void sqlite3CreateIndex(
|
||||
Vdbe *v;
|
||||
int lbl1, lbl2;
|
||||
int i;
|
||||
int addr;
|
||||
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
if( v==0 ) goto exit_create_index;
|
||||
if( pTable!=0 ){
|
||||
sqlite3BeginWriteOperation(pParse, 0, isTemp);
|
||||
sqlite3OpenMasterTable(v, isTemp);
|
||||
if( pTblName!=0 ){
|
||||
sqlite3BeginWriteOperation(pParse, 0, iDb);
|
||||
sqlite3OpenMasterTable(v, iDb);
|
||||
}
|
||||
sqlite3VdbeAddOp(v, OP_NewRecno, 0, 0);
|
||||
sqlite3VdbeOp3(v, OP_String, 0, 0, "index", P3_STATIC);
|
||||
sqlite3VdbeOp3(v, OP_String, 0, 0, pIndex->zName, 0);
|
||||
sqlite3VdbeOp3(v, OP_String, 0, 0, pTab->zName, 0);
|
||||
sqlite3VdbeOp3(v, OP_CreateIndex, 0, isTemp,(char*)&pIndex->tnum,P3_POINTER);
|
||||
sqlite3VdbeOp3(v, OP_CreateIndex, 0, iDb,(char*)&pIndex->tnum,P3_POINTER);
|
||||
pIndex->tnum = 0;
|
||||
if( pTable ){
|
||||
if( pTblName ){
|
||||
sqlite3VdbeCode(v,
|
||||
OP_Dup, 0, 0,
|
||||
OP_Integer, isTemp, 0,
|
||||
OP_Integer, iDb, 0,
|
||||
0);
|
||||
sqlite3VdbeOp3(v, OP_OpenWrite, 1, 0,
|
||||
(char*)&pIndex->keyInfo, P3_KEYINFO);
|
||||
}
|
||||
addr = sqlite3VdbeAddOp(v, OP_String, 0, 0);
|
||||
sqlite3VdbeAddOp(v, OP_String, 0, 0);
|
||||
if( pStart && pEnd ){
|
||||
n = Addr(pEnd->z) - Addr(pStart->z) + 1;
|
||||
sqlite3VdbeChangeP3(v, addr, pStart->z, n);
|
||||
sqlite3VdbeChangeP3(v, -1, "CREATE INDEX ", n);
|
||||
sqlite3VdbeAddOp(v, OP_String, 0, 0);
|
||||
n = Addr(pEnd->z) - Addr(pName->z) + 1;
|
||||
sqlite3VdbeChangeP3(v, -1, pName->z, n);
|
||||
sqlite3VdbeAddOp(v, OP_Concat, 2, 0);
|
||||
}
|
||||
sqlite3VdbeOp3(v, OP_MakeRecord, 5, 0, "tttit", P3_STATIC);
|
||||
sqlite3VdbeAddOp(v, OP_PutIntKey, 0, 0);
|
||||
if( pTable ){
|
||||
if( pTblName ){
|
||||
sqlite3VdbeAddOp(v, OP_Integer, pTab->iDb, 0);
|
||||
sqlite3VdbeAddOp(v, OP_OpenRead, 2, pTab->tnum);
|
||||
/* VdbeComment((v, "%s", pTab->zName)); */
|
||||
@@ -1784,9 +1900,9 @@ void sqlite3CreateIndex(
|
||||
sqlite3VdbeAddOp(v, OP_Close, 2, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Close, 1, 0);
|
||||
}
|
||||
if( pTable!=0 ){
|
||||
if( pTblName!=0 ){
|
||||
if( !isTemp ){
|
||||
sqlite3ChangeCookie(db, v);
|
||||
sqlite3ChangeCookie(db, v, iDb);
|
||||
}
|
||||
sqlite3VdbeAddOp(v, OP_Close, 0, 0);
|
||||
sqlite3EndWriteOperation(pParse);
|
||||
@@ -1796,7 +1912,7 @@ void sqlite3CreateIndex(
|
||||
/* Clean up before exiting */
|
||||
exit_create_index:
|
||||
sqlite3IdListDelete(pList);
|
||||
sqlite3SrcListDelete(pTable);
|
||||
/* sqlite3SrcListDelete(pTable); */
|
||||
sqliteFree(zName);
|
||||
return;
|
||||
}
|
||||
@@ -1863,8 +1979,8 @@ void sqlite3DropIndex(Parse *pParse, SrcList *pName){
|
||||
sqlite3OpenMasterTable(v, pIndex->iDb);
|
||||
base = sqlite3VdbeAddOpList(v, ArraySize(dropIndex), dropIndex);
|
||||
sqlite3VdbeChangeP3(v, base+1, pIndex->zName, 0);
|
||||
if( pIndex->iDb==0 ){
|
||||
sqlite3ChangeCookie(db, v);
|
||||
if( pIndex->iDb!=1 ){
|
||||
sqlite3ChangeCookie(db, v, pIndex->iDb);
|
||||
}
|
||||
sqlite3VdbeAddOp(v, OP_Close, 0, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Destroy, pIndex->tnum, pIndex->iDb);
|
||||
|
||||
17
src/parse.y
17
src/parse.y
@@ -14,7 +14,7 @@
|
||||
** the parser. Lemon will also generate a header file containing
|
||||
** numeric codes for all of the tokens.
|
||||
**
|
||||
** @(#) $Id: parse.y,v 1.119 2004/05/27 17:22:55 drh Exp $
|
||||
** @(#) $Id: parse.y,v 1.120 2004/05/28 11:37:28 danielk1977 Exp $
|
||||
*/
|
||||
%token_prefix TK_
|
||||
%token_type {Token}
|
||||
@@ -87,8 +87,8 @@ cmd ::= ROLLBACK trans_opt. {sqlite3RollbackTransaction(pParse);}
|
||||
///////////////////// The CREATE TABLE statement ////////////////////////////
|
||||
//
|
||||
cmd ::= create_table create_table_args.
|
||||
create_table ::= CREATE(X) temp(T) TABLE nm(Y). {
|
||||
sqlite3StartTable(pParse,&X,&Y,T,0);
|
||||
create_table ::= CREATE(X) temp(T) TABLE nm(Y) dbnm(Z). {
|
||||
sqlite3StartTable(pParse,&X,&Y,&Z,T,0);
|
||||
}
|
||||
%type temp {int}
|
||||
temp(A) ::= TEMP. {A = 1;}
|
||||
@@ -188,7 +188,7 @@ carg ::= DEFAULT NULL.
|
||||
ccons ::= NULL onconf.
|
||||
ccons ::= NOT NULL onconf(R). {sqlite3AddNotNull(pParse, R);}
|
||||
ccons ::= PRIMARY KEY sortorder onconf(R). {sqlite3AddPrimaryKey(pParse,0,R);}
|
||||
ccons ::= UNIQUE onconf(R). {sqlite3CreateIndex(pParse,0,0,0,R,0,0);}
|
||||
ccons ::= UNIQUE onconf(R). {sqlite3CreateIndex(pParse,0,0,0,0,R,0,0);}
|
||||
ccons ::= CHECK LP expr RP onconf.
|
||||
ccons ::= REFERENCES nm(T) idxlist_opt(TA) refargs(R).
|
||||
{sqlite3CreateForeignKey(pParse,0,&T,TA,R);}
|
||||
@@ -233,7 +233,7 @@ tcons ::= CONSTRAINT nm.
|
||||
tcons ::= PRIMARY KEY LP idxlist(X) RP onconf(R).
|
||||
{sqlite3AddPrimaryKey(pParse,X,R);}
|
||||
tcons ::= UNIQUE LP idxlist(X) RP onconf(R).
|
||||
{sqlite3CreateIndex(pParse,0,0,X,R,0,0);}
|
||||
{sqlite3CreateIndex(pParse,0,0,0,X,R,0,0);}
|
||||
tcons ::= CHECK expr onconf.
|
||||
tcons ::= FOREIGN KEY LP idxlist(FA) RP
|
||||
REFERENCES nm(T) idxlist_opt(TA) refargs(R) defer_subclause_opt(D). {
|
||||
@@ -727,12 +727,11 @@ expritem(A) ::= . {A = 0;}
|
||||
|
||||
///////////////////////////// The CREATE INDEX command ///////////////////////
|
||||
//
|
||||
cmd ::= CREATE(S) uniqueflag(U) INDEX nm(X)
|
||||
ON nm(Y) dbnm(D) LP idxlist(Z) RP(E) onconf(R). {
|
||||
SrcList *pSrc = sqlite3SrcListAppend(0, &Y, &D);
|
||||
cmd ::= CREATE(S) uniqueflag(U) INDEX nm(X) dbnm(D)
|
||||
ON nm(Y) LP idxlist(Z) RP(E) onconf(R). {
|
||||
if( U!=OE_None ) U = R;
|
||||
if( U==OE_Default) U = OE_Abort;
|
||||
sqlite3CreateIndex(pParse, &X, pSrc, Z, U, &S, &E);
|
||||
sqlite3CreateIndex(pParse, &X, &D, &Y, Z, U, &S, &E);
|
||||
}
|
||||
|
||||
%type uniqueflag {int}
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
*************************************************************************
|
||||
** Internal interface definitions for SQLite.
|
||||
**
|
||||
** @(#) $Id: sqliteInt.h,v 1.256 2004/05/27 17:22:56 drh Exp $
|
||||
** @(#) $Id: sqliteInt.h,v 1.257 2004/05/28 11:37:28 danielk1977 Exp $
|
||||
*/
|
||||
#include "config.h"
|
||||
#include "sqlite.h"
|
||||
@@ -969,7 +969,7 @@ struct Parse {
|
||||
int rc; /* Return code from execution */
|
||||
char *zErrMsg; /* An error message */
|
||||
Token sErrToken; /* The token at which the error occurred */
|
||||
Token sFirstToken; /* The first token parsed */
|
||||
Token sNameToken; /* Token with unqualified schema object name */
|
||||
Token sLastToken; /* The last token parsed */
|
||||
const char *zTail; /* All SQL text past the last semicolon parsed */
|
||||
Table *pNewTable; /* A table being constructed by CREATE TABLE */
|
||||
@@ -1199,7 +1199,7 @@ void sqlite3RollbackInternalChanges(sqlite*);
|
||||
void sqlite3CommitInternalChanges(sqlite*);
|
||||
Table *sqlite3ResultSetOfSelect(Parse*,char*,Select*);
|
||||
void sqlite3OpenMasterTable(Vdbe *v, int);
|
||||
void sqlite3StartTable(Parse*,Token*,Token*,int,int);
|
||||
void sqlite3StartTable(Parse*,Token*,Token*,Token*,int,int);
|
||||
void sqlite3AddColumn(Parse*,Token*);
|
||||
void sqlite3AddNotNull(Parse*, int);
|
||||
void sqlite3AddPrimaryKey(Parse*, IdList*, int);
|
||||
@@ -1221,7 +1221,7 @@ void sqlite3SrcListAddAlias(SrcList*, Token*);
|
||||
void sqlite3SrcListAssignCursors(Parse*, SrcList*);
|
||||
void sqlite3IdListDelete(IdList*);
|
||||
void sqlite3SrcListDelete(SrcList*);
|
||||
void sqlite3CreateIndex(Parse*,Token*,SrcList*,IdList*,int,Token*,Token*);
|
||||
void sqlite3CreateIndex(Parse*,Token*,Token*,Token*,IdList*,int,Token*,Token*);
|
||||
void sqlite3DropIndex(Parse*, SrcList*);
|
||||
void sqlite3AddKeyType(Vdbe*, ExprList*);
|
||||
void sqlite3AddIdxKeyType(Vdbe*, Index*);
|
||||
@@ -1284,7 +1284,7 @@ void sqlite3RegisterDateTimeFunctions(sqlite*);
|
||||
int sqlite3SafetyOn(sqlite*);
|
||||
int sqlite3SafetyOff(sqlite*);
|
||||
int sqlite3SafetyCheck(sqlite*);
|
||||
void sqlite3ChangeCookie(sqlite*, Vdbe*);
|
||||
void sqlite3ChangeCookie(sqlite*, Vdbe*, int);
|
||||
void sqlite3BeginTrigger(Parse*, Token*,int,int,IdList*,SrcList*,int,Expr*,int);
|
||||
void sqlite3FinishTrigger(Parse*, TriggerStep*, Token*);
|
||||
void sqlite3DropTrigger(Parse*, SrcList*);
|
||||
@@ -1350,4 +1350,4 @@ int sqlite3atoi64(const char*, i64*);
|
||||
void sqlite3Error(sqlite *, int, const char*,...);
|
||||
int sqlite3utfTranslate(const void *, int , u8 , void **, int *, u8);
|
||||
u8 sqlite3UtfReadBom(const void *zData, int nData);
|
||||
char *sqlite3HexToBlob(const char *z);
|
||||
void *sqlite3HexToBlob(const char *z);
|
||||
|
||||
@@ -205,7 +205,7 @@ void sqlite3FinishTrigger(
|
||||
sqlite3VdbeChangeP3(v, addr+3, nt->table, 0);
|
||||
sqlite3VdbeChangeP3(v, addr+5, pAll->z, pAll->n);
|
||||
if( nt->iDb==0 ){
|
||||
sqlite3ChangeCookie(db, v);
|
||||
sqlite3ChangeCookie(db, v, 0);
|
||||
}
|
||||
sqlite3VdbeAddOp(v, OP_Close, 0, 0);
|
||||
sqlite3EndWriteOperation(pParse);
|
||||
@@ -467,7 +467,7 @@ void sqlite3DropTriggerPtr(Parse *pParse, Trigger *pTrigger, int nested){
|
||||
base = sqlite3VdbeAddOpList(v, ArraySize(dropTrigger), dropTrigger);
|
||||
sqlite3VdbeChangeP3(v, base+1, pTrigger->name, 0);
|
||||
if( pTrigger->iDb==0 ){
|
||||
sqlite3ChangeCookie(db, v);
|
||||
sqlite3ChangeCookie(db, v, 0);
|
||||
}
|
||||
sqlite3VdbeAddOp(v, OP_Close, 0, 0);
|
||||
sqlite3EndWriteOperation(pParse);
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
** This file contains functions for allocating memory, comparing
|
||||
** strings, and stuff like that.
|
||||
**
|
||||
** $Id: util.c,v 1.92 2004/05/27 13:35:20 danielk1977 Exp $
|
||||
** $Id: util.c,v 1.93 2004/05/28 11:37:28 danielk1977 Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <stdarg.h>
|
||||
@@ -1299,7 +1299,7 @@ int sqlite3VarintLen(u64 v){
|
||||
return i;
|
||||
}
|
||||
|
||||
char * sqlite3HexToBlob(const char *z){
|
||||
void *sqlite3HexToBlob(const char *z){
|
||||
char *zBlob;
|
||||
int i;
|
||||
int n = strlen(z);
|
||||
|
||||
31
src/vdbe.c
31
src/vdbe.c
@@ -43,7 +43,7 @@
|
||||
** 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.343 2004/05/28 08:21:09 drh Exp $
|
||||
** $Id: vdbe.c,v 1.344 2004/05/28 11:37:28 danielk1977 Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "os.h"
|
||||
@@ -693,20 +693,39 @@ case OP_Real: {
|
||||
Realify(pTos, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* Opcode: String8 * * P3
|
||||
**
|
||||
** This opcode does not exist at vdbe execution time.
|
||||
*/
|
||||
case OP_String8: {
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Opcode: String * * P3
|
||||
**
|
||||
** The string value P3 is pushed onto the stack. If P3==0 then a
|
||||
** NULL is pushed onto the stack.
|
||||
** NULL is pushed onto the stack. P3 is assumed to be a nul terminated
|
||||
** string encoded with the database native encoding.
|
||||
*/
|
||||
case OP_String: {
|
||||
pTos++;
|
||||
if( pOp->p3 ){
|
||||
pTos->flags = MEM_Str|MEM_Static|MEM_Term;
|
||||
pTos->enc = TEXT_Utf8;
|
||||
pTos->z = pOp->p3;
|
||||
pTos->n = strlen(pTos->z);
|
||||
pTos->enc = TEXT_Utf8;
|
||||
sqlite3VdbeChangeEncoding(pTos, db->enc);
|
||||
/*
|
||||
if( db->enc==TEXT_Utf8 ){
|
||||
pTos->n = strlen(pTos->z);
|
||||
}else{
|
||||
pTos->n = sqlite3utf16ByteLen(pTos->z, -1);
|
||||
}
|
||||
pTos->enc = db->enc;
|
||||
*/
|
||||
}else{
|
||||
pTos->flags = MEM_Null;
|
||||
}
|
||||
@@ -726,7 +745,11 @@ case OP_HexBlob: {
|
||||
/* Opcode: Blob P1 * P3
|
||||
**
|
||||
** P3 points to a blob of data P1 bytes long. Push this
|
||||
** value onto the stack.
|
||||
** value onto the stack. This instruction is not coded directly
|
||||
** by the compiler. Instead, the compiler layer specifies
|
||||
** an OP_HexBlob opcode, with the hex string representation of
|
||||
** the blob as P3. This opcode is transformed to an OP_Blob
|
||||
** before execution (within the sqlite3_prepare() function).
|
||||
*/
|
||||
case OP_Blob: {
|
||||
pTos++;
|
||||
|
||||
@@ -610,7 +610,8 @@ int sqlite3VdbeList(
|
||||
** If pOp is an OP_HexBlob opcode, then transform it to an OP_Blob
|
||||
** opcode.
|
||||
*/
|
||||
static int translateOp(Op *pOp){
|
||||
static int translateOp(Op *pOp, u8 enc){
|
||||
|
||||
if( pOp->opcode==OP_HexBlob ){
|
||||
pOp->p1 = strlen(pOp->p3)/2;
|
||||
if( pOp->p1 ){
|
||||
@@ -627,6 +628,28 @@ static int translateOp(Op *pOp){
|
||||
}
|
||||
pOp->opcode = OP_Blob;
|
||||
}
|
||||
|
||||
else if( pOp->opcode==OP_String8 ){
|
||||
if( pOp->p3 ){
|
||||
void *z = 0;
|
||||
switch( enc ){
|
||||
case TEXT_Utf16be:
|
||||
z = sqlite3utf8to16be(pOp->p3, -1);
|
||||
if( !z ) return SQLITE_NOMEM;
|
||||
break;
|
||||
case TEXT_Utf16le:
|
||||
z = sqlite3utf8to16be(pOp->p3, -1);
|
||||
if( !z ) return SQLITE_NOMEM;
|
||||
break;
|
||||
}
|
||||
if( z ){
|
||||
if( pOp->p3type==P3_DYNAMIC ) sqliteFree( pOp->p3 );
|
||||
|
||||
}
|
||||
}
|
||||
pOp->opcode = OP_String;
|
||||
}
|
||||
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
@@ -704,7 +727,7 @@ void sqlite3VdbeMakeReady(
|
||||
if( !isExplain ){
|
||||
int i;
|
||||
for(i=0; i<p->nOp; i++){
|
||||
translateOp(&p->aOp[i]);
|
||||
translateOp(&p->aOp[i], p->db->enc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user