diff options
Diffstat (limited to 'ext/pdo_sqlite/sqlite/src/build.c')
| -rw-r--r-- | ext/pdo_sqlite/sqlite/src/build.c | 868 |
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; +} |
