summaryrefslogtreecommitdiff
path: root/ext/pdo_sqlite/sqlite/src/build.c
diff options
context:
space:
mode:
Diffstat (limited to 'ext/pdo_sqlite/sqlite/src/build.c')
-rw-r--r--ext/pdo_sqlite/sqlite/src/build.c868
1 files changed, 608 insertions, 260 deletions
diff --git a/ext/pdo_sqlite/sqlite/src/build.c b/ext/pdo_sqlite/sqlite/src/build.c
index 537eede8c..5294c1a31 100644
--- a/ext/pdo_sqlite/sqlite/src/build.c
+++ b/ext/pdo_sqlite/sqlite/src/build.c
@@ -36,6 +36,88 @@ void sqlite3BeginParse(Parse *pParse, int explainFlag){
pParse->nVar = 0;
}
+#ifndef SQLITE_OMIT_SHARED_CACHE
+/*
+** The TableLock structure is only used by the sqlite3TableLock() and
+** codeTableLocks() functions.
+*/
+struct TableLock {
+ int iDb; /* The database containing the table to be locked */
+ int iTab; /* The root page of the table to be locked */
+ u8 isWriteLock; /* True for write lock. False for a read lock */
+ const char *zName; /* Name of the table */
+};
+
+/*
+** Record the fact that we want to lock a table at run-time.
+**
+** The table to be locked has root page iTab and is found in database iDb.
+** A read or a write lock can be taken depending on isWritelock.
+**
+** This routine just records the fact that the lock is desired. The
+** code to make the lock occur is generated by a later call to
+** codeTableLocks() which occurs during sqlite3FinishCoding().
+*/
+void sqlite3TableLock(
+ Parse *pParse, /* Parsing context */
+ int iDb, /* Index of the database containing the table to lock */
+ int iTab, /* Root page number of the table to be locked */
+ u8 isWriteLock, /* True for a write lock */
+ const char *zName /* Name of the table to be locked */
+){
+ int i;
+ int nBytes;
+ TableLock *p;
+
+ if( 0==sqlite3ThreadDataReadOnly()->useSharedData || iDb<0 ){
+ return;
+ }
+
+ for(i=0; i<pParse->nTableLock; i++){
+ p = &pParse->aTableLock[i];
+ if( p->iDb==iDb && p->iTab==iTab ){
+ p->isWriteLock = (p->isWriteLock || isWriteLock);
+ return;
+ }
+ }
+
+ nBytes = sizeof(TableLock) * (pParse->nTableLock+1);
+ sqliteReallocOrFree((void **)&pParse->aTableLock, nBytes);
+ if( pParse->aTableLock ){
+ p = &pParse->aTableLock[pParse->nTableLock++];
+ p->iDb = iDb;
+ p->iTab = iTab;
+ p->isWriteLock = isWriteLock;
+ p->zName = zName;
+ }
+}
+
+/*
+** Code an OP_TableLock instruction for each table locked by the
+** statement (configured by calls to sqlite3TableLock()).
+*/
+static void codeTableLocks(Parse *pParse){
+ int i;
+ Vdbe *pVdbe;
+ assert( sqlite3ThreadDataReadOnly()->useSharedData || pParse->nTableLock==0 );
+
+ if( 0==(pVdbe = sqlite3GetVdbe(pParse)) ){
+ return;
+ }
+
+ for(i=0; i<pParse->nTableLock; i++){
+ TableLock *p = &pParse->aTableLock[i];
+ int p1 = p->iDb;
+ if( p->isWriteLock ){
+ p1 = -1*(p1+1);
+ }
+ sqlite3VdbeOp3(pVdbe, OP_TableLock, p1, p->iTab, p->zName, P3_STATIC);
+ }
+}
+#else
+ #define codeTableLocks(x)
+#endif
+
/*
** This routine is called after a single SQL statement has been
** parsed and a VDBE program to execute that statement has been
@@ -50,13 +132,13 @@ void sqlite3FinishCoding(Parse *pParse){
sqlite3 *db;
Vdbe *v;
- if( sqlite3_malloc_failed ) return;
+ if( sqlite3MallocFailed() ) return;
if( pParse->nested ) return;
if( !pParse->pVdbe ){
if( pParse->rc==SQLITE_OK && pParse->nErr ){
pParse->rc = SQLITE_ERROR;
+ return;
}
- return;
}
/* Begin by generating some termination code at the end of the
@@ -82,6 +164,18 @@ void sqlite3FinishCoding(Parse *pParse){
sqlite3VdbeAddOp(v, OP_Transaction, iDb, (mask & pParse->writeMask)!=0);
sqlite3VdbeAddOp(v, OP_VerifyCookie, iDb, pParse->cookieValue[iDb]);
}
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ if( pParse->pVirtualLock ){
+ char *vtab = (char *)pParse->pVirtualLock->pVtab;
+ sqlite3VdbeOp3(v, OP_VBegin, 0, 0, vtab, P3_VTAB);
+ }
+#endif
+
+ /* Once all the cookies have been verified and transactions opened,
+ ** obtain the required table-locks. This is a no-op unless the
+ ** shared-cache feature is enabled.
+ */
+ codeTableLocks(pParse);
sqlite3VdbeAddOp(v, OP_Goto, 0, pParse->cookieGoto);
}
@@ -99,7 +193,7 @@ void sqlite3FinishCoding(Parse *pParse){
/* Get the VDBE program ready for execution
*/
- if( v && pParse->nErr==0 ){
+ if( v && pParse->nErr==0 && !sqlite3MallocFailed() ){
FILE *trace = (db->flags & SQLITE_VdbeTrace)!=0 ? stdout : 0;
sqlite3VdbeTrace(v, trace);
sqlite3VdbeMakeReady(v, pParse->nVar, pParse->nMem+3,
@@ -168,11 +262,10 @@ Table *sqlite3FindTable(sqlite3 *db, const char *zName, const char *zDatabase){
Table *p = 0;
int i;
assert( zName!=0 );
- assert( (db->flags & SQLITE_Initialized) || db->init.busy );
for(i=OMIT_TEMPDB; i<db->nDb; i++){
int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */
if( zDatabase!=0 && sqlite3StrICmp(zDatabase, db->aDb[j].zName) ) continue;
- p = sqlite3HashFind(&db->aDb[j].tblHash, zName, strlen(zName)+1);
+ p = sqlite3HashFind(&db->aDb[j].pSchema->tblHash, zName, strlen(zName)+1);
if( p ) break;
}
return p;
@@ -224,11 +317,14 @@ Table *sqlite3LocateTable(Parse *pParse, const char *zName, const char *zDbase){
Index *sqlite3FindIndex(sqlite3 *db, const char *zName, const char *zDb){
Index *p = 0;
int i;
- assert( (db->flags & SQLITE_Initialized) || db->init.busy );
for(i=OMIT_TEMPDB; i<db->nDb; i++){
int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */
+ Schema *pSchema = db->aDb[j].pSchema;
if( zDb && sqlite3StrICmp(zDb, db->aDb[j].zName) ) continue;
- p = sqlite3HashFind(&db->aDb[j].idxHash, zName, strlen(zName)+1);
+ assert( pSchema || (j==1 && !db->aDb[1].pBt) );
+ if( pSchema ){
+ p = sqlite3HashFind(&pSchema->idxHash, zName, strlen(zName)+1);
+ }
if( p ) break;
}
return p;
@@ -250,12 +346,11 @@ static void freeIndex(Index *p){
** it is not unlinked from the Table that it indexes.
** Unlinking from the Table must be done by the calling function.
*/
-static void sqliteDeleteIndex(sqlite3 *db, Index *p){
+static void sqliteDeleteIndex(Index *p){
Index *pOld;
+ const char *zName = p->zName;
- assert( db!=0 && p->zName!=0 );
- pOld = sqlite3HashInsert(&db->aDb[p->iDb].idxHash, p->zName,
- strlen(p->zName)+1, 0);
+ pOld = sqlite3HashInsert(&p->pSchema->idxHash, zName, strlen( zName)+1, 0);
assert( pOld==0 || pOld==p );
freeIndex(p);
}
@@ -269,9 +364,10 @@ static void sqliteDeleteIndex(sqlite3 *db, Index *p){
void sqlite3UnlinkAndDeleteIndex(sqlite3 *db, int iDb, const char *zIdxName){
Index *pIndex;
int len;
+ Hash *pHash = &db->aDb[iDb].pSchema->idxHash;
len = strlen(zIdxName);
- pIndex = sqlite3HashInsert(&db->aDb[iDb].idxHash, zIdxName, len+1, 0);
+ pIndex = sqlite3HashInsert(pHash, zIdxName, len+1, 0);
if( pIndex ){
if( pIndex->pTable->pIndex==pIndex ){
pIndex->pTable->pIndex = pIndex->pNext;
@@ -299,39 +395,21 @@ void sqlite3UnlinkAndDeleteIndex(sqlite3 *db, int iDb, const char *zIdxName){
** single file indicated.
*/
void sqlite3ResetInternalSchema(sqlite3 *db, int iDb){
- HashElem *pElem;
- Hash temp1;
- Hash temp2;
int i, j;
assert( iDb>=0 && iDb<db->nDb );
- db->flags &= ~SQLITE_Initialized;
for(i=iDb; i<db->nDb; i++){
Db *pDb = &db->aDb[i];
- temp1 = pDb->tblHash;
- temp2 = pDb->trigHash;
- sqlite3HashInit(&pDb->trigHash, SQLITE_HASH_STRING, 0);
- sqlite3HashClear(&pDb->aFKey);
- sqlite3HashClear(&pDb->idxHash);
- for(pElem=sqliteHashFirst(&temp2); pElem; pElem=sqliteHashNext(pElem)){
- sqlite3DeleteTrigger((Trigger*)sqliteHashData(pElem));
- }
- sqlite3HashClear(&temp2);
- sqlite3HashInit(&pDb->tblHash, SQLITE_HASH_STRING, 0);
- for(pElem=sqliteHashFirst(&temp1); pElem; pElem=sqliteHashNext(pElem)){
- Table *pTab = sqliteHashData(pElem);
- sqlite3DeleteTable(db, pTab);
- }
- sqlite3HashClear(&temp1);
- pDb->pSeqTab = 0;
- DbClearProperty(db, i, DB_SchemaLoaded);
+ if( pDb->pSchema ){
+ sqlite3SchemaFree(pDb->pSchema);
+ }
if( iDb>0 ) return;
}
assert( iDb==0 );
db->flags &= ~SQLITE_InternChanges;
/* If one or more of the auxiliary database files has been closed,
- ** then remove then from the auxiliary database list. We take the
+ ** then remove them from the auxiliary database list. We take the
** opportunity to do this here since we have just deleted all of the
** schema hash tables and therefore do not have to make any changes
** to any of those tables.
@@ -394,6 +472,7 @@ static void sqliteResetColumnNames(Table *pTable){
sqliteFree(pCol->zName);
sqlite3ExprDelete(pCol->pDflt);
sqliteFree(pCol->zType);
+ sqliteFree(pCol->zColl);
}
sqliteFree(pTable->aCol);
}
@@ -420,6 +499,8 @@ void sqlite3DeleteTable(sqlite3 *db, Table *pTable){
Index *pIndex, *pNext;
FKey *pFKey, *pNextFKey;
+ db = 0;
+
if( pTable==0 ) return;
/* Do not delete the table until the reference count reaches zero. */
@@ -433,8 +514,8 @@ void sqlite3DeleteTable(sqlite3 *db, Table *pTable){
*/
for(pIndex = pTable->pIndex; pIndex; pIndex=pNext){
pNext = pIndex->pNext;
- assert( pIndex->iDb==pTable->iDb || (pTable->iDb==0 && pIndex->iDb==1) );
- sqliteDeleteIndex(db, pIndex);
+ assert( pIndex->pSchema==pTable->pSchema );
+ sqliteDeleteIndex(pIndex);
}
#ifndef SQLITE_OMIT_FOREIGN_KEY
@@ -443,8 +524,7 @@ void sqlite3DeleteTable(sqlite3 *db, Table *pTable){
*/
for(pFKey=pTable->pFKey; pFKey; pFKey=pNextFKey){
pNextFKey = pFKey->pNextFrom;
- assert( pTable->iDb<db->nDb );
- assert( sqlite3HashFind(&db->aDb[pTable->iDb].aFKey,
+ assert( sqlite3HashFind(&pTable->pSchema->aFKey,
pFKey->zTo, strlen(pFKey->zTo)+1)!=pFKey );
sqliteFree(pFKey);
}
@@ -456,6 +536,10 @@ void sqlite3DeleteTable(sqlite3 *db, Table *pTable){
sqliteFree(pTable->zName);
sqliteFree(pTable->zColAff);
sqlite3SelectDelete(pTable->pSelect);
+#ifndef SQLITE_OMIT_CHECK
+ sqlite3ExprDelete(pTable->pCheck);
+#endif
+ sqlite3VtabClear(pTable);
sqliteFree(pTable);
}
@@ -472,14 +556,14 @@ void sqlite3UnlinkAndDeleteTable(sqlite3 *db, int iDb, const char *zTabName){
assert( iDb>=0 && iDb<db->nDb );
assert( zTabName && zTabName[0] );
pDb = &db->aDb[iDb];
- p = sqlite3HashInsert(&pDb->tblHash, zTabName, strlen(zTabName)+1, 0);
+ p = sqlite3HashInsert(&pDb->pSchema->tblHash, zTabName, strlen(zTabName)+1,0);
if( p ){
#ifndef SQLITE_OMIT_FOREIGN_KEY
for(pF1=p->pFKey; pF1; pF1=pF1->pNextFrom){
int nTo = strlen(pF1->zTo) + 1;
- pF2 = sqlite3HashFind(&pDb->aFKey, pF1->zTo, nTo);
+ pF2 = sqlite3HashFind(&pDb->pSchema->aFKey, pF1->zTo, nTo);
if( pF2==pF1 ){
- sqlite3HashInsert(&pDb->aFKey, pF1->zTo, nTo, pF1->pNextTo);
+ sqlite3HashInsert(&pDb->pSchema->aFKey, pF1->zTo, nTo, pF1->pNextTo);
}else{
while( pF2 && pF2->pNextTo!=pF1 ){ pF2=pF2->pNextTo; }
if( pF2 ){
@@ -506,7 +590,7 @@ void sqlite3UnlinkAndDeleteTable(sqlite3 *db, int iDb, const char *zTabName){
char *sqlite3NameFromToken(Token *pName){
char *zName;
if( pName ){
- zName = sqliteStrNDup(pName->z, pName->n);
+ zName = sqliteStrNDup((char*)pName->z, pName->n);
sqlite3Dequote(zName);
}else{
zName = 0;
@@ -518,7 +602,9 @@ char *sqlite3NameFromToken(Token *pName){
** Open the sqlite_master table stored in database number iDb for
** writing. The table is opened using cursor 0.
*/
-void sqlite3OpenMasterTable(Vdbe *v, int iDb){
+void sqlite3OpenMasterTable(Parse *p, int iDb){
+ Vdbe *v = sqlite3GetVdbe(p);
+ sqlite3TableLock(p, iDb, MASTER_ROOT, 1, SCHEMA_TABLE(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 */
@@ -613,8 +699,7 @@ int sqlite3CheckObjectName(Parse *pParse, const char *zName){
** Begin constructing a new table representation in memory. This is
** the first of several action routines that get called in response
** to a CREATE TABLE statement. In particular, this routine is called
-** after seeing tokens "CREATE" and "TABLE" and the table name. The
-** pStart token is the CREATE and pName is the table name. The isTemp
+** after seeing tokens "CREATE" and "TABLE" and the table name. The isTemp
** flag is true if the table should be stored in the auxiliary database
** file instead of in the main database file. This is normally the case
** when the "TEMP" or "TEMPORARY" keyword occurs in between
@@ -628,11 +713,12 @@ int sqlite3CheckObjectName(Parse *pParse, const char *zName){
*/
void sqlite3StartTable(
Parse *pParse, /* Parser context */
- Token *pStart, /* The "CREATE" token */
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 */
+ int isView, /* True if this is a VIEW */
+ int isVirtual, /* True if this is a VIRTUAL table */
+ int noErr /* Do nothing if table already exists */
){
Table *pTable;
char *zName = 0; /* The name of the new table */
@@ -695,7 +781,7 @@ void sqlite3StartTable(
code = SQLITE_CREATE_TABLE;
}
}
- if( sqlite3AuthCheck(pParse, code, zName, 0, zDb) ){
+ if( !isVirtual && sqlite3AuthCheck(pParse, code, zName, 0, zDb) ){
goto begin_table_error;
}
}
@@ -703,20 +789,28 @@ void sqlite3StartTable(
/* 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.
+ ** 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( SQLITE_OK!=sqlite3ReadSchema(pParse) ){
- goto begin_table_error;
- }
- pTable = sqlite3FindTable(db, zName, db->aDb[iDb].zName);
- if( pTable ){
- 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;
+ 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;
@@ -724,11 +818,8 @@ void sqlite3StartTable(
goto begin_table_error;
}
pTable->zName = zName;
- pTable->nCol = 0;
- pTable->aCol = 0;
pTable->iPKey = -1;
- pTable->pIndex = 0;
- pTable->iDb = iDb;
+ pTable->pSchema = db->aDb[iDb].pSchema;
pTable->nRef = 1;
if( pParse->pNewTable ) sqlite3DeleteTable(db, pParse->pNewTable);
pParse->pNewTable = pTable;
@@ -739,7 +830,7 @@ void sqlite3StartTable(
*/
#ifndef SQLITE_OMIT_AUTOINCREMENT
if( !pParse->nested && strcmp(zName, "sqlite_sequence")==0 ){
- db->aDb[iDb].pSeqTab = pTable;
+ pTable->pSchema->pSeqTab = pTable;
}
#endif
@@ -753,17 +844,26 @@ void sqlite3StartTable(
*/
if( !db->init.busy && (v = sqlite3GetVdbe(pParse))!=0 ){
int lbl;
+ int fileFormat;
sqlite3BeginWriteOperation(pParse, 0, iDb);
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ if( isVirtual ){
+ sqlite3VdbeAddOp(v, OP_VBegin, 0, 0);
+ }
+#endif
+
/* If the file format and encoding in the database have not been set,
** set them now.
*/
sqlite3VdbeAddOp(v, OP_ReadCookie, iDb, 1); /* file_format */
lbl = sqlite3VdbeMakeLabel(v);
sqlite3VdbeAddOp(v, OP_If, 0, lbl);
- sqlite3VdbeAddOp(v, OP_Integer, db->file_format, 0);
+ fileFormat = (db->flags & SQLITE_LegacyFileFmt)!=0 ?
+ 1 : SQLITE_MAX_FILE_FORMAT;
+ sqlite3VdbeAddOp(v, OP_Integer, fileFormat, 0);
sqlite3VdbeAddOp(v, OP_SetCookie, iDb, 1);
- sqlite3VdbeAddOp(v, OP_Integer, db->enc, 0);
+ sqlite3VdbeAddOp(v, OP_Integer, ENC(db), 0);
sqlite3VdbeAddOp(v, OP_SetCookie, iDb, 4);
sqlite3VdbeResolveLabel(v, lbl);
@@ -775,15 +875,15 @@ void sqlite3StartTable(
** The rowid value is needed by the code that sqlite3EndTable will
** generate.
*/
-#ifndef SQLITE_OMIT_VIEW
- if( isView ){
+#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE)
+ if( isView || isVirtual ){
sqlite3VdbeAddOp(v, OP_Integer, 0, 0);
}else
#endif
{
sqlite3VdbeAddOp(v, OP_CreateTable, iDb, 0);
}
- sqlite3OpenMasterTable(v, iDb);
+ sqlite3OpenMasterTable(pParse, iDb);
sqlite3VdbeAddOp(v, OP_NewRowid, 0, 0);
sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
sqlite3VdbeAddOp(v, OP_Null, 0, 0);
@@ -855,7 +955,6 @@ void sqlite3AddColumn(Parse *pParse, Token *pName){
** be called next to set pCol->affinity correctly.
*/
pCol->affinity = SQLITE_AFF_NONE;
- pCol->pColl = pParse->db->pDfltColl;
p->nCol++;
}
@@ -891,6 +990,9 @@ void sqlite3AddNotNull(Parse *pParse, int onError){
** 'CLOB' | SQLITE_AFF_TEXT
** 'TEXT' | SQLITE_AFF_TEXT
** 'BLOB' | SQLITE_AFF_NONE
+** 'REAL' | SQLITE_AFF_REAL
+** 'FLOA' | SQLITE_AFF_REAL
+** 'DOUB' | SQLITE_AFF_REAL
**
** If none of the substrings in the above table are found,
** SQLITE_AFF_NUMERIC is returned.
@@ -911,10 +1013,21 @@ char sqlite3AffinityType(const Token *pType){
}else if( h==(('t'<<24)+('e'<<16)+('x'<<8)+'t') ){ /* TEXT */
aff = SQLITE_AFF_TEXT;
}else if( h==(('b'<<24)+('l'<<16)+('o'<<8)+'b') /* BLOB */
- && aff==SQLITE_AFF_NUMERIC ){
+ && (aff==SQLITE_AFF_NUMERIC || aff==SQLITE_AFF_REAL) ){
aff = SQLITE_AFF_NONE;
+#ifndef SQLITE_OMIT_FLOATING_POINT
+ }else if( h==(('r'<<24)+('e'<<16)+('a'<<8)+'l') /* REAL */
+ && aff==SQLITE_AFF_NUMERIC ){
+ aff = SQLITE_AFF_REAL;
+ }else if( h==(('f'<<24)+('l'<<16)+('o'<<8)+'a') /* FLOA */
+ && aff==SQLITE_AFF_NUMERIC ){
+ aff = SQLITE_AFF_REAL;
+ }else if( h==(('d'<<24)+('o'<<16)+('u'<<8)+'b') /* DOUB */
+ && aff==SQLITE_AFF_NUMERIC ){
+ aff = SQLITE_AFF_REAL;
+#endif
}else if( (h&0x00FFFFFF)==(('i'<<16)+('n'<<8)+'t') ){ /* INT */
- aff = SQLITE_AFF_INTEGER;
+ aff = SQLITE_AFF_INTEGER;
break;
}
}
@@ -993,12 +1106,13 @@ void sqlite3AddPrimaryKey(
Parse *pParse, /* Parsing context */
ExprList *pList, /* List of field names to be indexed */
int onError, /* What to do with a uniqueness conflict */
- int autoInc /* True if the AUTOINCREMENT keyword is present */
+ int autoInc, /* True if the AUTOINCREMENT keyword is present */
+ int sortOrder /* SQLITE_SO_ASC or SQLITE_SO_DESC */
){
Table *pTab = pParse->pNewTable;
char *zType = 0;
int iCol = -1, i;
- if( pTab==0 ) goto primary_key_exit;
+ if( pTab==0 || IN_DECLARE_VTAB ) goto primary_key_exit;
if( pTab->hasPrimKey ){
sqlite3ErrorMsg(pParse,
"table \"%s\" has more than one primary key", pTab->zName);
@@ -1024,7 +1138,8 @@ void sqlite3AddPrimaryKey(
if( iCol>=0 && iCol<pTab->nCol ){
zType = pTab->aCol[iCol].zType;
}
- if( zType && sqlite3StrICmp(zType, "INTEGER")==0 ){
+ if( zType && sqlite3StrICmp(zType, "INTEGER")==0
+ && sortOrder==SQLITE_SO_ASC ){
pTab->iPKey = iCol;
pTab->keyConf = onError;
pTab->autoInc = autoInc;
@@ -1034,7 +1149,7 @@ void sqlite3AddPrimaryKey(
"INTEGER PRIMARY KEY");
#endif
}else{
- sqlite3CreateIndex(pParse, 0, 0, 0, pList, onError, 0, 0);
+ sqlite3CreateIndex(pParse, 0, 0, 0, pList, onError, 0, 0, sortOrder, 0);
pList = 0;
}
@@ -1044,46 +1159,50 @@ primary_key_exit:
}
/*
+** Add a new CHECK constraint to the table currently under construction.
+*/
+void sqlite3AddCheckConstraint(
+ Parse *pParse, /* Parsing context */
+ Expr *pCheckExpr /* The check expression */
+){
+#ifndef SQLITE_OMIT_CHECK
+ Table *pTab = pParse->pNewTable;
+ if( pTab && !IN_DECLARE_VTAB ){
+ /* The CHECK expression must be duplicated so that tokens refer
+ ** to malloced space and not the (ephemeral) text of the CREATE TABLE
+ ** statement */
+ pTab->pCheck = sqlite3ExprAnd(pTab->pCheck, sqlite3ExprDup(pCheckExpr));
+ }
+#endif
+ sqlite3ExprDelete(pCheckExpr);
+}
+
+/*
** Set the collation function of the most recently parsed table column
** to the CollSeq given.
*/
void sqlite3AddCollateType(Parse *pParse, const char *zType, int nType){
Table *p;
- Index *pIdx;
- CollSeq *pColl;
int i;
if( (p = pParse->pNewTable)==0 ) return;
i = p->nCol-1;
- pColl = sqlite3LocateCollSeq(pParse, zType, nType);
- p->aCol[i].pColl = pColl;
-
- /* If the column is declared as "<name> PRIMARY KEY COLLATE <type>",
- ** then an index may have been created on this column before the
- ** collation type was added. Correct this if it is the case.
- */
- for(pIdx = p->pIndex; pIdx; pIdx=pIdx->pNext){
- assert( pIdx->nColumn==1 );
- if( pIdx->aiColumn[0]==i ) pIdx->keyInfo.aColl[0] = pColl;
- }
-}
-
-/*
-** Call sqlite3CheckCollSeq() for all collating sequences in an index,
-** in order to verify that all the necessary collating sequences are
-** loaded.
-*/
-int sqlite3CheckIndexCollSeq(Parse *pParse, Index *pIdx){
- if( pIdx ){
- int i;
- for(i=0; i<pIdx->nColumn; i++){
- if( sqlite3CheckCollSeq(pParse, pIdx->keyInfo.aColl[i]) ){
- return SQLITE_ERROR;
+ if( sqlite3LocateCollSeq(pParse, zType, nType) ){
+ Index *pIdx;
+ p->aCol[i].zColl = sqliteStrNDup(zType, nType);
+
+ /* If the column is declared as "<name> PRIMARY KEY COLLATE <type>",
+ ** then an index may have been created on this column before the
+ ** collation type was added. Correct this if it is the case.
+ */
+ for(pIdx=p->pIndex; pIdx; pIdx=pIdx->pNext){
+ assert( pIdx->nColumn==1 );
+ if( pIdx->aiColumn[0]==i ){
+ pIdx->azColl[0] = p->aCol[i].zColl;
}
}
}
- return SQLITE_OK;
}
/*
@@ -1102,10 +1221,11 @@ int sqlite3CheckIndexCollSeq(Parse *pParse, Index *pIdx){
*/
CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char *zName, int nName){
sqlite3 *db = pParse->db;
- u8 enc = db->enc;
+ u8 enc = ENC(db);
u8 initbusy = db->init.busy;
+ CollSeq *pColl;
- CollSeq *pColl = sqlite3FindCollSeq(db, enc, zName, nName, initbusy);
+ pColl = sqlite3FindCollSeq(db, enc, zName, nName, initbusy);
if( !initbusy && (!pColl || !pColl->xCmp) ){
pColl = sqlite3GetCollSeq(db, pColl, zName, nName);
if( !pColl ){
@@ -1138,7 +1258,7 @@ CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char *zName, int nName){
** 1 chance in 2^32. So we're safe enough.
*/
void sqlite3ChangeCookie(sqlite3 *db, Vdbe *v, int iDb){
- sqlite3VdbeAddOp(v, OP_Integer, db->aDb[iDb].schema_cookie+1, 0);
+ sqlite3VdbeAddOp(v, OP_Integer, db->aDb[iDb].pSchema->schema_cookie+1, 0);
sqlite3VdbeAddOp(v, OP_SetCookie, iDb, 0);
}
@@ -1186,7 +1306,7 @@ static void identPut(char *z, int *pIdx, char *zSignedIdent){
** table. Memory to hold the text of the statement is obtained
** from sqliteMalloc() and must be freed by the calling function.
*/
-static char *createTableStmt(Table *p){
+static char *createTableStmt(Table *p, int isTemp){
int i, k, n;
char *zStmt;
char *zSep, *zSep2, *zEnd, *z;
@@ -1212,7 +1332,7 @@ static char *createTableStmt(Table *p){
n += 35 + 6*p->nCol;
zStmt = sqliteMallocRaw( n );
if( zStmt==0 ) return 0;
- strcpy(zStmt, !OMIT_TEMPDB&&p->iDb==1 ? "CREATE TEMP TABLE ":"CREATE TABLE ");
+ strcpy(zStmt, !OMIT_TEMPDB&&isTemp ? "CREATE TEMP TABLE ":"CREATE TABLE ");
k = strlen(zStmt);
identPut(zStmt, &k, p->zName);
zStmt[k++] = '(';
@@ -1259,13 +1379,40 @@ void sqlite3EndTable(
){
Table *p;
sqlite3 *db = pParse->db;
+ int iDb;
- if( (pEnd==0 && pSelect==0) || pParse->nErr || sqlite3_malloc_failed ) return;
+ if( (pEnd==0 && pSelect==0) || pParse->nErr || sqlite3MallocFailed() ) {
+ return;
+ }
p = pParse->pNewTable;
if( p==0 ) return;
assert( !db->init.busy || !pSelect );
+ iDb = sqlite3SchemaToIndex(db, p->pSchema);
+
+#ifndef SQLITE_OMIT_CHECK
+ /* Resolve names in all CHECK constraint expressions.
+ */
+ if( p->pCheck ){
+ SrcList sSrc; /* Fake SrcList for pParse->pNewTable */
+ NameContext sNC; /* Name context for pParse->pNewTable */
+
+ memset(&sNC, 0, sizeof(sNC));
+ memset(&sSrc, 0, sizeof(sSrc));
+ sSrc.nSrc = 1;
+ sSrc.a[0].zName = p->zName;
+ sSrc.a[0].pTab = p;
+ sSrc.a[0].iCursor = -1;
+ sNC.pParse = pParse;
+ sNC.pSrcList = &sSrc;
+ sNC.isCheck = 1;
+ if( sqlite3ExprResolveNames(&sNC, p->pCheck) ){
+ return;
+ }
+ }
+#endif /* !defined(SQLITE_OMIT_CHECK) */
+
/* If the db->init.busy is 1 it means we are reading the SQL off the
** "sqlite_master" or "sqlite_temp_master" table on the disk.
** So do not write to the disk again. Extract the root page number
@@ -1318,11 +1465,16 @@ void sqlite3EndTable(
** Once the SELECT has been coded by sqlite3Select(), it is in a
** suitable state to query for the column names and types to be used
** by the new table.
+ **
+ ** A shared-cache write-lock is not required to write to the new table,
+ ** as a schema-lock must have already been obtained to create it. Since
+ ** a schema-lock excludes all other database users, the write-lock would
+ ** be redundant.
*/
if( pSelect ){
Table *pSelTab;
sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
- sqlite3VdbeAddOp(v, OP_Integer, p->iDb, 0);
+ sqlite3VdbeAddOp(v, OP_Integer, iDb, 0);
sqlite3VdbeAddOp(v, OP_OpenWrite, 1, 0);
pParse->nTab = 2;
sqlite3Select(pParse, pSelect, SRT_Table, 1, 0, 0, 0, 0);
@@ -1341,7 +1493,7 @@ void sqlite3EndTable(
/* Compute the complete text of the CREATE statement */
if( pSelect ){
- zStmt = createTableStmt(p);
+ zStmt = createTableStmt(p, p->pSchema==pParse->db->aDb[1].pSchema);
}else{
n = pEnd->z - pParse->sNameToken.z + 1;
zStmt = sqlite3MPrintf("CREATE %s %.*s", zType2, n, pParse->sNameToken.z);
@@ -1357,22 +1509,22 @@ void sqlite3EndTable(
"UPDATE %Q.%s "
"SET type='%s', name=%Q, tbl_name=%Q, rootpage=#0, sql=%Q "
"WHERE rowid=#1",
- db->aDb[p->iDb].zName, SCHEMA_TABLE(p->iDb),
+ db->aDb[iDb].zName, SCHEMA_TABLE(iDb),
zType,
p->zName,
p->zName,
zStmt
);
sqliteFree(zStmt);
- sqlite3ChangeCookie(db, v, p->iDb);
+ sqlite3ChangeCookie(db, v, iDb);
#ifndef SQLITE_OMIT_AUTOINCREMENT
/* Check to see if we need to create an sqlite_sequence table for
** keeping track of autoincrement keys.
*/
if( p->autoInc ){
- Db *pDb = &db->aDb[p->iDb];
- if( pDb->pSeqTab==0 ){
+ Db *pDb = &db->aDb[iDb];
+ if( pDb->pSchema->pSeqTab==0 ){
sqlite3NestedParse(pParse,
"CREATE TABLE %Q.sqlite_sequence(name,seq)",
pDb->zName
@@ -1382,7 +1534,7 @@ void sqlite3EndTable(
#endif
/* Reparse everything to update our internal data structures */
- sqlite3VdbeOp3(v, OP_ParseSchema, p->iDb, 0,
+ sqlite3VdbeOp3(v, OP_ParseSchema, iDb, 0,
sqlite3MPrintf("tbl_name='%q'",p->zName), P3_DYNAMIC);
}
@@ -1392,8 +1544,8 @@ void sqlite3EndTable(
if( db->init.busy && pParse->nErr==0 ){
Table *pOld;
FKey *pFKey;
- Db *pDb = &db->aDb[p->iDb];
- pOld = sqlite3HashInsert(&pDb->tblHash, p->zName, strlen(p->zName)+1, p);
+ Schema *pSchema = p->pSchema;
+ pOld = sqlite3HashInsert(&pSchema->tblHash, p->zName, strlen(p->zName)+1,p);
if( pOld ){
assert( p==pOld ); /* Malloc must have failed inside HashInsert() */
return;
@@ -1401,8 +1553,8 @@ void sqlite3EndTable(
#ifndef SQLITE_OMIT_FOREIGN_KEY
for(pFKey=p->pFKey; pFKey; pFKey=pFKey->pNextFrom){
int nTo = strlen(pFKey->zTo) + 1;
- pFKey->pNextTo = sqlite3HashFind(&pDb->aFKey, pFKey->zTo, nTo);
- sqlite3HashInsert(&pDb->aFKey, pFKey->zTo, nTo, pFKey);
+ pFKey->pNextTo = sqlite3HashFind(&pSchema->aFKey, pFKey->zTo, nTo);
+ sqlite3HashInsert(&pSchema->aFKey, pFKey->zTo, nTo, pFKey);
}
#endif
pParse->pNewTable = 0;
@@ -1411,9 +1563,14 @@ void sqlite3EndTable(
#ifndef SQLITE_OMIT_ALTERTABLE
if( !p->pSelect ){
+ const char *zName = (const char *)pParse->sNameToken.z;
+ int nName;
assert( !pSelect && pCons && pEnd );
- if( pCons->z==0 ) pCons = pEnd;
- p->addColOffset = 13 + (pCons->z - pParse->sNameToken.z);
+ if( pCons->z==0 ){
+ pCons = pEnd;
+ }
+ nName = (const char *)pCons->z - zName;
+ p->addColOffset = 13 + sqlite3utf8CharLen(zName, nName);
}
#endif
}
@@ -1437,20 +1594,22 @@ void sqlite3CreateView(
Token sEnd;
DbFixer sFix;
Token *pName;
+ int iDb;
if( pParse->nVar>0 ){
sqlite3ErrorMsg(pParse, "parameters are not allowed in views");
sqlite3SelectDelete(pSelect);
return;
}
- sqlite3StartTable(pParse, pBegin, pName1, pName2, isTemp, 1);
+ sqlite3StartTable(pParse, pName1, pName2, isTemp, 1, 0, 0);
p = pParse->pNewTable;
if( p==0 || pParse->nErr ){
sqlite3SelectDelete(pSelect);
return;
}
sqlite3TwoPartName(pParse, pName1, pName2, &pName);
- if( sqlite3FixInit(&sFix, pParse, p->iDb, "view", pName)
+ iDb = sqlite3SchemaToIndex(pParse->db, p->pSchema);
+ if( sqlite3FixInit(&sFix, pParse, iDb, "view", pName)
&& sqlite3FixSelect(&sFix, pSelect)
){
sqlite3SelectDelete(pSelect);
@@ -1464,6 +1623,9 @@ void sqlite3CreateView(
*/
p->pSelect = sqlite3SelectDup(pSelect);
sqlite3SelectDelete(pSelect);
+ if( sqlite3MallocFailed() ){
+ return;
+ }
if( !pParse->db->init.busy ){
sqlite3ViewGetColumnNames(pParse, p);
}
@@ -1488,7 +1650,7 @@ void sqlite3CreateView(
}
#endif /* SQLITE_OMIT_VIEW */
-#ifndef SQLITE_OMIT_VIEW
+#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE)
/*
** The Table structure pTable is really a VIEW. Fill in the names of
** the columns of the view in the pTable structure. Return the number
@@ -1502,6 +1664,14 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
assert( pTable );
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ if( sqlite3VtabCallConnect(pParse, pTable) ){
+ return SQLITE_ERROR;
+ }
+ if( IsVirtual(pTable) ) return 0;
+#endif
+
+#ifndef SQLITE_OMIT_VIEW
/* A positive nCol means the columns names for this view are
** already known.
*/
@@ -1517,12 +1687,10 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
** Actually, this error is caught previously and so the following test
** should always fail. But we will leave it in place just to be safe.
*/
-#if 0
if( pTable->nCol<0 ){
sqlite3ErrorMsg(pParse, "view %s is circularly defined", pTable->zName);
return 1;
}
-#endif
assert( pTable->nCol>=0 );
/* If we get this far, it means we need to compute the table names.
@@ -1534,27 +1702,32 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
*/
assert( pTable->pSelect );
pSel = sqlite3SelectDup(pTable->pSelect);
- n = pParse->nTab;
- sqlite3SrcListAssignCursors(pParse, pSel->pSrc);
- pTable->nCol = -1;
- pSelTab = sqlite3ResultSetOfSelect(pParse, 0, pSel);
- pParse->nTab = n;
- if( pSelTab ){
- assert( pTable->aCol==0 );
- pTable->nCol = pSelTab->nCol;
- pTable->aCol = pSelTab->aCol;
- pSelTab->nCol = 0;
- pSelTab->aCol = 0;
- sqlite3DeleteTable(0, pSelTab);
- DbSetProperty(pParse->db, pTable->iDb, DB_UnresetViews);
- }else{
- pTable->nCol = 0;
+ if( pSel ){
+ n = pParse->nTab;
+ sqlite3SrcListAssignCursors(pParse, pSel->pSrc);
+ pTable->nCol = -1;
+ pSelTab = sqlite3ResultSetOfSelect(pParse, 0, pSel);
+ pParse->nTab = n;
+ if( pSelTab ){
+ assert( pTable->aCol==0 );
+ pTable->nCol = pSelTab->nCol;
+ pTable->aCol = pSelTab->aCol;
+ pSelTab->nCol = 0;
+ pSelTab->aCol = 0;
+ sqlite3DeleteTable(0, pSelTab);
+ pTable->pSchema->flags |= DB_UnresetViews;
+ }else{
+ pTable->nCol = 0;
+ nErr++;
+ }
+ sqlite3SelectDelete(pSel);
+ } else {
nErr++;
}
- sqlite3SelectDelete(pSel);
+#endif /* SQLITE_OMIT_VIEW */
return nErr;
}
-#endif /* SQLITE_OMIT_VIEW */
+#endif /* !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE) */
#ifndef SQLITE_OMIT_VIEW
/*
@@ -1563,7 +1736,7 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
static void sqliteViewResetAll(sqlite3 *db, int idx){
HashElem *i;
if( !DbHasProperty(db, idx, DB_UnresetViews) ) return;
- for(i=sqliteHashFirst(&db->aDb[idx].tblHash); i; i=sqliteHashNext(i)){
+ for(i=sqliteHashFirst(&db->aDb[idx].pSchema->tblHash); i;i=sqliteHashNext(i)){
Table *pTab = sqliteHashData(i);
if( pTab->pSelect ){
sqliteResetColumnNames(pTab);
@@ -1580,26 +1753,37 @@ static void sqliteViewResetAll(sqlite3 *db, int idx){
** used by SQLite when the btree layer moves a table root page. The
** root-page of a table or index in database iDb has changed from iFrom
** to iTo.
+**
+** Ticket #1728: The symbol table might still contain information
+** on tables and/or indices that are the process of being deleted.
+** If you are unlucky, one of those deleted indices or tables might
+** have the same rootpage number as the real table or index that is
+** being moved. So we cannot stop searching after the first match
+** because the first match might be for one of the deleted indices
+** or tables and not the table/index that is actually being moved.
+** We must continue looping until all tables and indices with
+** rootpage==iFrom have been converted to have a rootpage of iTo
+** in order to be certain that we got the right one.
*/
#ifndef SQLITE_OMIT_AUTOVACUUM
void sqlite3RootPageMoved(Db *pDb, int iFrom, int iTo){
HashElem *pElem;
-
- for(pElem=sqliteHashFirst(&pDb->tblHash); pElem; pElem=sqliteHashNext(pElem)){
+ Hash *pHash;
+
+ pHash = &pDb->pSchema->tblHash;
+ for(pElem=sqliteHashFirst(pHash); pElem; pElem=sqliteHashNext(pElem)){
Table *pTab = sqliteHashData(pElem);
if( pTab->tnum==iFrom ){
pTab->tnum = iTo;
- return;
}
}
- for(pElem=sqliteHashFirst(&pDb->idxHash); pElem; pElem=sqliteHashNext(pElem)){
+ pHash = &pDb->pSchema->idxHash;
+ for(pElem=sqliteHashFirst(pHash); pElem; pElem=sqliteHashNext(pElem)){
Index *pIdx = sqliteHashData(pElem);
if( pIdx->tnum==iFrom ){
pIdx->tnum = iTo;
- return;
}
}
- assert(0);
}
#endif
@@ -1636,9 +1820,10 @@ static void destroyRootPage(Parse *pParse, int iTable, int iDb){
static void destroyTable(Parse *pParse, Table *pTab){
#ifdef SQLITE_OMIT_AUTOVACUUM
Index *pIdx;
- destroyRootPage(pParse, pTab->tnum, pTab->iDb);
+ int iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
+ destroyRootPage(pParse, pTab->tnum, iDb);
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
- destroyRootPage(pParse, pIdx->tnum, pIdx->iDb);
+ destroyRootPage(pParse, pIdx->tnum, iDb);
}
#else
/* If the database may be auto-vacuum capable (if SQLITE_OMIT_AUTOVACUUM
@@ -1669,14 +1854,18 @@ static void destroyTable(Parse *pParse, Table *pTab){
}
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
int iIdx = pIdx->tnum;
- assert( pIdx->iDb==pTab->iDb );
+ assert( pIdx->pSchema==pTab->pSchema );
if( (iDestroyed==0 || (iIdx<iDestroyed)) && iIdx>iLargest ){
iLargest = iIdx;
}
}
- if( iLargest==0 ) return;
- destroyRootPage(pParse, iLargest, pTab->iDb);
- iDestroyed = iLargest;
+ if( iLargest==0 ){
+ return;
+ }else{
+ int iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
+ destroyRootPage(pParse, iLargest, iDb);
+ iDestroyed = iLargest;
+ }
}
#endif
}
@@ -1685,24 +1874,32 @@ static void destroyTable(Parse *pParse, Table *pTab){
** This routine is called to do the work of a DROP TABLE statement.
** pName is the name of the table to be dropped.
*/
-void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView){
+void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, int noErr){
Table *pTab;
Vdbe *v;
sqlite3 *db = pParse->db;
int iDb;
- if( pParse->nErr || sqlite3_malloc_failed ) goto exit_drop_table;
+ if( pParse->nErr || sqlite3MallocFailed() ){
+ goto exit_drop_table;
+ }
assert( pName->nSrc==1 );
pTab = sqlite3LocateTable(pParse, pName->a[0].zName, pName->a[0].zDatabase);
- if( pTab==0 ) goto exit_drop_table;
- iDb = pTab->iDb;
+ if( pTab==0 ){
+ if( noErr ){
+ sqlite3ErrorClear(pParse);
+ }
+ goto exit_drop_table;
+ }
+ iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
assert( iDb>=0 && iDb<db->nDb );
#ifndef SQLITE_OMIT_AUTHORIZATION
{
int code;
- const char *zTab = SCHEMA_TABLE(pTab->iDb);
- const char *zDb = db->aDb[pTab->iDb].zName;
+ const char *zTab = SCHEMA_TABLE(iDb);
+ const char *zDb = db->aDb[iDb].zName;
+ const char *zArg2 = 0;
if( sqlite3AuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb)){
goto exit_drop_table;
}
@@ -1712,6 +1909,14 @@ void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView){
}else{
code = SQLITE_DROP_VIEW;
}
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ }else if( IsVirtual(pTab) ){
+ if( sqlite3ViewGetColumnNames(pParse, pTab) ){
+ goto exit_drop_table;
+ }
+ code = SQLITE_DROP_VTABLE;
+ zArg2 = pTab->pMod->zName;
+#endif
}else{
if( !OMIT_TEMPDB && iDb==1 ){
code = SQLITE_DROP_TEMP_TABLE;
@@ -1719,7 +1924,7 @@ void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView){
code = SQLITE_DROP_TABLE;
}
}
- if( sqlite3AuthCheck(pParse, code, pTab->zName, 0, zDb) ){
+ if( sqlite3AuthCheck(pParse, code, pTab->zName, zArg2, zDb) ){
goto exit_drop_table;
}
if( sqlite3AuthCheck(pParse, SQLITE_DELETE, pTab->zName, 0, zDb) ){
@@ -1727,7 +1932,7 @@ void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView){
}
}
#endif
- if( pTab->readOnly || pTab==db->aDb[iDb].pSeqTab ){
+ if( pTab->readOnly || pTab==db->aDb[iDb].pSchema->pSeqTab ){
sqlite3ErrorMsg(pParse, "table %s may not be dropped", pTab->zName);
goto exit_drop_table;
}
@@ -1752,18 +1957,27 @@ void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView){
v = sqlite3GetVdbe(pParse);
if( v ){
Trigger *pTrigger;
- int iDb = pTab->iDb;
Db *pDb = &db->aDb[iDb];
sqlite3BeginWriteOperation(pParse, 0, iDb);
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ if( IsVirtual(pTab) ){
+ Vdbe *v = sqlite3GetVdbe(pParse);
+ if( v ){
+ sqlite3VdbeAddOp(v, OP_VBegin, 0, 0);
+ }
+ }
+#endif
+
/* Drop all triggers associated with the table being dropped. Code
** is generated to remove entries from sqlite_master and/or
** sqlite_temp_master if required.
*/
pTrigger = pTab->pTrigger;
while( pTrigger ){
- assert( pTrigger->iDb==iDb || pTrigger->iDb==1 );
- sqlite3DropTriggerPtr(pParse, pTrigger, 1);
+ assert( pTrigger->pSchema==pTab->pSchema ||
+ pTrigger->pSchema==db->aDb[1].pSchema );
+ sqlite3DropTriggerPtr(pParse, pTrigger);
pTrigger = pTrigger->pNext;
}
@@ -1791,13 +2005,16 @@ void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView){
sqlite3NestedParse(pParse,
"DELETE FROM %Q.%s WHERE tbl_name=%Q and type!='trigger'",
pDb->zName, SCHEMA_TABLE(iDb), pTab->zName);
- if( !isView ){
+ if( !isView && !IsVirtual(pTab) ){
destroyTable(pParse, pTab);
}
/* Remove the table entry from SQLite's internal schema and modify
** the schema cookie.
*/
+ if( IsVirtual(pTab) ){
+ sqlite3VdbeOp3(v, OP_VDestroy, iDb, 0, pTab->zName, 0);
+ }
sqlite3VdbeOp3(v, OP_DropTable, iDb, 0, pTab->zName, 0);
sqlite3ChangeCookie(db, v, iDb);
}
@@ -1841,7 +2058,7 @@ void sqlite3CreateForeignKey(
char *z;
assert( pTo!=0 );
- if( p==0 || pParse->nErr ) goto fk_end;
+ if( p==0 || pParse->nErr || IN_DECLARE_VTAB ) goto fk_end;
if( pFromCol==0 ){
int iCol = p->nCol-1;
if( iCol<0 ) goto fk_end;
@@ -1958,21 +2175,18 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
int addr1; /* Address of top of loop */
int tnum; /* Root page of index */
Vdbe *v; /* Generate code into this virtual machine */
+ KeyInfo *pKey; /* KeyInfo for index */
+ int iDb = sqlite3SchemaToIndex(pParse->db, pIndex->pSchema);
#ifndef SQLITE_OMIT_AUTHORIZATION
if( sqlite3AuthCheck(pParse, SQLITE_REINDEX, pIndex->zName, 0,
- pParse->db->aDb[pIndex->iDb].zName ) ){
+ pParse->db->aDb[iDb].zName ) ){
return;
}
#endif
- /* Ensure all the required collation sequences are available. This
- ** routine will invoke the collation-needed callback if necessary (and
- ** if one has been registered).
- */
- if( sqlite3CheckIndexCollSeq(pParse, pIndex) ){
- return;
- }
+ /* Require a write-lock on the table to perform this operation */
+ sqlite3TableLock(pParse, iDb, pTab->tnum, 1, pTab->zName);
v = sqlite3GetVdbe(pParse);
if( v==0 ) return;
@@ -1981,12 +2195,12 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
tnum = 0;
}else{
tnum = pIndex->tnum;
- sqlite3VdbeAddOp(v, OP_Clear, tnum, pIndex->iDb);
+ sqlite3VdbeAddOp(v, OP_Clear, tnum, iDb);
}
- sqlite3VdbeAddOp(v, OP_Integer, pIndex->iDb, 0);
- sqlite3VdbeOp3(v, OP_OpenWrite, iIdx, tnum,
- (char*)&pIndex->keyInfo, P3_KEYINFO);
- sqlite3OpenTableForReading(v, iTab, pTab);
+ sqlite3VdbeAddOp(v, OP_Integer, iDb, 0);
+ pKey = sqlite3IndexKeyinfo(pParse, pIndex);
+ sqlite3VdbeOp3(v, OP_OpenWrite, iIdx, tnum, (char *)pKey, P3_KEYINFO_HANDOFF);
+ sqlite3OpenTable(pParse, iTab, iDb, pTab, OP_OpenRead);
addr1 = sqlite3VdbeAddOp(v, OP_Rewind, iTab, 0);
sqlite3GenerateIndexKey(v, pIndex, iTab);
if( pIndex->onError!=OE_None ){
@@ -2027,20 +2241,30 @@ void sqlite3CreateIndex(
ExprList *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 */
+ Token *pEnd, /* The ")" that closes the CREATE INDEX statement */
+ int sortOrder, /* Sort order of primary key when pList==NULL */
+ int ifNotExist /* Omit error if index already exists */
){
- Table *pTab = 0; /* Table to be indexed */
- Index *pIndex = 0; /* The index to be created */
- char *zName = 0;
+ Table *pTab = 0; /* Table to be indexed */
+ Index *pIndex = 0; /* The index to be created */
+ char *zName = 0; /* Name of the index */
+ int nName; /* Number of characters in zName */
int i, j;
- Token nullId; /* Fake token for an empty ID list */
- DbFixer sFix; /* For assigning database names to pTable */
+ Token nullId; /* Fake token for an empty ID list */
+ DbFixer sFix; /* For assigning database names to pTable */
+ int sortOrderMask; /* 1 to honor DESC in index. 0 to ignore. */
sqlite3 *db = pParse->db;
+ Db *pDb; /* The specific table containing the indexed database */
+ int iDb; /* Index of the database that is being written */
+ Token *pName = 0; /* Unqualified name of the index to create */
+ struct ExprList_item *pListItem; /* For looping over pList */
+ int nCol;
+ int nExtra = 0;
+ char *zExtra;
- 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( pParse->nErr || sqlite3MallocFailed() || IN_DECLARE_VTAB ){
+ goto exit_create_index;
+ }
/*
** Find the table that is to be indexed. Return early if not found.
@@ -2060,7 +2284,7 @@ void sqlite3CreateIndex(
** is a temp table. If so, set the database to 1.
*/
pTab = sqlite3SrcListLookup(pParse, pTblName);
- if( pName2 && pName2->n==0 && pTab && pTab->iDb==1 ){
+ if( pName2 && pName2->n==0 && pTab && pTab->pSchema==db->aDb[1].pSchema ){
iDb = 1;
}
#endif
@@ -2075,12 +2299,14 @@ void sqlite3CreateIndex(
pTab = sqlite3LocateTable(pParse, pTblName->a[0].zName,
pTblName->a[0].zDatabase);
if( !pTab ) goto exit_create_index;
- assert( iDb==pTab->iDb );
+ assert( db->aDb[iDb].pSchema==pTab->pSchema );
}else{
assert( pName==0 );
- pTab = pParse->pNewTable;
- iDb = pTab->iDb;
+ pTab = pParse->pNewTable;
+ if( !pTab ) goto exit_create_index;
+ iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
}
+ pDb = &db->aDb[iDb];
if( pTab==0 || pParse->nErr ) goto exit_create_index;
if( pTab->readOnly ){
@@ -2093,6 +2319,12 @@ void sqlite3CreateIndex(
goto exit_create_index;
}
#endif
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ if( IsVirtual(pTab) ){
+ sqlite3ErrorMsg(pParse, "virtual tables may not be indexed");
+ goto exit_create_index;
+ }
+#endif
/*
** Find the name of the index. Make sure there is not already another
@@ -2116,8 +2348,10 @@ void sqlite3CreateIndex(
}
if( !db->init.busy ){
if( SQLITE_OK!=sqlite3ReadSchema(pParse) ) goto exit_create_index;
- if( sqlite3FindIndex(db, zName, db->aDb[iDb].zName)!=0 ){
- sqlite3ErrorMsg(pParse, "index %s already exists", zName);
+ if( sqlite3FindIndex(db, zName, pDb->zName)!=0 ){
+ if( !ifNotExist ){
+ sqlite3ErrorMsg(pParse, "index %s already exists", zName);
+ }
goto exit_create_index;
}
if( sqlite3FindTable(db, zName, 0)!=0 ){
@@ -2140,7 +2374,7 @@ void sqlite3CreateIndex(
*/
#ifndef SQLITE_OMIT_AUTHORIZATION
{
- const char *zDb = db->aDb[iDb].zName;
+ const char *zDb = pDb->zName;
if( sqlite3AuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(iDb), 0, zDb) ){
goto exit_create_index;
}
@@ -2157,56 +2391,96 @@ void sqlite3CreateIndex(
** So create a fake list to simulate this.
*/
if( pList==0 ){
- nullId.z = pTab->aCol[pTab->nCol-1].zName;
- nullId.n = strlen(nullId.z);
+ nullId.z = (u8*)pTab->aCol[pTab->nCol-1].zName;
+ nullId.n = strlen((char*)nullId.z);
pList = sqlite3ExprListAppend(0, 0, &nullId);
if( pList==0 ) goto exit_create_index;
+ pList->a[0].sortOrder = sortOrder;
+ }
+
+ /* Figure out how many bytes of space are required to store explicitly
+ ** specified collation sequence names.
+ */
+ for(i=0; i<pList->nExpr; i++){
+ Expr *pExpr = pList->a[i].pExpr;
+ if( pExpr ){
+ nExtra += (1 + strlen(pExpr->pColl->zName));
+ }
}
/*
** Allocate the index structure.
*/
- pIndex = sqliteMalloc( sizeof(Index) + strlen(zName) + 1 + sizeof(int) +
- (sizeof(int)*2 + sizeof(CollSeq*))*pList->nExpr );
- if( sqlite3_malloc_failed ) goto exit_create_index;
- pIndex->aiColumn = (int*)&pIndex->keyInfo.aColl[pList->nExpr];
- pIndex->aiRowEst = (unsigned*)&pIndex->aiColumn[pList->nExpr];
- pIndex->zName = (char*)&pIndex->aiRowEst[pList->nExpr+1];
+ nName = strlen(zName);
+ nCol = pList->nExpr;
+ pIndex = sqliteMalloc(
+ sizeof(Index) + /* Index structure */
+ sizeof(int)*nCol + /* Index.aiColumn */
+ sizeof(int)*(nCol+1) + /* Index.aiRowEst */
+ sizeof(char *)*nCol + /* Index.azColl */
+ sizeof(u8)*nCol + /* Index.aSortOrder */
+ nName + 1 + /* Index.zName */
+ nExtra /* Collation sequence names */
+ );
+ if( sqlite3MallocFailed() ) goto exit_create_index;
+ pIndex->azColl = (char**)(&pIndex[1]);
+ pIndex->aiColumn = (int *)(&pIndex->azColl[nCol]);
+ pIndex->aiRowEst = (unsigned *)(&pIndex->aiColumn[nCol]);
+ pIndex->aSortOrder = (u8 *)(&pIndex->aiRowEst[nCol+1]);
+ pIndex->zName = (char *)(&pIndex->aSortOrder[nCol]);
+ zExtra = (char *)(&pIndex->zName[nName+1]);
strcpy(pIndex->zName, zName);
pIndex->pTable = pTab;
pIndex->nColumn = pList->nExpr;
pIndex->onError = onError;
pIndex->autoIndex = pName==0;
- pIndex->iDb = iDb;
+ pIndex->pSchema = db->aDb[iDb].pSchema;
+
+ /* Check to see if we should honor DESC requests on index columns
+ */
+ if( pDb->pSchema->file_format>=4 ){
+ sortOrderMask = -1; /* Honor DESC */
+ }else{
+ sortOrderMask = 0; /* Ignore DESC */
+ }
/* Scan the names of the columns of the table to be indexed and
** load the column indices into the Index structure. Report an error
** if any column is not found.
*/
- for(i=0; i<pList->nExpr; i++){
- for(j=0; j<pTab->nCol; j++){
- if( sqlite3StrICmp(pList->a[i].zName, pTab->aCol[j].zName)==0 ) break;
+ for(i=0, pListItem=pList->a; i<pList->nExpr; i++, pListItem++){
+ const char *zColName = pListItem->zName;
+ Column *pTabCol;
+ int requestedSortOrder;
+ char *zColl; /* Collation sequence */
+
+ for(j=0, pTabCol=pTab->aCol; j<pTab->nCol; j++, pTabCol++){
+ if( sqlite3StrICmp(zColName, pTabCol->zName)==0 ) break;
}
if( j>=pTab->nCol ){
sqlite3ErrorMsg(pParse, "table %s has no column named %s",
- pTab->zName, pList->a[i].zName);
+ pTab->zName, zColName);
goto exit_create_index;
}
pIndex->aiColumn[i] = j;
- if( pList->a[i].pExpr ){
- assert( pList->a[i].pExpr->pColl );
- pIndex->keyInfo.aColl[i] = pList->a[i].pExpr->pColl;
+ if( pListItem->pExpr ){
+ assert( pListItem->pExpr->pColl );
+ zColl = zExtra;
+ strcpy(zExtra, pListItem->pExpr->pColl->zName);
+ zExtra += (strlen(zColl) + 1);
}else{
- pIndex->keyInfo.aColl[i] = pTab->aCol[j].pColl;
+ zColl = pTab->aCol[j].zColl;
+ if( !zColl ){
+ zColl = db->pDfltColl->zName;
+ }
}
- assert( pIndex->keyInfo.aColl[i] );
- if( !db->init.busy &&
- sqlite3CheckCollSeq(pParse, pIndex->keyInfo.aColl[i])
- ){
+ if( !db->init.busy && !sqlite3LocateCollSeq(pParse, zColl, -1) ){
goto exit_create_index;
}
+ pIndex->azColl[i] = zColl;
+ requestedSortOrder = pListItem->sortOrder & sortOrderMask;
+ pIndex->aSortOrder[i] = requestedSortOrder;
}
- pIndex->keyInfo.nField = pList->nExpr;
sqlite3DefaultRowEst(pIndex);
if( pTab==pParse->pNewTable ){
@@ -2232,8 +2506,11 @@ void sqlite3CreateIndex(
if( pIdx->nColumn!=pIndex->nColumn ) continue;
for(k=0; k<pIdx->nColumn; k++){
+ const char *z1 = pIdx->azColl[k];
+ const char *z2 = pIndex->azColl[k];
if( pIdx->aiColumn[k]!=pIndex->aiColumn[k] ) break;
- if( pIdx->keyInfo.aColl[k]!=pIndex->keyInfo.aColl[k] ) break;
+ if( pIdx->aSortOrder[k]!=pIndex->aSortOrder[k] ) break;
+ if( z1!=z2 && sqlite3StrICmp(z1, z2) ) break;
}
if( k==pIdx->nColumn ){
if( pIdx->onError!=pIndex->onError ){
@@ -2262,7 +2539,7 @@ void sqlite3CreateIndex(
*/
if( db->init.busy ){
Index *p;
- p = sqlite3HashInsert(&db->aDb[pIndex->iDb].idxHash,
+ p = sqlite3HashInsert(&pIndex->pSchema->idxHash,
pIndex->zName, strlen(pIndex->zName)+1, pIndex);
if( p ){
assert( p==pIndex ); /* Malloc must have failed */
@@ -2297,6 +2574,7 @@ void sqlite3CreateIndex(
v = sqlite3GetVdbe(pParse);
if( v==0 ) goto exit_create_index;
+
/* Create the rootpage for the index
*/
sqlite3BeginWriteOperation(pParse, 1, iDb);
@@ -2375,6 +2653,22 @@ exit_create_index:
}
/*
+** Generate code to make sure the file format number is at least minFormat.
+** The generated code will increase the file format number if necessary.
+*/
+void sqlite3MinimumFileFormat(Parse *pParse, int iDb, int minFormat){
+ Vdbe *v;
+ v = sqlite3GetVdbe(pParse);
+ if( v ){
+ sqlite3VdbeAddOp(v, OP_ReadCookie, iDb, 1);
+ sqlite3VdbeAddOp(v, OP_Integer, minFormat, 0);
+ sqlite3VdbeAddOp(v, OP_Ge, 0, sqlite3VdbeCurrentAddr(v)+3);
+ sqlite3VdbeAddOp(v, OP_Integer, minFormat, 0);
+ sqlite3VdbeAddOp(v, OP_SetCookie, iDb, 1);
+ }
+}
+
+/*
** Fill the Index.aiRowEst[] array with default information - information
** to be used when we have not run the ANALYZE command.
**
@@ -2397,8 +2691,12 @@ void sqlite3DefaultRowEst(Index *pIdx){
int i;
assert( a!=0 );
a[0] = 1000000;
- for(i=pIdx->nColumn; i>=1; i--){
- a[i] = 10;
+ for(i=pIdx->nColumn; i>=5; i--){
+ a[i] = 5;
+ }
+ while( i>=1 ){
+ a[i] = 11 - i;
+ i--;
}
if( pIdx->onError!=OE_None ){
a[pIdx->nColumn] = 1;
@@ -2409,12 +2707,13 @@ void sqlite3DefaultRowEst(Index *pIdx){
** This routine will drop an existing named index. This routine
** implements the DROP INDEX statement.
*/
-void sqlite3DropIndex(Parse *pParse, SrcList *pName){
+void sqlite3DropIndex(Parse *pParse, SrcList *pName, int ifExists){
Index *pIndex;
Vdbe *v;
sqlite3 *db = pParse->db;
+ int iDb;
- if( pParse->nErr || sqlite3_malloc_failed ){
+ if( pParse->nErr || sqlite3MallocFailed() ){
goto exit_drop_index;
}
assert( pName->nSrc==1 );
@@ -2423,7 +2722,9 @@ void sqlite3DropIndex(Parse *pParse, SrcList *pName){
}
pIndex = sqlite3FindIndex(db, pName->a[0].zName, pName->a[0].zDatabase);
if( pIndex==0 ){
- sqlite3ErrorMsg(pParse, "no such index: %S", pName, 0);
+ if( !ifExists ){
+ sqlite3ErrorMsg(pParse, "no such index: %S", pName, 0);
+ }
pParse->checkSchema = 1;
goto exit_drop_index;
}
@@ -2432,16 +2733,17 @@ void sqlite3DropIndex(Parse *pParse, SrcList *pName){
"or PRIMARY KEY constraint cannot be dropped", 0);
goto exit_drop_index;
}
+ iDb = sqlite3SchemaToIndex(db, pIndex->pSchema);
#ifndef SQLITE_OMIT_AUTHORIZATION
{
int code = SQLITE_DROP_INDEX;
Table *pTab = pIndex->pTable;
- const char *zDb = db->aDb[pIndex->iDb].zName;
- const char *zTab = SCHEMA_TABLE(pIndex->iDb);
+ const char *zDb = db->aDb[iDb].zName;
+ const char *zTab = SCHEMA_TABLE(iDb);
if( sqlite3AuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb) ){
goto exit_drop_index;
}
- if( !OMIT_TEMPDB && pIndex->iDb ) code = SQLITE_DROP_TEMP_INDEX;
+ if( !OMIT_TEMPDB && iDb ) code = SQLITE_DROP_TEMP_INDEX;
if( sqlite3AuthCheck(pParse, code, pIndex->zName, pTab->zName, zDb) ){
goto exit_drop_index;
}
@@ -2451,7 +2753,6 @@ void sqlite3DropIndex(Parse *pParse, SrcList *pName){
/* Generate code to remove the index and from the master table */
v = sqlite3GetVdbe(pParse);
if( v ){
- int iDb = pIndex->iDb;
sqlite3NestedParse(pParse,
"DELETE FROM %Q.%s WHERE name=%Q",
db->aDb[iDb].zName, SCHEMA_TABLE(iDb),
@@ -2611,6 +2912,7 @@ SrcList *sqlite3SrcListAppend(SrcList *pList, Token *pTable, Token *pDatabase){
pItem->zName = sqlite3NameFromToken(pTable);
pItem->zDatabase = sqlite3NameFromToken(pDatabase);
pItem->iCursor = -1;
+ pItem->isPopulated = 0;
pList->nSrc++;
return pList;
}
@@ -2621,11 +2923,14 @@ SrcList *sqlite3SrcListAppend(SrcList *pList, Token *pTable, Token *pDatabase){
void sqlite3SrcListAssignCursors(Parse *pParse, SrcList *pList){
int i;
struct SrcList_item *pItem;
- for(i=0, pItem=pList->a; i<pList->nSrc; i++, pItem++){
- if( pItem->iCursor>=0 ) break;
- pItem->iCursor = pParse->nTab++;
- if( pItem->pSelect ){
- sqlite3SrcListAssignCursors(pParse, pItem->pSelect->pSrc);
+ assert(pList || sqlite3MallocFailed() );
+ if( pList ){
+ for(i=0, pItem=pList->a; i<pList->nSrc; i++, pItem++){
+ if( pItem->iCursor>=0 ) break;
+ pItem->iCursor = pParse->nTab++;
+ if( pItem->pSelect ){
+ sqlite3SrcListAssignCursors(pParse, pItem->pSelect->pSrc);
+ }
}
}
}
@@ -2667,7 +2972,7 @@ void sqlite3BeginTransaction(Parse *pParse, int type){
int i;
if( pParse==0 || (db=pParse->db)==0 || db->aDb[0].pBt==0 ) return;
- if( pParse->nErr || sqlite3_malloc_failed ) return;
+ if( pParse->nErr || sqlite3MallocFailed() ) return;
if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, "BEGIN", 0, 0) ) return;
v = sqlite3GetVdbe(pParse);
@@ -2688,7 +2993,7 @@ void sqlite3CommitTransaction(Parse *pParse){
Vdbe *v;
if( pParse==0 || (db=pParse->db)==0 || db->aDb[0].pBt==0 ) return;
- if( pParse->nErr || sqlite3_malloc_failed ) return;
+ if( pParse->nErr || sqlite3MallocFailed() ) return;
if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, "COMMIT", 0, 0) ) return;
v = sqlite3GetVdbe(pParse);
@@ -2705,7 +3010,7 @@ void sqlite3RollbackTransaction(Parse *pParse){
Vdbe *v;
if( pParse==0 || (db=pParse->db)==0 || db->aDb[0].pBt==0 ) return;
- if( pParse->nErr || sqlite3_malloc_failed ) return;
+ if( pParse->nErr || sqlite3MallocFailed() ) return;
if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, "ROLLBACK", 0, 0) ) return;
v = sqlite3GetVdbe(pParse);
@@ -2718,7 +3023,7 @@ void sqlite3RollbackTransaction(Parse *pParse){
** Make sure the TEMP database is open and available for use. Return
** the number of errors. Leave any error messages in the pParse structure.
*/
-static int sqlite3OpenTempDatabase(Parse *pParse){
+int sqlite3OpenTempDatabase(Parse *pParse){
sqlite3 *db = pParse->db;
if( db->aDb[1].pBt==0 && !pParse->explain ){
int rc = sqlite3BtreeFactory(db, 0, 0, MAX_PAGES, &db->aDb[1].pBt);
@@ -2737,6 +3042,7 @@ static int sqlite3OpenTempDatabase(Parse *pParse){
return 1;
}
}
+ assert( db->aDb[1].pSchema );
}
return 0;
}
@@ -2777,11 +3083,11 @@ void sqlite3CodeVerifySchema(Parse *pParse, int iDb){
if( iDb>=0 ){
assert( iDb<db->nDb );
assert( db->aDb[iDb].pBt!=0 || iDb==1 );
- assert( iDb<32 );
+ assert( iDb<MAX_ATTACHED+2 );
mask = 1<<iDb;
if( (pParse->cookieMask & mask)==0 ){
pParse->cookieMask |= mask;
- pParse->cookieValue[iDb] = db->aDb[iDb].schema_cookie;
+ pParse->cookieValue[iDb] = db->aDb[iDb].pSchema->schema_cookie;
if( !OMIT_TEMPDB && iDb==1 ){
sqlite3OpenTempDatabase(pParse);
}
@@ -2825,12 +3131,13 @@ void sqlite3BeginWriteOperation(Parse *pParse, int setStatement, int iDb){
** true if it does and false if it does not.
*/
#ifndef SQLITE_OMIT_REINDEX
-static int collationMatch(CollSeq *pColl, Index *pIndex){
- int n = pIndex->keyInfo.nField;
- CollSeq **pp = pIndex->keyInfo.aColl;
- while( n-- ){
- if( *pp==pColl ) return 1;
- pp++;
+static int collationMatch(const char *zColl, Index *pIndex){
+ int i;
+ for(i=0; i<pIndex->nColumn; i++){
+ const char *z = pIndex->azColl[i];
+ if( z==zColl || (z && zColl && 0==sqlite3StrICmp(z, zColl)) ){
+ return 1;
+ }
}
return 0;
}
@@ -2841,12 +3148,13 @@ static int collationMatch(CollSeq *pColl, Index *pIndex){
** If pColl==0 then recompute all indices of pTab.
*/
#ifndef SQLITE_OMIT_REINDEX
-static void reindexTable(Parse *pParse, Table *pTab, CollSeq *pColl){
+static void reindexTable(Parse *pParse, Table *pTab, char const *zColl){
Index *pIndex; /* An index associated with pTab */
for(pIndex=pTab->pIndex; pIndex; pIndex=pIndex->pNext){
- if( pColl==0 || collationMatch(pColl,pIndex) ){
- sqlite3BeginWriteOperation(pParse, 0, pTab->iDb);
+ if( zColl==0 || collationMatch(zColl, pIndex) ){
+ int iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
+ sqlite3BeginWriteOperation(pParse, 0, iDb);
sqlite3RefillIndex(pParse, pIndex, -1);
}
}
@@ -2859,7 +3167,7 @@ static void reindexTable(Parse *pParse, Table *pTab, CollSeq *pColl){
** all indices everywhere.
*/
#ifndef SQLITE_OMIT_REINDEX
-static void reindexDatabases(Parse *pParse, CollSeq *pColl){
+static void reindexDatabases(Parse *pParse, char const *zColl){
Db *pDb; /* A single database */
int iDb; /* The database index number */
sqlite3 *db = pParse->db; /* The database connection */
@@ -2867,10 +3175,10 @@ static void reindexDatabases(Parse *pParse, CollSeq *pColl){
Table *pTab; /* A table in the database */
for(iDb=0, pDb=db->aDb; iDb<db->nDb; iDb++, pDb++){
- if( pDb==0 ) continue;
- for(k=sqliteHashFirst(&pDb->tblHash); k; k=sqliteHashNext(k)){
+ assert( pDb!=0 );
+ for(k=sqliteHashFirst(&pDb->pSchema->tblHash); k; k=sqliteHashNext(k)){
pTab = (Table*)sqliteHashData(k);
- reindexTable(pParse, pTab, pColl);
+ reindexTable(pParse, pTab, zColl);
}
}
}
@@ -2910,9 +3218,14 @@ void sqlite3Reindex(Parse *pParse, Token *pName1, Token *pName2){
reindexDatabases(pParse, 0);
return;
}else if( pName2==0 || pName2->z==0 ){
- pColl = sqlite3FindCollSeq(db, db->enc, pName1->z, pName1->n, 0);
+ assert( pName1->z );
+ pColl = sqlite3FindCollSeq(db, ENC(db), (char*)pName1->z, pName1->n, 0);
if( pColl ){
- reindexDatabases(pParse, pColl);
+ char *zColl = sqliteStrNDup((const char *)pName1->z, pName1->n);
+ if( zColl ){
+ reindexDatabases(pParse, zColl);
+ sqliteFree(zColl);
+ }
return;
}
}
@@ -2936,3 +3249,38 @@ void sqlite3Reindex(Parse *pParse, Token *pName1, Token *pName2){
sqlite3ErrorMsg(pParse, "unable to identify the object to be reindexed");
}
#endif
+
+/*
+** Return a dynamicly allocated KeyInfo structure that can be used
+** with OP_OpenRead or OP_OpenWrite to access database index pIdx.
+**
+** If successful, a pointer to the new structure is returned. In this case
+** the caller is responsible for calling sqliteFree() on the returned
+** pointer. If an error occurs (out of memory or missing collation
+** sequence), NULL is returned and the state of pParse updated to reflect
+** the error.
+*/
+KeyInfo *sqlite3IndexKeyinfo(Parse *pParse, Index *pIdx){
+ int i;
+ int nCol = pIdx->nColumn;
+ int nBytes = sizeof(KeyInfo) + (nCol-1)*sizeof(CollSeq*) + nCol;
+ KeyInfo *pKey = (KeyInfo *)sqliteMalloc(nBytes);
+
+ if( pKey ){
+ pKey->aSortOrder = (u8 *)&(pKey->aColl[nCol]);
+ assert( &pKey->aSortOrder[nCol]==&(((u8 *)pKey)[nBytes]) );
+ for(i=0; i<nCol; i++){
+ char *zColl = pIdx->azColl[i];
+ assert( zColl );
+ pKey->aColl[i] = sqlite3LocateCollSeq(pParse, zColl, -1);
+ pKey->aSortOrder[i] = pIdx->aSortOrder[i];
+ }
+ pKey->nField = nCol;
+ }
+
+ if( pParse->nErr ){
+ sqliteFree(pKey);
+ pKey = 0;
+ }
+ return pKey;
+}