| Index: third_party/sqlite/src/src/build.c
|
| diff --git a/third_party/sqlite/src/src/build.c b/third_party/sqlite/src/src/build.c
|
| index 25a74ca7ed250873d1e31614772656bba0d06938..b897494db3c2e478402917cfbe724de567177ac7 100644
|
| --- a/third_party/sqlite/src/src/build.c
|
| +++ b/third_party/sqlite/src/src/build.c
|
| @@ -114,6 +114,19 @@ static void codeTableLocks(Parse *pParse){
|
| #endif
|
|
|
| /*
|
| +** Return TRUE if the given yDbMask object is empty - if it contains no
|
| +** 1 bits. This routine is used by the DbMaskAllZero() and DbMaskNotZero()
|
| +** macros when SQLITE_MAX_ATTACHED is greater than 30.
|
| +*/
|
| +#if SQLITE_MAX_ATTACHED>30
|
| +int sqlite3DbMaskAllZero(yDbMask m){
|
| + int i;
|
| + for(i=0; i<sizeof(yDbMask); i++) if( m[i] ) return 0;
|
| + return 1;
|
| +}
|
| +#endif
|
| +
|
| +/*
|
| ** This routine is called after a single SQL statement has been
|
| ** parsed and a VDBE program to execute that statement has been
|
| ** prepared. This routine puts the finishing touches on the
|
| @@ -127,6 +140,7 @@ void sqlite3FinishCoding(Parse *pParse){
|
| sqlite3 *db;
|
| Vdbe *v;
|
|
|
| + assert( pParse->pToplevel==0 );
|
| db = pParse->db;
|
| if( db->mallocFailed ) return;
|
| if( pParse->nested ) return;
|
| @@ -139,38 +153,50 @@ void sqlite3FinishCoding(Parse *pParse){
|
| assert( !pParse->isMultiWrite
|
| || sqlite3VdbeAssertMayAbort(v, pParse->mayAbort));
|
| if( v ){
|
| + while( sqlite3VdbeDeletePriorOpcode(v, OP_Close) ){}
|
| sqlite3VdbeAddOp0(v, OP_Halt);
|
|
|
| +#if SQLITE_USER_AUTHENTICATION
|
| + if( pParse->nTableLock>0 && db->init.busy==0 ){
|
| + sqlite3UserAuthInit(db);
|
| + if( db->auth.authLevel<UAUTH_User ){
|
| + pParse->rc = SQLITE_AUTH_USER;
|
| + sqlite3ErrorMsg(pParse, "user not authenticated");
|
| + return;
|
| + }
|
| + }
|
| +#endif
|
| +
|
| /* The cookie mask contains one bit for each database file open.
|
| ** (Bit 0 is for main, bit 1 is for temp, and so forth.) Bits are
|
| ** set for each database that is used. Generate code to start a
|
| ** transaction on each used database and to verify the schema cookie
|
| ** on each used database.
|
| */
|
| - if( pParse->cookieGoto>0 ){
|
| - yDbMask mask;
|
| - int iDb;
|
| - sqlite3VdbeJumpHere(v, pParse->cookieGoto-1);
|
| - for(iDb=0, mask=1; iDb<db->nDb; mask<<=1, iDb++){
|
| - if( (mask & pParse->cookieMask)==0 ) continue;
|
| + if( db->mallocFailed==0
|
| + && (DbMaskNonZero(pParse->cookieMask) || pParse->pConstExpr)
|
| + ){
|
| + int iDb, i;
|
| + assert( sqlite3VdbeGetOp(v, 0)->opcode==OP_Init );
|
| + sqlite3VdbeJumpHere(v, 0);
|
| + for(iDb=0; iDb<db->nDb; iDb++){
|
| + if( DbMaskTest(pParse->cookieMask, iDb)==0 ) continue;
|
| sqlite3VdbeUsesBtree(v, iDb);
|
| - sqlite3VdbeAddOp2(v,OP_Transaction, iDb, (mask & pParse->writeMask)!=0);
|
| - if( db->init.busy==0 ){
|
| - assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
|
| - sqlite3VdbeAddOp3(v, OP_VerifyCookie,
|
| - iDb, pParse->cookieValue[iDb],
|
| - db->aDb[iDb].pSchema->iGeneration);
|
| - }
|
| + sqlite3VdbeAddOp4Int(v,
|
| + OP_Transaction, /* Opcode */
|
| + iDb, /* P1 */
|
| + DbMaskTest(pParse->writeMask,iDb), /* P2 */
|
| + pParse->cookieValue[iDb], /* P3 */
|
| + db->aDb[iDb].pSchema->iGeneration /* P4 */
|
| + );
|
| + if( db->init.busy==0 ) sqlite3VdbeChangeP5(v, 1);
|
| }
|
| #ifndef SQLITE_OMIT_VIRTUALTABLE
|
| - {
|
| - int i;
|
| - for(i=0; i<pParse->nVtabLock; i++){
|
| - char *vtab = (char *)sqlite3GetVTable(db, pParse->apVtabLock[i]);
|
| - sqlite3VdbeAddOp4(v, OP_VBegin, 0, 0, 0, vtab, P4_VTAB);
|
| - }
|
| - pParse->nVtabLock = 0;
|
| + for(i=0; i<pParse->nVtabLock; i++){
|
| + char *vtab = (char *)sqlite3GetVTable(db, pParse->apVtabLock[i]);
|
| + sqlite3VdbeAddOp4(v, OP_VBegin, 0, 0, 0, vtab, P4_VTAB);
|
| }
|
| + pParse->nVtabLock = 0;
|
| #endif
|
|
|
| /* Once all the cookies have been verified and transactions opened,
|
| @@ -183,8 +209,17 @@ void sqlite3FinishCoding(Parse *pParse){
|
| */
|
| sqlite3AutoincrementBegin(pParse);
|
|
|
| + /* Code constant expressions that where factored out of inner loops */
|
| + if( pParse->pConstExpr ){
|
| + ExprList *pEL = pParse->pConstExpr;
|
| + pParse->okConstFactor = 0;
|
| + for(i=0; i<pEL->nExpr; i++){
|
| + sqlite3ExprCode(pParse, pEL->a[i].pExpr, pEL->a[i].u.iConstExprReg);
|
| + }
|
| + }
|
| +
|
| /* Finally, jump back to the beginning of the executable code. */
|
| - sqlite3VdbeAddOp2(v, OP_Goto, 0, pParse->cookieGoto);
|
| + sqlite3VdbeAddOp2(v, OP_Goto, 0, 1);
|
| }
|
| }
|
|
|
| @@ -192,17 +227,11 @@ void sqlite3FinishCoding(Parse *pParse){
|
| /* Get the VDBE program ready for execution
|
| */
|
| if( v && ALWAYS(pParse->nErr==0) && !db->mallocFailed ){
|
| -#ifdef SQLITE_DEBUG
|
| - FILE *trace = (db->flags & SQLITE_VdbeTrace)!=0 ? stdout : 0;
|
| - sqlite3VdbeTrace(v, trace);
|
| -#endif
|
| assert( pParse->iCacheLevel==0 ); /* Disables and re-enables match */
|
| /* A minimum of one cursor is required if autoincrement is used
|
| * See ticket [a696379c1f08866] */
|
| if( pParse->pAinc!=0 && pParse->nTab==0 ) pParse->nTab = 1;
|
| - sqlite3VdbeMakeReady(v, pParse->nVar, pParse->nMem,
|
| - pParse->nTab, pParse->nMaxArg, pParse->explain,
|
| - pParse->isMultiWrite && pParse->mayAbort);
|
| + sqlite3VdbeMakeReady(v, pParse);
|
| pParse->rc = SQLITE_DONE;
|
| pParse->colNamesSet = 0;
|
| }else{
|
| @@ -212,8 +241,7 @@ void sqlite3FinishCoding(Parse *pParse){
|
| pParse->nMem = 0;
|
| pParse->nSet = 0;
|
| pParse->nVar = 0;
|
| - pParse->cookieMask = 0;
|
| - pParse->cookieGoto = 0;
|
| + DbMaskZero(pParse->cookieMask);
|
| }
|
|
|
| /*
|
| @@ -254,6 +282,16 @@ void sqlite3NestedParse(Parse *pParse, const char *zFormat, ...){
|
| pParse->nested--;
|
| }
|
|
|
| +#if SQLITE_USER_AUTHENTICATION
|
| +/*
|
| +** Return TRUE if zTable is the name of the system table that stores the
|
| +** list of users and their access credentials.
|
| +*/
|
| +int sqlite3UserAuthTable(const char *zTable){
|
| + return sqlite3_stricmp(zTable, "sqlite_user")==0;
|
| +}
|
| +#endif
|
| +
|
| /*
|
| ** Locate the in-memory structure that describes a particular database
|
| ** table given the name of that table and (optionally) the name of the
|
| @@ -269,16 +307,21 @@ void sqlite3NestedParse(Parse *pParse, const char *zFormat, ...){
|
| Table *sqlite3FindTable(sqlite3 *db, const char *zName, const char *zDatabase){
|
| Table *p = 0;
|
| int i;
|
| - int nName;
|
| assert( zName!=0 );
|
| - nName = sqlite3Strlen30(zName);
|
| /* All mutexes are required for schema access. Make sure we hold them. */
|
| assert( zDatabase!=0 || sqlite3BtreeHoldsAllMutexes(db) );
|
| +#if SQLITE_USER_AUTHENTICATION
|
| + /* Only the admin user is allowed to know that the sqlite_user table
|
| + ** exists */
|
| + if( db->auth.authLevel<UAUTH_Admin && sqlite3UserAuthTable(zName)!=0 ){
|
| + return 0;
|
| + }
|
| +#endif
|
| 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;
|
| assert( sqlite3SchemaMutexHeld(db, j, 0) );
|
| - p = sqlite3HashFind(&db->aDb[j].pSchema->tblHash, zName, nName);
|
| + p = sqlite3HashFind(&db->aDb[j].pSchema->tblHash, zName);
|
| if( p ) break;
|
| }
|
| return p;
|
| @@ -318,10 +361,41 @@ Table *sqlite3LocateTable(
|
| }
|
| pParse->checkSchema = 1;
|
| }
|
| +#if SQLITE_USER_AUTHENICATION
|
| + else if( pParse->db->auth.authLevel<UAUTH_User ){
|
| + sqlite3ErrorMsg(pParse, "user not authenticated");
|
| + p = 0;
|
| + }
|
| +#endif
|
| return p;
|
| }
|
|
|
| /*
|
| +** Locate the table identified by *p.
|
| +**
|
| +** This is a wrapper around sqlite3LocateTable(). The difference between
|
| +** sqlite3LocateTable() and this function is that this function restricts
|
| +** the search to schema (p->pSchema) if it is not NULL. p->pSchema may be
|
| +** non-NULL if it is part of a view or trigger program definition. See
|
| +** sqlite3FixSrcList() for details.
|
| +*/
|
| +Table *sqlite3LocateTableItem(
|
| + Parse *pParse,
|
| + int isView,
|
| + struct SrcList_item *p
|
| +){
|
| + const char *zDb;
|
| + assert( p->pSchema==0 || p->zDatabase==0 );
|
| + if( p->pSchema ){
|
| + int iDb = sqlite3SchemaToIndex(pParse->db, p->pSchema);
|
| + zDb = pParse->db->aDb[iDb].zName;
|
| + }else{
|
| + zDb = p->zDatabase;
|
| + }
|
| + return sqlite3LocateTable(pParse, isView, p->zName, zDb);
|
| +}
|
| +
|
| +/*
|
| ** Locate the in-memory structure that describes
|
| ** a particular index given the name of that index
|
| ** and the name of the database that contains the index.
|
| @@ -336,7 +410,6 @@ Table *sqlite3LocateTable(
|
| Index *sqlite3FindIndex(sqlite3 *db, const char *zName, const char *zDb){
|
| Index *p = 0;
|
| int i;
|
| - int nName = sqlite3Strlen30(zName);
|
| /* All mutexes are required for schema access. Make sure we hold them. */
|
| assert( zDb!=0 || sqlite3BtreeHoldsAllMutexes(db) );
|
| for(i=OMIT_TEMPDB; i<db->nDb; i++){
|
| @@ -345,7 +418,7 @@ Index *sqlite3FindIndex(sqlite3 *db, const char *zName, const char *zDb){
|
| assert( pSchema );
|
| if( zDb && sqlite3StrICmp(zDb, db->aDb[j].zName) ) continue;
|
| assert( sqlite3SchemaMutexHeld(db, j, 0) );
|
| - p = sqlite3HashFind(&pSchema->idxHash, zName, nName);
|
| + p = sqlite3HashFind(&pSchema->idxHash, zName);
|
| if( p ) break;
|
| }
|
| return p;
|
| @@ -358,7 +431,13 @@ static void freeIndex(sqlite3 *db, Index *p){
|
| #ifndef SQLITE_OMIT_ANALYZE
|
| sqlite3DeleteIndexSamples(db, p);
|
| #endif
|
| + if( db==0 || db->pnBytesFreed==0 ) sqlite3KeyInfoUnref(p->pKeyInfo);
|
| + sqlite3ExprDelete(db, p->pPartIdxWhere);
|
| sqlite3DbFree(db, p->zColAff);
|
| + if( p->isResized ) sqlite3DbFree(db, p->azColl);
|
| +#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
| + sqlite3_free(p->aiRowEst);
|
| +#endif
|
| sqlite3DbFree(db, p);
|
| }
|
|
|
| @@ -370,13 +449,11 @@ static void freeIndex(sqlite3 *db, Index *p){
|
| */
|
| void sqlite3UnlinkAndDeleteIndex(sqlite3 *db, int iDb, const char *zIdxName){
|
| Index *pIndex;
|
| - int len;
|
| Hash *pHash;
|
|
|
| assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
|
| pHash = &db->aDb[iDb].pSchema->idxHash;
|
| - len = sqlite3Strlen30(zIdxName);
|
| - pIndex = sqlite3HashInsert(pHash, zIdxName, len, 0);
|
| + pIndex = sqlite3HashInsert(pHash, zIdxName, 0);
|
| if( ALWAYS(pIndex) ){
|
| if( pIndex->pTable->pIndex==pIndex ){
|
| pIndex->pTable->pIndex = pIndex->pNext;
|
| @@ -396,58 +473,15 @@ void sqlite3UnlinkAndDeleteIndex(sqlite3 *db, int iDb, const char *zIdxName){
|
| }
|
|
|
| /*
|
| -** Erase all schema information from the in-memory hash tables of
|
| -** a single database. This routine is called to reclaim memory
|
| -** before the database closes. It is also called during a rollback
|
| -** if there were schema changes during the transaction or if a
|
| -** schema-cookie mismatch occurs.
|
| +** Look through the list of open database files in db->aDb[] and if
|
| +** any have been closed, remove them from the list. Reallocate the
|
| +** db->aDb[] structure to a smaller size, if possible.
|
| **
|
| -** If iDb<0 then reset the internal schema tables for all database
|
| -** files. If iDb>=0 then reset the internal schema for only the
|
| -** single file indicated.
|
| +** Entry 0 (the "main" database) and entry 1 (the "temp" database)
|
| +** are never candidates for being collapsed.
|
| */
|
| -void sqlite3ResetInternalSchema(sqlite3 *db, int iDb){
|
| +void sqlite3CollapseDatabaseArray(sqlite3 *db){
|
| int i, j;
|
| - assert( iDb<db->nDb );
|
| -
|
| - if( iDb>=0 ){
|
| - /* Case 1: Reset the single schema identified by iDb */
|
| - Db *pDb = &db->aDb[iDb];
|
| - assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
|
| - assert( pDb->pSchema!=0 );
|
| - sqlite3SchemaClear(pDb->pSchema);
|
| -
|
| - /* If any database other than TEMP is reset, then also reset TEMP
|
| - ** since TEMP might be holding triggers that reference tables in the
|
| - ** other database.
|
| - */
|
| - if( iDb!=1 ){
|
| - pDb = &db->aDb[1];
|
| - assert( pDb->pSchema!=0 );
|
| - sqlite3SchemaClear(pDb->pSchema);
|
| - }
|
| - return;
|
| - }
|
| - /* Case 2 (from here to the end): Reset all schemas for all attached
|
| - ** databases. */
|
| - assert( iDb<0 );
|
| - sqlite3BtreeEnterAll(db);
|
| - for(i=0; i<db->nDb; i++){
|
| - Db *pDb = &db->aDb[i];
|
| - if( pDb->pSchema ){
|
| - sqlite3SchemaClear(pDb->pSchema);
|
| - }
|
| - }
|
| - db->flags &= ~SQLITE_InternChanges;
|
| - sqlite3VtabUnlockList(db);
|
| - sqlite3BtreeLeaveAll(db);
|
| -
|
| - /* If one or more of the auxiliary database files has been closed,
|
| - ** 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.
|
| - */
|
| for(i=j=2; i<db->nDb; i++){
|
| struct Db *pDb = &db->aDb[i];
|
| if( pDb->pBt==0 ){
|
| @@ -470,6 +504,51 @@ void sqlite3ResetInternalSchema(sqlite3 *db, int iDb){
|
| }
|
|
|
| /*
|
| +** Reset the schema for the database at index iDb. Also reset the
|
| +** TEMP schema.
|
| +*/
|
| +void sqlite3ResetOneSchema(sqlite3 *db, int iDb){
|
| + Db *pDb;
|
| + assert( iDb<db->nDb );
|
| +
|
| + /* Case 1: Reset the single schema identified by iDb */
|
| + pDb = &db->aDb[iDb];
|
| + assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
|
| + assert( pDb->pSchema!=0 );
|
| + sqlite3SchemaClear(pDb->pSchema);
|
| +
|
| + /* If any database other than TEMP is reset, then also reset TEMP
|
| + ** since TEMP might be holding triggers that reference tables in the
|
| + ** other database.
|
| + */
|
| + if( iDb!=1 ){
|
| + pDb = &db->aDb[1];
|
| + assert( pDb->pSchema!=0 );
|
| + sqlite3SchemaClear(pDb->pSchema);
|
| + }
|
| + return;
|
| +}
|
| +
|
| +/*
|
| +** Erase all schema information from all attached databases (including
|
| +** "main" and "temp") for a single database connection.
|
| +*/
|
| +void sqlite3ResetAllSchemasOfConnection(sqlite3 *db){
|
| + int i;
|
| + sqlite3BtreeEnterAll(db);
|
| + for(i=0; i<db->nDb; i++){
|
| + Db *pDb = &db->aDb[i];
|
| + if( pDb->pSchema ){
|
| + sqlite3SchemaClear(pDb->pSchema);
|
| + }
|
| + }
|
| + db->flags &= ~SQLITE_InternChanges;
|
| + sqlite3VtabUnlockList(db);
|
| + sqlite3BtreeLeaveAll(db);
|
| + sqlite3CollapseDatabaseArray(db);
|
| +}
|
| +
|
| +/*
|
| ** This routine is called when a commit occurs.
|
| */
|
| void sqlite3CommitInternalChanges(sqlite3 *db){
|
| @@ -504,9 +583,16 @@ static void sqliteDeleteColumnNames(sqlite3 *db, Table *pTable){
|
| ** the table data structure from the hash table. But it does destroy
|
| ** memory structures of the indices and foreign keys associated with
|
| ** the table.
|
| +**
|
| +** The db parameter is optional. It is needed if the Table object
|
| +** contains lookaside memory. (Table objects in the schema do not use
|
| +** lookaside memory, but some ephemeral Table objects do.) Or the
|
| +** db parameter can be used with db->pnBytesFreed to measure the memory
|
| +** used by the Table object.
|
| */
|
| void sqlite3DeleteTable(sqlite3 *db, Table *pTable){
|
| Index *pIndex, *pNext;
|
| + TESTONLY( int nLookaside; ) /* Used to verify lookaside not used for schema */
|
|
|
| assert( !pTable || pTable->nRef>0 );
|
|
|
| @@ -514,6 +600,12 @@ void sqlite3DeleteTable(sqlite3 *db, Table *pTable){
|
| if( !pTable ) return;
|
| if( ((!db || db->pnBytesFreed==0) && (--pTable->nRef)>0) ) return;
|
|
|
| + /* Record the number of outstanding lookaside allocations in schema Tables
|
| + ** prior to doing any free() operations. Since schema Tables do not use
|
| + ** lookaside, this number should not change. */
|
| + TESTONLY( nLookaside = (db && (pTable->tabFlags & TF_Ephemeral)==0) ?
|
| + db->lookaside.nOut : 0 );
|
| +
|
| /* Delete all indices associated with this table. */
|
| for(pIndex = pTable->pIndex; pIndex; pIndex=pNext){
|
| pNext = pIndex->pNext;
|
| @@ -521,7 +613,7 @@ void sqlite3DeleteTable(sqlite3 *db, Table *pTable){
|
| if( !db || db->pnBytesFreed==0 ){
|
| char *zName = pIndex->zName;
|
| TESTONLY ( Index *pOld = ) sqlite3HashInsert(
|
| - &pIndex->pSchema->idxHash, zName, sqlite3Strlen30(zName), 0
|
| + &pIndex->pSchema->idxHash, zName, 0
|
| );
|
| assert( db==0 || sqlite3SchemaMutexHeld(db, 0, pIndex->pSchema) );
|
| assert( pOld==pIndex || pOld==0 );
|
| @@ -539,12 +631,15 @@ void sqlite3DeleteTable(sqlite3 *db, Table *pTable){
|
| sqlite3DbFree(db, pTable->zColAff);
|
| sqlite3SelectDelete(db, pTable->pSelect);
|
| #ifndef SQLITE_OMIT_CHECK
|
| - sqlite3ExprDelete(db, pTable->pCheck);
|
| + sqlite3ExprListDelete(db, pTable->pCheck);
|
| #endif
|
| #ifndef SQLITE_OMIT_VIRTUALTABLE
|
| sqlite3VtabClear(db, pTable);
|
| #endif
|
| sqlite3DbFree(db, pTable);
|
| +
|
| + /* Verify that no lookaside memory was used by schema tables */
|
| + assert( nLookaside==0 || nLookaside==db->lookaside.nOut );
|
| }
|
|
|
| /*
|
| @@ -561,8 +656,7 @@ void sqlite3UnlinkAndDeleteTable(sqlite3 *db, int iDb, const char *zTabName){
|
| assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
|
| testcase( zTabName[0]==0 ); /* Zero-length table names are allowed */
|
| pDb = &db->aDb[iDb];
|
| - p = sqlite3HashInsert(&pDb->pSchema->tblHash, zTabName,
|
| - sqlite3Strlen30(zTabName),0);
|
| + p = sqlite3HashInsert(&pDb->pSchema->tblHash, zTabName, 0);
|
| sqlite3DeleteTable(db, p);
|
| db->flags |= SQLITE_InternChanges;
|
| }
|
| @@ -598,8 +692,7 @@ char *sqlite3NameFromToken(sqlite3 *db, Token *pName){
|
| void sqlite3OpenMasterTable(Parse *p, int iDb){
|
| Vdbe *v = sqlite3GetVdbe(p);
|
| sqlite3TableLock(p, iDb, MASTER_ROOT, 1, SCHEMA_TABLE(iDb));
|
| - sqlite3VdbeAddOp3(v, OP_OpenWrite, 0, MASTER_ROOT, iDb);
|
| - sqlite3VdbeChangeP4(v, -1, (char *)5, P4_INT32); /* 5 column table */
|
| + sqlite3VdbeAddOp4Int(v, OP_OpenWrite, 0, MASTER_ROOT, iDb, 5);
|
| if( p->nTab==0 ){
|
| p->nTab = 1;
|
| }
|
| @@ -705,6 +798,27 @@ int sqlite3CheckObjectName(Parse *pParse, const char *zName){
|
| }
|
|
|
| /*
|
| +** Return the PRIMARY KEY index of a table
|
| +*/
|
| +Index *sqlite3PrimaryKeyIndex(Table *pTab){
|
| + Index *p;
|
| + for(p=pTab->pIndex; p && !IsPrimaryKeyIndex(p); p=p->pNext){}
|
| + return p;
|
| +}
|
| +
|
| +/*
|
| +** Return the column of index pIdx that corresponds to table
|
| +** column iCol. Return -1 if not found.
|
| +*/
|
| +i16 sqlite3ColumnOfIndex(Index *pIdx, i16 iCol){
|
| + int i;
|
| + for(i=0; i<pIdx->nColumn; i++){
|
| + if( iCol==pIdx->aiColumn[i] ) return i;
|
| + }
|
| + return -1;
|
| +}
|
| +
|
| +/*
|
| ** 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
|
| @@ -836,7 +950,7 @@ void sqlite3StartTable(
|
| pTable->iPKey = -1;
|
| pTable->pSchema = db->aDb[iDb].pSchema;
|
| pTable->nRef = 1;
|
| - pTable->nRowEst = 1000000;
|
| + pTable->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) );
|
| assert( pParse->pNewTable==0 );
|
| pParse->pNewTable = pTable;
|
|
|
| @@ -879,7 +993,7 @@ void sqlite3StartTable(
|
| reg3 = ++pParse->nMem;
|
| sqlite3VdbeAddOp3(v, OP_ReadCookie, iDb, reg3, BTREE_FILE_FORMAT);
|
| sqlite3VdbeUsesBtree(v, iDb);
|
| - j1 = sqlite3VdbeAddOp1(v, OP_If, reg3);
|
| + j1 = sqlite3VdbeAddOp1(v, OP_If, reg3); VdbeCoverage(v);
|
| fileFormat = (db->flags & SQLITE_LegacyFileFmt)!=0 ?
|
| 1 : SQLITE_MAX_FILE_FORMAT;
|
| sqlite3VdbeAddOp2(v, OP_Integer, fileFormat, reg3);
|
| @@ -903,7 +1017,7 @@ void sqlite3StartTable(
|
| }else
|
| #endif
|
| {
|
| - sqlite3VdbeAddOp2(v, OP_CreateTable, iDb, reg2);
|
| + pParse->addrCrTab = sqlite3VdbeAddOp2(v, OP_CreateTable, iDb, reg2);
|
| }
|
| sqlite3OpenMasterTable(pParse, iDb);
|
| sqlite3VdbeAddOp2(v, OP_NewRowid, 0, reg1);
|
| @@ -983,6 +1097,7 @@ void sqlite3AddColumn(Parse *pParse, Token *pName){
|
| ** be called next to set pCol->affinity correctly.
|
| */
|
| pCol->affinity = SQLITE_AFF_NONE;
|
| + pCol->szEst = 1;
|
| p->nCol++;
|
| }
|
|
|
| @@ -1024,15 +1139,18 @@ void sqlite3AddNotNull(Parse *pParse, int onError){
|
| ** If none of the substrings in the above table are found,
|
| ** SQLITE_AFF_NUMERIC is returned.
|
| */
|
| -char sqlite3AffinityType(const char *zIn){
|
| +char sqlite3AffinityType(const char *zIn, u8 *pszEst){
|
| u32 h = 0;
|
| char aff = SQLITE_AFF_NUMERIC;
|
| + const char *zChar = 0;
|
|
|
| - if( zIn ) while( zIn[0] ){
|
| + if( zIn==0 ) return aff;
|
| + while( zIn[0] ){
|
| h = (h<<8) + sqlite3UpperToLower[(*zIn)&0xff];
|
| zIn++;
|
| if( h==(('c'<<24)+('h'<<16)+('a'<<8)+'r') ){ /* CHAR */
|
| - aff = SQLITE_AFF_TEXT;
|
| + aff = SQLITE_AFF_TEXT;
|
| + zChar = zIn;
|
| }else if( h==(('c'<<24)+('l'<<16)+('o'<<8)+'b') ){ /* CLOB */
|
| aff = SQLITE_AFF_TEXT;
|
| }else if( h==(('t'<<24)+('e'<<16)+('x'<<8)+'t') ){ /* TEXT */
|
| @@ -1040,6 +1158,7 @@ char sqlite3AffinityType(const char *zIn){
|
| }else if( h==(('b'<<24)+('l'<<16)+('o'<<8)+'b') /* BLOB */
|
| && (aff==SQLITE_AFF_NUMERIC || aff==SQLITE_AFF_REAL) ){
|
| aff = SQLITE_AFF_NONE;
|
| + if( zIn[0]=='(' ) zChar = zIn;
|
| #ifndef SQLITE_OMIT_FLOATING_POINT
|
| }else if( h==(('r'<<24)+('e'<<16)+('a'<<8)+'l') /* REAL */
|
| && aff==SQLITE_AFF_NUMERIC ){
|
| @@ -1057,6 +1176,28 @@ char sqlite3AffinityType(const char *zIn){
|
| }
|
| }
|
|
|
| + /* If pszEst is not NULL, store an estimate of the field size. The
|
| + ** estimate is scaled so that the size of an integer is 1. */
|
| + if( pszEst ){
|
| + *pszEst = 1; /* default size is approx 4 bytes */
|
| + if( aff<SQLITE_AFF_NUMERIC ){
|
| + if( zChar ){
|
| + while( zChar[0] ){
|
| + if( sqlite3Isdigit(zChar[0]) ){
|
| + int v = 0;
|
| + sqlite3GetInt32(zChar, &v);
|
| + v = v/4 + 1;
|
| + if( v>255 ) v = 255;
|
| + *pszEst = v; /* BLOB(k), VARCHAR(k), CHAR(k) -> r=(k/4+1) */
|
| + break;
|
| + }
|
| + zChar++;
|
| + }
|
| + }else{
|
| + *pszEst = 5; /* BLOB, TEXT, CLOB -> r=5 (approx 20 bytes)*/
|
| + }
|
| + }
|
| + }
|
| return aff;
|
| }
|
|
|
| @@ -1078,7 +1219,7 @@ void sqlite3AddColumnType(Parse *pParse, Token *pType){
|
| pCol = &p->aCol[p->nCol-1];
|
| assert( pCol->zType==0 );
|
| pCol->zType = sqlite3NameFromToken(pParse->db, pType);
|
| - pCol->affinity = sqlite3AffinityType(pCol->zType);
|
| + pCol->affinity = sqlite3AffinityType(pCol->zType, &pCol->szEst);
|
| }
|
|
|
| /*
|
| @@ -1098,7 +1239,7 @@ void sqlite3AddDefaultValue(Parse *pParse, ExprSpan *pSpan){
|
| p = pParse->pNewTable;
|
| if( p!=0 ){
|
| pCol = &(p->aCol[p->nCol-1]);
|
| - if( !sqlite3ExprIsConstantOrFunction(pSpan->pExpr) ){
|
| + if( !sqlite3ExprIsConstantOrFunction(pSpan->pExpr, db->init.busy) ){
|
| sqlite3ErrorMsg(pParse, "default value of column [%s] is not constant",
|
| pCol->zName);
|
| }else{
|
| @@ -1144,6 +1285,7 @@ void sqlite3AddPrimaryKey(
|
| Table *pTab = pParse->pNewTable;
|
| char *zType = 0;
|
| int iCol = -1, i;
|
| + int nTerm;
|
| if( pTab==0 || IN_DECLARE_VTAB ) goto primary_key_exit;
|
| if( pTab->tabFlags & TF_HasPrimaryKey ){
|
| sqlite3ErrorMsg(pParse,
|
| @@ -1153,39 +1295,44 @@ void sqlite3AddPrimaryKey(
|
| pTab->tabFlags |= TF_HasPrimaryKey;
|
| if( pList==0 ){
|
| iCol = pTab->nCol - 1;
|
| - pTab->aCol[iCol].isPrimKey = 1;
|
| + pTab->aCol[iCol].colFlags |= COLFLAG_PRIMKEY;
|
| + zType = pTab->aCol[iCol].zType;
|
| + nTerm = 1;
|
| }else{
|
| - for(i=0; i<pList->nExpr; i++){
|
| + nTerm = pList->nExpr;
|
| + for(i=0; i<nTerm; i++){
|
| for(iCol=0; iCol<pTab->nCol; iCol++){
|
| if( sqlite3StrICmp(pList->a[i].zName, pTab->aCol[iCol].zName)==0 ){
|
| + pTab->aCol[iCol].colFlags |= COLFLAG_PRIMKEY;
|
| + zType = pTab->aCol[iCol].zType;
|
| break;
|
| }
|
| }
|
| - if( iCol<pTab->nCol ){
|
| - pTab->aCol[iCol].isPrimKey = 1;
|
| - }
|
| }
|
| - if( pList->nExpr>1 ) iCol = -1;
|
| }
|
| - if( iCol>=0 && iCol<pTab->nCol ){
|
| - zType = pTab->aCol[iCol].zType;
|
| - }
|
| - if( zType && sqlite3StrICmp(zType, "INTEGER")==0
|
| - && sortOrder==SQLITE_SO_ASC ){
|
| + if( nTerm==1
|
| + && zType && sqlite3StrICmp(zType, "INTEGER")==0
|
| + && sortOrder==SQLITE_SO_ASC
|
| + ){
|
| pTab->iPKey = iCol;
|
| pTab->keyConf = (u8)onError;
|
| assert( autoInc==0 || autoInc==1 );
|
| pTab->tabFlags |= autoInc*TF_Autoincrement;
|
| + if( pList ) pParse->iPkSortOrder = pList->a[0].sortOrder;
|
| }else if( autoInc ){
|
| #ifndef SQLITE_OMIT_AUTOINCREMENT
|
| sqlite3ErrorMsg(pParse, "AUTOINCREMENT is only allowed on an "
|
| "INTEGER PRIMARY KEY");
|
| #endif
|
| }else{
|
| + Vdbe *v = pParse->pVdbe;
|
| Index *p;
|
| - p = sqlite3CreateIndex(pParse, 0, 0, 0, pList, onError, 0, 0, sortOrder, 0);
|
| + if( v ) pParse->addrSkipPK = sqlite3VdbeAddOp0(v, OP_Noop);
|
| + p = sqlite3CreateIndex(pParse, 0, 0, 0, pList, onError, 0,
|
| + 0, sortOrder, 0);
|
| if( p ){
|
| - p->autoIndex = 2;
|
| + p->idxType = SQLITE_IDXTYPE_PRIMARYKEY;
|
| + if( v ) sqlite3VdbeJumpHere(v, pParse->addrSkipPK);
|
| }
|
| pList = 0;
|
| }
|
| @@ -1202,15 +1349,20 @@ void sqlite3AddCheckConstraint(
|
| Parse *pParse, /* Parsing context */
|
| Expr *pCheckExpr /* The check expression */
|
| ){
|
| - sqlite3 *db = pParse->db;
|
| #ifndef SQLITE_OMIT_CHECK
|
| Table *pTab = pParse->pNewTable;
|
| - if( pTab && !IN_DECLARE_VTAB ){
|
| - pTab->pCheck = sqlite3ExprAnd(db, pTab->pCheck, pCheckExpr);
|
| + sqlite3 *db = pParse->db;
|
| + if( pTab && !IN_DECLARE_VTAB
|
| + && !sqlite3BtreeIsReadonly(db->aDb[db->init.iDb].pBt)
|
| + ){
|
| + pTab->pCheck = sqlite3ExprListAppend(pParse, pTab->pCheck, pCheckExpr);
|
| + if( pParse->constraintName.n ){
|
| + sqlite3ExprListSetName(pParse, pTab->pCheck, &pParse->constraintName, 1);
|
| + }
|
| }else
|
| #endif
|
| {
|
| - sqlite3ExprDelete(db, pCheckExpr);
|
| + sqlite3ExprDelete(pParse->db, pCheckExpr);
|
| }
|
| }
|
|
|
| @@ -1232,6 +1384,7 @@ void sqlite3AddCollateType(Parse *pParse, Token *pToken){
|
|
|
| if( sqlite3LocateCollSeq(pParse, zColl) ){
|
| Index *pIdx;
|
| + sqlite3DbFree(db, p->aCol[i].zColl);
|
| p->aCol[i].zColl = zColl;
|
|
|
| /* If the column is declared as "<name> PRIMARY KEY COLLATE <type>",
|
| @@ -1239,7 +1392,7 @@ void sqlite3AddCollateType(Parse *pParse, Token *pToken){
|
| ** collation type was added. Correct this if it is the case.
|
| */
|
| for(pIdx=p->pIndex; pIdx; pIdx=pIdx->pNext){
|
| - assert( pIdx->nColumn==1 );
|
| + assert( pIdx->nKeyCol==1 );
|
| if( pIdx->aiColumn[0]==i ){
|
| pIdx->azColl[0] = p->aCol[i].zColl;
|
| }
|
| @@ -1277,10 +1430,7 @@ CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char *zName){
|
|
|
| pColl = sqlite3FindCollSeq(db, enc, zName, initbusy);
|
| if( !initbusy && (!pColl || !pColl->xCmp) ){
|
| - pColl = sqlite3GetCollSeq(db, enc, pColl, zName);
|
| - if( !pColl ){
|
| - sqlite3ErrorMsg(pParse, "no such collation sequence: %s", zName);
|
| - }
|
| + pColl = sqlite3GetCollSeq(pParse, enc, pColl, zName);
|
| }
|
|
|
| return pColl;
|
| @@ -1350,10 +1500,10 @@ static void identPut(char *z, int *pIdx, char *zSignedIdent){
|
| for(j=0; zIdent[j]; j++){
|
| if( !sqlite3Isalnum(zIdent[j]) && zIdent[j]!='_' ) break;
|
| }
|
| - needQuote = sqlite3Isdigit(zIdent[0]) || sqlite3KeywordCode(zIdent, j)!=TK_ID;
|
| - if( !needQuote ){
|
| - needQuote = zIdent[j];
|
| - }
|
| + needQuote = sqlite3Isdigit(zIdent[0])
|
| + || sqlite3KeywordCode(zIdent, j)!=TK_ID
|
| + || zIdent[j]!=0
|
| + || j==0;
|
|
|
| if( needQuote ) z[i++] = '"';
|
| for(j=0; zIdent[j]; j++){
|
| @@ -1401,8 +1551,8 @@ static char *createTableStmt(sqlite3 *db, Table *p){
|
| zStmt[k++] = '(';
|
| for(pCol=p->aCol, i=0; i<p->nCol; i++, pCol++){
|
| static const char * const azType[] = {
|
| - /* SQLITE_AFF_TEXT */ " TEXT",
|
| /* SQLITE_AFF_NONE */ "",
|
| + /* SQLITE_AFF_TEXT */ " TEXT",
|
| /* SQLITE_AFF_NUMERIC */ " NUM",
|
| /* SQLITE_AFF_INTEGER */ " INT",
|
| /* SQLITE_AFF_REAL */ " REAL"
|
| @@ -1414,18 +1564,18 @@ static char *createTableStmt(sqlite3 *db, Table *p){
|
| k += sqlite3Strlen30(&zStmt[k]);
|
| zSep = zSep2;
|
| identPut(zStmt, &k, pCol->zName);
|
| - assert( pCol->affinity-SQLITE_AFF_TEXT >= 0 );
|
| - assert( pCol->affinity-SQLITE_AFF_TEXT < ArraySize(azType) );
|
| - testcase( pCol->affinity==SQLITE_AFF_TEXT );
|
| + assert( pCol->affinity-SQLITE_AFF_NONE >= 0 );
|
| + assert( pCol->affinity-SQLITE_AFF_NONE < ArraySize(azType) );
|
| testcase( pCol->affinity==SQLITE_AFF_NONE );
|
| + testcase( pCol->affinity==SQLITE_AFF_TEXT );
|
| testcase( pCol->affinity==SQLITE_AFF_NUMERIC );
|
| testcase( pCol->affinity==SQLITE_AFF_INTEGER );
|
| testcase( pCol->affinity==SQLITE_AFF_REAL );
|
|
|
| - zType = azType[pCol->affinity - SQLITE_AFF_TEXT];
|
| + zType = azType[pCol->affinity - SQLITE_AFF_NONE];
|
| len = sqlite3Strlen30(zType);
|
| assert( pCol->affinity==SQLITE_AFF_NONE
|
| - || pCol->affinity==sqlite3AffinityType(zType) );
|
| + || pCol->affinity==sqlite3AffinityType(zType, 0) );
|
| memcpy(&zStmt[k], zType, len);
|
| k += len;
|
| assert( k<=n );
|
| @@ -1435,6 +1585,191 @@ static char *createTableStmt(sqlite3 *db, Table *p){
|
| }
|
|
|
| /*
|
| +** Resize an Index object to hold N columns total. Return SQLITE_OK
|
| +** on success and SQLITE_NOMEM on an OOM error.
|
| +*/
|
| +static int resizeIndexObject(sqlite3 *db, Index *pIdx, int N){
|
| + char *zExtra;
|
| + int nByte;
|
| + if( pIdx->nColumn>=N ) return SQLITE_OK;
|
| + assert( pIdx->isResized==0 );
|
| + nByte = (sizeof(char*) + sizeof(i16) + 1)*N;
|
| + zExtra = sqlite3DbMallocZero(db, nByte);
|
| + if( zExtra==0 ) return SQLITE_NOMEM;
|
| + memcpy(zExtra, pIdx->azColl, sizeof(char*)*pIdx->nColumn);
|
| + pIdx->azColl = (char**)zExtra;
|
| + zExtra += sizeof(char*)*N;
|
| + memcpy(zExtra, pIdx->aiColumn, sizeof(i16)*pIdx->nColumn);
|
| + pIdx->aiColumn = (i16*)zExtra;
|
| + zExtra += sizeof(i16)*N;
|
| + memcpy(zExtra, pIdx->aSortOrder, pIdx->nColumn);
|
| + pIdx->aSortOrder = (u8*)zExtra;
|
| + pIdx->nColumn = N;
|
| + pIdx->isResized = 1;
|
| + return SQLITE_OK;
|
| +}
|
| +
|
| +/*
|
| +** Estimate the total row width for a table.
|
| +*/
|
| +static void estimateTableWidth(Table *pTab){
|
| + unsigned wTable = 0;
|
| + const Column *pTabCol;
|
| + int i;
|
| + for(i=pTab->nCol, pTabCol=pTab->aCol; i>0; i--, pTabCol++){
|
| + wTable += pTabCol->szEst;
|
| + }
|
| + if( pTab->iPKey<0 ) wTable++;
|
| + pTab->szTabRow = sqlite3LogEst(wTable*4);
|
| +}
|
| +
|
| +/*
|
| +** Estimate the average size of a row for an index.
|
| +*/
|
| +static void estimateIndexWidth(Index *pIdx){
|
| + unsigned wIndex = 0;
|
| + int i;
|
| + const Column *aCol = pIdx->pTable->aCol;
|
| + for(i=0; i<pIdx->nColumn; i++){
|
| + i16 x = pIdx->aiColumn[i];
|
| + assert( x<pIdx->pTable->nCol );
|
| + wIndex += x<0 ? 1 : aCol[pIdx->aiColumn[i]].szEst;
|
| + }
|
| + pIdx->szIdxRow = sqlite3LogEst(wIndex*4);
|
| +}
|
| +
|
| +/* Return true if value x is found any of the first nCol entries of aiCol[]
|
| +*/
|
| +static int hasColumn(const i16 *aiCol, int nCol, int x){
|
| + while( nCol-- > 0 ) if( x==*(aiCol++) ) return 1;
|
| + return 0;
|
| +}
|
| +
|
| +/*
|
| +** This routine runs at the end of parsing a CREATE TABLE statement that
|
| +** has a WITHOUT ROWID clause. The job of this routine is to convert both
|
| +** internal schema data structures and the generated VDBE code so that they
|
| +** are appropriate for a WITHOUT ROWID table instead of a rowid table.
|
| +** Changes include:
|
| +**
|
| +** (1) Convert the OP_CreateTable into an OP_CreateIndex. There is
|
| +** no rowid btree for a WITHOUT ROWID. Instead, the canonical
|
| +** data storage is a covering index btree.
|
| +** (2) Bypass the creation of the sqlite_master table entry
|
| +** for the PRIMARY KEY as the primary key index is now
|
| +** identified by the sqlite_master table entry of the table itself.
|
| +** (3) Set the Index.tnum of the PRIMARY KEY Index object in the
|
| +** schema to the rootpage from the main table.
|
| +** (4) Set all columns of the PRIMARY KEY schema object to be NOT NULL.
|
| +** (5) Add all table columns to the PRIMARY KEY Index object
|
| +** so that the PRIMARY KEY is a covering index. The surplus
|
| +** columns are part of KeyInfo.nXField and are not used for
|
| +** sorting or lookup or uniqueness checks.
|
| +** (6) Replace the rowid tail on all automatically generated UNIQUE
|
| +** indices with the PRIMARY KEY columns.
|
| +*/
|
| +static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
|
| + Index *pIdx;
|
| + Index *pPk;
|
| + int nPk;
|
| + int i, j;
|
| + sqlite3 *db = pParse->db;
|
| + Vdbe *v = pParse->pVdbe;
|
| +
|
| + /* Convert the OP_CreateTable opcode that would normally create the
|
| + ** root-page for the table into an OP_CreateIndex opcode. The index
|
| + ** created will become the PRIMARY KEY index.
|
| + */
|
| + if( pParse->addrCrTab ){
|
| + assert( v );
|
| + sqlite3VdbeGetOp(v, pParse->addrCrTab)->opcode = OP_CreateIndex;
|
| + }
|
| +
|
| + /* Bypass the creation of the PRIMARY KEY btree and the sqlite_master
|
| + ** table entry.
|
| + */
|
| + if( pParse->addrSkipPK ){
|
| + assert( v );
|
| + sqlite3VdbeGetOp(v, pParse->addrSkipPK)->opcode = OP_Goto;
|
| + }
|
| +
|
| + /* Locate the PRIMARY KEY index. Or, if this table was originally
|
| + ** an INTEGER PRIMARY KEY table, create a new PRIMARY KEY index.
|
| + */
|
| + if( pTab->iPKey>=0 ){
|
| + ExprList *pList;
|
| + pList = sqlite3ExprListAppend(pParse, 0, 0);
|
| + if( pList==0 ) return;
|
| + pList->a[0].zName = sqlite3DbStrDup(pParse->db,
|
| + pTab->aCol[pTab->iPKey].zName);
|
| + pList->a[0].sortOrder = pParse->iPkSortOrder;
|
| + assert( pParse->pNewTable==pTab );
|
| + pPk = sqlite3CreateIndex(pParse, 0, 0, 0, pList, pTab->keyConf, 0, 0, 0, 0);
|
| + if( pPk==0 ) return;
|
| + pPk->idxType = SQLITE_IDXTYPE_PRIMARYKEY;
|
| + pTab->iPKey = -1;
|
| + }else{
|
| + pPk = sqlite3PrimaryKeyIndex(pTab);
|
| + }
|
| + pPk->isCovering = 1;
|
| + assert( pPk!=0 );
|
| + nPk = pPk->nKeyCol;
|
| +
|
| + /* Make sure every column of the PRIMARY KEY is NOT NULL */
|
| + for(i=0; i<nPk; i++){
|
| + pTab->aCol[pPk->aiColumn[i]].notNull = 1;
|
| + }
|
| + pPk->uniqNotNull = 1;
|
| +
|
| + /* The root page of the PRIMARY KEY is the table root page */
|
| + pPk->tnum = pTab->tnum;
|
| +
|
| + /* Update the in-memory representation of all UNIQUE indices by converting
|
| + ** the final rowid column into one or more columns of the PRIMARY KEY.
|
| + */
|
| + for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
| + int n;
|
| + if( IsPrimaryKeyIndex(pIdx) ) continue;
|
| + for(i=n=0; i<nPk; i++){
|
| + if( !hasColumn(pIdx->aiColumn, pIdx->nKeyCol, pPk->aiColumn[i]) ) n++;
|
| + }
|
| + if( n==0 ){
|
| + /* This index is a superset of the primary key */
|
| + pIdx->nColumn = pIdx->nKeyCol;
|
| + continue;
|
| + }
|
| + if( resizeIndexObject(db, pIdx, pIdx->nKeyCol+n) ) return;
|
| + for(i=0, j=pIdx->nKeyCol; i<nPk; i++){
|
| + if( !hasColumn(pIdx->aiColumn, pIdx->nKeyCol, pPk->aiColumn[i]) ){
|
| + pIdx->aiColumn[j] = pPk->aiColumn[i];
|
| + pIdx->azColl[j] = pPk->azColl[i];
|
| + j++;
|
| + }
|
| + }
|
| + assert( pIdx->nColumn>=pIdx->nKeyCol+n );
|
| + assert( pIdx->nColumn>=j );
|
| + }
|
| +
|
| + /* Add all table columns to the PRIMARY KEY index
|
| + */
|
| + if( nPk<pTab->nCol ){
|
| + if( resizeIndexObject(db, pPk, pTab->nCol) ) return;
|
| + for(i=0, j=nPk; i<pTab->nCol; i++){
|
| + if( !hasColumn(pPk->aiColumn, j, i) ){
|
| + assert( j<pPk->nColumn );
|
| + pPk->aiColumn[j] = i;
|
| + pPk->azColl[j] = "BINARY";
|
| + j++;
|
| + }
|
| + }
|
| + assert( pPk->nColumn==j );
|
| + assert( pTab->nCol==j );
|
| + }else{
|
| + pPk->nColumn = pTab->nCol;
|
| + }
|
| +}
|
| +
|
| +/*
|
| ** This routine is called to report the final ")" that terminates
|
| ** a CREATE TABLE statement.
|
| **
|
| @@ -1457,12 +1792,14 @@ static char *createTableStmt(sqlite3 *db, Table *p){
|
| void sqlite3EndTable(
|
| Parse *pParse, /* Parse context */
|
| Token *pCons, /* The ',' token after the last column defn. */
|
| - Token *pEnd, /* The final ')' token in the CREATE TABLE */
|
| + Token *pEnd, /* The ')' before options in the CREATE TABLE */
|
| + u8 tabOpts, /* Extra table options. Usually 0. */
|
| Select *pSelect /* Select from a "CREATE ... AS SELECT" */
|
| ){
|
| - Table *p;
|
| - sqlite3 *db = pParse->db;
|
| - int iDb;
|
| + Table *p; /* The new table */
|
| + sqlite3 *db = pParse->db; /* The database connection */
|
| + int iDb; /* Database in which the table lives */
|
| + Index *pIdx; /* An implied index of the table */
|
|
|
| if( (pEnd==0 && pSelect==0) || db->mallocFailed ){
|
| return;
|
| @@ -1472,38 +1809,45 @@ void sqlite3EndTable(
|
|
|
| assert( !db->init.busy || !pSelect );
|
|
|
| + /* 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
|
| + ** for the table from the db->init.newTnum field. (The page number
|
| + ** should have been put there by the sqliteOpenCb routine.)
|
| + */
|
| + if( db->init.busy ){
|
| + p->tnum = db->init.newTnum;
|
| + }
|
| +
|
| + /* Special processing for WITHOUT ROWID Tables */
|
| + if( tabOpts & TF_WithoutRowid ){
|
| + if( (p->tabFlags & TF_Autoincrement) ){
|
| + sqlite3ErrorMsg(pParse,
|
| + "AUTOINCREMENT not allowed on WITHOUT ROWID tables");
|
| + return;
|
| + }
|
| + if( (p->tabFlags & TF_HasPrimaryKey)==0 ){
|
| + sqlite3ErrorMsg(pParse, "PRIMARY KEY missing on table %s", p->zName);
|
| + }else{
|
| + p->tabFlags |= TF_WithoutRowid;
|
| + convertToWithoutRowidTable(pParse, p);
|
| + }
|
| + }
|
| +
|
| 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( sqlite3ResolveExprNames(&sNC, p->pCheck) ){
|
| - return;
|
| - }
|
| + sqlite3ResolveSelfReference(pParse, p, NC_IsCheck, 0, p->pCheck);
|
| }
|
| #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
|
| - ** for the table from the db->init.newTnum field. (The page number
|
| - ** should have been put there by the sqliteOpenCb routine.)
|
| - */
|
| - if( db->init.busy ){
|
| - p->tnum = db->init.newTnum;
|
| + /* Estimate the average row size for the table and for all implied indices */
|
| + estimateTableWidth(p);
|
| + for(pIdx=p->pIndex; pIdx; pIdx=pIdx->pNext){
|
| + estimateIndexWidth(pIdx);
|
| }
|
|
|
| /* If not initializing, then create a record for the new table
|
| @@ -1558,7 +1902,7 @@ void sqlite3EndTable(
|
|
|
| assert(pParse->nTab==1);
|
| sqlite3VdbeAddOp3(v, OP_OpenWrite, 1, pParse->regRoot, iDb);
|
| - sqlite3VdbeChangeP5(v, 1);
|
| + sqlite3VdbeChangeP5(v, OPFLAG_P2ISREG);
|
| pParse->nTab = 2;
|
| sqlite3SelectDestInit(&dest, SRT_Table, 1);
|
| sqlite3Select(pParse, pSelect, &dest);
|
| @@ -1579,7 +1923,9 @@ void sqlite3EndTable(
|
| if( pSelect ){
|
| zStmt = createTableStmt(db, p);
|
| }else{
|
| - n = (int)(pEnd->z - pParse->sNameToken.z) + 1;
|
| + Token *pEnd2 = tabOpts ? &pParse->sLastToken : pEnd;
|
| + n = (int)(pEnd2->z - pParse->sNameToken.z);
|
| + if( pEnd2->z[0]!=';' ) n += pEnd2->n;
|
| zStmt = sqlite3MPrintf(db,
|
| "CREATE %s %.*s", zType2, n, pParse->sNameToken.z
|
| );
|
| @@ -1621,8 +1967,8 @@ void sqlite3EndTable(
|
| #endif
|
|
|
| /* Reparse everything to update our internal data structures */
|
| - sqlite3VdbeAddOp4(v, OP_ParseSchema, iDb, 0, 0,
|
| - sqlite3MPrintf(db, "tbl_name='%q'",p->zName), P4_DYNAMIC);
|
| + sqlite3VdbeAddParseSchemaOp(v, iDb,
|
| + sqlite3MPrintf(db, "tbl_name='%q' AND type!='trigger'", p->zName));
|
| }
|
|
|
|
|
| @@ -1632,15 +1978,13 @@ void sqlite3EndTable(
|
| Table *pOld;
|
| Schema *pSchema = p->pSchema;
|
| assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
|
| - pOld = sqlite3HashInsert(&pSchema->tblHash, p->zName,
|
| - sqlite3Strlen30(p->zName),p);
|
| + pOld = sqlite3HashInsert(&pSchema->tblHash, p->zName, p);
|
| if( pOld ){
|
| assert( p==pOld ); /* Malloc must have failed inside HashInsert() */
|
| db->mallocFailed = 1;
|
| return;
|
| }
|
| pParse->pNewTable = 0;
|
| - db->nTable++;
|
| db->flags |= SQLITE_InternChanges;
|
|
|
| #ifndef SQLITE_OMIT_ALTERTABLE
|
| @@ -1676,7 +2020,7 @@ void sqlite3CreateView(
|
| const char *z;
|
| Token sEnd;
|
| DbFixer sFix;
|
| - Token *pName;
|
| + Token *pName = 0;
|
| int iDb;
|
| sqlite3 *db = pParse->db;
|
|
|
| @@ -1693,9 +2037,8 @@ void sqlite3CreateView(
|
| }
|
| sqlite3TwoPartName(pParse, pName1, pName2, &pName);
|
| iDb = sqlite3SchemaToIndex(db, p->pSchema);
|
| - if( sqlite3FixInit(&sFix, pParse, iDb, "view", pName)
|
| - && sqlite3FixSelect(&sFix, pSelect)
|
| - ){
|
| + sqlite3FixInit(&sFix, pParse, iDb, "view", pName);
|
| + if( sqlite3FixSelect(&sFix, pSelect) ){
|
| sqlite3SelectDelete(db, pSelect);
|
| return;
|
| }
|
| @@ -1729,7 +2072,7 @@ void sqlite3CreateView(
|
| sEnd.n = 1;
|
|
|
| /* Use sqlite3EndTable() to add the view to the SQLITE_MASTER table */
|
| - sqlite3EndTable(pParse, 0, &sEnd, 0);
|
| + sqlite3EndTable(pParse, 0, &sEnd, 0, 0);
|
| return;
|
| }
|
| #endif /* SQLITE_OMIT_VIEW */
|
| @@ -1746,7 +2089,7 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
|
| int nErr = 0; /* Number of errors encountered */
|
| int n; /* Temporarily holds the number of cursors assigned */
|
| sqlite3 *db = pParse->db; /* Database connection for malloc errors */
|
| - int (*xAuth)(void*,int,const char*,const char*,const char*,const char*);
|
| + sqlite3_xauth xAuth; /* Saved xAuth pointer */
|
|
|
| assert( pTable );
|
|
|
| @@ -1817,7 +2160,7 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
|
| pSelTab->aCol = 0;
|
| sqlite3DeleteTable(db, pSelTab);
|
| assert( sqlite3SchemaMutexHeld(db, 0, pTable->pSchema) );
|
| - pTable->pSchema->flags |= DB_UnresetViews;
|
| + pTable->pSchema->schemaFlags |= DB_UnresetViews;
|
| }else{
|
| pTable->nCol = 0;
|
| nErr++;
|
| @@ -1975,6 +2318,7 @@ static void destroyTable(Parse *pParse, Table *pTab){
|
| return;
|
| }else{
|
| int iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
|
| + assert( iDb>=0 && iDb<pParse->db->nDb );
|
| destroyRootPage(pParse, iLargest, iDb);
|
| iDestroyed = iLargest;
|
| }
|
| @@ -1983,6 +2327,100 @@ static void destroyTable(Parse *pParse, Table *pTab){
|
| }
|
|
|
| /*
|
| +** Remove entries from the sqlite_statN tables (for N in (1,2,3))
|
| +** after a DROP INDEX or DROP TABLE command.
|
| +*/
|
| +static void sqlite3ClearStatTables(
|
| + Parse *pParse, /* The parsing context */
|
| + int iDb, /* The database number */
|
| + const char *zType, /* "idx" or "tbl" */
|
| + const char *zName /* Name of index or table */
|
| +){
|
| + int i;
|
| + const char *zDbName = pParse->db->aDb[iDb].zName;
|
| + for(i=1; i<=4; i++){
|
| + char zTab[24];
|
| + sqlite3_snprintf(sizeof(zTab),zTab,"sqlite_stat%d",i);
|
| + if( sqlite3FindTable(pParse->db, zTab, zDbName) ){
|
| + sqlite3NestedParse(pParse,
|
| + "DELETE FROM %Q.%s WHERE %s=%Q",
|
| + zDbName, zTab, zType, zName
|
| + );
|
| + }
|
| + }
|
| +}
|
| +
|
| +/*
|
| +** Generate code to drop a table.
|
| +*/
|
| +void sqlite3CodeDropTable(Parse *pParse, Table *pTab, int iDb, int isView){
|
| + Vdbe *v;
|
| + sqlite3 *db = pParse->db;
|
| + Trigger *pTrigger;
|
| + Db *pDb = &db->aDb[iDb];
|
| +
|
| + v = sqlite3GetVdbe(pParse);
|
| + assert( v!=0 );
|
| + sqlite3BeginWriteOperation(pParse, 1, iDb);
|
| +
|
| +#ifndef SQLITE_OMIT_VIRTUALTABLE
|
| + if( IsVirtual(pTab) ){
|
| + sqlite3VdbeAddOp0(v, OP_VBegin);
|
| + }
|
| +#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 = sqlite3TriggerList(pParse, pTab);
|
| + while( pTrigger ){
|
| + assert( pTrigger->pSchema==pTab->pSchema ||
|
| + pTrigger->pSchema==db->aDb[1].pSchema );
|
| + sqlite3DropTriggerPtr(pParse, pTrigger);
|
| + pTrigger = pTrigger->pNext;
|
| + }
|
| +
|
| +#ifndef SQLITE_OMIT_AUTOINCREMENT
|
| + /* Remove any entries of the sqlite_sequence table associated with
|
| + ** the table being dropped. This is done before the table is dropped
|
| + ** at the btree level, in case the sqlite_sequence table needs to
|
| + ** move as a result of the drop (can happen in auto-vacuum mode).
|
| + */
|
| + if( pTab->tabFlags & TF_Autoincrement ){
|
| + sqlite3NestedParse(pParse,
|
| + "DELETE FROM %Q.sqlite_sequence WHERE name=%Q",
|
| + pDb->zName, pTab->zName
|
| + );
|
| + }
|
| +#endif
|
| +
|
| + /* Drop all SQLITE_MASTER table and index entries that refer to the
|
| + ** table. The program name loops through the master table and deletes
|
| + ** every row that refers to a table of the same name as the one being
|
| + ** dropped. Triggers are handled separately because a trigger can be
|
| + ** created in the temp database that refers to a table in another
|
| + ** database.
|
| + */
|
| + sqlite3NestedParse(pParse,
|
| + "DELETE FROM %Q.%s WHERE tbl_name=%Q and type!='trigger'",
|
| + pDb->zName, SCHEMA_TABLE(iDb), pTab->zName);
|
| + if( !isView && !IsVirtual(pTab) ){
|
| + destroyTable(pParse, pTab);
|
| + }
|
| +
|
| + /* Remove the table entry from SQLite's internal schema and modify
|
| + ** the schema cookie.
|
| + */
|
| + if( IsVirtual(pTab) ){
|
| + sqlite3VdbeAddOp4(v, OP_VDestroy, iDb, 0, 0, pTab->zName, 0);
|
| + }
|
| + sqlite3VdbeAddOp4(v, OP_DropTable, iDb, 0, 0, pTab->zName, 0);
|
| + sqlite3ChangeCookie(pParse, iDb);
|
| + sqliteViewResetAll(db, iDb);
|
| +}
|
| +
|
| +/*
|
| ** This routine is called to do the work of a DROP TABLE statement.
|
| ** pName is the name of the table to be dropped.
|
| */
|
| @@ -1998,8 +2436,7 @@ void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, int noErr){
|
| assert( pParse->nErr==0 );
|
| assert( pName->nSrc==1 );
|
| if( noErr ) db->suppressErr++;
|
| - pTab = sqlite3LocateTable(pParse, isView,
|
| - pName->a[0].zName, pName->a[0].zDatabase);
|
| + pTab = sqlite3LocateTableItem(pParse, isView, &pName->a[0]);
|
| if( noErr ) db->suppressErr--;
|
|
|
| if( pTab==0 ){
|
| @@ -2050,7 +2487,8 @@ void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, int noErr){
|
| }
|
| }
|
| #endif
|
| - if( sqlite3StrNICmp(pTab->zName, "sqlite_", 7)==0 ){
|
| + if( sqlite3StrNICmp(pTab->zName, "sqlite_", 7)==0
|
| + && sqlite3StrNICmp(pTab->zName, "sqlite_stat", 11)!=0 ){
|
| sqlite3ErrorMsg(pParse, "table %s may not be dropped", pTab->zName);
|
| goto exit_drop_table;
|
| }
|
| @@ -2074,75 +2512,11 @@ void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, int noErr){
|
| */
|
| v = sqlite3GetVdbe(pParse);
|
| if( v ){
|
| - Trigger *pTrigger;
|
| - Db *pDb = &db->aDb[iDb];
|
| sqlite3BeginWriteOperation(pParse, 1, iDb);
|
| -
|
| -#ifndef SQLITE_OMIT_VIRTUALTABLE
|
| - if( IsVirtual(pTab) ){
|
| - sqlite3VdbeAddOp0(v, OP_VBegin);
|
| - }
|
| -#endif
|
| + sqlite3ClearStatTables(pParse, iDb, "tbl", pTab->zName);
|
| sqlite3FkDropTable(pParse, pName, pTab);
|
| -
|
| - /* 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 = sqlite3TriggerList(pParse, pTab);
|
| - while( pTrigger ){
|
| - assert( pTrigger->pSchema==pTab->pSchema ||
|
| - pTrigger->pSchema==db->aDb[1].pSchema );
|
| - sqlite3DropTriggerPtr(pParse, pTrigger);
|
| - pTrigger = pTrigger->pNext;
|
| - }
|
| -
|
| -#ifndef SQLITE_OMIT_AUTOINCREMENT
|
| - /* Remove any entries of the sqlite_sequence table associated with
|
| - ** the table being dropped. This is done before the table is dropped
|
| - ** at the btree level, in case the sqlite_sequence table needs to
|
| - ** move as a result of the drop (can happen in auto-vacuum mode).
|
| - */
|
| - if( pTab->tabFlags & TF_Autoincrement ){
|
| - sqlite3NestedParse(pParse,
|
| - "DELETE FROM %s.sqlite_sequence WHERE name=%Q",
|
| - pDb->zName, pTab->zName
|
| - );
|
| - }
|
| -#endif
|
| -
|
| - /* Drop all SQLITE_MASTER table and index entries that refer to the
|
| - ** table. The program name loops through the master table and deletes
|
| - ** every row that refers to a table of the same name as the one being
|
| - ** dropped. Triggers are handled seperately because a trigger can be
|
| - ** created in the temp database that refers to a table in another
|
| - ** database.
|
| - */
|
| - sqlite3NestedParse(pParse,
|
| - "DELETE FROM %Q.%s WHERE tbl_name=%Q and type!='trigger'",
|
| - pDb->zName, SCHEMA_TABLE(iDb), pTab->zName);
|
| -
|
| - /* Drop any statistics from the sqlite_stat1 table, if it exists */
|
| - if( sqlite3FindTable(db, "sqlite_stat1", db->aDb[iDb].zName) ){
|
| - sqlite3NestedParse(pParse,
|
| - "DELETE FROM %Q.sqlite_stat1 WHERE tbl=%Q", pDb->zName, pTab->zName
|
| - );
|
| - }
|
| -
|
| - if( !isView && !IsVirtual(pTab) ){
|
| - destroyTable(pParse, pTab);
|
| - }
|
| -
|
| - /* Remove the table entry from SQLite's internal schema and modify
|
| - ** the schema cookie.
|
| - */
|
| - if( IsVirtual(pTab) ){
|
| - sqlite3VdbeAddOp4(v, OP_VDestroy, iDb, 0, 0, pTab->zName, 0);
|
| - }
|
| - sqlite3VdbeAddOp4(v, OP_DropTable, iDb, 0, 0, pTab->zName, 0);
|
| - sqlite3ChangeCookie(pParse, iDb);
|
| + sqlite3CodeDropTable(pParse, pTab, iDb, isView);
|
| }
|
| - sqliteViewResetAll(db, iDb);
|
|
|
| exit_drop_table:
|
| sqlite3SrcListDelete(db, pName);
|
| @@ -2153,8 +2527,8 @@ exit_drop_table:
|
| ** currently under construction. pFromCol determines which columns
|
| ** in the current table point to the foreign key. If pFromCol==0 then
|
| ** connect the key to the last column inserted. pTo is the name of
|
| -** the table referred to. pToCol is a list of tables in the other
|
| -** pTo table that the foreign key points to. flags contains all
|
| +** the table referred to (a.k.a the "parent" table). pToCol is a list
|
| +** of tables in the parent pTo table. flags contains all
|
| ** information about the conflict resolution algorithms specified
|
| ** in the ON DELETE, ON UPDATE and ON INSERT clauses.
|
| **
|
| @@ -2254,7 +2628,7 @@ void sqlite3CreateForeignKey(
|
|
|
| assert( sqlite3SchemaMutexHeld(db, 0, p->pSchema) );
|
| pNextTo = (FKey *)sqlite3HashInsert(&p->pSchema->fkeyHash,
|
| - pFKey->zTo, sqlite3Strlen30(pFKey->zTo), (void *)pFKey
|
| + pFKey->zTo, (void *)pFKey
|
| );
|
| if( pNextTo==pFKey ){
|
| db->mallocFailed = 1;
|
| @@ -2310,12 +2684,14 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
|
| Table *pTab = pIndex->pTable; /* The table that is indexed */
|
| int iTab = pParse->nTab++; /* Btree cursor used for pTab */
|
| int iIdx = pParse->nTab++; /* Btree cursor used for pIndex */
|
| + int iSorter; /* Cursor opened by OpenSorter (if in use) */
|
| int addr1; /* Address of top of loop */
|
| + int addr2; /* Address to jump to for next iteration */
|
| int tnum; /* Root page of index */
|
| + int iPartIdxLabel; /* Jump to this label to skip a row */
|
| Vdbe *v; /* Generate code into this virtual machine */
|
| KeyInfo *pKey; /* KeyInfo for index */
|
| - int regIdxKey; /* Registers containing the index key */
|
| - int regRecord; /* Register holding assemblied index record */
|
| + int regRecord; /* Register holding assembled index record */
|
| sqlite3 *db = pParse->db; /* The database connection */
|
| int iDb = sqlite3SchemaToIndex(db, pIndex->pSchema);
|
|
|
| @@ -2335,43 +2711,87 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
|
| tnum = memRootPage;
|
| }else{
|
| tnum = pIndex->tnum;
|
| - sqlite3VdbeAddOp2(v, OP_Clear, tnum, iDb);
|
| - }
|
| - pKey = sqlite3IndexKeyinfo(pParse, pIndex);
|
| - sqlite3VdbeAddOp4(v, OP_OpenWrite, iIdx, tnum, iDb,
|
| - (char *)pKey, P4_KEYINFO_HANDOFF);
|
| - if( memRootPage>=0 ){
|
| - sqlite3VdbeChangeP5(v, 1);
|
| }
|
| + pKey = sqlite3KeyInfoOfIndex(pParse, pIndex);
|
| +
|
| + /* Open the sorter cursor if we are to use one. */
|
| + iSorter = pParse->nTab++;
|
| + sqlite3VdbeAddOp4(v, OP_SorterOpen, iSorter, 0, pIndex->nKeyCol, (char*)
|
| + sqlite3KeyInfoRef(pKey), P4_KEYINFO);
|
| +
|
| + /* Open the table. Loop through all rows of the table, inserting index
|
| + ** records into the sorter. */
|
| sqlite3OpenTable(pParse, iTab, iDb, pTab, OP_OpenRead);
|
| - addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iTab, 0);
|
| + addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iTab, 0); VdbeCoverage(v);
|
| regRecord = sqlite3GetTempReg(pParse);
|
| - regIdxKey = sqlite3GenerateIndexKey(pParse, pIndex, iTab, regRecord, 1);
|
| - if( pIndex->onError!=OE_None ){
|
| - const int regRowid = regIdxKey + pIndex->nColumn;
|
| - const int j2 = sqlite3VdbeCurrentAddr(v) + 2;
|
| - void * const pRegKey = SQLITE_INT_TO_PTR(regIdxKey);
|
| -
|
| - /* The registers accessed by the OP_IsUnique opcode were allocated
|
| - ** using sqlite3GetTempRange() inside of the sqlite3GenerateIndexKey()
|
| - ** call above. Just before that function was freed they were released
|
| - ** (made available to the compiler for reuse) using
|
| - ** sqlite3ReleaseTempRange(). So in some ways having the OP_IsUnique
|
| - ** opcode use the values stored within seems dangerous. However, since
|
| - ** we can be sure that no other temp registers have been allocated
|
| - ** since sqlite3ReleaseTempRange() was called, it is safe to do so.
|
| - */
|
| - sqlite3VdbeAddOp4(v, OP_IsUnique, iIdx, j2, regRowid, pRegKey, P4_INT32);
|
| - sqlite3HaltConstraint(
|
| - pParse, OE_Abort, "indexed columns are not unique", P4_STATIC);
|
| +
|
| + sqlite3GenerateIndexKey(pParse,pIndex,iTab,regRecord,0,&iPartIdxLabel,0,0);
|
| + sqlite3VdbeAddOp2(v, OP_SorterInsert, iSorter, regRecord);
|
| + sqlite3ResolvePartIdxLabel(pParse, iPartIdxLabel);
|
| + sqlite3VdbeAddOp2(v, OP_Next, iTab, addr1+1); VdbeCoverage(v);
|
| + sqlite3VdbeJumpHere(v, addr1);
|
| + if( memRootPage<0 ) sqlite3VdbeAddOp2(v, OP_Clear, tnum, iDb);
|
| + sqlite3VdbeAddOp4(v, OP_OpenWrite, iIdx, tnum, iDb,
|
| + (char *)pKey, P4_KEYINFO);
|
| + sqlite3VdbeChangeP5(v, OPFLAG_BULKCSR|((memRootPage>=0)?OPFLAG_P2ISREG:0));
|
| +
|
| + addr1 = sqlite3VdbeAddOp2(v, OP_SorterSort, iSorter, 0); VdbeCoverage(v);
|
| + assert( pKey!=0 || db->mallocFailed || pParse->nErr );
|
| + if( IsUniqueIndex(pIndex) && pKey!=0 ){
|
| + int j2 = sqlite3VdbeCurrentAddr(v) + 3;
|
| + sqlite3VdbeAddOp2(v, OP_Goto, 0, j2);
|
| + addr2 = sqlite3VdbeCurrentAddr(v);
|
| + sqlite3VdbeAddOp4Int(v, OP_SorterCompare, iSorter, j2, regRecord,
|
| + pIndex->nKeyCol); VdbeCoverage(v);
|
| + sqlite3UniqueConstraint(pParse, OE_Abort, pIndex);
|
| + }else{
|
| + addr2 = sqlite3VdbeCurrentAddr(v);
|
| }
|
| - sqlite3VdbeAddOp2(v, OP_IdxInsert, iIdx, regRecord);
|
| + sqlite3VdbeAddOp3(v, OP_SorterData, iSorter, regRecord, iIdx);
|
| + sqlite3VdbeAddOp3(v, OP_IdxInsert, iIdx, regRecord, 1);
|
| sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT);
|
| sqlite3ReleaseTempReg(pParse, regRecord);
|
| - sqlite3VdbeAddOp2(v, OP_Next, iTab, addr1+1);
|
| + sqlite3VdbeAddOp2(v, OP_SorterNext, iSorter, addr2); VdbeCoverage(v);
|
| sqlite3VdbeJumpHere(v, addr1);
|
| +
|
| sqlite3VdbeAddOp1(v, OP_Close, iTab);
|
| sqlite3VdbeAddOp1(v, OP_Close, iIdx);
|
| + sqlite3VdbeAddOp1(v, OP_Close, iSorter);
|
| +}
|
| +
|
| +/*
|
| +** Allocate heap space to hold an Index object with nCol columns.
|
| +**
|
| +** Increase the allocation size to provide an extra nExtra bytes
|
| +** of 8-byte aligned space after the Index object and return a
|
| +** pointer to this extra space in *ppExtra.
|
| +*/
|
| +Index *sqlite3AllocateIndexObject(
|
| + sqlite3 *db, /* Database connection */
|
| + i16 nCol, /* Total number of columns in the index */
|
| + int nExtra, /* Number of bytes of extra space to alloc */
|
| + char **ppExtra /* Pointer to the "extra" space */
|
| +){
|
| + Index *p; /* Allocated index object */
|
| + int nByte; /* Bytes of space for Index object + arrays */
|
| +
|
| + nByte = ROUND8(sizeof(Index)) + /* Index structure */
|
| + ROUND8(sizeof(char*)*nCol) + /* Index.azColl */
|
| + ROUND8(sizeof(LogEst)*(nCol+1) + /* Index.aiRowLogEst */
|
| + sizeof(i16)*nCol + /* Index.aiColumn */
|
| + sizeof(u8)*nCol); /* Index.aSortOrder */
|
| + p = sqlite3DbMallocZero(db, nByte + nExtra);
|
| + if( p ){
|
| + char *pExtra = ((char*)p)+ROUND8(sizeof(Index));
|
| + p->azColl = (char**)pExtra; pExtra += ROUND8(sizeof(char*)*nCol);
|
| + p->aiRowLogEst = (LogEst*)pExtra; pExtra += sizeof(LogEst)*(nCol+1);
|
| + p->aiColumn = (i16*)pExtra; pExtra += sizeof(i16)*nCol;
|
| + p->aSortOrder = (u8*)pExtra;
|
| + p->nColumn = nCol;
|
| + p->nKeyCol = nCol - 1;
|
| + *ppExtra = ((char*)p) + nByte;
|
| + }
|
| + return p;
|
| }
|
|
|
| /*
|
| @@ -2388,7 +2808,7 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
|
| **
|
| ** If the index is created successfully, return a pointer to the new Index
|
| ** structure. This is used by sqlite3AddPrimaryKey() to mark the index
|
| -** as the tables primary key (Index.autoIndex==2).
|
| +** as the tables primary key (Index.idxType==SQLITE_IDXTYPE_PRIMARYKEY)
|
| */
|
| Index *sqlite3CreateIndex(
|
| Parse *pParse, /* All information about this parse */
|
| @@ -2398,7 +2818,7 @@ Index *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 this statement */
|
| - Token *pEnd, /* The ")" that closes the CREATE INDEX statement */
|
| + Expr *pPIWhere, /* WHERE clause for partial indices */
|
| int sortOrder, /* Sort order of primary key when pList==NULL */
|
| int ifNotExist /* Omit error if index already exists */
|
| ){
|
| @@ -2408,7 +2828,6 @@ Index *sqlite3CreateIndex(
|
| 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 */
|
| int sortOrderMask; /* 1 to honor DESC in index. 0 to ignore. */
|
| sqlite3 *db = pParse->db;
|
| @@ -2416,11 +2835,12 @@ Index *sqlite3CreateIndex(
|
| 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;
|
| + const Column *pTabCol; /* A column in the table */
|
| + int nExtra = 0; /* Space allocated for zExtra[] */
|
| + int nExtraCol; /* Number of extra columns needed */
|
| + char *zExtra = 0; /* Extra space after the Index object */
|
| + Index *pPk = 0; /* PRIMARY KEY index for WITHOUT ROWID tables */
|
|
|
| - assert( pStart==0 || pEnd!=0 ); /* pEnd must be non-NULL if pStart is */
|
| assert( pParse->nErr==0 ); /* Never called with prior errors */
|
| if( db->mallocFailed || IN_DECLARE_VTAB ){
|
| goto exit_create_index;
|
| @@ -2441,9 +2861,10 @@ Index *sqlite3CreateIndex(
|
| assert( pName1 && pName2 );
|
| iDb = sqlite3TwoPartName(pParse, pName1, pName2, &pName);
|
| if( iDb<0 ) goto exit_create_index;
|
| + assert( pName && pName->z );
|
|
|
| #ifndef SQLITE_OMIT_TEMPDB
|
| - /* If the index name was unqualified, check if the the table
|
| + /* If the index name was unqualified, check if the table
|
| ** is a temp table. If so, set the database to 1. Do not do this
|
| ** if initialising a database schema.
|
| */
|
| @@ -2455,19 +2876,25 @@ Index *sqlite3CreateIndex(
|
| }
|
| #endif
|
|
|
| - if( sqlite3FixInit(&sFix, pParse, iDb, "index", pName) &&
|
| - sqlite3FixSrcList(&sFix, pTblName)
|
| - ){
|
| + sqlite3FixInit(&sFix, pParse, iDb, "index", pName);
|
| + if( sqlite3FixSrcList(&sFix, pTblName) ){
|
| /* Because the parser constructs pTblName from a single identifier,
|
| ** sqlite3FixSrcList can never fail. */
|
| assert(0);
|
| }
|
| - pTab = sqlite3LocateTable(pParse, 0, pTblName->a[0].zName,
|
| - pTblName->a[0].zDatabase);
|
| - if( !pTab || db->mallocFailed ) goto exit_create_index;
|
| - assert( db->aDb[iDb].pSchema==pTab->pSchema );
|
| + pTab = sqlite3LocateTableItem(pParse, 0, &pTblName->a[0]);
|
| + assert( db->mallocFailed==0 || pTab==0 );
|
| + if( pTab==0 ) goto exit_create_index;
|
| + if( iDb==1 && db->aDb[iDb].pSchema!=pTab->pSchema ){
|
| + sqlite3ErrorMsg(pParse,
|
| + "cannot create a TEMP index on non-TEMP table \"%s\"",
|
| + pTab->zName);
|
| + goto exit_create_index;
|
| + }
|
| + if( !HasRowid(pTab) ) pPk = sqlite3PrimaryKeyIndex(pTab);
|
| }else{
|
| assert( pName==0 );
|
| + assert( pStart==0 );
|
| pTab = pParse->pNewTable;
|
| if( !pTab ) goto exit_create_index;
|
| iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
|
| @@ -2477,6 +2904,10 @@ Index *sqlite3CreateIndex(
|
| assert( pTab!=0 );
|
| assert( pParse->nErr==0 );
|
| if( sqlite3StrNICmp(pTab->zName, "sqlite_", 7)==0
|
| + && db->init.busy==0
|
| +#if SQLITE_USER_AUTHENTICATION
|
| + && sqlite3UserAuthTable(pTab->zName)==0
|
| +#endif
|
| && sqlite3StrNICmp(&pTab->zName[7],"altertab_",9)!=0 ){
|
| sqlite3ErrorMsg(pParse, "table %s may not be indexed", pTab->zName);
|
| goto exit_create_index;
|
| @@ -2510,6 +2941,7 @@ Index *sqlite3CreateIndex(
|
| if( pName ){
|
| zName = sqlite3NameFromToken(db, pName);
|
| if( zName==0 ) goto exit_create_index;
|
| + assert( pName->z!=0 );
|
| if( SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){
|
| goto exit_create_index;
|
| }
|
| @@ -2559,11 +2991,10 @@ Index *sqlite3CreateIndex(
|
| ** So create a fake list to simulate this.
|
| */
|
| if( pList==0 ){
|
| - nullId.z = pTab->aCol[pTab->nCol-1].zName;
|
| - nullId.n = sqlite3Strlen30((char*)nullId.z);
|
| pList = sqlite3ExprListAppend(pParse, 0, 0);
|
| if( pList==0 ) goto exit_create_index;
|
| - sqlite3ExprListSetName(pParse, pList, &nullId, 0);
|
| + pList->a[0].zName = sqlite3DbStrDup(pParse->db,
|
| + pTab->aCol[pTab->nCol-1].zName);
|
| pList->a[0].sortOrder = (u8)sortOrder;
|
| }
|
|
|
| @@ -2573,12 +3004,8 @@ Index *sqlite3CreateIndex(
|
| for(i=0; i<pList->nExpr; i++){
|
| Expr *pExpr = pList->a[i].pExpr;
|
| if( pExpr ){
|
| - CollSeq *pColl = pExpr->pColl;
|
| - /* Either pColl!=0 or there was an OOM failure. But if an OOM
|
| - ** failure we have quit before reaching this point. */
|
| - if( ALWAYS(pColl) ){
|
| - nExtra += (1 + sqlite3Strlen30(pColl->zName));
|
| - }
|
| + assert( pExpr->op==TK_COLLATE );
|
| + nExtra += (1 + sqlite3Strlen30(pExpr->u.zToken));
|
| }
|
| }
|
|
|
| @@ -2586,31 +3013,28 @@ Index *sqlite3CreateIndex(
|
| ** Allocate the index structure.
|
| */
|
| nName = sqlite3Strlen30(zName);
|
| - nCol = pList->nExpr;
|
| - pIndex = sqlite3DbMallocZero(db,
|
| - 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 */
|
| - );
|
| + nExtraCol = pPk ? pPk->nKeyCol : 1;
|
| + pIndex = sqlite3AllocateIndexObject(db, pList->nExpr + nExtraCol,
|
| + nName + nExtra + 1, &zExtra);
|
| if( db->mallocFailed ){
|
| 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]);
|
| + assert( EIGHT_BYTE_ALIGNMENT(pIndex->aiRowLogEst) );
|
| + assert( EIGHT_BYTE_ALIGNMENT(pIndex->azColl) );
|
| + pIndex->zName = zExtra;
|
| + zExtra += nName + 1;
|
| memcpy(pIndex->zName, zName, nName+1);
|
| pIndex->pTable = pTab;
|
| - pIndex->nColumn = pList->nExpr;
|
| pIndex->onError = (u8)onError;
|
| - pIndex->autoIndex = (u8)(pName==0);
|
| + pIndex->uniqNotNull = onError!=OE_None;
|
| + pIndex->idxType = pName ? SQLITE_IDXTYPE_APPDEF : SQLITE_IDXTYPE_UNIQUE;
|
| pIndex->pSchema = db->aDb[iDb].pSchema;
|
| + pIndex->nKeyCol = pList->nExpr;
|
| + if( pPIWhere ){
|
| + sqlite3ResolveSelfReference(pParse, pTab, NC_PartIdx, pPIWhere, 0);
|
| + pIndex->pPartIdxWhere = pPIWhere;
|
| + pPIWhere = 0;
|
| + }
|
| assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
|
|
|
| /* Check to see if we should honor DESC requests on index columns
|
| @@ -2633,7 +3057,6 @@ Index *sqlite3CreateIndex(
|
| */
|
| for(i=0, pListItem=pList->a; i<pList->nExpr; i++, pListItem++){
|
| const char *zColName = pListItem->zName;
|
| - Column *pTabCol;
|
| int requestedSortOrder;
|
| char *zColl; /* Collation sequence name */
|
|
|
| @@ -2646,15 +3069,12 @@ Index *sqlite3CreateIndex(
|
| pParse->checkSchema = 1;
|
| goto exit_create_index;
|
| }
|
| - pIndex->aiColumn[i] = j;
|
| - /* Justification of the ALWAYS(pListItem->pExpr->pColl): Because of
|
| - ** the way the "idxlist" non-terminal is constructed by the parser,
|
| - ** if pListItem->pExpr is not null then either pListItem->pExpr->pColl
|
| - ** must exist or else there must have been an OOM error. But if there
|
| - ** was an OOM error, we would never reach this point. */
|
| - if( pListItem->pExpr && ALWAYS(pListItem->pExpr->pColl) ){
|
| + assert( j<=0x7fff );
|
| + pIndex->aiColumn[i] = (i16)j;
|
| + if( pListItem->pExpr ){
|
| int nColl;
|
| - zColl = pListItem->pExpr->pColl->zName;
|
| + assert( pListItem->pExpr->op==TK_COLLATE );
|
| + zColl = pListItem->pExpr->u.zToken;
|
| nColl = sqlite3Strlen30(zColl) + 1;
|
| assert( nExtra>=nColl );
|
| memcpy(zExtra, zColl, nColl);
|
| @@ -2663,9 +3083,7 @@ Index *sqlite3CreateIndex(
|
| nExtra -= nColl;
|
| }else{
|
| zColl = pTab->aCol[j].zColl;
|
| - if( !zColl ){
|
| - zColl = db->pDfltColl->zName;
|
| - }
|
| + if( !zColl ) zColl = "BINARY";
|
| }
|
| if( !db->init.busy && !sqlite3LocateCollSeq(pParse, zColl) ){
|
| goto exit_create_index;
|
| @@ -2673,8 +3091,27 @@ Index *sqlite3CreateIndex(
|
| pIndex->azColl[i] = zColl;
|
| requestedSortOrder = pListItem->sortOrder & sortOrderMask;
|
| pIndex->aSortOrder[i] = (u8)requestedSortOrder;
|
| + if( pTab->aCol[j].notNull==0 ) pIndex->uniqNotNull = 0;
|
| + }
|
| + if( pPk ){
|
| + for(j=0; j<pPk->nKeyCol; j++){
|
| + int x = pPk->aiColumn[j];
|
| + if( hasColumn(pIndex->aiColumn, pIndex->nKeyCol, x) ){
|
| + pIndex->nColumn--;
|
| + }else{
|
| + pIndex->aiColumn[i] = x;
|
| + pIndex->azColl[i] = pPk->azColl[j];
|
| + pIndex->aSortOrder[i] = pPk->aSortOrder[j];
|
| + i++;
|
| + }
|
| + }
|
| + assert( i==pIndex->nColumn );
|
| + }else{
|
| + pIndex->aiColumn[i] = -1;
|
| + pIndex->azColl[i] = "BINARY";
|
| }
|
| sqlite3DefaultRowEst(pIndex);
|
| + if( pParse->pNewTable==0 ) estimateIndexWidth(pIndex);
|
|
|
| if( pTab==pParse->pNewTable ){
|
| /* This routine has been called to create an automatic index as a
|
| @@ -2701,12 +3138,12 @@ Index *sqlite3CreateIndex(
|
| Index *pIdx;
|
| for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
| int k;
|
| - assert( pIdx->onError!=OE_None );
|
| - assert( pIdx->autoIndex );
|
| - assert( pIndex->onError!=OE_None );
|
| + assert( IsUniqueIndex(pIdx) );
|
| + assert( pIdx->idxType!=SQLITE_IDXTYPE_APPDEF );
|
| + assert( IsUniqueIndex(pIndex) );
|
|
|
| - if( pIdx->nColumn!=pIndex->nColumn ) continue;
|
| - for(k=0; k<pIdx->nColumn; k++){
|
| + if( pIdx->nKeyCol!=pIndex->nKeyCol ) continue;
|
| + for(k=0; k<pIdx->nKeyCol; k++){
|
| const char *z1;
|
| const char *z2;
|
| if( pIdx->aiColumn[k]!=pIndex->aiColumn[k] ) break;
|
| @@ -2714,14 +3151,14 @@ Index *sqlite3CreateIndex(
|
| z2 = pIndex->azColl[k];
|
| if( z1!=z2 && sqlite3StrICmp(z1, z2) ) break;
|
| }
|
| - if( k==pIdx->nColumn ){
|
| + if( k==pIdx->nKeyCol ){
|
| if( pIdx->onError!=pIndex->onError ){
|
| /* This constraint creates the same index as a previous
|
| ** constraint specified somewhere in the CREATE TABLE statement.
|
| ** However the ON CONFLICT clauses are different. If both this
|
| ** constraint and the previous equivalent constraint have explicit
|
| ** ON CONFLICT clauses this is an error. Otherwise, use the
|
| - ** explicitly specified behaviour for the index.
|
| + ** explicitly specified behavior for the index.
|
| */
|
| if( !(pIdx->onError==OE_Default || pIndex->onError==OE_Default) ){
|
| sqlite3ErrorMsg(pParse,
|
| @@ -2743,8 +3180,7 @@ Index *sqlite3CreateIndex(
|
| Index *p;
|
| assert( sqlite3SchemaMutexHeld(db, 0, pIndex->pSchema) );
|
| p = sqlite3HashInsert(&pIndex->pSchema->idxHash,
|
| - pIndex->zName, sqlite3Strlen30(pIndex->zName),
|
| - pIndex);
|
| + pIndex->zName, pIndex);
|
| if( p ){
|
| assert( p==pIndex ); /* Malloc must have failed */
|
| db->mallocFailed = 1;
|
| @@ -2756,22 +3192,20 @@ Index *sqlite3CreateIndex(
|
| }
|
| }
|
|
|
| - /* If the db->init.busy is 0 then create the index on disk. This
|
| - ** involves writing the index into the master table and filling in the
|
| - ** index with the current table contents.
|
| - **
|
| - ** The db->init.busy is 0 when the user first enters a CREATE INDEX
|
| - ** command. db->init.busy is 1 when a database is opened and
|
| - ** CREATE INDEX statements are read out of the master table. In
|
| - ** the latter case the index already exists on disk, which is why
|
| - ** we don't want to recreate it.
|
| + /* If this is the initial CREATE INDEX statement (or CREATE TABLE if the
|
| + ** index is an implied index for a UNIQUE or PRIMARY KEY constraint) then
|
| + ** emit code to allocate the index rootpage on disk and make an entry for
|
| + ** the index in the sqlite_master table and populate the index with
|
| + ** content. But, do not do this if we are simply reading the sqlite_master
|
| + ** table to parse the schema, or if this index is the PRIMARY KEY index
|
| + ** of a WITHOUT ROWID table.
|
| **
|
| - ** If pTblName==0 it means this index is generated as a primary key
|
| - ** or UNIQUE constraint of a CREATE TABLE statement. Since the table
|
| + ** If pTblName==0 it means this index is generated as an implied PRIMARY KEY
|
| + ** or UNIQUE index in a CREATE TABLE statement. Since the table
|
| ** has just been created, it contains no data and the index initialization
|
| ** step can be skipped.
|
| */
|
| - else{ /* if( db->init.busy==0 ) */
|
| + else if( pParse->nErr==0 && (HasRowid(pTab) || pTblName!=0) ){
|
| Vdbe *v;
|
| char *zStmt;
|
| int iMem = ++pParse->nMem;
|
| @@ -2789,12 +3223,11 @@ Index *sqlite3CreateIndex(
|
| ** the zStmt variable
|
| */
|
| if( pStart ){
|
| - assert( pEnd!=0 );
|
| + int n = (int)(pParse->sLastToken.z - pName->z) + pParse->sLastToken.n;
|
| + if( pName->z[n-1]==';' ) n--;
|
| /* A named index with an explicit CREATE INDEX statement */
|
| zStmt = sqlite3MPrintf(db, "CREATE%s INDEX %.*s",
|
| - onError==OE_None ? "" : " UNIQUE",
|
| - pEnd->z - pName->z + 1,
|
| - pName->z);
|
| + onError==OE_None ? "" : " UNIQUE", n, pName->z);
|
| }else{
|
| /* An automatic index created by a PRIMARY KEY or UNIQUE constraint */
|
| /* zStmt = sqlite3MPrintf(""); */
|
| @@ -2819,9 +3252,8 @@ Index *sqlite3CreateIndex(
|
| if( pTblName ){
|
| sqlite3RefillIndex(pParse, pIndex, iMem);
|
| sqlite3ChangeCookie(pParse, iDb);
|
| - sqlite3VdbeAddOp4(v, OP_ParseSchema, iDb, 0, 0,
|
| - sqlite3MPrintf(db, "name='%q' AND type='index'", pIndex->zName),
|
| - P4_DYNAMIC);
|
| + sqlite3VdbeAddParseSchemaOp(v, iDb,
|
| + sqlite3MPrintf(db, "name='%q' AND type='index'", pIndex->zName));
|
| sqlite3VdbeAddOp1(v, OP_Expire, 0);
|
| }
|
| }
|
| @@ -2851,10 +3283,8 @@ Index *sqlite3CreateIndex(
|
|
|
| /* Clean up before exiting */
|
| exit_create_index:
|
| - if( pIndex ){
|
| - sqlite3DbFree(db, pIndex->zColAff);
|
| - sqlite3DbFree(db, pIndex);
|
| - }
|
| + if( pIndex ) freeIndex(db, pIndex);
|
| + sqlite3ExprDelete(db, pPIWhere);
|
| sqlite3ExprListDelete(db, pList);
|
| sqlite3SrcListDelete(db, pTblName);
|
| sqlite3DbFree(db, zName);
|
| @@ -2865,11 +3295,11 @@ exit_create_index:
|
| ** Fill the Index.aiRowEst[] array with default information - information
|
| ** to be used when we have not run the ANALYZE command.
|
| **
|
| -** aiRowEst[0] is suppose to contain the number of elements in the index.
|
| +** aiRowEst[0] is supposed to contain the number of elements in the index.
|
| ** Since we do not know, guess 1 million. aiRowEst[1] is an estimate of the
|
| ** number of rows in the table that match any particular value of the
|
| ** first column of the index. aiRowEst[2] is an estimate of the number
|
| -** of rows that match any particular combiniation of the first 2 columns
|
| +** of rows that match any particular combination of the first 2 columns
|
| ** of the index. And so forth. It must always be the case that
|
| *
|
| ** aiRowEst[N]<=aiRowEst[N-1]
|
| @@ -2880,20 +3310,27 @@ exit_create_index:
|
| ** are based on typical values found in actual indices.
|
| */
|
| void sqlite3DefaultRowEst(Index *pIdx){
|
| - unsigned *a = pIdx->aiRowEst;
|
| + /* 10, 9, 8, 7, 6 */
|
| + LogEst aVal[] = { 33, 32, 30, 28, 26 };
|
| + LogEst *a = pIdx->aiRowLogEst;
|
| + int nCopy = MIN(ArraySize(aVal), pIdx->nKeyCol);
|
| int i;
|
| - unsigned n;
|
| - assert( a!=0 );
|
| - a[0] = pIdx->pTable->nRowEst;
|
| - if( a[0]<10 ) a[0] = 10;
|
| - n = 10;
|
| - for(i=1; i<=pIdx->nColumn; i++){
|
| - a[i] = n;
|
| - if( n>5 ) n--;
|
| - }
|
| - if( pIdx->onError!=OE_None ){
|
| - a[pIdx->nColumn] = 1;
|
| +
|
| + /* Set the first entry (number of rows in the index) to the estimated
|
| + ** number of rows in the table. Or 10, if the estimated number of rows
|
| + ** in the table is less than that. */
|
| + a[0] = pIdx->pTable->nRowLogEst;
|
| + if( a[0]<33 ) a[0] = 33; assert( 33==sqlite3LogEst(10) );
|
| +
|
| + /* Estimate that a[1] is 10, a[2] is 9, a[3] is 8, a[4] is 7, a[5] is
|
| + ** 6 and each subsequent value (if any) is 5. */
|
| + memcpy(&a[1], aVal, nCopy*sizeof(LogEst));
|
| + for(i=nCopy+1; i<=pIdx->nKeyCol; i++){
|
| + a[i] = 23; assert( 23==sqlite3LogEst(5) );
|
| }
|
| +
|
| + assert( 0==sqlite3LogEst(1) );
|
| + if( IsUniqueIndex(pIdx) ) a[pIdx->nKeyCol] = 0;
|
| }
|
|
|
| /*
|
| @@ -2924,7 +3361,7 @@ void sqlite3DropIndex(Parse *pParse, SrcList *pName, int ifExists){
|
| pParse->checkSchema = 1;
|
| goto exit_drop_index;
|
| }
|
| - if( pIndex->autoIndex ){
|
| + if( pIndex->idxType!=SQLITE_IDXTYPE_APPDEF ){
|
| sqlite3ErrorMsg(pParse, "index associated with UNIQUE "
|
| "or PRIMARY KEY constraint cannot be dropped", 0);
|
| goto exit_drop_index;
|
| @@ -2952,15 +3389,9 @@ void sqlite3DropIndex(Parse *pParse, SrcList *pName, int ifExists){
|
| sqlite3BeginWriteOperation(pParse, 1, iDb);
|
| sqlite3NestedParse(pParse,
|
| "DELETE FROM %Q.%s WHERE name=%Q AND type='index'",
|
| - db->aDb[iDb].zName, SCHEMA_TABLE(iDb),
|
| - pIndex->zName
|
| + db->aDb[iDb].zName, SCHEMA_TABLE(iDb), pIndex->zName
|
| );
|
| - if( sqlite3FindTable(db, "sqlite_stat1", db->aDb[iDb].zName) ){
|
| - sqlite3NestedParse(pParse,
|
| - "DELETE FROM %Q.sqlite_stat1 WHERE idx=%Q",
|
| - db->aDb[iDb].zName, pIndex->zName
|
| - );
|
| - }
|
| + sqlite3ClearStatTables(pParse, iDb, "idx", pIndex->zName);
|
| sqlite3ChangeCookie(pParse, iDb);
|
| destroyRootPage(pParse, pIndex->tnum, iDb);
|
| sqlite3VdbeAddOp4(v, OP_DropIndex, iDb, 0, 0, pIndex->zName, 0);
|
| @@ -2971,45 +3402,43 @@ exit_drop_index:
|
| }
|
|
|
| /*
|
| -** pArray is a pointer to an array of objects. Each object in the
|
| -** array is szEntry bytes in size. This routine allocates a new
|
| -** object on the end of the array.
|
| +** pArray is a pointer to an array of objects. Each object in the
|
| +** array is szEntry bytes in size. This routine uses sqlite3DbRealloc()
|
| +** to extend the array so that there is space for a new object at the end.
|
| **
|
| -** *pnEntry is the number of entries already in use. *pnAlloc is
|
| -** the previously allocated size of the array. initSize is the
|
| -** suggested initial array size allocation.
|
| +** When this function is called, *pnEntry contains the current size of
|
| +** the array (in entries - so the allocation is ((*pnEntry) * szEntry) bytes
|
| +** in total).
|
| **
|
| -** The index of the new entry is returned in *pIdx.
|
| +** If the realloc() is successful (i.e. if no OOM condition occurs), the
|
| +** space allocated for the new object is zeroed, *pnEntry updated to
|
| +** reflect the new size of the array and a pointer to the new allocation
|
| +** returned. *pIdx is set to the index of the new array entry in this case.
|
| **
|
| -** This routine returns a pointer to the array of objects. This
|
| -** might be the same as the pArray parameter or it might be a different
|
| -** pointer if the array was resized.
|
| +** Otherwise, if the realloc() fails, *pIdx is set to -1, *pnEntry remains
|
| +** unchanged and a copy of pArray returned.
|
| */
|
| void *sqlite3ArrayAllocate(
|
| sqlite3 *db, /* Connection to notify of malloc failures */
|
| void *pArray, /* Array of objects. Might be reallocated */
|
| int szEntry, /* Size of each object in the array */
|
| - int initSize, /* Suggested initial allocation, in elements */
|
| int *pnEntry, /* Number of objects currently in use */
|
| - int *pnAlloc, /* Current size of the allocation, in elements */
|
| int *pIdx /* Write the index of a new slot here */
|
| ){
|
| char *z;
|
| - if( *pnEntry >= *pnAlloc ){
|
| - void *pNew;
|
| - int newSize;
|
| - newSize = (*pnAlloc)*2 + initSize;
|
| - pNew = sqlite3DbRealloc(db, pArray, newSize*szEntry);
|
| + int n = *pnEntry;
|
| + if( (n & (n-1))==0 ){
|
| + int sz = (n==0) ? 1 : 2*n;
|
| + void *pNew = sqlite3DbRealloc(db, pArray, sz*szEntry);
|
| if( pNew==0 ){
|
| *pIdx = -1;
|
| return pArray;
|
| }
|
| - *pnAlloc = sqlite3DbMallocSize(db, pNew)/szEntry;
|
| pArray = pNew;
|
| }
|
| z = (char*)pArray;
|
| - memset(&z[*pnEntry * szEntry], 0, szEntry);
|
| - *pIdx = *pnEntry;
|
| + memset(&z[n * szEntry], 0, szEntry);
|
| + *pIdx = n;
|
| ++*pnEntry;
|
| return pArray;
|
| }
|
| @@ -3025,15 +3454,12 @@ IdList *sqlite3IdListAppend(sqlite3 *db, IdList *pList, Token *pToken){
|
| if( pList==0 ){
|
| pList = sqlite3DbMallocZero(db, sizeof(IdList) );
|
| if( pList==0 ) return 0;
|
| - pList->nAlloc = 0;
|
| }
|
| pList->a = sqlite3ArrayAllocate(
|
| db,
|
| pList->a,
|
| sizeof(pList->a[0]),
|
| - 5,
|
| &pList->nId,
|
| - &pList->nAlloc,
|
| &i
|
| );
|
| if( i<0 ){
|
| @@ -3104,7 +3530,7 @@ SrcList *sqlite3SrcListEnlarge(
|
| assert( iStart<=pSrc->nSrc );
|
|
|
| /* Allocate additional space if needed */
|
| - if( pSrc->nSrc+nExtra>pSrc->nAlloc ){
|
| + if( (u32)pSrc->nSrc+nExtra>pSrc->nAlloc ){
|
| SrcList *pNew;
|
| int nAlloc = pSrc->nSrc+nExtra;
|
| int nGot;
|
| @@ -3116,7 +3542,7 @@ SrcList *sqlite3SrcListEnlarge(
|
| }
|
| pSrc = pNew;
|
| nGot = (sqlite3DbMallocSize(db, pNew) - sizeof(*pSrc))/sizeof(pSrc->a[0])+1;
|
| - pSrc->nAlloc = (u16)nGot;
|
| + pSrc->nAlloc = nGot;
|
| }
|
|
|
| /* Move existing slots that come after the newly inserted slots
|
| @@ -3124,7 +3550,7 @@ SrcList *sqlite3SrcListEnlarge(
|
| for(i=pSrc->nSrc-1; i>=iStart; i--){
|
| pSrc->a[i+nExtra] = pSrc->a[i];
|
| }
|
| - pSrc->nSrc += (i16)nExtra;
|
| + pSrc->nSrc += nExtra;
|
|
|
| /* Zero the newly allocated slots */
|
| memset(&pSrc->a[iStart], 0, sizeof(pSrc->a[0])*nExtra);
|
| @@ -3248,7 +3674,7 @@ void sqlite3SrcListDelete(sqlite3 *db, SrcList *pList){
|
| ** if this is the first term of the FROM clause. pTable and pDatabase
|
| ** are the name of the table and database named in the FROM clause term.
|
| ** pDatabase is NULL if the database name qualifier is missing - the
|
| -** usual case. If the term has a alias, then pAlias points to the
|
| +** usual case. If the term has an alias, then pAlias points to the
|
| ** alias token. If the term is a subquery, then pSubquery is the
|
| ** SELECT statement that the subquery encodes. The pTable and
|
| ** pDatabase parameters are NULL for subqueries. The pOn and pUsing
|
| @@ -3332,8 +3758,9 @@ void sqlite3SrcListIndexedBy(Parse *pParse, SrcList *p, Token *pIndexedBy){
|
| ** operator with A. This routine shifts that operator over to B.
|
| */
|
| void sqlite3SrcListShiftJoinType(SrcList *p){
|
| - if( p && p->a ){
|
| + if( p ){
|
| int i;
|
| + assert( p->a || p->nSrc==0 );
|
| for(i=p->nSrc-1; i>0; i--){
|
| p->a[i].jointype = p->a[i-1].jointype;
|
| }
|
| @@ -3371,13 +3798,10 @@ void sqlite3BeginTransaction(Parse *pParse, int type){
|
| ** Commit a transaction
|
| */
|
| void sqlite3CommitTransaction(Parse *pParse){
|
| - sqlite3 *db;
|
| Vdbe *v;
|
|
|
| assert( pParse!=0 );
|
| - db = pParse->db;
|
| - assert( db!=0 );
|
| -/* if( db->aDb[0].pBt==0 ) return; */
|
| + assert( pParse->db!=0 );
|
| if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, "COMMIT", 0, 0) ){
|
| return;
|
| }
|
| @@ -3391,13 +3815,10 @@ void sqlite3CommitTransaction(Parse *pParse){
|
| ** Rollback a transaction
|
| */
|
| void sqlite3RollbackTransaction(Parse *pParse){
|
| - sqlite3 *db;
|
| Vdbe *v;
|
|
|
| assert( pParse!=0 );
|
| - db = pParse->db;
|
| - assert( db!=0 );
|
| -/* if( db->aDb[0].pBt==0 ) return; */
|
| + assert( pParse->db!=0 );
|
| if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, "ROLLBACK", 0, 0) ){
|
| return;
|
| }
|
| @@ -3443,7 +3864,7 @@ int sqlite3OpenTempDatabase(Parse *pParse){
|
| SQLITE_OPEN_DELETEONCLOSE |
|
| SQLITE_OPEN_TEMP_DB;
|
|
|
| - rc = sqlite3BtreeOpen(0, db, &pBt, 0, flags);
|
| + rc = sqlite3BtreeOpen(db->pVfs, 0, db, &pBt, 0, flags);
|
| if( rc!=SQLITE_OK ){
|
| sqlite3ErrorMsg(pParse, "unable to open a temporary database "
|
| "file for storing temporary tables");
|
| @@ -3461,50 +3882,24 @@ int sqlite3OpenTempDatabase(Parse *pParse){
|
| }
|
|
|
| /*
|
| -** Generate VDBE code that will verify the schema cookie and start
|
| -** a read-transaction for all named database files.
|
| -**
|
| -** It is important that all schema cookies be verified and all
|
| -** read transactions be started before anything else happens in
|
| -** the VDBE program. But this routine can be called after much other
|
| -** code has been generated. So here is what we do:
|
| -**
|
| -** The first time this routine is called, we code an OP_Goto that
|
| -** will jump to a subroutine at the end of the program. Then we
|
| -** record every database that needs its schema verified in the
|
| -** pParse->cookieMask field. Later, after all other code has been
|
| -** generated, the subroutine that does the cookie verifications and
|
| -** starts the transactions will be coded and the OP_Goto P2 value
|
| -** will be made to point to that subroutine. The generation of the
|
| -** cookie verification subroutine code happens in sqlite3FinishCoding().
|
| -**
|
| -** If iDb<0 then code the OP_Goto only - don't set flag to verify the
|
| -** schema on any databases. This can be used to position the OP_Goto
|
| -** early in the code, before we know if any database tables will be used.
|
| +** Record the fact that the schema cookie will need to be verified
|
| +** for database iDb. The code to actually verify the schema cookie
|
| +** will occur at the end of the top-level VDBE and will be generated
|
| +** later, by sqlite3FinishCoding().
|
| */
|
| void sqlite3CodeVerifySchema(Parse *pParse, int iDb){
|
| Parse *pToplevel = sqlite3ParseToplevel(pParse);
|
| + sqlite3 *db = pToplevel->db;
|
|
|
| - if( pToplevel->cookieGoto==0 ){
|
| - Vdbe *v = sqlite3GetVdbe(pToplevel);
|
| - if( v==0 ) return; /* This only happens if there was a prior error */
|
| - pToplevel->cookieGoto = sqlite3VdbeAddOp2(v, OP_Goto, 0, 0)+1;
|
| - }
|
| - if( iDb>=0 ){
|
| - sqlite3 *db = pToplevel->db;
|
| - yDbMask mask;
|
| -
|
| - assert( iDb<db->nDb );
|
| - assert( db->aDb[iDb].pBt!=0 || iDb==1 );
|
| - assert( iDb<SQLITE_MAX_ATTACHED+2 );
|
| - assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
|
| - mask = ((yDbMask)1)<<iDb;
|
| - if( (pToplevel->cookieMask & mask)==0 ){
|
| - pToplevel->cookieMask |= mask;
|
| - pToplevel->cookieValue[iDb] = db->aDb[iDb].pSchema->schema_cookie;
|
| - if( !OMIT_TEMPDB && iDb==1 ){
|
| - sqlite3OpenTempDatabase(pToplevel);
|
| - }
|
| + assert( iDb>=0 && iDb<db->nDb );
|
| + assert( db->aDb[iDb].pBt!=0 || iDb==1 );
|
| + assert( iDb<SQLITE_MAX_ATTACHED+2 );
|
| + assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
|
| + if( DbMaskTest(pToplevel->cookieMask, iDb)==0 ){
|
| + DbMaskSet(pToplevel->cookieMask, iDb);
|
| + pToplevel->cookieValue[iDb] = db->aDb[iDb].pSchema->schema_cookie;
|
| + if( !OMIT_TEMPDB && iDb==1 ){
|
| + sqlite3OpenTempDatabase(pToplevel);
|
| }
|
| }
|
| }
|
| @@ -3540,7 +3935,7 @@ void sqlite3CodeVerifyNamedSchema(Parse *pParse, const char *zDb){
|
| void sqlite3BeginWriteOperation(Parse *pParse, int setStatement, int iDb){
|
| Parse *pToplevel = sqlite3ParseToplevel(pParse);
|
| sqlite3CodeVerifySchema(pParse, iDb);
|
| - pToplevel->writeMask |= ((yDbMask)1)<<iDb;
|
| + DbMaskSet(pToplevel->writeMask, iDb);
|
| pToplevel->isMultiWrite |= setStatement;
|
| }
|
|
|
| @@ -3582,12 +3977,73 @@ void sqlite3MayAbort(Parse *pParse){
|
| ** error. The onError parameter determines which (if any) of the statement
|
| ** and/or current transaction is rolled back.
|
| */
|
| -void sqlite3HaltConstraint(Parse *pParse, int onError, char *p4, int p4type){
|
| +void sqlite3HaltConstraint(
|
| + Parse *pParse, /* Parsing context */
|
| + int errCode, /* extended error code */
|
| + int onError, /* Constraint type */
|
| + char *p4, /* Error message */
|
| + i8 p4type, /* P4_STATIC or P4_TRANSIENT */
|
| + u8 p5Errmsg /* P5_ErrMsg type */
|
| +){
|
| Vdbe *v = sqlite3GetVdbe(pParse);
|
| + assert( (errCode&0xff)==SQLITE_CONSTRAINT );
|
| if( onError==OE_Abort ){
|
| sqlite3MayAbort(pParse);
|
| }
|
| - sqlite3VdbeAddOp4(v, OP_Halt, SQLITE_CONSTRAINT, onError, 0, p4, p4type);
|
| + sqlite3VdbeAddOp4(v, OP_Halt, errCode, onError, 0, p4, p4type);
|
| + if( p5Errmsg ) sqlite3VdbeChangeP5(v, p5Errmsg);
|
| +}
|
| +
|
| +/*
|
| +** Code an OP_Halt due to UNIQUE or PRIMARY KEY constraint violation.
|
| +*/
|
| +void sqlite3UniqueConstraint(
|
| + Parse *pParse, /* Parsing context */
|
| + int onError, /* Constraint type */
|
| + Index *pIdx /* The index that triggers the constraint */
|
| +){
|
| + char *zErr;
|
| + int j;
|
| + StrAccum errMsg;
|
| + Table *pTab = pIdx->pTable;
|
| +
|
| + sqlite3StrAccumInit(&errMsg, 0, 0, 200);
|
| + errMsg.db = pParse->db;
|
| + for(j=0; j<pIdx->nKeyCol; j++){
|
| + char *zCol = pTab->aCol[pIdx->aiColumn[j]].zName;
|
| + if( j ) sqlite3StrAccumAppend(&errMsg, ", ", 2);
|
| + sqlite3StrAccumAppendAll(&errMsg, pTab->zName);
|
| + sqlite3StrAccumAppend(&errMsg, ".", 1);
|
| + sqlite3StrAccumAppendAll(&errMsg, zCol);
|
| + }
|
| + zErr = sqlite3StrAccumFinish(&errMsg);
|
| + sqlite3HaltConstraint(pParse,
|
| + IsPrimaryKeyIndex(pIdx) ? SQLITE_CONSTRAINT_PRIMARYKEY
|
| + : SQLITE_CONSTRAINT_UNIQUE,
|
| + onError, zErr, P4_DYNAMIC, P5_ConstraintUnique);
|
| +}
|
| +
|
| +
|
| +/*
|
| +** Code an OP_Halt due to non-unique rowid.
|
| +*/
|
| +void sqlite3RowidConstraint(
|
| + Parse *pParse, /* Parsing context */
|
| + int onError, /* Conflict resolution algorithm */
|
| + Table *pTab /* The table with the non-unique rowid */
|
| +){
|
| + char *zMsg;
|
| + int rc;
|
| + if( pTab->iPKey>=0 ){
|
| + zMsg = sqlite3MPrintf(pParse->db, "%s.%s", pTab->zName,
|
| + pTab->aCol[pTab->iPKey].zName);
|
| + rc = SQLITE_CONSTRAINT_PRIMARYKEY;
|
| + }else{
|
| + zMsg = sqlite3MPrintf(pParse->db, "%s.rowid", pTab->zName);
|
| + rc = SQLITE_CONSTRAINT_ROWID;
|
| + }
|
| + sqlite3HaltConstraint(pParse, rc, onError, zMsg, P4_DYNAMIC,
|
| + P5_ConstraintUnique);
|
| }
|
|
|
| /*
|
| @@ -3600,8 +4056,8 @@ static int collationMatch(const char *zColl, Index *pIndex){
|
| assert( zColl!=0 );
|
| for(i=0; i<pIndex->nColumn; i++){
|
| const char *z = pIndex->azColl[i];
|
| - assert( z!=0 );
|
| - if( 0==sqlite3StrICmp(z, zColl) ){
|
| + assert( z!=0 || pIndex->aiColumn[i]<0 );
|
| + if( pIndex->aiColumn[i]>=0 && 0==sqlite3StrICmp(z, zColl) ){
|
| return 1;
|
| }
|
| }
|
| @@ -3720,38 +4176,118 @@ void sqlite3Reindex(Parse *pParse, Token *pName1, Token *pName2){
|
| #endif
|
|
|
| /*
|
| -** Return a dynamicly allocated KeyInfo structure that can be used
|
| -** with OP_OpenRead or OP_OpenWrite to access database index pIdx.
|
| +** Return a KeyInfo structure that is appropriate for the given Index.
|
| +**
|
| +** The KeyInfo structure for an index is cached in the Index object.
|
| +** So there might be multiple references to the returned pointer. The
|
| +** caller should not try to modify the KeyInfo object.
|
| **
|
| -** If successful, a pointer to the new structure is returned. In this case
|
| -** the caller is responsible for calling sqlite3DbFree(db, ) 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.
|
| +** The caller should invoke sqlite3KeyInfoUnref() on the returned object
|
| +** when it has finished using it.
|
| */
|
| -KeyInfo *sqlite3IndexKeyinfo(Parse *pParse, Index *pIdx){
|
| - int i;
|
| - int nCol = pIdx->nColumn;
|
| - int nBytes = sizeof(KeyInfo) + (nCol-1)*sizeof(CollSeq*) + nCol;
|
| +KeyInfo *sqlite3KeyInfoOfIndex(Parse *pParse, Index *pIdx){
|
| + if( pParse->nErr ) return 0;
|
| +#ifndef SQLITE_OMIT_SHARED_CACHE
|
| + if( pIdx->pKeyInfo && pIdx->pKeyInfo->db!=pParse->db ){
|
| + sqlite3KeyInfoUnref(pIdx->pKeyInfo);
|
| + pIdx->pKeyInfo = 0;
|
| + }
|
| +#endif
|
| + if( pIdx->pKeyInfo==0 ){
|
| + int i;
|
| + int nCol = pIdx->nColumn;
|
| + int nKey = pIdx->nKeyCol;
|
| + KeyInfo *pKey;
|
| + if( pIdx->uniqNotNull ){
|
| + pKey = sqlite3KeyInfoAlloc(pParse->db, nKey, nCol-nKey);
|
| + }else{
|
| + pKey = sqlite3KeyInfoAlloc(pParse->db, nCol, 0);
|
| + }
|
| + if( pKey ){
|
| + assert( sqlite3KeyInfoIsWriteable(pKey) );
|
| + for(i=0; i<nCol; i++){
|
| + char *zColl = pIdx->azColl[i];
|
| + assert( zColl!=0 );
|
| + pKey->aColl[i] = strcmp(zColl,"BINARY")==0 ? 0 :
|
| + sqlite3LocateCollSeq(pParse, zColl);
|
| + pKey->aSortOrder[i] = pIdx->aSortOrder[i];
|
| + }
|
| + if( pParse->nErr ){
|
| + sqlite3KeyInfoUnref(pKey);
|
| + }else{
|
| + pIdx->pKeyInfo = pKey;
|
| + }
|
| + }
|
| + }
|
| + return sqlite3KeyInfoRef(pIdx->pKeyInfo);
|
| +}
|
| +
|
| +#ifndef SQLITE_OMIT_CTE
|
| +/*
|
| +** This routine is invoked once per CTE by the parser while parsing a
|
| +** WITH clause.
|
| +*/
|
| +With *sqlite3WithAdd(
|
| + Parse *pParse, /* Parsing context */
|
| + With *pWith, /* Existing WITH clause, or NULL */
|
| + Token *pName, /* Name of the common-table */
|
| + ExprList *pArglist, /* Optional column name list for the table */
|
| + Select *pQuery /* Query used to initialize the table */
|
| +){
|
| sqlite3 *db = pParse->db;
|
| - KeyInfo *pKey = (KeyInfo *)sqlite3DbMallocZero(db, nBytes);
|
| + With *pNew;
|
| + char *zName;
|
|
|
| - if( pKey ){
|
| - pKey->db = pParse->db;
|
| - 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);
|
| - pKey->aSortOrder[i] = pIdx->aSortOrder[i];
|
| + /* Check that the CTE name is unique within this WITH clause. If
|
| + ** not, store an error in the Parse structure. */
|
| + zName = sqlite3NameFromToken(pParse->db, pName);
|
| + if( zName && pWith ){
|
| + int i;
|
| + for(i=0; i<pWith->nCte; i++){
|
| + if( sqlite3StrICmp(zName, pWith->a[i].zName)==0 ){
|
| + sqlite3ErrorMsg(pParse, "duplicate WITH table name: %s", zName);
|
| + }
|
| }
|
| - pKey->nField = (u16)nCol;
|
| }
|
|
|
| - if( pParse->nErr ){
|
| - sqlite3DbFree(db, pKey);
|
| - pKey = 0;
|
| + if( pWith ){
|
| + int nByte = sizeof(*pWith) + (sizeof(pWith->a[1]) * pWith->nCte);
|
| + pNew = sqlite3DbRealloc(db, pWith, nByte);
|
| + }else{
|
| + pNew = sqlite3DbMallocZero(db, sizeof(*pWith));
|
| + }
|
| + assert( zName!=0 || pNew==0 );
|
| + assert( db->mallocFailed==0 || pNew==0 );
|
| +
|
| + if( pNew==0 ){
|
| + sqlite3ExprListDelete(db, pArglist);
|
| + sqlite3SelectDelete(db, pQuery);
|
| + sqlite3DbFree(db, zName);
|
| + pNew = pWith;
|
| + }else{
|
| + pNew->a[pNew->nCte].pSelect = pQuery;
|
| + pNew->a[pNew->nCte].pCols = pArglist;
|
| + pNew->a[pNew->nCte].zName = zName;
|
| + pNew->a[pNew->nCte].zErr = 0;
|
| + pNew->nCte++;
|
| + }
|
| +
|
| + return pNew;
|
| +}
|
| +
|
| +/*
|
| +** Free the contents of the With object passed as the second argument.
|
| +*/
|
| +void sqlite3WithDelete(sqlite3 *db, With *pWith){
|
| + if( pWith ){
|
| + int i;
|
| + for(i=0; i<pWith->nCte; i++){
|
| + struct Cte *pCte = &pWith->a[i];
|
| + sqlite3ExprListDelete(db, pCte->pCols);
|
| + sqlite3SelectDelete(db, pCte->pSelect);
|
| + sqlite3DbFree(db, pCte->zName);
|
| + }
|
| + sqlite3DbFree(db, pWith);
|
| }
|
| - return pKey;
|
| }
|
| +#endif /* !defined(SQLITE_OMIT_CTE) */
|
|
|