| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | #include "sqliteInt.h" |
| |
|
| | #ifndef SQLITE_OMIT_SHARED_CACHE |
| | |
| | |
| | |
| | |
| | struct TableLock { |
| | int iDb; |
| | Pgno iTab; |
| | u8 isWriteLock; |
| | const char *zLockName; |
| | }; |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | static SQLITE_NOINLINE void lockTable( |
| | Parse *pParse, |
| | int iDb, |
| | Pgno iTab, |
| | u8 isWriteLock, |
| | const char *zName |
| | ){ |
| | Parse *pToplevel; |
| | int i; |
| | int nBytes; |
| | TableLock *p; |
| | assert( iDb>=0 ); |
| |
|
| | pToplevel = sqlite3ParseToplevel(pParse); |
| | for(i=0; i<pToplevel->nTableLock; i++){ |
| | p = &pToplevel->aTableLock[i]; |
| | if( p->iDb==iDb && p->iTab==iTab ){ |
| | p->isWriteLock = (p->isWriteLock || isWriteLock); |
| | return; |
| | } |
| | } |
| |
|
| | assert( pToplevel->nTableLock < 0x7fff0000 ); |
| | nBytes = sizeof(TableLock) * (pToplevel->nTableLock+1); |
| | pToplevel->aTableLock = |
| | sqlite3DbReallocOrFree(pToplevel->db, pToplevel->aTableLock, nBytes); |
| | if( pToplevel->aTableLock ){ |
| | p = &pToplevel->aTableLock[pToplevel->nTableLock++]; |
| | p->iDb = iDb; |
| | p->iTab = iTab; |
| | p->isWriteLock = isWriteLock; |
| | p->zLockName = zName; |
| | }else{ |
| | pToplevel->nTableLock = 0; |
| | sqlite3OomFault(pToplevel->db); |
| | } |
| | } |
| | void sqlite3TableLock( |
| | Parse *pParse, |
| | int iDb, |
| | Pgno iTab, |
| | u8 isWriteLock, |
| | const char *zName |
| | ){ |
| | if( iDb==1 ) return; |
| | if( !sqlite3BtreeSharable(pParse->db->aDb[iDb].pBt) ) return; |
| | lockTable(pParse, iDb, iTab, isWriteLock, zName); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | static void codeTableLocks(Parse *pParse){ |
| | int i; |
| | Vdbe *pVdbe = pParse->pVdbe; |
| | assert( pVdbe!=0 ); |
| |
|
| | for(i=0; i<pParse->nTableLock; i++){ |
| | TableLock *p = &pParse->aTableLock[i]; |
| | int p1 = p->iDb; |
| | sqlite3VdbeAddOp4(pVdbe, OP_TableLock, p1, p->iTab, p->isWriteLock, |
| | p->zLockName, P4_STATIC); |
| | } |
| | } |
| | #else |
| | #define codeTableLocks(x) |
| | #endif |
| |
|
| | |
| | |
| | |
| | |
| | |
| | #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 |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | void sqlite3FinishCoding(Parse *pParse){ |
| | sqlite3 *db; |
| | Vdbe *v; |
| | int iDb, i; |
| |
|
| | assert( pParse->pToplevel==0 ); |
| | db = pParse->db; |
| | assert( db->pParse==pParse ); |
| | if( pParse->nested ) return; |
| | if( pParse->nErr ){ |
| | if( db->mallocFailed ) pParse->rc = SQLITE_NOMEM; |
| | return; |
| | } |
| | assert( db->mallocFailed==0 ); |
| |
|
| | |
| | |
| | |
| | v = pParse->pVdbe; |
| | if( v==0 ){ |
| | if( db->init.busy ){ |
| | pParse->rc = SQLITE_DONE; |
| | return; |
| | } |
| | v = sqlite3GetVdbe(pParse); |
| | if( v==0 ) pParse->rc = SQLITE_ERROR; |
| | } |
| | assert( !pParse->isMultiWrite |
| | || sqlite3VdbeAssertMayAbort(v, pParse->mayAbort)); |
| | if( v ){ |
| | if( pParse->bReturning ){ |
| | Returning *pReturning; |
| | int addrRewind; |
| | int reg; |
| |
|
| | assert( !pParse->isCreate ); |
| | pReturning = pParse->u1.d.pReturning; |
| | if( pReturning->nRetCol ){ |
| | sqlite3VdbeAddOp0(v, OP_FkCheck); |
| | addrRewind = |
| | sqlite3VdbeAddOp1(v, OP_Rewind, pReturning->iRetCur); |
| | VdbeCoverage(v); |
| | reg = pReturning->iRetReg; |
| | for(i=0; i<pReturning->nRetCol; i++){ |
| | sqlite3VdbeAddOp3(v, OP_Column, pReturning->iRetCur, i, reg+i); |
| | } |
| | sqlite3VdbeAddOp2(v, OP_ResultRow, reg, i); |
| | sqlite3VdbeAddOp2(v, OP_Next, pReturning->iRetCur, addrRewind+1); |
| | VdbeCoverage(v); |
| | sqlite3VdbeJumpHere(v, addrRewind); |
| | } |
| | } |
| | sqlite3VdbeAddOp0(v, OP_Halt); |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | assert( pParse->nErr>0 || sqlite3VdbeGetOp(v, 0)->opcode==OP_Init ); |
| | sqlite3VdbeJumpHere(v, 0); |
| | assert( db->nDb>0 ); |
| | iDb = 0; |
| | do{ |
| | Schema *pSchema; |
| | if( DbMaskTest(pParse->cookieMask, iDb)==0 ) continue; |
| | sqlite3VdbeUsesBtree(v, iDb); |
| | pSchema = db->aDb[iDb].pSchema; |
| | sqlite3VdbeAddOp4Int(v, |
| | OP_Transaction, |
| | iDb, |
| | DbMaskTest(pParse->writeMask,iDb), |
| | pSchema->schema_cookie, |
| | pSchema->iGeneration |
| | ); |
| | if( db->init.busy==0 ) sqlite3VdbeChangeP5(v, 1); |
| | VdbeComment((v, |
| | "usesStmtJournal=%d", pParse->mayAbort && pParse->isMultiWrite)); |
| | }while( ++iDb<db->nDb ); |
| | #ifndef SQLITE_OMIT_VIRTUALTABLE |
| | 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 |
| |
|
| | #ifndef SQLITE_OMIT_SHARED_CACHE |
| | |
| | |
| | |
| | |
| | if( pParse->nTableLock ) codeTableLocks(pParse); |
| | #endif |
| |
|
| | |
| | |
| | if( pParse->pAinc ) sqlite3AutoincrementBegin(pParse); |
| |
|
| | |
| | |
| | if( pParse->pConstExpr ){ |
| | ExprList *pEL = pParse->pConstExpr; |
| | pParse->okConstFactor = 0; |
| | for(i=0; i<pEL->nExpr; i++){ |
| | assert( pEL->a[i].u.iConstExprReg>0 ); |
| | sqlite3ExprCode(pParse, pEL->a[i].pExpr, pEL->a[i].u.iConstExprReg); |
| | } |
| | } |
| |
|
| | if( pParse->bReturning ){ |
| | Returning *pRet; |
| | assert( !pParse->isCreate ); |
| | pRet = pParse->u1.d.pReturning; |
| | if( pRet->nRetCol ){ |
| | sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pRet->iRetCur, pRet->nRetCol); |
| | } |
| | } |
| |
|
| | |
| | sqlite3VdbeGoto(v, 1); |
| | } |
| |
|
| | |
| | |
| | assert( v!=0 || pParse->nErr ); |
| | assert( db->mallocFailed==0 || pParse->nErr ); |
| | if( pParse->nErr==0 ){ |
| | |
| | |
| | assert( pParse->pAinc==0 || pParse->nTab>0 ); |
| | sqlite3VdbeMakeReady(v, pParse); |
| | pParse->rc = SQLITE_DONE; |
| | }else{ |
| | pParse->rc = SQLITE_ERROR; |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | void sqlite3NestedParse(Parse *pParse, const char *zFormat, ...){ |
| | va_list ap; |
| | char *zSql; |
| | sqlite3 *db = pParse->db; |
| | u32 savedDbFlags = db->mDbFlags; |
| | char saveBuf[PARSE_TAIL_SZ]; |
| |
|
| | if( pParse->nErr ) return; |
| | if( pParse->eParseMode ) return; |
| | assert( pParse->nested<10 ); |
| | va_start(ap, zFormat); |
| | zSql = sqlite3VMPrintf(db, zFormat, ap); |
| | va_end(ap); |
| | if( zSql==0 ){ |
| | |
| | |
| | |
| | if( !db->mallocFailed ) pParse->rc = SQLITE_TOOBIG; |
| | pParse->nErr++; |
| | return; |
| | } |
| | pParse->nested++; |
| | memcpy(saveBuf, PARSE_TAIL(pParse), PARSE_TAIL_SZ); |
| | memset(PARSE_TAIL(pParse), 0, PARSE_TAIL_SZ); |
| | db->mDbFlags |= DBFLAG_PreferBuiltin; |
| | sqlite3RunParser(pParse, zSql); |
| | db->mDbFlags = savedDbFlags; |
| | sqlite3DbFree(db, zSql); |
| | memcpy(PARSE_TAIL(pParse), saveBuf, PARSE_TAIL_SZ); |
| | pParse->nested--; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | Table *sqlite3FindTable(sqlite3 *db, const char *zName, const char *zDatabase){ |
| | Table *p = 0; |
| | int i; |
| |
|
| | |
| | assert( zDatabase!=0 || sqlite3BtreeHoldsAllMutexes(db) ); |
| | if( zDatabase ){ |
| | for(i=0; i<db->nDb; i++){ |
| | if( sqlite3StrICmp(zDatabase, db->aDb[i].zDbSName)==0 ) break; |
| | } |
| | if( i>=db->nDb ){ |
| | |
| | |
| | if( sqlite3StrICmp(zDatabase,"main")==0 ){ |
| | i = 0; |
| | }else{ |
| | return 0; |
| | } |
| | } |
| | p = sqlite3HashFind(&db->aDb[i].pSchema->tblHash, zName); |
| | if( p==0 && sqlite3StrNICmp(zName, "sqlite_", 7)==0 ){ |
| | if( i==1 ){ |
| | if( sqlite3StrICmp(zName+7, &PREFERRED_TEMP_SCHEMA_TABLE[7])==0 |
| | || sqlite3StrICmp(zName+7, &PREFERRED_SCHEMA_TABLE[7])==0 |
| | || sqlite3StrICmp(zName+7, &LEGACY_SCHEMA_TABLE[7])==0 |
| | ){ |
| | p = sqlite3HashFind(&db->aDb[1].pSchema->tblHash, |
| | LEGACY_TEMP_SCHEMA_TABLE); |
| | } |
| | }else{ |
| | if( sqlite3StrICmp(zName+7, &PREFERRED_SCHEMA_TABLE[7])==0 ){ |
| | p = sqlite3HashFind(&db->aDb[i].pSchema->tblHash, |
| | LEGACY_SCHEMA_TABLE); |
| | } |
| | } |
| | } |
| | }else{ |
| | |
| | p = sqlite3HashFind(&db->aDb[1].pSchema->tblHash, zName); |
| | if( p ) return p; |
| | |
| | p = sqlite3HashFind(&db->aDb[0].pSchema->tblHash, zName); |
| | if( p ) return p; |
| | |
| | for(i=2; i<db->nDb; i++){ |
| | assert( sqlite3SchemaMutexHeld(db, i, 0) ); |
| | p = sqlite3HashFind(&db->aDb[i].pSchema->tblHash, zName); |
| | if( p ) break; |
| | } |
| | if( p==0 && sqlite3StrNICmp(zName, "sqlite_", 7)==0 ){ |
| | if( sqlite3StrICmp(zName+7, &PREFERRED_SCHEMA_TABLE[7])==0 ){ |
| | p = sqlite3HashFind(&db->aDb[0].pSchema->tblHash, LEGACY_SCHEMA_TABLE); |
| | }else if( sqlite3StrICmp(zName+7, &PREFERRED_TEMP_SCHEMA_TABLE[7])==0 ){ |
| | p = sqlite3HashFind(&db->aDb[1].pSchema->tblHash, |
| | LEGACY_TEMP_SCHEMA_TABLE); |
| | } |
| | } |
| | } |
| | return p; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | Table *sqlite3LocateTable( |
| | Parse *pParse, |
| | u32 flags, |
| | const char *zName, |
| | const char *zDbase |
| | ){ |
| | Table *p; |
| | sqlite3 *db = pParse->db; |
| |
|
| | |
| | |
| | if( (db->mDbFlags & DBFLAG_SchemaKnownOk)==0 |
| | && SQLITE_OK!=sqlite3ReadSchema(pParse) |
| | ){ |
| | return 0; |
| | } |
| |
|
| | p = sqlite3FindTable(db, zName, zDbase); |
| | if( p==0 ){ |
| | #ifndef SQLITE_OMIT_VIRTUALTABLE |
| | |
| | |
| | |
| | if( (pParse->prepFlags & SQLITE_PREPARE_NO_VTAB)==0 && db->init.busy==0 ){ |
| | Module *pMod = (Module*)sqlite3HashFind(&db->aModule, zName); |
| | if( pMod==0 && sqlite3_strnicmp(zName, "pragma_", 7)==0 ){ |
| | pMod = sqlite3PragmaVtabRegister(db, zName); |
| | } |
| | #ifndef SQLITE_OMIT_JSON |
| | if( pMod==0 && sqlite3_strnicmp(zName, "json", 4)==0 ){ |
| | pMod = sqlite3JsonVtabRegister(db, zName); |
| | } |
| | #endif |
| | #ifdef SQLITE_ENABLE_CARRAY |
| | if( pMod==0 && sqlite3_stricmp(zName, "carray")==0 ){ |
| | pMod = sqlite3CarrayRegister(db); |
| | } |
| | #endif |
| | if( pMod && sqlite3VtabEponymousTableInit(pParse, pMod) ){ |
| | testcase( pMod->pEpoTab==0 ); |
| | return pMod->pEpoTab; |
| | } |
| | } |
| | #endif |
| | if( flags & LOCATE_NOERR ) return 0; |
| | pParse->checkSchema = 1; |
| | }else if( IsVirtual(p) && (pParse->prepFlags & SQLITE_PREPARE_NO_VTAB)!=0 ){ |
| | p = 0; |
| | } |
| |
|
| | if( p==0 ){ |
| | const char *zMsg = flags & LOCATE_VIEW ? "no such view" : "no such table"; |
| | if( zDbase ){ |
| | sqlite3ErrorMsg(pParse, "%s: %s.%s", zMsg, zDbase, zName); |
| | }else{ |
| | sqlite3ErrorMsg(pParse, "%s: %s", zMsg, zName); |
| | } |
| | }else{ |
| | assert( HasRowid(p) || p->iPKey<0 ); |
| | } |
| |
|
| | return p; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | Table *sqlite3LocateTableItem( |
| | Parse *pParse, |
| | u32 flags, |
| | SrcItem *p |
| | ){ |
| | const char *zDb; |
| | if( p->fg.fixedSchema ){ |
| | int iDb = sqlite3SchemaToIndex(pParse->db, p->u4.pSchema); |
| | zDb = pParse->db->aDb[iDb].zDbSName; |
| | }else{ |
| | assert( !p->fg.isSubquery ); |
| | zDb = p->u4.zDatabase; |
| | } |
| | return sqlite3LocateTable(pParse, flags, p->zName, zDb); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | const char *sqlite3PreferredTableName(const char *zName){ |
| | if( sqlite3StrNICmp(zName, "sqlite_", 7)==0 ){ |
| | if( sqlite3StrICmp(zName+7, &LEGACY_SCHEMA_TABLE[7])==0 ){ |
| | return PREFERRED_SCHEMA_TABLE; |
| | } |
| | if( sqlite3StrICmp(zName+7, &LEGACY_TEMP_SCHEMA_TABLE[7])==0 ){ |
| | return PREFERRED_TEMP_SCHEMA_TABLE; |
| | } |
| | } |
| | return zName; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | Index *sqlite3FindIndex(sqlite3 *db, const char *zName, const char *zDb){ |
| | Index *p = 0; |
| | int i; |
| | |
| | assert( zDb!=0 || sqlite3BtreeHoldsAllMutexes(db) ); |
| | for(i=OMIT_TEMPDB; i<db->nDb; i++){ |
| | int j = (i<2) ? i^1 : i; |
| | Schema *pSchema = db->aDb[j].pSchema; |
| | assert( pSchema ); |
| | if( zDb && sqlite3DbIsNamed(db, j, zDb)==0 ) continue; |
| | assert( sqlite3SchemaMutexHeld(db, j, 0) ); |
| | p = sqlite3HashFind(&pSchema->idxHash, zName); |
| | if( p ) break; |
| | } |
| | return p; |
| | } |
| |
|
| | |
| | |
| | |
| | void sqlite3FreeIndex(sqlite3 *db, Index *p){ |
| | #ifndef SQLITE_OMIT_ANALYZE |
| | sqlite3DeleteIndexSamples(db, p); |
| | #endif |
| | sqlite3ExprDelete(db, p->pPartIdxWhere); |
| | sqlite3ExprListDelete(db, p->aColExpr); |
| | sqlite3DbFree(db, p->zColAff); |
| | if( p->isResized ) sqlite3DbFree(db, (void *)p->azColl); |
| | #ifdef SQLITE_ENABLE_STAT4 |
| | sqlite3_free(p->aiRowEst); |
| | #endif |
| | sqlite3DbFree(db, p); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | void sqlite3UnlinkAndDeleteIndex(sqlite3 *db, int iDb, const char *zIdxName){ |
| | Index *pIndex; |
| | Hash *pHash; |
| |
|
| | assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); |
| | pHash = &db->aDb[iDb].pSchema->idxHash; |
| | pIndex = sqlite3HashInsert(pHash, zIdxName, 0); |
| | if( ALWAYS(pIndex) ){ |
| | if( pIndex->pTable->pIndex==pIndex ){ |
| | pIndex->pTable->pIndex = pIndex->pNext; |
| | }else{ |
| | Index *p; |
| | |
| | |
| | p = pIndex->pTable->pIndex; |
| | while( ALWAYS(p) && p->pNext!=pIndex ){ p = p->pNext; } |
| | if( ALWAYS(p && p->pNext==pIndex) ){ |
| | p->pNext = pIndex->pNext; |
| | } |
| | } |
| | sqlite3FreeIndex(db, pIndex); |
| | } |
| | db->mDbFlags |= DBFLAG_SchemaChange; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | void sqlite3CollapseDatabaseArray(sqlite3 *db){ |
| | int i, j; |
| | for(i=j=2; i<db->nDb; i++){ |
| | struct Db *pDb = &db->aDb[i]; |
| | if( pDb->pBt==0 ){ |
| | sqlite3DbFree(db, pDb->zDbSName); |
| | pDb->zDbSName = 0; |
| | continue; |
| | } |
| | if( j<i ){ |
| | db->aDb[j] = db->aDb[i]; |
| | } |
| | j++; |
| | } |
| | db->nDb = j; |
| | if( db->nDb<=2 && db->aDb!=db->aDbStatic ){ |
| | memcpy(db->aDbStatic, db->aDb, 2*sizeof(db->aDb[0])); |
| | sqlite3DbFree(db, db->aDb); |
| | db->aDb = db->aDbStatic; |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | void sqlite3ResetOneSchema(sqlite3 *db, int iDb){ |
| | int i; |
| | assert( iDb<db->nDb ); |
| |
|
| | if( iDb>=0 ){ |
| | assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); |
| | DbSetProperty(db, iDb, DB_ResetWanted); |
| | DbSetProperty(db, 1, DB_ResetWanted); |
| | db->mDbFlags &= ~DBFLAG_SchemaKnownOk; |
| | } |
| |
|
| | if( db->nSchemaLock==0 ){ |
| | for(i=0; i<db->nDb; i++){ |
| | if( DbHasProperty(db, i, DB_ResetWanted) ){ |
| | sqlite3SchemaClear(db->aDb[i].pSchema); |
| | } |
| | } |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | void sqlite3ResetAllSchemasOfConnection(sqlite3 *db){ |
| | int i; |
| | sqlite3BtreeEnterAll(db); |
| | for(i=0; i<db->nDb; i++){ |
| | Db *pDb = &db->aDb[i]; |
| | if( pDb->pSchema ){ |
| | if( db->nSchemaLock==0 ){ |
| | sqlite3SchemaClear(pDb->pSchema); |
| | }else{ |
| | DbSetProperty(db, i, DB_ResetWanted); |
| | } |
| | } |
| | } |
| | db->mDbFlags &= ~(DBFLAG_SchemaChange|DBFLAG_SchemaKnownOk); |
| | sqlite3VtabUnlockList(db); |
| | sqlite3BtreeLeaveAll(db); |
| | if( db->nSchemaLock==0 ){ |
| | sqlite3CollapseDatabaseArray(db); |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | void sqlite3CommitInternalChanges(sqlite3 *db){ |
| | db->mDbFlags &= ~DBFLAG_SchemaChange; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | void sqlite3ColumnSetExpr( |
| | Parse *pParse, |
| | Table *pTab, |
| | Column *pCol, |
| | Expr *pExpr |
| | ){ |
| | ExprList *pList; |
| | assert( IsOrdinaryTable(pTab) ); |
| | pList = pTab->u.tab.pDfltList; |
| | if( pCol->iDflt==0 |
| | || NEVER(pList==0) |
| | || NEVER(pList->nExpr<pCol->iDflt) |
| | ){ |
| | pCol->iDflt = pList==0 ? 1 : pList->nExpr+1; |
| | pTab->u.tab.pDfltList = sqlite3ExprListAppend(pParse, pList, pExpr); |
| | }else{ |
| | sqlite3ExprDelete(pParse->db, pList->a[pCol->iDflt-1].pExpr); |
| | pList->a[pCol->iDflt-1].pExpr = pExpr; |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | Expr *sqlite3ColumnExpr(Table *pTab, Column *pCol){ |
| | if( pCol->iDflt==0 ) return 0; |
| | if( !IsOrdinaryTable(pTab) ) return 0; |
| | if( NEVER(pTab->u.tab.pDfltList==0) ) return 0; |
| | if( NEVER(pTab->u.tab.pDfltList->nExpr<pCol->iDflt) ) return 0; |
| | return pTab->u.tab.pDfltList->a[pCol->iDflt-1].pExpr; |
| | } |
| |
|
| | |
| | |
| | |
| | void sqlite3ColumnSetColl( |
| | sqlite3 *db, |
| | Column *pCol, |
| | const char *zColl |
| | ){ |
| | i64 nColl; |
| | i64 n; |
| | char *zNew; |
| | assert( zColl!=0 ); |
| | n = sqlite3Strlen30(pCol->zCnName) + 1; |
| | if( pCol->colFlags & COLFLAG_HASTYPE ){ |
| | n += sqlite3Strlen30(pCol->zCnName+n) + 1; |
| | } |
| | nColl = sqlite3Strlen30(zColl) + 1; |
| | zNew = sqlite3DbRealloc(db, pCol->zCnName, nColl+n); |
| | if( zNew ){ |
| | pCol->zCnName = zNew; |
| | memcpy(pCol->zCnName + n, zColl, nColl); |
| | pCol->colFlags |= COLFLAG_HASCOLL; |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | const char *sqlite3ColumnColl(Column *pCol){ |
| | const char *z; |
| | if( (pCol->colFlags & COLFLAG_HASCOLL)==0 ) return 0; |
| | z = pCol->zCnName; |
| | while( *z ){ z++; } |
| | if( pCol->colFlags & COLFLAG_HASTYPE ){ |
| | do{ z++; }while( *z ); |
| | } |
| | return z+1; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | void sqlite3DeleteColumnNames(sqlite3 *db, Table *pTable){ |
| | int i; |
| | Column *pCol; |
| | assert( pTable!=0 ); |
| | assert( db!=0 ); |
| | if( (pCol = pTable->aCol)!=0 ){ |
| | for(i=0; i<pTable->nCol; i++, pCol++){ |
| | assert( pCol->zCnName==0 || pCol->hName==sqlite3StrIHash(pCol->zCnName) ); |
| | sqlite3DbFree(db, pCol->zCnName); |
| | } |
| | sqlite3DbNNFreeNN(db, pTable->aCol); |
| | if( IsOrdinaryTable(pTable) ){ |
| | sqlite3ExprListDelete(db, pTable->u.tab.pDfltList); |
| | } |
| | if( db->pnBytesFreed==0 ){ |
| | pTable->aCol = 0; |
| | pTable->nCol = 0; |
| | if( IsOrdinaryTable(pTable) ){ |
| | pTable->u.tab.pDfltList = 0; |
| | } |
| | } |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | static void SQLITE_NOINLINE deleteTable(sqlite3 *db, Table *pTable){ |
| | Index *pIndex, *pNext; |
| |
|
| | #ifdef SQLITE_DEBUG |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | int nLookaside = 0; |
| | assert( db!=0 ); |
| | if( !db->mallocFailed && (pTable->tabFlags & TF_Ephemeral)==0 ){ |
| | nLookaside = sqlite3LookasideUsed(db, 0); |
| | } |
| | #endif |
| |
|
| | |
| | for(pIndex = pTable->pIndex; pIndex; pIndex=pNext){ |
| | pNext = pIndex->pNext; |
| | assert( pIndex->pSchema==pTable->pSchema |
| | || (IsVirtual(pTable) && pIndex->idxType!=SQLITE_IDXTYPE_APPDEF) ); |
| | if( db->pnBytesFreed==0 && !IsVirtual(pTable) ){ |
| | char *zName = pIndex->zName; |
| | TESTONLY ( Index *pOld = ) sqlite3HashInsert( |
| | &pIndex->pSchema->idxHash, zName, 0 |
| | ); |
| | assert( db==0 || sqlite3SchemaMutexHeld(db, 0, pIndex->pSchema) ); |
| | assert( pOld==pIndex || pOld==0 ); |
| | } |
| | sqlite3FreeIndex(db, pIndex); |
| | } |
| |
|
| | if( IsOrdinaryTable(pTable) ){ |
| | sqlite3FkDelete(db, pTable); |
| | } |
| | #ifndef SQLITE_OMIT_VIRTUALTABLE |
| | else if( IsVirtual(pTable) ){ |
| | sqlite3VtabClear(db, pTable); |
| | } |
| | #endif |
| | else{ |
| | assert( IsView(pTable) ); |
| | sqlite3SelectDelete(db, pTable->u.view.pSelect); |
| | } |
| |
|
| | |
| | |
| | sqlite3DeleteColumnNames(db, pTable); |
| | sqlite3DbFree(db, pTable->zName); |
| | sqlite3DbFree(db, pTable->zColAff); |
| | sqlite3ExprListDelete(db, pTable->pCheck); |
| | sqlite3DbFree(db, pTable); |
| |
|
| | |
| | assert( nLookaside==0 || nLookaside==sqlite3LookasideUsed(db,0) ); |
| | } |
| | void sqlite3DeleteTable(sqlite3 *db, Table *pTable){ |
| | |
| | assert( db!=0 ); |
| | if( !pTable ) return; |
| | if( db->pnBytesFreed==0 && (--pTable->nTabRef)>0 ) return; |
| | deleteTable(db, pTable); |
| | } |
| | void sqlite3DeleteTableGeneric(sqlite3 *db, void *pTable){ |
| | sqlite3DeleteTable(db, (Table*)pTable); |
| | } |
| |
|
| |
|
| | |
| | |
| | |
| | |
| | void sqlite3UnlinkAndDeleteTable(sqlite3 *db, int iDb, const char *zTabName){ |
| | Table *p; |
| | Db *pDb; |
| |
|
| | assert( db!=0 ); |
| | assert( iDb>=0 && iDb<db->nDb ); |
| | assert( zTabName ); |
| | assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); |
| | testcase( zTabName[0]==0 ); |
| | pDb = &db->aDb[iDb]; |
| | p = sqlite3HashInsert(&pDb->pSchema->tblHash, zTabName, 0); |
| | sqlite3DeleteTable(db, p); |
| | db->mDbFlags |= DBFLAG_SchemaChange; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | char *sqlite3NameFromToken(sqlite3 *db, const Token *pName){ |
| | char *zName; |
| | if( pName ){ |
| | zName = sqlite3DbStrNDup(db, (const char*)pName->z, pName->n); |
| | sqlite3Dequote(zName); |
| | }else{ |
| | zName = 0; |
| | } |
| | return zName; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | void sqlite3OpenSchemaTable(Parse *p, int iDb){ |
| | Vdbe *v = sqlite3GetVdbe(p); |
| | sqlite3TableLock(p, iDb, SCHEMA_ROOT, 1, LEGACY_SCHEMA_TABLE); |
| | sqlite3VdbeAddOp4Int(v, OP_OpenWrite, 0, SCHEMA_ROOT, iDb, 5); |
| | if( p->nTab==0 ){ |
| | p->nTab = 1; |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | int sqlite3FindDbName(sqlite3 *db, const char *zName){ |
| | int i = -1; |
| | if( zName ){ |
| | Db *pDb; |
| | for(i=(db->nDb-1), pDb=&db->aDb[i]; i>=0; i--, pDb--){ |
| | if( 0==sqlite3_stricmp(pDb->zDbSName, zName) ) break; |
| | |
| | |
| | if( i==0 && 0==sqlite3_stricmp("main", zName) ) break; |
| | } |
| | } |
| | return i; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | int sqlite3FindDb(sqlite3 *db, Token *pName){ |
| | int i; |
| | char *zName; |
| | zName = sqlite3NameFromToken(db, pName); |
| | i = sqlite3FindDbName(db, zName); |
| | sqlite3DbFree(db, zName); |
| | return i; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | int sqlite3TwoPartName( |
| | Parse *pParse, |
| | Token *pName1, |
| | Token *pName2, |
| | Token **pUnqual |
| | ){ |
| | int iDb; |
| | sqlite3 *db = pParse->db; |
| |
|
| | assert( pName2!=0 ); |
| | if( pName2->n>0 ){ |
| | if( db->init.busy ) { |
| | sqlite3ErrorMsg(pParse, "corrupt database"); |
| | return -1; |
| | } |
| | *pUnqual = pName2; |
| | iDb = sqlite3FindDb(db, pName1); |
| | if( iDb<0 ){ |
| | sqlite3ErrorMsg(pParse, "unknown database %T", pName1); |
| | return -1; |
| | } |
| | }else{ |
| | assert( db->init.iDb==0 || db->init.busy || IN_SPECIAL_PARSE |
| | || (db->mDbFlags & DBFLAG_Vacuum)!=0); |
| | iDb = db->init.iDb; |
| | *pUnqual = pName1; |
| | } |
| | return iDb; |
| | } |
| |
|
| | |
| | |
| | |
| | int sqlite3WritableSchema(sqlite3 *db){ |
| | testcase( (db->flags&(SQLITE_WriteSchema|SQLITE_Defensive))==0 ); |
| | testcase( (db->flags&(SQLITE_WriteSchema|SQLITE_Defensive))== |
| | SQLITE_WriteSchema ); |
| | testcase( (db->flags&(SQLITE_WriteSchema|SQLITE_Defensive))== |
| | SQLITE_Defensive ); |
| | testcase( (db->flags&(SQLITE_WriteSchema|SQLITE_Defensive))== |
| | (SQLITE_WriteSchema|SQLITE_Defensive) ); |
| | return (db->flags&(SQLITE_WriteSchema|SQLITE_Defensive))==SQLITE_WriteSchema; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | int sqlite3CheckObjectName( |
| | Parse *pParse, |
| | const char *zName, |
| | const char *zType, |
| | const char *zTblName |
| | ){ |
| | sqlite3 *db = pParse->db; |
| | if( sqlite3WritableSchema(db) |
| | || db->init.imposterTable |
| | || !sqlite3Config.bExtraSchemaChecks |
| | ){ |
| | |
| | return SQLITE_OK; |
| | } |
| | if( db->init.busy ){ |
| | if( sqlite3_stricmp(zType, db->init.azInit[0]) |
| | || sqlite3_stricmp(zName, db->init.azInit[1]) |
| | || sqlite3_stricmp(zTblName, db->init.azInit[2]) |
| | ){ |
| | sqlite3ErrorMsg(pParse, ""); |
| | return SQLITE_ERROR; |
| | } |
| | }else{ |
| | if( (pParse->nested==0 && 0==sqlite3StrNICmp(zName, "sqlite_", 7)) |
| | || (sqlite3ReadOnlyShadowTables(db) && sqlite3ShadowTableName(db, zName)) |
| | ){ |
| | sqlite3ErrorMsg(pParse, "object name reserved for internal use: %s", |
| | zName); |
| | return SQLITE_ERROR; |
| | } |
| |
|
| | } |
| | return SQLITE_OK; |
| | } |
| |
|
| | |
| | |
| | |
| | Index *sqlite3PrimaryKeyIndex(Table *pTab){ |
| | Index *p; |
| | for(p=pTab->pIndex; p && !IsPrimaryKeyIndex(p); p=p->pNext){} |
| | return p; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | int sqlite3TableColumnToIndex(Index *pIdx, int iCol){ |
| | int i; |
| | i16 iCol16; |
| | assert( iCol>=(-1) && iCol<=SQLITE_MAX_COLUMN ); |
| | assert( pIdx->nColumn<=SQLITE_MAX_COLUMN*2 ); |
| | iCol16 = iCol; |
| | for(i=0; i<pIdx->nColumn; i++){ |
| | if( iCol16==pIdx->aiColumn[i] ){ |
| | return i; |
| | } |
| | } |
| | return -1; |
| | } |
| |
|
| | #ifndef SQLITE_OMIT_GENERATED_COLUMNS |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | i16 sqlite3StorageColumnToTable(Table *pTab, i16 iCol){ |
| | if( pTab->tabFlags & TF_HasVirtual ){ |
| | int i; |
| | for(i=0; i<=iCol; i++){ |
| | if( pTab->aCol[i].colFlags & COLFLAG_VIRTUAL ) iCol++; |
| | } |
| | } |
| | return iCol; |
| | } |
| | #endif |
| |
|
| | #ifndef SQLITE_OMIT_GENERATED_COLUMNS |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | i16 sqlite3TableColumnToStorage(Table *pTab, i16 iCol){ |
| | int i; |
| | i16 n; |
| | assert( iCol<pTab->nCol ); |
| | if( (pTab->tabFlags & TF_HasVirtual)==0 || iCol<0 ) return iCol; |
| | for(i=0, n=0; i<iCol; i++){ |
| | if( (pTab->aCol[i].colFlags & COLFLAG_VIRTUAL)==0 ) n++; |
| | } |
| | if( pTab->aCol[i].colFlags & COLFLAG_VIRTUAL ){ |
| | |
| | return pTab->nNVCol + i - n; |
| | }else{ |
| | |
| | return n; |
| | } |
| | } |
| | #endif |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | static void sqlite3ForceNotReadOnly(Parse *pParse){ |
| | int iReg = ++pParse->nMem; |
| | Vdbe *v = sqlite3GetVdbe(pParse); |
| | if( v ){ |
| | sqlite3VdbeAddOp3(v, OP_JournalMode, 0, iReg, PAGER_JOURNALMODE_QUERY); |
| | sqlite3VdbeUsesBtree(v, 0); |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | void sqlite3StartTable( |
| | Parse *pParse, |
| | Token *pName1, |
| | Token *pName2, |
| | int isTemp, |
| | int isView, |
| | int isVirtual, |
| | int noErr |
| | ){ |
| | Table *pTable; |
| | char *zName = 0; |
| | sqlite3 *db = pParse->db; |
| | Vdbe *v; |
| | int iDb; |
| | Token *pName; |
| |
|
| | if( db->init.busy && db->init.newTnum==1 ){ |
| | |
| | iDb = db->init.iDb; |
| | zName = sqlite3DbStrDup(db, SCHEMA_TABLE(iDb)); |
| | pName = pName1; |
| | }else{ |
| | |
| | iDb = sqlite3TwoPartName(pParse, pName1, pName2, &pName); |
| | if( iDb<0 ) return; |
| | if( !OMIT_TEMPDB && isTemp && pName2->n>0 && iDb!=1 ){ |
| | |
| | |
| | sqlite3ErrorMsg(pParse, "temporary table name must be unqualified"); |
| | return; |
| | } |
| | if( !OMIT_TEMPDB && isTemp ) iDb = 1; |
| | zName = sqlite3NameFromToken(db, pName); |
| | if( IN_RENAME_OBJECT ){ |
| | sqlite3RenameTokenMap(pParse, (void*)zName, pName); |
| | } |
| | } |
| | pParse->sNameToken = *pName; |
| | if( zName==0 ) return; |
| | if( sqlite3CheckObjectName(pParse, zName, isView?"view":"table", zName) ){ |
| | goto begin_table_error; |
| | } |
| | if( db->init.iDb==1 ) isTemp = 1; |
| | #ifndef SQLITE_OMIT_AUTHORIZATION |
| | assert( isTemp==0 || isTemp==1 ); |
| | assert( isView==0 || isView==1 ); |
| | { |
| | static const u8 aCode[] = { |
| | SQLITE_CREATE_TABLE, |
| | SQLITE_CREATE_TEMP_TABLE, |
| | SQLITE_CREATE_VIEW, |
| | SQLITE_CREATE_TEMP_VIEW |
| | }; |
| | char *zDb = db->aDb[iDb].zDbSName; |
| | if( sqlite3AuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(isTemp), 0, zDb) ){ |
| | goto begin_table_error; |
| | } |
| | if( !isVirtual && sqlite3AuthCheck(pParse, (int)aCode[isTemp+2*isView], |
| | zName, 0, zDb) ){ |
| | goto begin_table_error; |
| | } |
| | } |
| | #endif |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | if( !IN_SPECIAL_PARSE ){ |
| | char *zDb = db->aDb[iDb].zDbSName; |
| | if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){ |
| | goto begin_table_error; |
| | } |
| | pTable = sqlite3FindTable(db, zName, zDb); |
| | if( pTable ){ |
| | if( !noErr ){ |
| | sqlite3ErrorMsg(pParse, "%s %T already exists", |
| | (IsView(pTable)? "view" : "table"), pName); |
| | }else{ |
| | assert( !db->init.busy || CORRUPT_DB ); |
| | sqlite3CodeVerifySchema(pParse, iDb); |
| | sqlite3ForceNotReadOnly(pParse); |
| | } |
| | goto begin_table_error; |
| | } |
| | if( sqlite3FindIndex(db, zName, zDb)!=0 ){ |
| | sqlite3ErrorMsg(pParse, "there is already an index named %s", zName); |
| | goto begin_table_error; |
| | } |
| | } |
| |
|
| | pTable = sqlite3DbMallocZero(db, sizeof(Table)); |
| | if( pTable==0 ){ |
| | assert( db->mallocFailed ); |
| | pParse->rc = SQLITE_NOMEM_BKPT; |
| | pParse->nErr++; |
| | goto begin_table_error; |
| | } |
| | pTable->zName = zName; |
| | pTable->iPKey = -1; |
| | pTable->pSchema = db->aDb[iDb].pSchema; |
| | pTable->nTabRef = 1; |
| | #ifdef SQLITE_DEFAULT_ROWEST |
| | pTable->nRowLogEst = sqlite3LogEst(SQLITE_DEFAULT_ROWEST); |
| | #else |
| | pTable->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) ); |
| | #endif |
| | assert( pParse->pNewTable==0 ); |
| | pParse->pNewTable = pTable; |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | if( !db->init.busy && (v = sqlite3GetVdbe(pParse))!=0 ){ |
| | int addr1; |
| | int fileFormat; |
| | int reg1, reg2, reg3; |
| | |
| | static const char nullRow[] = { 6, 0, 0, 0, 0, 0 }; |
| | sqlite3BeginWriteOperation(pParse, 1, iDb); |
| |
|
| | #ifndef SQLITE_OMIT_VIRTUALTABLE |
| | if( isVirtual ){ |
| | sqlite3VdbeAddOp0(v, OP_VBegin); |
| | } |
| | #endif |
| |
|
| | |
| | |
| | |
| | assert( pParse->isCreate ); |
| | reg1 = pParse->u1.cr.regRowid = ++pParse->nMem; |
| | reg2 = pParse->u1.cr.regRoot = ++pParse->nMem; |
| | reg3 = ++pParse->nMem; |
| | sqlite3VdbeAddOp3(v, OP_ReadCookie, iDb, reg3, BTREE_FILE_FORMAT); |
| | sqlite3VdbeUsesBtree(v, iDb); |
| | addr1 = sqlite3VdbeAddOp1(v, OP_If, reg3); VdbeCoverage(v); |
| | fileFormat = (db->flags & SQLITE_LegacyFileFmt)!=0 ? |
| | 1 : SQLITE_MAX_FILE_FORMAT; |
| | sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_FILE_FORMAT, fileFormat); |
| | sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_TEXT_ENCODING, ENC(db)); |
| | sqlite3VdbeJumpHere(v, addr1); |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | #if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE) |
| | if( isView || isVirtual ){ |
| | sqlite3VdbeAddOp2(v, OP_Integer, 0, reg2); |
| | }else |
| | #endif |
| | { |
| | assert( !pParse->bReturning ); |
| | pParse->u1.cr.addrCrTab = |
| | sqlite3VdbeAddOp3(v, OP_CreateBtree, iDb, reg2, BTREE_INTKEY); |
| | } |
| | sqlite3OpenSchemaTable(pParse, iDb); |
| | sqlite3VdbeAddOp2(v, OP_NewRowid, 0, reg1); |
| | sqlite3VdbeAddOp4(v, OP_Blob, 6, reg3, 0, nullRow, P4_STATIC); |
| | sqlite3VdbeAddOp3(v, OP_Insert, 0, reg3, reg1); |
| | sqlite3VdbeChangeP5(v, OPFLAG_APPEND); |
| | sqlite3VdbeAddOp0(v, OP_Close); |
| | }else if( db->init.imposterTable ){ |
| | pTable->tabFlags |= TF_Imposter; |
| | if( db->init.imposterTable>=2 ) pTable->tabFlags |= TF_Readonly; |
| | } |
| |
|
| | |
| | return; |
| |
|
| | |
| | begin_table_error: |
| | pParse->checkSchema = 1; |
| | sqlite3DbFree(db, zName); |
| | return; |
| | } |
| |
|
| | |
| | |
| | |
| | #if SQLITE_ENABLE_HIDDEN_COLUMNS |
| | void sqlite3ColumnPropertiesFromName(Table *pTab, Column *pCol){ |
| | if( sqlite3_strnicmp(pCol->zCnName, "__hidden__", 10)==0 ){ |
| | pCol->colFlags |= COLFLAG_HIDDEN; |
| | if( pTab ) pTab->tabFlags |= TF_HasHidden; |
| | }else if( pTab && pCol!=pTab->aCol && (pCol[-1].colFlags & COLFLAG_HIDDEN) ){ |
| | pTab->tabFlags |= TF_OOOHidden; |
| | } |
| | } |
| | #endif |
| |
|
| | |
| | |
| | |
| | static void sqlite3DeleteReturning(sqlite3 *db, void *pArg){ |
| | Returning *pRet = (Returning*)pArg; |
| | Hash *pHash; |
| | pHash = &(db->aDb[1].pSchema->trigHash); |
| | sqlite3HashInsert(pHash, pRet->zName, 0); |
| | sqlite3ExprListDelete(db, pRet->pReturnEL); |
| | sqlite3DbFree(db, pRet); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | void sqlite3AddReturning(Parse *pParse, ExprList *pList){ |
| | Returning *pRet; |
| | Hash *pHash; |
| | sqlite3 *db = pParse->db; |
| | if( pParse->pNewTrigger ){ |
| | sqlite3ErrorMsg(pParse, "cannot use RETURNING in a trigger"); |
| | }else{ |
| | assert( pParse->bReturning==0 || pParse->ifNotExists ); |
| | } |
| | pParse->bReturning = 1; |
| | pRet = sqlite3DbMallocZero(db, sizeof(*pRet)); |
| | if( pRet==0 ){ |
| | sqlite3ExprListDelete(db, pList); |
| | return; |
| | } |
| | assert( !pParse->isCreate ); |
| | pParse->u1.d.pReturning = pRet; |
| | pRet->pParse = pParse; |
| | pRet->pReturnEL = pList; |
| | sqlite3ParserAddCleanup(pParse, sqlite3DeleteReturning, pRet); |
| | testcase( pParse->earlyCleanup ); |
| | if( db->mallocFailed ) return; |
| | sqlite3_snprintf(sizeof(pRet->zName), pRet->zName, |
| | "sqlite_returning_%p", pParse); |
| | pRet->retTrig.zName = pRet->zName; |
| | pRet->retTrig.op = TK_RETURNING; |
| | pRet->retTrig.tr_tm = TRIGGER_AFTER; |
| | pRet->retTrig.bReturning = 1; |
| | pRet->retTrig.pSchema = db->aDb[1].pSchema; |
| | pRet->retTrig.pTabSchema = db->aDb[1].pSchema; |
| | pRet->retTrig.step_list = &pRet->retTStep; |
| | pRet->retTStep.op = TK_RETURNING; |
| | pRet->retTStep.pTrig = &pRet->retTrig; |
| | pRet->retTStep.pExprList = pList; |
| | pHash = &(db->aDb[1].pSchema->trigHash); |
| | assert( sqlite3HashFind(pHash, pRet->zName)==0 |
| | || pParse->nErr || pParse->ifNotExists ); |
| | if( sqlite3HashInsert(pHash, pRet->zName, &pRet->retTrig) |
| | ==&pRet->retTrig ){ |
| | sqlite3OomFault(db); |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | void sqlite3AddColumn(Parse *pParse, Token sName, Token sType){ |
| | Table *p; |
| | int i; |
| | char *z; |
| | char *zType; |
| | Column *pCol; |
| | sqlite3 *db = pParse->db; |
| | Column *aNew; |
| | u8 eType = COLTYPE_CUSTOM; |
| | u8 szEst = 1; |
| | char affinity = SQLITE_AFF_BLOB; |
| |
|
| | if( (p = pParse->pNewTable)==0 ) return; |
| | if( p->nCol+1>db->aLimit[SQLITE_LIMIT_COLUMN] ){ |
| | sqlite3ErrorMsg(pParse, "too many columns on %s", p->zName); |
| | return; |
| | } |
| | if( !IN_RENAME_OBJECT ) sqlite3DequoteToken(&sName); |
| |
|
| | |
| | |
| | |
| | |
| | if( sType.n>=16 |
| | && sqlite3_strnicmp(sType.z+(sType.n-6),"always",6)==0 |
| | ){ |
| | sType.n -= 6; |
| | while( ALWAYS(sType.n>0) && sqlite3Isspace(sType.z[sType.n-1]) ) sType.n--; |
| | if( sType.n>=9 |
| | && sqlite3_strnicmp(sType.z+(sType.n-9),"generated",9)==0 |
| | ){ |
| | sType.n -= 9; |
| | while( sType.n>0 && sqlite3Isspace(sType.z[sType.n-1]) ) sType.n--; |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | if( sType.n>=3 ){ |
| | sqlite3DequoteToken(&sType); |
| | for(i=0; i<SQLITE_N_STDTYPE; i++){ |
| | if( sType.n==sqlite3StdTypeLen[i] |
| | && sqlite3_strnicmp(sType.z, sqlite3StdType[i], sType.n)==0 |
| | ){ |
| | sType.n = 0; |
| | eType = i+1; |
| | affinity = sqlite3StdTypeAffinity[i]; |
| | if( affinity<=SQLITE_AFF_TEXT ) szEst = 5; |
| | break; |
| | } |
| | } |
| | } |
| |
|
| | z = sqlite3DbMallocRaw(db, (i64)sName.n + 1 + (i64)sType.n + (sType.n>0) ); |
| | if( z==0 ) return; |
| | if( IN_RENAME_OBJECT ) sqlite3RenameTokenMap(pParse, (void*)z, &sName); |
| | memcpy(z, sName.z, sName.n); |
| | z[sName.n] = 0; |
| | sqlite3Dequote(z); |
| | if( p->nCol && sqlite3ColumnIndex(p, z)>=0 ){ |
| | sqlite3ErrorMsg(pParse, "duplicate column name: %s", z); |
| | sqlite3DbFree(db, z); |
| | return; |
| | } |
| | aNew = sqlite3DbRealloc(db,p->aCol,((i64)p->nCol+1)*sizeof(p->aCol[0])); |
| | if( aNew==0 ){ |
| | sqlite3DbFree(db, z); |
| | return; |
| | } |
| | p->aCol = aNew; |
| | pCol = &p->aCol[p->nCol]; |
| | memset(pCol, 0, sizeof(p->aCol[0])); |
| | pCol->zCnName = z; |
| | pCol->hName = sqlite3StrIHash(z); |
| | sqlite3ColumnPropertiesFromName(p, pCol); |
| |
|
| | if( sType.n==0 ){ |
| | |
| | |
| | pCol->affinity = affinity; |
| | pCol->eCType = eType; |
| | pCol->szEst = szEst; |
| | #ifdef SQLITE_ENABLE_SORTER_REFERENCES |
| | if( affinity==SQLITE_AFF_BLOB ){ |
| | if( 4>=sqlite3GlobalConfig.szSorterRef ){ |
| | pCol->colFlags |= COLFLAG_SORTERREF; |
| | } |
| | } |
| | #endif |
| | }else{ |
| | zType = z + sqlite3Strlen30(z) + 1; |
| | memcpy(zType, sType.z, sType.n); |
| | zType[sType.n] = 0; |
| | sqlite3Dequote(zType); |
| | pCol->affinity = sqlite3AffinityType(zType, pCol); |
| | pCol->colFlags |= COLFLAG_HASTYPE; |
| | } |
| | if( p->nCol<=0xff ){ |
| | u8 h = pCol->hName % sizeof(p->aHx); |
| | p->aHx[h] = p->nCol; |
| | } |
| | p->nCol++; |
| | p->nNVCol++; |
| | assert( pParse->isCreate ); |
| | pParse->u1.cr.constraintName.n = 0; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | void sqlite3AddNotNull(Parse *pParse, int onError){ |
| | Table *p; |
| | Column *pCol; |
| | p = pParse->pNewTable; |
| | if( p==0 || NEVER(p->nCol<1) ) return; |
| | pCol = &p->aCol[p->nCol-1]; |
| | pCol->notNull = (u8)onError; |
| | p->tabFlags |= TF_HasNotNull; |
| |
|
| | |
| | |
| | if( pCol->colFlags & COLFLAG_UNIQUE ){ |
| | Index *pIdx; |
| | for(pIdx=p->pIndex; pIdx; pIdx=pIdx->pNext){ |
| | assert( pIdx->nKeyCol==1 && pIdx->onError!=OE_None ); |
| | if( pIdx->aiColumn[0]==p->nCol-1 ){ |
| | pIdx->uniqNotNull = 1; |
| | } |
| | } |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | char sqlite3AffinityType(const char *zIn, Column *pCol){ |
| | u32 h = 0; |
| | char aff = SQLITE_AFF_NUMERIC; |
| | const char *zChar = 0; |
| |
|
| | assert( zIn!=0 ); |
| | while( zIn[0] ){ |
| | u8 x = *(u8*)zIn; |
| | h = (h<<8) + sqlite3UpperToLower[x]; |
| | zIn++; |
| | if( h==(('c'<<24)+('h'<<16)+('a'<<8)+'r') ){ |
| | aff = SQLITE_AFF_TEXT; |
| | zChar = zIn; |
| | }else if( h==(('c'<<24)+('l'<<16)+('o'<<8)+'b') ){ |
| | aff = SQLITE_AFF_TEXT; |
| | }else if( h==(('t'<<24)+('e'<<16)+('x'<<8)+'t') ){ |
| | aff = SQLITE_AFF_TEXT; |
| | }else if( h==(('b'<<24)+('l'<<16)+('o'<<8)+'b') |
| | && (aff==SQLITE_AFF_NUMERIC || aff==SQLITE_AFF_REAL) ){ |
| | aff = SQLITE_AFF_BLOB; |
| | if( zIn[0]=='(' ) zChar = zIn; |
| | #ifndef SQLITE_OMIT_FLOATING_POINT |
| | }else if( h==(('r'<<24)+('e'<<16)+('a'<<8)+'l') |
| | && aff==SQLITE_AFF_NUMERIC ){ |
| | aff = SQLITE_AFF_REAL; |
| | }else if( h==(('f'<<24)+('l'<<16)+('o'<<8)+'a') |
| | && aff==SQLITE_AFF_NUMERIC ){ |
| | aff = SQLITE_AFF_REAL; |
| | }else if( h==(('d'<<24)+('o'<<16)+('u'<<8)+'b') |
| | && aff==SQLITE_AFF_NUMERIC ){ |
| | aff = SQLITE_AFF_REAL; |
| | #endif |
| | }else if( (h&0x00FFFFFF)==(('i'<<16)+('n'<<8)+'t') ){ |
| | aff = SQLITE_AFF_INTEGER; |
| | break; |
| | } |
| | } |
| |
|
| | |
| | |
| | if( pCol ){ |
| | int v = 0; |
| | if( aff<SQLITE_AFF_NUMERIC ){ |
| | if( zChar ){ |
| | while( zChar[0] ){ |
| | if( sqlite3Isdigit(zChar[0]) ){ |
| | |
| | sqlite3GetInt32(zChar, &v); |
| | break; |
| | } |
| | zChar++; |
| | } |
| | }else{ |
| | v = 16; |
| | } |
| | } |
| | #ifdef SQLITE_ENABLE_SORTER_REFERENCES |
| | if( v>=sqlite3GlobalConfig.szSorterRef ){ |
| | pCol->colFlags |= COLFLAG_SORTERREF; |
| | } |
| | #endif |
| | v = v/4 + 1; |
| | if( v>255 ) v = 255; |
| | pCol->szEst = v; |
| | } |
| | return aff; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | void sqlite3AddDefaultValue( |
| | Parse *pParse, |
| | Expr *pExpr, |
| | const char *zStart, |
| | const char *zEnd |
| | ){ |
| | Table *p; |
| | Column *pCol; |
| | sqlite3 *db = pParse->db; |
| | p = pParse->pNewTable; |
| | if( p!=0 ){ |
| | int isInit = db->init.busy && db->init.iDb!=1; |
| | pCol = &(p->aCol[p->nCol-1]); |
| | if( !sqlite3ExprIsConstantOrFunction(pExpr, isInit) ){ |
| | sqlite3ErrorMsg(pParse, "default value of column [%s] is not constant", |
| | pCol->zCnName); |
| | #ifndef SQLITE_OMIT_GENERATED_COLUMNS |
| | }else if( pCol->colFlags & COLFLAG_GENERATED ){ |
| | testcase( pCol->colFlags & COLFLAG_VIRTUAL ); |
| | testcase( pCol->colFlags & COLFLAG_STORED ); |
| | sqlite3ErrorMsg(pParse, "cannot use DEFAULT on a generated column"); |
| | #endif |
| | }else{ |
| | |
| | |
| | |
| | Expr x, *pDfltExpr; |
| | memset(&x, 0, sizeof(x)); |
| | x.op = TK_SPAN; |
| | x.u.zToken = sqlite3DbSpanDup(db, zStart, zEnd); |
| | x.pLeft = pExpr; |
| | x.flags = EP_Skip; |
| | pDfltExpr = sqlite3ExprDup(db, &x, EXPRDUP_REDUCE); |
| | sqlite3DbFree(db, x.u.zToken); |
| | sqlite3ColumnSetExpr(pParse, p, pCol, pDfltExpr); |
| | } |
| | } |
| | if( IN_RENAME_OBJECT ){ |
| | sqlite3RenameExprUnmap(pParse, pExpr); |
| | } |
| | sqlite3ExprDelete(db, pExpr); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | static void sqlite3StringToId(Expr *p){ |
| | if( p->op==TK_STRING ){ |
| | p->op = TK_ID; |
| | }else if( p->op==TK_COLLATE && p->pLeft->op==TK_STRING ){ |
| | p->pLeft->op = TK_ID; |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | static void makeColumnPartOfPrimaryKey(Parse *pParse, Column *pCol){ |
| | pCol->colFlags |= COLFLAG_PRIMKEY; |
| | #ifndef SQLITE_OMIT_GENERATED_COLUMNS |
| | if( pCol->colFlags & COLFLAG_GENERATED ){ |
| | testcase( pCol->colFlags & COLFLAG_VIRTUAL ); |
| | testcase( pCol->colFlags & COLFLAG_STORED ); |
| | sqlite3ErrorMsg(pParse, |
| | "generated columns cannot be part of the PRIMARY KEY"); |
| | } |
| | #endif |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | void sqlite3AddPrimaryKey( |
| | Parse *pParse, |
| | ExprList *pList, |
| | int onError, |
| | int autoInc, |
| | int sortOrder |
| | ){ |
| | Table *pTab = pParse->pNewTable; |
| | Column *pCol = 0; |
| | int iCol = -1, i; |
| | int nTerm; |
| | if( pTab==0 ) goto primary_key_exit; |
| | if( pTab->tabFlags & TF_HasPrimaryKey ){ |
| | sqlite3ErrorMsg(pParse, |
| | "table \"%s\" has more than one primary key", pTab->zName); |
| | goto primary_key_exit; |
| | } |
| | pTab->tabFlags |= TF_HasPrimaryKey; |
| | if( pList==0 ){ |
| | iCol = pTab->nCol - 1; |
| | pCol = &pTab->aCol[iCol]; |
| | makeColumnPartOfPrimaryKey(pParse, pCol); |
| | nTerm = 1; |
| | }else{ |
| | nTerm = pList->nExpr; |
| | for(i=0; i<nTerm; i++){ |
| | Expr *pCExpr = sqlite3ExprSkipCollate(pList->a[i].pExpr); |
| | assert( pCExpr!=0 ); |
| | sqlite3StringToId(pCExpr); |
| | if( pCExpr->op==TK_ID ){ |
| | assert( !ExprHasProperty(pCExpr, EP_IntValue) ); |
| | iCol = sqlite3ColumnIndex(pTab, pCExpr->u.zToken); |
| | if( iCol>=0 ){ |
| | pCol = &pTab->aCol[iCol]; |
| | makeColumnPartOfPrimaryKey(pParse, pCol); |
| | } |
| | } |
| | } |
| | } |
| | if( nTerm==1 |
| | && pCol |
| | && pCol->eCType==COLTYPE_INTEGER |
| | && sortOrder!=SQLITE_SO_DESC |
| | ){ |
| | if( IN_RENAME_OBJECT && pList ){ |
| | Expr *pCExpr = sqlite3ExprSkipCollate(pList->a[0].pExpr); |
| | sqlite3RenameTokenRemap(pParse, &pTab->iPKey, pCExpr); |
| | } |
| | pTab->iPKey = iCol; |
| | pTab->keyConf = (u8)onError; |
| | assert( autoInc==0 || autoInc==1 ); |
| | pTab->tabFlags |= autoInc*TF_Autoincrement; |
| | if( pList ) pParse->iPkSortOrder = pList->a[0].fg.sortFlags; |
| | (void)sqlite3HasExplicitNulls(pParse, pList); |
| | }else if( autoInc ){ |
| | #ifndef SQLITE_OMIT_AUTOINCREMENT |
| | sqlite3ErrorMsg(pParse, "AUTOINCREMENT is only allowed on an " |
| | "INTEGER PRIMARY KEY"); |
| | #endif |
| | }else{ |
| | sqlite3CreateIndex(pParse, 0, 0, 0, pList, onError, 0, |
| | 0, sortOrder, 0, SQLITE_IDXTYPE_PRIMARYKEY); |
| | pList = 0; |
| | } |
| |
|
| | primary_key_exit: |
| | sqlite3ExprListDelete(pParse->db, pList); |
| | return; |
| | } |
| |
|
| | |
| | |
| | |
| | void sqlite3AddCheckConstraint( |
| | Parse *pParse, |
| | Expr *pCheckExpr, |
| | const char *zStart, |
| | const char *zEnd |
| | ){ |
| | #ifndef SQLITE_OMIT_CHECK |
| | Table *pTab = pParse->pNewTable; |
| | sqlite3 *db = pParse->db; |
| | if( pTab && !IN_DECLARE_VTAB |
| | && !sqlite3BtreeIsReadonly(db->aDb[db->init.iDb].pBt) |
| | ){ |
| | pTab->pCheck = sqlite3ExprListAppend(pParse, pTab->pCheck, pCheckExpr); |
| | assert( pParse->isCreate ); |
| | if( pParse->u1.cr.constraintName.n ){ |
| | sqlite3ExprListSetName(pParse, pTab->pCheck, |
| | &pParse->u1.cr.constraintName, 1); |
| | }else{ |
| | Token t; |
| | for(zStart++; sqlite3Isspace(zStart[0]); zStart++){} |
| | while( sqlite3Isspace(zEnd[-1]) ){ zEnd--; } |
| | t.z = zStart; |
| | t.n = (int)(zEnd - t.z); |
| | sqlite3ExprListSetName(pParse, pTab->pCheck, &t, 1); |
| | } |
| | }else |
| | #endif |
| | { |
| | sqlite3ExprDelete(pParse->db, pCheckExpr); |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | void sqlite3AddCollateType(Parse *pParse, Token *pToken){ |
| | Table *p; |
| | int i; |
| | char *zColl; |
| | sqlite3 *db; |
| |
|
| | if( (p = pParse->pNewTable)==0 || IN_RENAME_OBJECT ) return; |
| | i = p->nCol-1; |
| | db = pParse->db; |
| | zColl = sqlite3NameFromToken(db, pToken); |
| | if( !zColl ) return; |
| |
|
| | if( sqlite3LocateCollSeq(pParse, zColl) ){ |
| | Index *pIdx; |
| | sqlite3ColumnSetColl(db, &p->aCol[i], zColl); |
| | |
| | |
| | |
| | |
| | |
| | for(pIdx=p->pIndex; pIdx; pIdx=pIdx->pNext){ |
| | assert( pIdx->nKeyCol==1 ); |
| | if( pIdx->aiColumn[0]==i ){ |
| | pIdx->azColl[0] = sqlite3ColumnColl(&p->aCol[i]); |
| | } |
| | } |
| | } |
| | sqlite3DbFree(db, zColl); |
| | } |
| |
|
| | |
| | |
| | |
| | void sqlite3AddGenerated(Parse *pParse, Expr *pExpr, Token *pType){ |
| | #ifndef SQLITE_OMIT_GENERATED_COLUMNS |
| | u8 eType = COLFLAG_VIRTUAL; |
| | Table *pTab = pParse->pNewTable; |
| | Column *pCol; |
| | if( pTab==0 ){ |
| | |
| | goto generated_done; |
| | } |
| | pCol = &(pTab->aCol[pTab->nCol-1]); |
| | if( IN_DECLARE_VTAB ){ |
| | sqlite3ErrorMsg(pParse, "virtual tables cannot use computed columns"); |
| | goto generated_done; |
| | } |
| | if( pCol->iDflt>0 ) goto generated_error; |
| | if( pType ){ |
| | if( pType->n==7 && sqlite3StrNICmp("virtual",pType->z,7)==0 ){ |
| | |
| | }else if( pType->n==6 && sqlite3StrNICmp("stored",pType->z,6)==0 ){ |
| | eType = COLFLAG_STORED; |
| | }else{ |
| | goto generated_error; |
| | } |
| | } |
| | if( eType==COLFLAG_VIRTUAL ) pTab->nNVCol--; |
| | pCol->colFlags |= eType; |
| | assert( TF_HasVirtual==COLFLAG_VIRTUAL ); |
| | assert( TF_HasStored==COLFLAG_STORED ); |
| | pTab->tabFlags |= eType; |
| | if( pCol->colFlags & COLFLAG_PRIMKEY ){ |
| | makeColumnPartOfPrimaryKey(pParse, pCol); |
| | } |
| | if( ALWAYS(pExpr) && pExpr->op==TK_ID ){ |
| | |
| | |
| | |
| | |
| | pExpr = sqlite3PExpr(pParse, TK_UPLUS, pExpr, 0); |
| | } |
| | if( pExpr && pExpr->op!=TK_RAISE ) pExpr->affExpr = pCol->affinity; |
| | sqlite3ColumnSetExpr(pParse, pTab, pCol, pExpr); |
| | pExpr = 0; |
| | goto generated_done; |
| |
|
| | generated_error: |
| | sqlite3ErrorMsg(pParse, "error in generated column \"%s\"", |
| | pCol->zCnName); |
| | generated_done: |
| | sqlite3ExprDelete(pParse->db, pExpr); |
| | #else |
| | |
| | |
| | sqlite3ErrorMsg(pParse, "generated columns not supported"); |
| | sqlite3ExprDelete(pParse->db, pExpr); |
| | #endif |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | void sqlite3ChangeCookie(Parse *pParse, int iDb){ |
| | sqlite3 *db = pParse->db; |
| | Vdbe *v = pParse->pVdbe; |
| | assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); |
| | sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_SCHEMA_VERSION, |
| | (int)(1+(unsigned)db->aDb[iDb].pSchema->schema_cookie)); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | static i64 identLength(const char *z){ |
| | i64 n; |
| | for(n=0; *z; n++, z++){ |
| | if( *z=='"' ){ n++; } |
| | } |
| | return n + 2; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | static void identPut(char *z, int *pIdx, char *zSignedIdent){ |
| | unsigned char *zIdent = (unsigned char*)zSignedIdent; |
| | int i, j, needQuote; |
| | i = *pIdx; |
| |
|
| | for(j=0; zIdent[j]; j++){ |
| | if( !sqlite3Isalnum(zIdent[j]) && zIdent[j]!='_' ) break; |
| | } |
| | needQuote = sqlite3Isdigit(zIdent[0]) |
| | || sqlite3KeywordCode(zIdent, j)!=TK_ID |
| | || zIdent[j]!=0 |
| | || j==0; |
| |
|
| | if( needQuote ) z[i++] = '"'; |
| | for(j=0; zIdent[j]; j++){ |
| | z[i++] = zIdent[j]; |
| | if( zIdent[j]=='"' ) z[i++] = '"'; |
| | } |
| | if( needQuote ) z[i++] = '"'; |
| | z[i] = 0; |
| | *pIdx = i; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | static char *createTableStmt(sqlite3 *db, Table *p){ |
| | int i, k, len; |
| | i64 n; |
| | char *zStmt; |
| | char *zSep, *zSep2, *zEnd; |
| | Column *pCol; |
| | n = 0; |
| | for(pCol = p->aCol, i=0; i<p->nCol; i++, pCol++){ |
| | n += identLength(pCol->zCnName) + 5; |
| | } |
| | n += identLength(p->zName); |
| | if( n<50 ){ |
| | zSep = ""; |
| | zSep2 = ","; |
| | zEnd = ")"; |
| | }else{ |
| | zSep = "\n "; |
| | zSep2 = ",\n "; |
| | zEnd = "\n)"; |
| | } |
| | n += 35 + 6*p->nCol; |
| | zStmt = sqlite3DbMallocRaw(0, n); |
| | if( zStmt==0 ){ |
| | sqlite3OomFault(db); |
| | return 0; |
| | } |
| | assert( n>14 && n<=0x7fffffff ); |
| | memcpy(zStmt, "CREATE TABLE ", 13); |
| | k = 13; |
| | identPut(zStmt, &k, p->zName); |
| | zStmt[k++] = '('; |
| | for(pCol=p->aCol, i=0; i<p->nCol; i++, pCol++){ |
| | static const char * const azType[] = { |
| | "", |
| | " TEXT", |
| | " NUM", |
| | " INT", |
| | " REAL", |
| | " NUM", |
| | }; |
| | const char *zType; |
| |
|
| | len = sqlite3Strlen30(zSep); |
| | assert( k+len<n ); |
| | memcpy(&zStmt[k], zSep, len); |
| | k += len; |
| | zSep = zSep2; |
| | identPut(zStmt, &k, pCol->zCnName); |
| | assert( k<n ); |
| | assert( pCol->affinity-SQLITE_AFF_BLOB >= 0 ); |
| | assert( pCol->affinity-SQLITE_AFF_BLOB < ArraySize(azType) ); |
| | testcase( pCol->affinity==SQLITE_AFF_BLOB ); |
| | testcase( pCol->affinity==SQLITE_AFF_TEXT ); |
| | testcase( pCol->affinity==SQLITE_AFF_NUMERIC ); |
| | testcase( pCol->affinity==SQLITE_AFF_INTEGER ); |
| | testcase( pCol->affinity==SQLITE_AFF_REAL ); |
| | testcase( pCol->affinity==SQLITE_AFF_FLEXNUM ); |
| | |
| | zType = azType[pCol->affinity - SQLITE_AFF_BLOB]; |
| | len = sqlite3Strlen30(zType); |
| | assert( pCol->affinity==SQLITE_AFF_BLOB |
| | || pCol->affinity==SQLITE_AFF_FLEXNUM |
| | || pCol->affinity==sqlite3AffinityType(zType, 0) ); |
| | assert( k+len<n ); |
| | memcpy(&zStmt[k], zType, len); |
| | k += len; |
| | assert( k<=n ); |
| | } |
| | len = sqlite3Strlen30(zEnd); |
| | assert( k+len<n ); |
| | memcpy(&zStmt[k], zEnd, len+1); |
| | return zStmt; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | static int resizeIndexObject(Parse *pParse, Index *pIdx, int N){ |
| | char *zExtra; |
| | u64 nByte; |
| | sqlite3 *db; |
| | if( pIdx->nColumn>=N ) return SQLITE_OK; |
| | db = pParse->db; |
| | assert( N>0 ); |
| | assert( N <= SQLITE_MAX_COLUMN*2 ); |
| | testcase( N==2*pParse->db->aLimit[SQLITE_LIMIT_COLUMN] ); |
| | assert( pIdx->isResized==0 ); |
| | nByte = (sizeof(char*) + sizeof(LogEst) + sizeof(i16) + 1)*(u64)N; |
| | zExtra = sqlite3DbMallocZero(db, nByte); |
| | if( zExtra==0 ) return SQLITE_NOMEM_BKPT; |
| | memcpy(zExtra, pIdx->azColl, sizeof(char*)*pIdx->nColumn); |
| | pIdx->azColl = (const char**)zExtra; |
| | zExtra += sizeof(char*)*N; |
| | memcpy(zExtra, pIdx->aiRowLogEst, sizeof(LogEst)*(pIdx->nKeyCol+1)); |
| | pIdx->aiRowLogEst = (LogEst*)zExtra; |
| | zExtra += sizeof(LogEst)*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 = (u16)N; |
| | pIdx->isResized = 1; |
| | return SQLITE_OK; |
| | } |
| |
|
| | |
| | |
| | |
| | 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); |
| | } |
| |
|
| | |
| | |
| | |
| | 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[x].szEst; |
| | } |
| | pIdx->szIdxRow = sqlite3LogEst(wIndex*4); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | static int hasColumn(const i16 *aiCol, int nCol, int x){ |
| | while( nCol-- > 0 ){ |
| | if( x==*(aiCol++) ){ |
| | return 1; |
| | } |
| | } |
| | return 0; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | static int isDupColumn(Index *pIdx, int nKey, Index *pPk, int iCol){ |
| | int i, j; |
| | assert( nKey<=pIdx->nColumn ); |
| | assert( iCol<MAX(pPk->nColumn,pPk->nKeyCol) ); |
| | assert( pPk->idxType==SQLITE_IDXTYPE_PRIMARYKEY ); |
| | assert( pPk->pTable->tabFlags & TF_WithoutRowid ); |
| | assert( pPk->pTable==pIdx->pTable ); |
| | testcase( pPk==pIdx ); |
| | j = pPk->aiColumn[iCol]; |
| | assert( j!=XN_ROWID && j!=XN_EXPR ); |
| | for(i=0; i<nKey; i++){ |
| | assert( pIdx->aiColumn[i]>=0 || j>=0 ); |
| | if( pIdx->aiColumn[i]==j |
| | && sqlite3StrICmp(pIdx->azColl[i], pPk->azColl[iCol])==0 |
| | ){ |
| | return 1; |
| | } |
| | } |
| | return 0; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | static void recomputeColumnsNotIndexed(Index *pIdx){ |
| | Bitmask m = 0; |
| | int j; |
| | Table *pTab = pIdx->pTable; |
| | for(j=pIdx->nColumn-1; j>=0; j--){ |
| | int x = pIdx->aiColumn[j]; |
| | if( x>=0 && (pTab->aCol[x].colFlags & COLFLAG_VIRTUAL)==0 ){ |
| | testcase( x==BMS-1 ); |
| | testcase( x==BMS-2 ); |
| | if( x<BMS-1 ) m |= MASKBIT(x); |
| | } |
| | } |
| | pIdx->colNotIdxed = ~m; |
| | assert( (pIdx->colNotIdxed>>63)==1 ); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){ |
| | Index *pIdx; |
| | Index *pPk; |
| | int nPk; |
| | int nExtra; |
| | int i, j; |
| | sqlite3 *db = pParse->db; |
| | Vdbe *v = pParse->pVdbe; |
| |
|
| | |
| | |
| | if( !db->init.imposterTable ){ |
| | for(i=0; i<pTab->nCol; i++){ |
| | if( (pTab->aCol[i].colFlags & COLFLAG_PRIMKEY)!=0 |
| | && (pTab->aCol[i].notNull==OE_None) |
| | ){ |
| | pTab->aCol[i].notNull = OE_Abort; |
| | } |
| | } |
| | pTab->tabFlags |= TF_HasNotNull; |
| | } |
| |
|
| | |
| | |
| | |
| | assert( !pParse->bReturning ); |
| | if( pParse->u1.cr.addrCrTab ){ |
| | assert( v ); |
| | sqlite3VdbeChangeP3(v, pParse->u1.cr.addrCrTab, BTREE_BLOBKEY); |
| | } |
| |
|
| | |
| | |
| | |
| | if( pTab->iPKey>=0 ){ |
| | ExprList *pList; |
| | Token ipkToken; |
| | sqlite3TokenInit(&ipkToken, pTab->aCol[pTab->iPKey].zCnName); |
| | pList = sqlite3ExprListAppend(pParse, 0, |
| | sqlite3ExprAlloc(db, TK_ID, &ipkToken, 0)); |
| | if( pList==0 ){ |
| | pTab->tabFlags &= ~TF_WithoutRowid; |
| | return; |
| | } |
| | if( IN_RENAME_OBJECT ){ |
| | sqlite3RenameTokenRemap(pParse, pList->a[0].pExpr, &pTab->iPKey); |
| | } |
| | pList->a[0].fg.sortFlags = pParse->iPkSortOrder; |
| | assert( pParse->pNewTable==pTab ); |
| | pTab->iPKey = -1; |
| | sqlite3CreateIndex(pParse, 0, 0, 0, pList, pTab->keyConf, 0, 0, 0, 0, |
| | SQLITE_IDXTYPE_PRIMARYKEY); |
| | if( pParse->nErr ){ |
| | pTab->tabFlags &= ~TF_WithoutRowid; |
| | return; |
| | } |
| | assert( db->mallocFailed==0 ); |
| | pPk = sqlite3PrimaryKeyIndex(pTab); |
| | assert( pPk->nKeyCol==1 ); |
| | }else{ |
| | pPk = sqlite3PrimaryKeyIndex(pTab); |
| | assert( pPk!=0 ); |
| |
|
| | |
| | |
| | |
| | |
| | |
| | for(i=j=1; i<pPk->nKeyCol; i++){ |
| | if( isDupColumn(pPk, j, pPk, i) ){ |
| | pPk->nColumn--; |
| | }else{ |
| | testcase( hasColumn(pPk->aiColumn, j, pPk->aiColumn[i]) ); |
| | pPk->azColl[j] = pPk->azColl[i]; |
| | pPk->aSortOrder[j] = pPk->aSortOrder[i]; |
| | pPk->aiColumn[j++] = pPk->aiColumn[i]; |
| | } |
| | } |
| | pPk->nKeyCol = j; |
| | } |
| | assert( pPk!=0 ); |
| | pPk->isCovering = 1; |
| | if( !db->init.imposterTable ) pPk->uniqNotNull = 1; |
| | nPk = pPk->nColumn = pPk->nKeyCol; |
| |
|
| | |
| | |
| | |
| | |
| | if( v && pPk->tnum>0 ){ |
| | assert( db->init.busy==0 ); |
| | sqlite3VdbeChangeOpcode(v, (int)pPk->tnum, OP_Goto); |
| | } |
| |
|
| | |
| | pPk->tnum = pTab->tnum; |
| |
|
| | |
| | |
| | |
| | for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ |
| | int n; |
| | if( IsPrimaryKeyIndex(pIdx) ) continue; |
| | for(i=n=0; i<nPk; i++){ |
| | if( !isDupColumn(pIdx, pIdx->nKeyCol, pPk, i) ){ |
| | testcase( hasColumn(pIdx->aiColumn, pIdx->nKeyCol, pPk->aiColumn[i]) ); |
| | n++; |
| | } |
| | } |
| | if( n==0 ){ |
| | |
| | pIdx->nColumn = pIdx->nKeyCol; |
| | continue; |
| | } |
| | if( resizeIndexObject(pParse, pIdx, pIdx->nKeyCol+n) ) return; |
| | for(i=0, j=pIdx->nKeyCol; i<nPk; i++){ |
| | if( !isDupColumn(pIdx, pIdx->nKeyCol, pPk, i) ){ |
| | testcase( hasColumn(pIdx->aiColumn, pIdx->nKeyCol, pPk->aiColumn[i]) ); |
| | pIdx->aiColumn[j] = pPk->aiColumn[i]; |
| | pIdx->azColl[j] = pPk->azColl[i]; |
| | if( pPk->aSortOrder[i] ){ |
| | |
| | pIdx->bAscKeyBug = 1; |
| | } |
| | j++; |
| | } |
| | } |
| | assert( pIdx->nColumn>=pIdx->nKeyCol+n ); |
| | assert( pIdx->nColumn>=j ); |
| | } |
| |
|
| | |
| | |
| | nExtra = 0; |
| | for(i=0; i<pTab->nCol; i++){ |
| | if( !hasColumn(pPk->aiColumn, nPk, i) |
| | && (pTab->aCol[i].colFlags & COLFLAG_VIRTUAL)==0 ) nExtra++; |
| | } |
| | if( resizeIndexObject(pParse, pPk, nPk+nExtra) ) return; |
| | for(i=0, j=nPk; i<pTab->nCol; i++){ |
| | if( !hasColumn(pPk->aiColumn, j, i) |
| | && (pTab->aCol[i].colFlags & COLFLAG_VIRTUAL)==0 |
| | ){ |
| | assert( j<pPk->nColumn ); |
| | pPk->aiColumn[j] = i; |
| | pPk->azColl[j] = sqlite3StrBINARY; |
| | j++; |
| | } |
| | } |
| | assert( pPk->nColumn==j ); |
| | assert( pTab->nNVCol<=j ); |
| | recomputeColumnsNotIndexed(pPk); |
| | } |
| |
|
| |
|
| | #ifndef SQLITE_OMIT_VIRTUALTABLE |
| | |
| | |
| | |
| | |
| | int sqlite3IsShadowTableOf(sqlite3 *db, Table *pTab, const char *zName){ |
| | int nName; |
| | Module *pMod; |
| |
|
| | if( !IsVirtual(pTab) ) return 0; |
| | nName = sqlite3Strlen30(pTab->zName); |
| | if( sqlite3_strnicmp(zName, pTab->zName, nName)!=0 ) return 0; |
| | if( zName[nName]!='_' ) return 0; |
| | pMod = (Module*)sqlite3HashFind(&db->aModule, pTab->u.vtab.azArg[0]); |
| | if( pMod==0 ) return 0; |
| | if( pMod->pModule->iVersion<3 ) return 0; |
| | if( pMod->pModule->xShadowName==0 ) return 0; |
| | return pMod->pModule->xShadowName(zName+nName+1); |
| | } |
| | #endif |
| |
|
| | #ifndef SQLITE_OMIT_VIRTUALTABLE |
| | |
| | |
| | |
| | |
| | |
| | |
| | void sqlite3MarkAllShadowTablesOf(sqlite3 *db, Table *pTab){ |
| | int nName; |
| | Module *pMod; |
| | HashElem *k; |
| |
|
| | assert( IsVirtual(pTab) ); |
| | pMod = (Module*)sqlite3HashFind(&db->aModule, pTab->u.vtab.azArg[0]); |
| | if( pMod==0 ) return; |
| | if( NEVER(pMod->pModule==0) ) return; |
| | if( pMod->pModule->iVersion<3 ) return; |
| | if( pMod->pModule->xShadowName==0 ) return; |
| | assert( pTab->zName!=0 ); |
| | nName = sqlite3Strlen30(pTab->zName); |
| | for(k=sqliteHashFirst(&pTab->pSchema->tblHash); k; k=sqliteHashNext(k)){ |
| | Table *pOther = sqliteHashData(k); |
| | assert( pOther->zName!=0 ); |
| | if( !IsOrdinaryTable(pOther) ) continue; |
| | if( pOther->tabFlags & TF_Shadow ) continue; |
| | if( sqlite3StrNICmp(pOther->zName, pTab->zName, nName)==0 |
| | && pOther->zName[nName]=='_' |
| | && pMod->pModule->xShadowName(pOther->zName+nName+1) |
| | ){ |
| | pOther->tabFlags |= TF_Shadow; |
| | } |
| | } |
| | } |
| | #endif |
| |
|
| | #ifndef SQLITE_OMIT_VIRTUALTABLE |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | int sqlite3ShadowTableName(sqlite3 *db, const char *zName){ |
| | char *zTail; |
| | Table *pTab; |
| | zTail = strrchr(zName, '_'); |
| | if( zTail==0 ) return 0; |
| | *zTail = 0; |
| | pTab = sqlite3FindTable(db, zName, 0); |
| | *zTail = '_'; |
| | if( pTab==0 ) return 0; |
| | if( !IsVirtual(pTab) ) return 0; |
| | return sqlite3IsShadowTableOf(db, pTab, zName); |
| | } |
| | #endif |
| |
|
| |
|
| | #ifdef SQLITE_DEBUG |
| | |
| | |
| | |
| | |
| | |
| | |
| | static int markImmutableExprStep(Walker *pWalker, Expr *pExpr){ |
| | (void)pWalker; |
| | ExprSetVVAProperty(pExpr, EP_Immutable); |
| | return WRC_Continue; |
| | } |
| | static void markExprListImmutable(ExprList *pList){ |
| | if( pList ){ |
| | Walker w; |
| | memset(&w, 0, sizeof(w)); |
| | w.xExprCallback = markImmutableExprStep; |
| | w.xSelectCallback = sqlite3SelectWalkNoop; |
| | w.xSelectCallback2 = 0; |
| | sqlite3WalkExprList(&w, pList); |
| | } |
| | } |
| | #else |
| | #define markExprListImmutable(X) |
| | #endif |
| |
|
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | void sqlite3EndTable( |
| | Parse *pParse, |
| | Token *pCons, |
| | Token *pEnd, |
| | u32 tabOpts, |
| | Select *pSelect |
| | ){ |
| | Table *p; |
| | sqlite3 *db = pParse->db; |
| | int iDb; |
| | Index *pIdx; |
| |
|
| | if( pEnd==0 && pSelect==0 ){ |
| | return; |
| | } |
| | p = pParse->pNewTable; |
| | if( p==0 ) return; |
| |
|
| | if( pSelect==0 && sqlite3ShadowTableName(db, p->zName) ){ |
| | p->tabFlags |= TF_Shadow; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | if( db->init.busy ){ |
| | if( pSelect || (!IsOrdinaryTable(p) && db->init.newTnum) ){ |
| | sqlite3ErrorMsg(pParse, ""); |
| | return; |
| | } |
| | p->tnum = db->init.newTnum; |
| | if( p->tnum==1 ) p->tabFlags |= TF_Readonly; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | if( tabOpts & TF_Strict ){ |
| | int ii; |
| | p->tabFlags |= TF_Strict; |
| | for(ii=0; ii<p->nCol; ii++){ |
| | Column *pCol = &p->aCol[ii]; |
| | if( pCol->eCType==COLTYPE_CUSTOM ){ |
| | if( pCol->colFlags & COLFLAG_HASTYPE ){ |
| | sqlite3ErrorMsg(pParse, |
| | "unknown datatype for %s.%s: \"%s\"", |
| | p->zName, pCol->zCnName, sqlite3ColumnType(pCol, "") |
| | ); |
| | }else{ |
| | sqlite3ErrorMsg(pParse, "missing datatype for %s.%s", |
| | p->zName, pCol->zCnName); |
| | } |
| | return; |
| | }else if( pCol->eCType==COLTYPE_ANY ){ |
| | pCol->affinity = SQLITE_AFF_BLOB; |
| | } |
| | if( (pCol->colFlags & COLFLAG_PRIMKEY)!=0 |
| | && p->iPKey!=ii |
| | && pCol->notNull == OE_None |
| | ){ |
| | pCol->notNull = OE_Abort; |
| | p->tabFlags |= TF_HasNotNull; |
| | } |
| | } |
| | } |
| |
|
| | assert( (p->tabFlags & TF_HasPrimaryKey)==0 |
| | || p->iPKey>=0 || sqlite3PrimaryKeyIndex(p)!=0 ); |
| | assert( (p->tabFlags & TF_HasPrimaryKey)!=0 |
| | || (p->iPKey<0 && sqlite3PrimaryKeyIndex(p)==0) ); |
| |
|
| | |
| | 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); |
| | return; |
| | } |
| | p->tabFlags |= TF_WithoutRowid | TF_NoVisibleRowid; |
| | convertToWithoutRowidTable(pParse, p); |
| | } |
| | iDb = sqlite3SchemaToIndex(db, p->pSchema); |
| |
|
| | #ifndef SQLITE_OMIT_CHECK |
| | |
| | |
| | if( p->pCheck ){ |
| | sqlite3ResolveSelfReference(pParse, p, NC_IsCheck, 0, p->pCheck); |
| | if( pParse->nErr ){ |
| | |
| | |
| | sqlite3ExprListDelete(db, p->pCheck); |
| | p->pCheck = 0; |
| | }else{ |
| | markExprListImmutable(p->pCheck); |
| | } |
| | } |
| | #endif |
| | #ifndef SQLITE_OMIT_GENERATED_COLUMNS |
| | if( p->tabFlags & TF_HasGenerated ){ |
| | int ii, nNG = 0; |
| | testcase( p->tabFlags & TF_HasVirtual ); |
| | testcase( p->tabFlags & TF_HasStored ); |
| | for(ii=0; ii<p->nCol; ii++){ |
| | u32 colFlags = p->aCol[ii].colFlags; |
| | if( (colFlags & COLFLAG_GENERATED)!=0 ){ |
| | Expr *pX = sqlite3ColumnExpr(p, &p->aCol[ii]); |
| | testcase( colFlags & COLFLAG_VIRTUAL ); |
| | testcase( colFlags & COLFLAG_STORED ); |
| | if( sqlite3ResolveSelfReference(pParse, p, NC_GenCol, pX, 0) ){ |
| | |
| | |
| | |
| | |
| | |
| | |
| | sqlite3ColumnSetExpr(pParse, p, &p->aCol[ii], |
| | sqlite3ExprAlloc(db, TK_NULL, 0, 0)); |
| | } |
| | }else{ |
| | nNG++; |
| | } |
| | } |
| | if( nNG==0 ){ |
| | sqlite3ErrorMsg(pParse, "must have at least one non-generated column"); |
| | return; |
| | } |
| | } |
| | #endif |
| |
|
| | |
| | estimateTableWidth(p); |
| | for(pIdx=p->pIndex; pIdx; pIdx=pIdx->pNext){ |
| | estimateIndexWidth(pIdx); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | if( !db->init.busy ){ |
| | int n; |
| | Vdbe *v; |
| | char *zType; |
| | char *zType2; |
| | char *zStmt; |
| |
|
| | v = sqlite3GetVdbe(pParse); |
| | if( NEVER(v==0) ) return; |
| |
|
| | sqlite3VdbeAddOp1(v, OP_Close, 0); |
| |
|
| | |
| | |
| | |
| | if( IsOrdinaryTable(p) ){ |
| | |
| | zType = "table"; |
| | zType2 = "TABLE"; |
| | #ifndef SQLITE_OMIT_VIEW |
| | }else{ |
| | |
| | zType = "view"; |
| | zType2 = "VIEW"; |
| | #endif |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | if( pSelect ){ |
| | SelectDest dest; |
| | int regYield; |
| | int addrTop; |
| | int regRec; |
| | int regRowid; |
| | int addrInsLoop; |
| | Table *pSelTab; |
| | int iCsr; |
| |
|
| | if( IN_SPECIAL_PARSE ){ |
| | pParse->rc = SQLITE_ERROR; |
| | pParse->nErr++; |
| | return; |
| | } |
| | iCsr = pParse->nTab++; |
| | regYield = ++pParse->nMem; |
| | regRec = ++pParse->nMem; |
| | regRowid = ++pParse->nMem; |
| | sqlite3MayAbort(pParse); |
| | assert( pParse->isCreate ); |
| | sqlite3VdbeAddOp3(v, OP_OpenWrite, iCsr, pParse->u1.cr.regRoot, iDb); |
| | sqlite3VdbeChangeP5(v, OPFLAG_P2ISREG); |
| | addrTop = sqlite3VdbeCurrentAddr(v) + 1; |
| | sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, addrTop); |
| | if( pParse->nErr ) return; |
| | pSelTab = sqlite3ResultSetOfSelect(pParse, pSelect, SQLITE_AFF_BLOB); |
| | if( pSelTab==0 ) return; |
| | assert( p->aCol==0 ); |
| | p->nCol = p->nNVCol = pSelTab->nCol; |
| | p->aCol = pSelTab->aCol; |
| | pSelTab->nCol = 0; |
| | pSelTab->aCol = 0; |
| | sqlite3DeleteTable(db, pSelTab); |
| | sqlite3SelectDestInit(&dest, SRT_Coroutine, regYield); |
| | sqlite3Select(pParse, pSelect, &dest); |
| | if( pParse->nErr ) return; |
| | sqlite3VdbeEndCoroutine(v, regYield); |
| | sqlite3VdbeJumpHere(v, addrTop - 1); |
| | addrInsLoop = sqlite3VdbeAddOp1(v, OP_Yield, dest.iSDParm); |
| | VdbeCoverage(v); |
| | sqlite3VdbeAddOp3(v, OP_MakeRecord, dest.iSdst, dest.nSdst, regRec); |
| | sqlite3TableAffinity(v, p, 0); |
| | sqlite3VdbeAddOp2(v, OP_NewRowid, iCsr, regRowid); |
| | sqlite3VdbeAddOp3(v, OP_Insert, iCsr, regRec, regRowid); |
| | sqlite3VdbeGoto(v, addrInsLoop); |
| | sqlite3VdbeJumpHere(v, addrInsLoop); |
| | sqlite3VdbeAddOp1(v, OP_Close, iCsr); |
| | } |
| |
|
| | |
| | if( pSelect ){ |
| | zStmt = createTableStmt(db, p); |
| | }else{ |
| | 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 |
| | ); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | assert( pParse->isCreate ); |
| | sqlite3NestedParse(pParse, |
| | "UPDATE %Q." LEGACY_SCHEMA_TABLE |
| | " SET type='%s', name=%Q, tbl_name=%Q, rootpage=#%d, sql=%Q" |
| | " WHERE rowid=#%d", |
| | db->aDb[iDb].zDbSName, |
| | zType, |
| | p->zName, |
| | p->zName, |
| | pParse->u1.cr.regRoot, |
| | zStmt, |
| | pParse->u1.cr.regRowid |
| | ); |
| | sqlite3DbFree(db, zStmt); |
| | sqlite3ChangeCookie(pParse, iDb); |
| |
|
| | #ifndef SQLITE_OMIT_AUTOINCREMENT |
| | |
| | |
| | |
| | if( (p->tabFlags & TF_Autoincrement)!=0 && !IN_SPECIAL_PARSE ){ |
| | Db *pDb = &db->aDb[iDb]; |
| | assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); |
| | if( pDb->pSchema->pSeqTab==0 ){ |
| | sqlite3NestedParse(pParse, |
| | "CREATE TABLE %Q.sqlite_sequence(name,seq)", |
| | pDb->zDbSName |
| | ); |
| | } |
| | } |
| | #endif |
| |
|
| | |
| | sqlite3VdbeAddParseSchemaOp(v, iDb, |
| | sqlite3MPrintf(db, "tbl_name='%q' AND type!='trigger'", p->zName),0); |
| |
|
| | |
| | |
| | if( p->tabFlags & TF_HasGenerated ){ |
| | sqlite3VdbeAddOp4(v, OP_SqlExec, 0x0001, 0, 0, |
| | sqlite3MPrintf(db, "SELECT*FROM\"%w\".\"%w\"", |
| | db->aDb[iDb].zDbSName, p->zName), P4_DYNAMIC); |
| | } |
| | } |
| |
|
| | |
| | |
| | if( db->init.busy ){ |
| | Table *pOld; |
| | Schema *pSchema = p->pSchema; |
| | assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); |
| | assert( HasRowid(p) || p->iPKey<0 ); |
| | pOld = sqlite3HashInsert(&pSchema->tblHash, p->zName, p); |
| | if( pOld ){ |
| | assert( p==pOld ); |
| | sqlite3OomFault(db); |
| | return; |
| | } |
| | pParse->pNewTable = 0; |
| | db->mDbFlags |= DBFLAG_SchemaChange; |
| |
|
| | |
| | |
| | |
| | assert( !pParse->nested ); |
| | #ifndef SQLITE_OMIT_AUTOINCREMENT |
| | if( strcmp(p->zName, "sqlite_sequence")==0 ){ |
| | assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); |
| | p->pSchema->pSeqTab = p; |
| | } |
| | #endif |
| | } |
| |
|
| | #ifndef SQLITE_OMIT_ALTERTABLE |
| | if( !pSelect && IsOrdinaryTable(p) ){ |
| | assert( pCons && pEnd ); |
| | if( pCons->z==0 ){ |
| | pCons = pEnd; |
| | } |
| | p->u.tab.addColOffset = 13 + (int)(pCons->z - pParse->sNameToken.z); |
| | } |
| | #endif |
| | } |
| |
|
| | #ifndef SQLITE_OMIT_VIEW |
| | |
| | |
| | |
| | void sqlite3CreateView( |
| | Parse *pParse, |
| | Token *pBegin, |
| | Token *pName1, |
| | Token *pName2, |
| | ExprList *pCNames, |
| | Select *pSelect, |
| | int isTemp, |
| | int noErr |
| | ){ |
| | Table *p; |
| | int n; |
| | const char *z; |
| | Token sEnd; |
| | DbFixer sFix; |
| | Token *pName = 0; |
| | int iDb; |
| | sqlite3 *db = pParse->db; |
| |
|
| | if( pParse->nVar>0 ){ |
| | sqlite3ErrorMsg(pParse, "parameters are not allowed in views"); |
| | goto create_view_fail; |
| | } |
| | sqlite3StartTable(pParse, pName1, pName2, isTemp, 1, 0, noErr); |
| | p = pParse->pNewTable; |
| | if( p==0 || pParse->nErr ) goto create_view_fail; |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | #ifdef SQLITE_ALLOW_ROWID_IN_VIEW |
| | p->tabFlags |= sqlite3Config.mNoVisibleRowid; |
| | #else |
| | p->tabFlags |= TF_NoVisibleRowid; |
| | #endif |
| |
|
| | sqlite3TwoPartName(pParse, pName1, pName2, &pName); |
| | iDb = sqlite3SchemaToIndex(db, p->pSchema); |
| | sqlite3FixInit(&sFix, pParse, iDb, "view", pName); |
| | if( sqlite3FixSelect(&sFix, pSelect) ) goto create_view_fail; |
| |
|
| | |
| | |
| | |
| | |
| | |
| | pSelect->selFlags |= SF_View; |
| | if( IN_RENAME_OBJECT ){ |
| | p->u.view.pSelect = pSelect; |
| | pSelect = 0; |
| | }else{ |
| | p->u.view.pSelect = sqlite3SelectDup(db, pSelect, EXPRDUP_REDUCE); |
| | } |
| | p->pCheck = sqlite3ExprListDup(db, pCNames, EXPRDUP_REDUCE); |
| | p->eTabType = TABTYP_VIEW; |
| | if( db->mallocFailed ) goto create_view_fail; |
| |
|
| | |
| | |
| | |
| | sEnd = pParse->sLastToken; |
| | assert( sEnd.z[0]!=0 || sEnd.n==0 ); |
| | if( sEnd.z[0]!=';' ){ |
| | sEnd.z += sEnd.n; |
| | } |
| | sEnd.n = 0; |
| | n = (int)(sEnd.z - pBegin->z); |
| | assert( n>0 ); |
| | z = pBegin->z; |
| | while( sqlite3Isspace(z[n-1]) ){ n--; } |
| | sEnd.z = &z[n-1]; |
| | sEnd.n = 1; |
| |
|
| | |
| | sqlite3EndTable(pParse, 0, &sEnd, 0, 0); |
| |
|
| | create_view_fail: |
| | sqlite3SelectDelete(db, pSelect); |
| | if( IN_RENAME_OBJECT ){ |
| | sqlite3RenameExprlistUnmap(pParse, pCNames); |
| | } |
| | sqlite3ExprListDelete(db, pCNames); |
| | return; |
| | } |
| | #endif |
| |
|
| | #if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE) |
| | |
| | |
| | |
| | |
| | |
| | |
| | static SQLITE_NOINLINE int viewGetColumnNames(Parse *pParse, Table *pTable){ |
| | Table *pSelTab; |
| | Select *pSel; |
| | int nErr = 0; |
| | sqlite3 *db = pParse->db; |
| | #ifndef SQLITE_OMIT_VIRTUALTABLE |
| | int rc; |
| | #endif |
| | #ifndef SQLITE_OMIT_AUTHORIZATION |
| | sqlite3_xauth xAuth; |
| | #endif |
| |
|
| | assert( pTable ); |
| |
|
| | #ifndef SQLITE_OMIT_VIRTUALTABLE |
| | if( IsVirtual(pTable) ){ |
| | db->nSchemaLock++; |
| | rc = sqlite3VtabCallConnect(pParse, pTable); |
| | db->nSchemaLock--; |
| | return rc; |
| | } |
| | #endif |
| |
|
| | #ifndef SQLITE_OMIT_VIEW |
| | |
| | |
| | |
| | |
| | assert( pTable->nCol<=0 ); |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | if( pTable->nCol<0 ){ |
| | sqlite3ErrorMsg(pParse, "view %s is circularly defined", pTable->zName); |
| | return 1; |
| | } |
| | assert( pTable->nCol>=0 ); |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | assert( IsView(pTable) ); |
| | pSel = sqlite3SelectDup(db, pTable->u.view.pSelect, 0); |
| | if( pSel ){ |
| | u8 eParseMode = pParse->eParseMode; |
| | int nTab = pParse->nTab; |
| | int nSelect = pParse->nSelect; |
| | pParse->eParseMode = PARSE_MODE_NORMAL; |
| | sqlite3SrcListAssignCursors(pParse, pSel->pSrc); |
| | pTable->nCol = -1; |
| | DisableLookaside; |
| | #ifndef SQLITE_OMIT_AUTHORIZATION |
| | xAuth = db->xAuth; |
| | db->xAuth = 0; |
| | pSelTab = sqlite3ResultSetOfSelect(pParse, pSel, SQLITE_AFF_NONE); |
| | db->xAuth = xAuth; |
| | #else |
| | pSelTab = sqlite3ResultSetOfSelect(pParse, pSel, SQLITE_AFF_NONE); |
| | #endif |
| | pParse->nTab = nTab; |
| | pParse->nSelect = nSelect; |
| | if( pSelTab==0 ){ |
| | pTable->nCol = 0; |
| | nErr++; |
| | }else if( pTable->pCheck ){ |
| | |
| | |
| | |
| | |
| | |
| | |
| | sqlite3ColumnsFromExprList(pParse, pTable->pCheck, |
| | &pTable->nCol, &pTable->aCol); |
| | if( pParse->nErr==0 |
| | && pTable->nCol==pSel->pEList->nExpr |
| | ){ |
| | assert( db->mallocFailed==0 ); |
| | sqlite3SubqueryColumnTypes(pParse, pTable, pSel, SQLITE_AFF_NONE); |
| | } |
| | }else{ |
| | |
| | |
| | |
| | assert( pTable->aCol==0 ); |
| | pTable->nCol = pSelTab->nCol; |
| | pTable->aCol = pSelTab->aCol; |
| | pTable->tabFlags |= (pSelTab->tabFlags & COLFLAG_NOINSERT); |
| | pSelTab->nCol = 0; |
| | pSelTab->aCol = 0; |
| | assert( sqlite3SchemaMutexHeld(db, 0, pTable->pSchema) ); |
| | } |
| | pTable->nNVCol = pTable->nCol; |
| | sqlite3DeleteTable(db, pSelTab); |
| | sqlite3SelectDelete(db, pSel); |
| | EnableLookaside; |
| | pParse->eParseMode = eParseMode; |
| | } else { |
| | nErr++; |
| | } |
| | pTable->pSchema->schemaFlags |= DB_UnresetViews; |
| | if( db->mallocFailed ){ |
| | sqlite3DeleteColumnNames(db, pTable); |
| | } |
| | #endif |
| | return nErr + pParse->nErr; |
| | } |
| | int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){ |
| | assert( pTable!=0 ); |
| | if( !IsVirtual(pTable) && pTable->nCol>0 ) return 0; |
| | return viewGetColumnNames(pParse, pTable); |
| | } |
| | #endif |
| |
|
| | #ifndef SQLITE_OMIT_VIEW |
| | |
| | |
| | |
| | static void sqliteViewResetAll(sqlite3 *db, int idx){ |
| | HashElem *i; |
| | assert( sqlite3SchemaMutexHeld(db, idx, 0) ); |
| | if( !DbHasProperty(db, idx, DB_UnresetViews) ) return; |
| | for(i=sqliteHashFirst(&db->aDb[idx].pSchema->tblHash); i;i=sqliteHashNext(i)){ |
| | Table *pTab = sqliteHashData(i); |
| | if( IsView(pTab) ){ |
| | sqlite3DeleteColumnNames(db, pTab); |
| | } |
| | } |
| | DbClearProperty(db, idx, DB_UnresetViews); |
| | } |
| | #else |
| | # define sqliteViewResetAll(A,B) |
| | #endif |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | #ifndef SQLITE_OMIT_AUTOVACUUM |
| | void sqlite3RootPageMoved(sqlite3 *db, int iDb, Pgno iFrom, Pgno iTo){ |
| | HashElem *pElem; |
| | Hash *pHash; |
| | Db *pDb; |
| |
|
| | assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); |
| | pDb = &db->aDb[iDb]; |
| | pHash = &pDb->pSchema->tblHash; |
| | for(pElem=sqliteHashFirst(pHash); pElem; pElem=sqliteHashNext(pElem)){ |
| | Table *pTab = sqliteHashData(pElem); |
| | if( pTab->tnum==iFrom ){ |
| | pTab->tnum = iTo; |
| | } |
| | } |
| | pHash = &pDb->pSchema->idxHash; |
| | for(pElem=sqliteHashFirst(pHash); pElem; pElem=sqliteHashNext(pElem)){ |
| | Index *pIdx = sqliteHashData(pElem); |
| | if( pIdx->tnum==iFrom ){ |
| | pIdx->tnum = iTo; |
| | } |
| | } |
| | } |
| | #endif |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | static void destroyRootPage(Parse *pParse, int iTable, int iDb){ |
| | Vdbe *v = sqlite3GetVdbe(pParse); |
| | int r1 = sqlite3GetTempReg(pParse); |
| | if( iTable<2 ) sqlite3ErrorMsg(pParse, "corrupt schema"); |
| | sqlite3VdbeAddOp3(v, OP_Destroy, iTable, r1, iDb); |
| | sqlite3MayAbort(pParse); |
| | #ifndef SQLITE_OMIT_AUTOVACUUM |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | sqlite3NestedParse(pParse, |
| | "UPDATE %Q." LEGACY_SCHEMA_TABLE |
| | " SET rootpage=%d WHERE #%d AND rootpage=#%d", |
| | pParse->db->aDb[iDb].zDbSName, iTable, r1, r1); |
| | #endif |
| | sqlite3ReleaseTempReg(pParse, r1); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | static void destroyTable(Parse *pParse, Table *pTab){ |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | Pgno iTab = pTab->tnum; |
| | Pgno iDestroyed = 0; |
| |
|
| | while( 1 ){ |
| | Index *pIdx; |
| | Pgno iLargest = 0; |
| |
|
| | if( iDestroyed==0 || iTab<iDestroyed ){ |
| | iLargest = iTab; |
| | } |
| | for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ |
| | Pgno iIdx = pIdx->tnum; |
| | assert( pIdx->pSchema==pTab->pSchema ); |
| | if( (iDestroyed==0 || (iIdx<iDestroyed)) && iIdx>iLargest ){ |
| | iLargest = iIdx; |
| | } |
| | } |
| | if( iLargest==0 ){ |
| | return; |
| | }else{ |
| | int iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); |
| | assert( iDb>=0 && iDb<pParse->db->nDb ); |
| | destroyRootPage(pParse, iLargest, iDb); |
| | iDestroyed = iLargest; |
| | } |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | static void sqlite3ClearStatTables( |
| | Parse *pParse, |
| | int iDb, |
| | const char *zType, |
| | const char *zName |
| | ){ |
| | int i; |
| | const char *zDbName = pParse->db->aDb[iDb].zDbSName; |
| | 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 |
| | ); |
| | } |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | 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 |
| |
|
| | |
| | |
| | |
| | |
| | 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 |
| | |
| | |
| | |
| | |
| | |
| | if( pTab->tabFlags & TF_Autoincrement ){ |
| | sqlite3NestedParse(pParse, |
| | "DELETE FROM %Q.sqlite_sequence WHERE name=%Q", |
| | pDb->zDbSName, pTab->zName |
| | ); |
| | } |
| | #endif |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | sqlite3NestedParse(pParse, |
| | "DELETE FROM %Q." LEGACY_SCHEMA_TABLE |
| | " WHERE tbl_name=%Q and type!='trigger'", |
| | pDb->zDbSName, pTab->zName); |
| | if( !isView && !IsVirtual(pTab) ){ |
| | destroyTable(pParse, pTab); |
| | } |
| |
|
| | |
| | |
| | |
| | if( IsVirtual(pTab) ){ |
| | sqlite3VdbeAddOp4(v, OP_VDestroy, iDb, 0, 0, pTab->zName, 0); |
| | sqlite3MayAbort(pParse); |
| | } |
| | sqlite3VdbeAddOp4(v, OP_DropTable, iDb, 0, 0, pTab->zName, 0); |
| | sqlite3ChangeCookie(pParse, iDb); |
| | sqliteViewResetAll(db, iDb); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | int sqlite3ReadOnlyShadowTables(sqlite3 *db){ |
| | #ifndef SQLITE_OMIT_VIRTUALTABLE |
| | if( (db->flags & SQLITE_Defensive)!=0 |
| | && db->pVtabCtx==0 |
| | && db->nVdbeExec==0 |
| | && !sqlite3VtabInSync(db) |
| | ){ |
| | return 1; |
| | } |
| | #endif |
| | return 0; |
| | } |
| |
|
| | |
| | |
| | |
| | static int tableMayNotBeDropped(sqlite3 *db, Table *pTab){ |
| | if( sqlite3StrNICmp(pTab->zName, "sqlite_", 7)==0 ){ |
| | if( sqlite3StrNICmp(pTab->zName+7, "stat", 4)==0 ) return 0; |
| | if( sqlite3StrNICmp(pTab->zName+7, "parameters", 10)==0 ) return 0; |
| | return 1; |
| | } |
| | if( (pTab->tabFlags & TF_Shadow)!=0 && sqlite3ReadOnlyShadowTables(db) ){ |
| | return 1; |
| | } |
| | if( pTab->tabFlags & TF_Eponymous ){ |
| | return 1; |
| | } |
| | return 0; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, int noErr){ |
| | Table *pTab; |
| | Vdbe *v; |
| | sqlite3 *db = pParse->db; |
| | int iDb; |
| |
|
| | if( db->mallocFailed ){ |
| | goto exit_drop_table; |
| | } |
| | assert( pParse->nErr==0 ); |
| | assert( pName->nSrc==1 ); |
| | assert( pName->a[0].fg.fixedSchema==0 ); |
| | assert( pName->a[0].fg.isSubquery==0 ); |
| | if( sqlite3ReadSchema(pParse) ) goto exit_drop_table; |
| | if( noErr ) db->suppressErr++; |
| | assert( isView==0 || isView==LOCATE_VIEW ); |
| | pTab = sqlite3LocateTableItem(pParse, isView, &pName->a[0]); |
| | if( noErr ) db->suppressErr--; |
| |
|
| | if( pTab==0 ){ |
| | if( noErr ){ |
| | sqlite3CodeVerifyNamedSchema(pParse, pName->a[0].u4.zDatabase); |
| | sqlite3ForceNotReadOnly(pParse); |
| | } |
| | goto exit_drop_table; |
| | } |
| | iDb = sqlite3SchemaToIndex(db, pTab->pSchema); |
| | assert( iDb>=0 && iDb<db->nDb ); |
| |
|
| | |
| | |
| | |
| | if( IsVirtual(pTab) && sqlite3ViewGetColumnNames(pParse, pTab) ){ |
| | goto exit_drop_table; |
| | } |
| | #ifndef SQLITE_OMIT_AUTHORIZATION |
| | { |
| | int code; |
| | const char *zTab = SCHEMA_TABLE(iDb); |
| | const char *zDb = db->aDb[iDb].zDbSName; |
| | const char *zArg2 = 0; |
| | if( sqlite3AuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb)){ |
| | goto exit_drop_table; |
| | } |
| | if( isView ){ |
| | if( !OMIT_TEMPDB && iDb==1 ){ |
| | code = SQLITE_DROP_TEMP_VIEW; |
| | }else{ |
| | code = SQLITE_DROP_VIEW; |
| | } |
| | #ifndef SQLITE_OMIT_VIRTUALTABLE |
| | }else if( IsVirtual(pTab) ){ |
| | code = SQLITE_DROP_VTABLE; |
| | zArg2 = sqlite3GetVTable(db, pTab)->pMod->zName; |
| | #endif |
| | }else{ |
| | if( !OMIT_TEMPDB && iDb==1 ){ |
| | code = SQLITE_DROP_TEMP_TABLE; |
| | }else{ |
| | code = SQLITE_DROP_TABLE; |
| | } |
| | } |
| | if( sqlite3AuthCheck(pParse, code, pTab->zName, zArg2, zDb) ){ |
| | goto exit_drop_table; |
| | } |
| | if( sqlite3AuthCheck(pParse, SQLITE_DELETE, pTab->zName, 0, zDb) ){ |
| | goto exit_drop_table; |
| | } |
| | } |
| | #endif |
| | if( tableMayNotBeDropped(db, pTab) ){ |
| | sqlite3ErrorMsg(pParse, "table %s may not be dropped", pTab->zName); |
| | goto exit_drop_table; |
| | } |
| |
|
| | #ifndef SQLITE_OMIT_VIEW |
| | |
| | |
| | |
| | if( isView && !IsView(pTab) ){ |
| | sqlite3ErrorMsg(pParse, "use DROP TABLE to delete table %s", pTab->zName); |
| | goto exit_drop_table; |
| | } |
| | if( !isView && IsView(pTab) ){ |
| | sqlite3ErrorMsg(pParse, "use DROP VIEW to delete view %s", pTab->zName); |
| | goto exit_drop_table; |
| | } |
| | #endif |
| |
|
| | |
| | |
| | |
| | v = sqlite3GetVdbe(pParse); |
| | if( v ){ |
| | sqlite3BeginWriteOperation(pParse, 1, iDb); |
| | if( !isView ){ |
| | sqlite3ClearStatTables(pParse, iDb, "tbl", pTab->zName); |
| | sqlite3FkDropTable(pParse, pName, pTab); |
| | } |
| | sqlite3CodeDropTable(pParse, pTab, iDb, isView); |
| | } |
| |
|
| | exit_drop_table: |
| | sqlite3SrcListDelete(db, pName); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | void sqlite3CreateForeignKey( |
| | Parse *pParse, |
| | ExprList *pFromCol, |
| | Token *pTo, |
| | ExprList *pToCol, |
| | int flags |
| | ){ |
| | sqlite3 *db = pParse->db; |
| | #ifndef SQLITE_OMIT_FOREIGN_KEY |
| | FKey *pFKey = 0; |
| | FKey *pNextTo; |
| | Table *p = pParse->pNewTable; |
| | i64 nByte; |
| | int i; |
| | int nCol; |
| | char *z; |
| |
|
| | assert( pTo!=0 ); |
| | if( p==0 || IN_DECLARE_VTAB ) goto fk_end; |
| | if( pFromCol==0 ){ |
| | int iCol = p->nCol-1; |
| | if( NEVER(iCol<0) ) goto fk_end; |
| | if( pToCol && pToCol->nExpr!=1 ){ |
| | sqlite3ErrorMsg(pParse, "foreign key on %s" |
| | " should reference only one column of table %T", |
| | p->aCol[iCol].zCnName, pTo); |
| | goto fk_end; |
| | } |
| | nCol = 1; |
| | }else if( pToCol && pToCol->nExpr!=pFromCol->nExpr ){ |
| | sqlite3ErrorMsg(pParse, |
| | "number of columns in foreign key does not match the number of " |
| | "columns in the referenced table"); |
| | goto fk_end; |
| | }else{ |
| | nCol = pFromCol->nExpr; |
| | } |
| | nByte = SZ_FKEY(nCol) + pTo->n + 1; |
| | if( pToCol ){ |
| | for(i=0; i<pToCol->nExpr; i++){ |
| | nByte += sqlite3Strlen30(pToCol->a[i].zEName) + 1; |
| | } |
| | } |
| | pFKey = sqlite3DbMallocZero(db, nByte ); |
| | if( pFKey==0 ){ |
| | goto fk_end; |
| | } |
| | pFKey->pFrom = p; |
| | assert( IsOrdinaryTable(p) ); |
| | pFKey->pNextFrom = p->u.tab.pFKey; |
| | z = (char*)&pFKey->aCol[nCol]; |
| | pFKey->zTo = z; |
| | if( IN_RENAME_OBJECT ){ |
| | sqlite3RenameTokenMap(pParse, (void*)z, pTo); |
| | } |
| | memcpy(z, pTo->z, pTo->n); |
| | z[pTo->n] = 0; |
| | sqlite3Dequote(z); |
| | z += pTo->n+1; |
| | pFKey->nCol = nCol; |
| | if( pFromCol==0 ){ |
| | pFKey->aCol[0].iFrom = p->nCol-1; |
| | }else{ |
| | for(i=0; i<nCol; i++){ |
| | int j; |
| | for(j=0; j<p->nCol; j++){ |
| | if( sqlite3StrICmp(p->aCol[j].zCnName, pFromCol->a[i].zEName)==0 ){ |
| | pFKey->aCol[i].iFrom = j; |
| | break; |
| | } |
| | } |
| | if( j>=p->nCol ){ |
| | sqlite3ErrorMsg(pParse, |
| | "unknown column \"%s\" in foreign key definition", |
| | pFromCol->a[i].zEName); |
| | goto fk_end; |
| | } |
| | if( IN_RENAME_OBJECT ){ |
| | sqlite3RenameTokenRemap(pParse, &pFKey->aCol[i], pFromCol->a[i].zEName); |
| | } |
| | } |
| | } |
| | if( pToCol ){ |
| | for(i=0; i<nCol; i++){ |
| | int n = sqlite3Strlen30(pToCol->a[i].zEName); |
| | pFKey->aCol[i].zCol = z; |
| | if( IN_RENAME_OBJECT ){ |
| | sqlite3RenameTokenRemap(pParse, z, pToCol->a[i].zEName); |
| | } |
| | memcpy(z, pToCol->a[i].zEName, n); |
| | z[n] = 0; |
| | z += n+1; |
| | } |
| | } |
| | pFKey->isDeferred = 0; |
| | pFKey->aAction[0] = (u8)(flags & 0xff); |
| | pFKey->aAction[1] = (u8)((flags >> 8 ) & 0xff); |
| |
|
| | assert( sqlite3SchemaMutexHeld(db, 0, p->pSchema) ); |
| | pNextTo = (FKey *)sqlite3HashInsert(&p->pSchema->fkeyHash, |
| | pFKey->zTo, (void *)pFKey |
| | ); |
| | if( pNextTo==pFKey ){ |
| | sqlite3OomFault(db); |
| | goto fk_end; |
| | } |
| | if( pNextTo ){ |
| | assert( pNextTo->pPrevTo==0 ); |
| | pFKey->pNextTo = pNextTo; |
| | pNextTo->pPrevTo = pFKey; |
| | } |
| |
|
| | |
| | |
| | assert( IsOrdinaryTable(p) ); |
| | p->u.tab.pFKey = pFKey; |
| | pFKey = 0; |
| |
|
| | fk_end: |
| | sqlite3DbFree(db, pFKey); |
| | #endif |
| | sqlite3ExprListDelete(db, pFromCol); |
| | sqlite3ExprListDelete(db, pToCol); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | void sqlite3DeferForeignKey(Parse *pParse, int isDeferred){ |
| | #ifndef SQLITE_OMIT_FOREIGN_KEY |
| | Table *pTab; |
| | FKey *pFKey; |
| | if( (pTab = pParse->pNewTable)==0 ) return; |
| | if( NEVER(!IsOrdinaryTable(pTab)) ) return; |
| | if( (pFKey = pTab->u.tab.pFKey)==0 ) return; |
| | assert( isDeferred==0 || isDeferred==1 ); |
| | pFKey->isDeferred = (u8)isDeferred; |
| | #endif |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){ |
| | Table *pTab = pIndex->pTable; |
| | int iTab = pParse->nTab++; |
| | int iIdx = pParse->nTab++; |
| | int iSorter; |
| | int addr1; |
| | int addr2; |
| | Pgno tnum; |
| | int iPartIdxLabel; |
| | Vdbe *v; |
| | KeyInfo *pKey; |
| | int regRecord; |
| | sqlite3 *db = pParse->db; |
| | int iDb = sqlite3SchemaToIndex(db, pIndex->pSchema); |
| |
|
| | #ifndef SQLITE_OMIT_AUTHORIZATION |
| | if( sqlite3AuthCheck(pParse, SQLITE_REINDEX, pIndex->zName, 0, |
| | db->aDb[iDb].zDbSName ) ){ |
| | return; |
| | } |
| | #endif |
| |
|
| | |
| | sqlite3TableLock(pParse, iDb, pTab->tnum, 1, pTab->zName); |
| |
|
| | v = sqlite3GetVdbe(pParse); |
| | if( v==0 ) return; |
| | if( memRootPage>=0 ){ |
| | tnum = (Pgno)memRootPage; |
| | }else{ |
| | tnum = pIndex->tnum; |
| | } |
| | pKey = sqlite3KeyInfoOfIndex(pParse, pIndex); |
| | assert( pKey!=0 || pParse->nErr ); |
| |
|
| | |
| | iSorter = pParse->nTab++; |
| | sqlite3VdbeAddOp4(v, OP_SorterOpen, iSorter, 0, pIndex->nKeyCol, (char*) |
| | sqlite3KeyInfoRef(pKey), P4_KEYINFO); |
| |
|
| | |
| | |
| | sqlite3OpenTable(pParse, iTab, iDb, pTab, OP_OpenRead); |
| | addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iTab, 0); VdbeCoverage(v); |
| | regRecord = sqlite3GetTempReg(pParse); |
| | sqlite3MultiWrite(pParse); |
| |
|
| | 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, (int)tnum, iDb, |
| | (char *)pKey, P4_KEYINFO); |
| | sqlite3VdbeChangeP5(v, OPFLAG_BULKCSR|((memRootPage>=0)?OPFLAG_P2ISREG:0)); |
| |
|
| | addr1 = sqlite3VdbeAddOp2(v, OP_SorterSort, iSorter, 0); VdbeCoverage(v); |
| | if( IsUniqueIndex(pIndex) ){ |
| | int j2 = sqlite3VdbeGoto(v, 1); |
| | addr2 = sqlite3VdbeCurrentAddr(v); |
| | sqlite3VdbeVerifyAbortable(v, OE_Abort); |
| | sqlite3VdbeAddOp4Int(v, OP_SorterCompare, iSorter, j2, regRecord, |
| | pIndex->nKeyCol); VdbeCoverage(v); |
| | sqlite3UniqueConstraint(pParse, OE_Abort, pIndex); |
| | sqlite3VdbeJumpHere(v, j2); |
| | }else{ |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | sqlite3MayAbort(pParse); |
| | addr2 = sqlite3VdbeCurrentAddr(v); |
| | } |
| | sqlite3VdbeAddOp3(v, OP_SorterData, iSorter, regRecord, iIdx); |
| | if( !pIndex->bAscKeyBug ){ |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | sqlite3VdbeAddOp1(v, OP_SeekEnd, iIdx); |
| | } |
| | sqlite3VdbeAddOp2(v, OP_IdxInsert, iIdx, regRecord); |
| | sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT); |
| | sqlite3ReleaseTempReg(pParse, regRecord); |
| | 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); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | Index *sqlite3AllocateIndexObject( |
| | sqlite3 *db, |
| | int nCol, |
| | int nExtra, |
| | char **ppExtra |
| | ){ |
| | Index *p; |
| | i64 nByte; |
| |
|
| | assert( nCol <= 2*db->aLimit[SQLITE_LIMIT_COLUMN] ); |
| | nByte = ROUND8(sizeof(Index)) + |
| | ROUND8(sizeof(char*)*nCol) + |
| | ROUND8(sizeof(LogEst)*(nCol+1) + |
| | sizeof(i16)*nCol + |
| | sizeof(u8)*nCol); |
| | p = sqlite3DbMallocZero(db, nByte + nExtra); |
| | if( p ){ |
| | char *pExtra = ((char*)p)+ROUND8(sizeof(Index)); |
| | p->azColl = (const 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; |
| | assert( nCol>0 ); |
| | p->nColumn = (u16)nCol; |
| | p->nKeyCol = (u16)(nCol - 1); |
| | *ppExtra = ((char*)p) + nByte; |
| | } |
| | return p; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | int sqlite3HasExplicitNulls(Parse *pParse, ExprList *pList){ |
| | if( pList ){ |
| | int i; |
| | for(i=0; i<pList->nExpr; i++){ |
| | if( pList->a[i].fg.bNulls ){ |
| | u8 sf = pList->a[i].fg.sortFlags; |
| | sqlite3ErrorMsg(pParse, "unsupported use of NULLS %s", |
| | (sf==0 || sf==3) ? "FIRST" : "LAST" |
| | ); |
| | return 1; |
| | } |
| | } |
| | } |
| | return 0; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | void sqlite3CreateIndex( |
| | Parse *pParse, |
| | Token *pName1, |
| | Token *pName2, |
| | SrcList *pTblName, |
| | ExprList *pList, |
| | int onError, |
| | Token *pStart, |
| | Expr *pPIWhere, |
| | int sortOrder, |
| | int ifNotExist, |
| | u8 idxType |
| | ){ |
| | Table *pTab = 0; |
| | Index *pIndex = 0; |
| | char *zName = 0; |
| | int nName; |
| | int i, j; |
| | DbFixer sFix; |
| | int sortOrderMask; |
| | sqlite3 *db = pParse->db; |
| | Db *pDb; |
| | int iDb; |
| | Token *pName = 0; |
| | struct ExprList_item *pListItem; |
| | int nExtra = 0; |
| | int nExtraCol; |
| | char *zExtra = 0; |
| | Index *pPk = 0; |
| |
|
| | assert( db->pParse==pParse ); |
| | if( pParse->nErr ){ |
| | goto exit_create_index; |
| | } |
| | assert( db->mallocFailed==0 ); |
| | if( IN_DECLARE_VTAB && idxType!=SQLITE_IDXTYPE_PRIMARYKEY ){ |
| | goto exit_create_index; |
| | } |
| | if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){ |
| | goto exit_create_index; |
| | } |
| | if( sqlite3HasExplicitNulls(pParse, pList) ){ |
| | goto exit_create_index; |
| | } |
| |
|
| | |
| | |
| | |
| | if( pTblName!=0 ){ |
| |
|
| | |
| | |
| | |
| | |
| | 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( !db->init.busy ){ |
| | pTab = sqlite3SrcListLookup(pParse, pTblName); |
| | if( pName2->n==0 && pTab && pTab->pSchema==db->aDb[1].pSchema ){ |
| | iDb = 1; |
| | } |
| | } |
| | #endif |
| |
|
| | sqlite3FixInit(&sFix, pParse, iDb, "index", pName); |
| | if( sqlite3FixSrcList(&sFix, pTblName) ){ |
| | |
| | |
| | assert(0); |
| | } |
| | 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); |
| | } |
| | pDb = &db->aDb[iDb]; |
| |
|
| | assert( pTab!=0 ); |
| | if( sqlite3StrNICmp(pTab->zName, "sqlite_", 7)==0 |
| | && db->init.busy==0 |
| | && pTblName!=0 |
| | ){ |
| | sqlite3ErrorMsg(pParse, "table %s may not be indexed", pTab->zName); |
| | goto exit_create_index; |
| | } |
| | #ifndef SQLITE_OMIT_VIEW |
| | if( IsView(pTab) ){ |
| | sqlite3ErrorMsg(pParse, "views may not be indexed"); |
| | goto exit_create_index; |
| | } |
| | #endif |
| | #ifndef SQLITE_OMIT_VIRTUALTABLE |
| | if( IsVirtual(pTab) ){ |
| | sqlite3ErrorMsg(pParse, "virtual tables may not be indexed"); |
| | goto exit_create_index; |
| | } |
| | #endif |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | if( pName ){ |
| | zName = sqlite3NameFromToken(db, pName); |
| | if( zName==0 ) goto exit_create_index; |
| | assert( pName->z!=0 ); |
| | if( SQLITE_OK!=sqlite3CheckObjectName(pParse, zName,"index",pTab->zName) ){ |
| | goto exit_create_index; |
| | } |
| | if( !IN_RENAME_OBJECT ){ |
| | if( !db->init.busy ){ |
| | if( sqlite3FindTable(db, zName, pDb->zDbSName)!=0 ){ |
| | sqlite3ErrorMsg(pParse, "there is already a table named %s", zName); |
| | goto exit_create_index; |
| | } |
| | } |
| | if( sqlite3FindIndex(db, zName, pDb->zDbSName)!=0 ){ |
| | if( !ifNotExist ){ |
| | sqlite3ErrorMsg(pParse, "index %s already exists", zName); |
| | }else{ |
| | assert( !db->init.busy ); |
| | sqlite3CodeVerifySchema(pParse, iDb); |
| | sqlite3ForceNotReadOnly(pParse); |
| | } |
| | goto exit_create_index; |
| | } |
| | } |
| | }else{ |
| | int n; |
| | Index *pLoop; |
| | for(pLoop=pTab->pIndex, n=1; pLoop; pLoop=pLoop->pNext, n++){} |
| | zName = sqlite3MPrintf(db, "sqlite_autoindex_%s_%d", pTab->zName, n); |
| | if( zName==0 ){ |
| | goto exit_create_index; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | if( IN_SPECIAL_PARSE ) zName[7]++; |
| | } |
| |
|
| | |
| | |
| | #ifndef SQLITE_OMIT_AUTHORIZATION |
| | if( !IN_RENAME_OBJECT ){ |
| | const char *zDb = pDb->zDbSName; |
| | if( sqlite3AuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(iDb), 0, zDb) ){ |
| | goto exit_create_index; |
| | } |
| | i = SQLITE_CREATE_INDEX; |
| | if( !OMIT_TEMPDB && iDb==1 ) i = SQLITE_CREATE_TEMP_INDEX; |
| | if( sqlite3AuthCheck(pParse, i, zName, pTab->zName, zDb) ){ |
| | goto exit_create_index; |
| | } |
| | } |
| | #endif |
| |
|
| | |
| | |
| | |
| | |
| | if( pList==0 ){ |
| | Token prevCol; |
| | Column *pCol = &pTab->aCol[pTab->nCol-1]; |
| | pCol->colFlags |= COLFLAG_UNIQUE; |
| | sqlite3TokenInit(&prevCol, pCol->zCnName); |
| | pList = sqlite3ExprListAppend(pParse, 0, |
| | sqlite3ExprAlloc(db, TK_ID, &prevCol, 0)); |
| | if( pList==0 ) goto exit_create_index; |
| | assert( pList->nExpr==1 ); |
| | sqlite3ExprListSetSortOrder(pList, sortOrder, SQLITE_SO_UNDEFINED); |
| | }else{ |
| | sqlite3ExprListCheckLength(pParse, pList, "index"); |
| | if( pParse->nErr ) goto exit_create_index; |
| | } |
| |
|
| | |
| | |
| | |
| | for(i=0; i<pList->nExpr; i++){ |
| | Expr *pExpr = pList->a[i].pExpr; |
| | assert( pExpr!=0 ); |
| | if( pExpr->op==TK_COLLATE ){ |
| | assert( !ExprHasProperty(pExpr, EP_IntValue) ); |
| | nExtra += (1 + sqlite3Strlen30(pExpr->u.zToken)); |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | nName = sqlite3Strlen30(zName); |
| | nExtraCol = pPk ? pPk->nKeyCol : 1; |
| | assert( pList->nExpr + nExtraCol <= 32767 ); |
| | pIndex = sqlite3AllocateIndexObject(db, pList->nExpr + nExtraCol, |
| | nName + nExtra + 1, &zExtra); |
| | if( db->mallocFailed ){ |
| | goto exit_create_index; |
| | } |
| | 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->onError = (u8)onError; |
| | pIndex->uniqNotNull = onError!=OE_None; |
| | pIndex->idxType = idxType; |
| | 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) ); |
| |
|
| | |
| | |
| | if( pDb->pSchema->file_format>=4 ){ |
| | sortOrderMask = -1; |
| | }else{ |
| | sortOrderMask = 0; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | pListItem = pList->a; |
| | if( IN_RENAME_OBJECT ){ |
| | pIndex->aColExpr = pList; |
| | pList = 0; |
| | } |
| | for(i=0; i<pIndex->nKeyCol; i++, pListItem++){ |
| | Expr *pCExpr; |
| | int requestedSortOrder; |
| | const char *zColl; |
| |
|
| | sqlite3StringToId(pListItem->pExpr); |
| | sqlite3ResolveSelfReference(pParse, pTab, NC_IdxExpr, pListItem->pExpr, 0); |
| | if( pParse->nErr ) goto exit_create_index; |
| | pCExpr = sqlite3ExprSkipCollate(pListItem->pExpr); |
| | if( pCExpr->op!=TK_COLUMN ){ |
| | if( pTab==pParse->pNewTable ){ |
| | sqlite3ErrorMsg(pParse, "expressions prohibited in PRIMARY KEY and " |
| | "UNIQUE constraints"); |
| | goto exit_create_index; |
| | } |
| | if( pIndex->aColExpr==0 ){ |
| | pIndex->aColExpr = pList; |
| | pList = 0; |
| | } |
| | j = XN_EXPR; |
| | pIndex->aiColumn[i] = XN_EXPR; |
| | pIndex->uniqNotNull = 0; |
| | pIndex->bHasExpr = 1; |
| | }else{ |
| | j = pCExpr->iColumn; |
| | assert( j<=0x7fff ); |
| | if( j<0 ){ |
| | j = pTab->iPKey; |
| | }else{ |
| | if( pTab->aCol[j].notNull==0 ){ |
| | pIndex->uniqNotNull = 0; |
| | } |
| | if( pTab->aCol[j].colFlags & COLFLAG_VIRTUAL ){ |
| | pIndex->bHasVCol = 1; |
| | pIndex->bHasExpr = 1; |
| | } |
| | } |
| | pIndex->aiColumn[i] = (i16)j; |
| | } |
| | zColl = 0; |
| | if( pListItem->pExpr->op==TK_COLLATE ){ |
| | int nColl; |
| | assert( !ExprHasProperty(pListItem->pExpr, EP_IntValue) ); |
| | zColl = pListItem->pExpr->u.zToken; |
| | nColl = sqlite3Strlen30(zColl) + 1; |
| | assert( nExtra>=nColl ); |
| | memcpy(zExtra, zColl, nColl); |
| | zColl = zExtra; |
| | zExtra += nColl; |
| | nExtra -= nColl; |
| | }else if( j>=0 ){ |
| | zColl = sqlite3ColumnColl(&pTab->aCol[j]); |
| | } |
| | if( !zColl ) zColl = sqlite3StrBINARY; |
| | if( !db->init.busy && !sqlite3LocateCollSeq(pParse, zColl) ){ |
| | goto exit_create_index; |
| | } |
| | pIndex->azColl[i] = zColl; |
| | requestedSortOrder = pListItem->fg.sortFlags & sortOrderMask; |
| | pIndex->aSortOrder[i] = (u8)requestedSortOrder; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | if( pPk ){ |
| | for(j=0; j<pPk->nKeyCol; j++){ |
| | int x = pPk->aiColumn[j]; |
| | assert( x>=0 ); |
| | if( isDupColumn(pIndex, pIndex->nKeyCol, pPk, j) ){ |
| | pIndex->nColumn--; |
| | }else{ |
| | testcase( hasColumn(pIndex->aiColumn,pIndex->nKeyCol,x) ); |
| | 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] = XN_ROWID; |
| | pIndex->azColl[i] = sqlite3StrBINARY; |
| | } |
| | sqlite3DefaultRowEst(pIndex); |
| | if( pParse->pNewTable==0 ) estimateIndexWidth(pIndex); |
| |
|
| | |
| | |
| | assert( HasRowid(pTab) |
| | || pTab->iPKey<0 || sqlite3TableColumnToIndex(pIndex, pTab->iPKey)>=0 ); |
| | recomputeColumnsNotIndexed(pIndex); |
| | if( pTblName!=0 && pIndex->nColumn>=pTab->nCol ){ |
| | pIndex->isCovering = 1; |
| | for(j=0; j<pTab->nCol; j++){ |
| | if( j==pTab->iPKey ) continue; |
| | if( sqlite3TableColumnToIndex(pIndex,j)>=0 ) continue; |
| | pIndex->isCovering = 0; |
| | break; |
| | } |
| | } |
| |
|
| | if( pTab==pParse->pNewTable ){ |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | Index *pIdx; |
| | for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ |
| | int k; |
| | assert( IsUniqueIndex(pIdx) ); |
| | assert( pIdx->idxType!=SQLITE_IDXTYPE_APPDEF ); |
| | assert( IsUniqueIndex(pIndex) ); |
| |
|
| | if( pIdx->nKeyCol!=pIndex->nKeyCol ) continue; |
| | for(k=0; k<pIdx->nKeyCol; k++){ |
| | const char *z1; |
| | const char *z2; |
| | assert( pIdx->aiColumn[k]>=0 ); |
| | if( pIdx->aiColumn[k]!=pIndex->aiColumn[k] ) break; |
| | z1 = pIdx->azColl[k]; |
| | z2 = pIndex->azColl[k]; |
| | if( sqlite3StrICmp(z1, z2) ) break; |
| | } |
| | if( k==pIdx->nKeyCol ){ |
| | if( pIdx->onError!=pIndex->onError ){ |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | if( !(pIdx->onError==OE_Default || pIndex->onError==OE_Default) ){ |
| | sqlite3ErrorMsg(pParse, |
| | "conflicting ON CONFLICT clauses specified", 0); |
| | } |
| | if( pIdx->onError==OE_Default ){ |
| | pIdx->onError = pIndex->onError; |
| | } |
| | } |
| | if( idxType==SQLITE_IDXTYPE_PRIMARYKEY ) pIdx->idxType = idxType; |
| | if( IN_RENAME_OBJECT ){ |
| | pIndex->pNext = pParse->pNewIndex; |
| | pParse->pNewIndex = pIndex; |
| | pIndex = 0; |
| | } |
| | goto exit_create_index; |
| | } |
| | } |
| | } |
| |
|
| | if( !IN_RENAME_OBJECT ){ |
| |
|
| | |
| | |
| | |
| | assert( pParse->nErr==0 ); |
| | if( db->init.busy ){ |
| | Index *p; |
| | assert( !IN_SPECIAL_PARSE ); |
| | assert( sqlite3SchemaMutexHeld(db, 0, pIndex->pSchema) ); |
| | if( pTblName!=0 ){ |
| | pIndex->tnum = db->init.newTnum; |
| | if( sqlite3IndexHasDuplicateRootPage(pIndex) ){ |
| | sqlite3ErrorMsg(pParse, "invalid rootpage"); |
| | pParse->rc = SQLITE_CORRUPT_BKPT; |
| | goto exit_create_index; |
| | } |
| | } |
| | p = sqlite3HashInsert(&pIndex->pSchema->idxHash, |
| | pIndex->zName, pIndex); |
| | if( p ){ |
| | assert( p==pIndex ); |
| | sqlite3OomFault(db); |
| | goto exit_create_index; |
| | } |
| | db->mDbFlags |= DBFLAG_SchemaChange; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | else if( HasRowid(pTab) || pTblName!=0 ){ |
| | Vdbe *v; |
| | char *zStmt; |
| | int iMem = ++pParse->nMem; |
| |
|
| | v = sqlite3GetVdbe(pParse); |
| | if( v==0 ) goto exit_create_index; |
| |
|
| | sqlite3BeginWriteOperation(pParse, 1, iDb); |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | pIndex->tnum = (Pgno)sqlite3VdbeAddOp0(v, OP_Noop); |
| | sqlite3VdbeAddOp3(v, OP_CreateBtree, iDb, iMem, BTREE_BLOBKEY); |
| |
|
| | |
| | |
| | |
| | assert( pName!=0 || pStart==0 ); |
| | if( pStart ){ |
| | int n = (int)(pParse->sLastToken.z - pName->z) + pParse->sLastToken.n; |
| | if( pName->z[n-1]==';' ) n--; |
| | |
| | zStmt = sqlite3MPrintf(db, "CREATE%s INDEX %.*s", |
| | onError==OE_None ? "" : " UNIQUE", n, pName->z); |
| | }else{ |
| | |
| | |
| | zStmt = 0; |
| | } |
| |
|
| | |
| | |
| | sqlite3NestedParse(pParse, |
| | "INSERT INTO %Q." LEGACY_SCHEMA_TABLE " VALUES('index',%Q,%Q,#%d,%Q);", |
| | db->aDb[iDb].zDbSName, |
| | pIndex->zName, |
| | pTab->zName, |
| | iMem, |
| | zStmt |
| | ); |
| | sqlite3DbFree(db, zStmt); |
| |
|
| | |
| | |
| | |
| | if( pTblName ){ |
| | sqlite3RefillIndex(pParse, pIndex, iMem); |
| | sqlite3ChangeCookie(pParse, iDb); |
| | sqlite3VdbeAddParseSchemaOp(v, iDb, |
| | sqlite3MPrintf(db, "name='%q' AND type='index'", pIndex->zName), 0); |
| | sqlite3VdbeAddOp2(v, OP_Expire, 0, 1); |
| | } |
| |
|
| | sqlite3VdbeJumpHere(v, (int)pIndex->tnum); |
| | } |
| | } |
| | if( db->init.busy || pTblName==0 ){ |
| | pIndex->pNext = pTab->pIndex; |
| | pTab->pIndex = pIndex; |
| | pIndex = 0; |
| | } |
| | else if( IN_RENAME_OBJECT ){ |
| | assert( pParse->pNewIndex==0 ); |
| | pParse->pNewIndex = pIndex; |
| | pIndex = 0; |
| | } |
| |
|
| | |
| | exit_create_index: |
| | if( pIndex ) sqlite3FreeIndex(db, pIndex); |
| | if( pTab ){ |
| | |
| | |
| | |
| | |
| | Index **ppFrom; |
| | Index *pThis; |
| | for(ppFrom=&pTab->pIndex; (pThis = *ppFrom)!=0; ppFrom=&pThis->pNext){ |
| | Index *pNext; |
| | if( pThis->onError!=OE_Replace ) continue; |
| | while( (pNext = pThis->pNext)!=0 && pNext->onError!=OE_Replace ){ |
| | *ppFrom = pNext; |
| | pThis->pNext = pNext->pNext; |
| | pNext->pNext = pThis; |
| | ppFrom = &pNext->pNext; |
| | } |
| | break; |
| | } |
| | #ifdef SQLITE_DEBUG |
| | |
| | |
| | |
| | for(pThis = pTab->pIndex; pThis; pThis=pThis->pNext){ |
| | assert( pThis->onError!=OE_Replace |
| | || pThis->pNext==0 |
| | || pThis->pNext->onError==OE_Replace ); |
| | } |
| | #endif |
| | } |
| | sqlite3ExprDelete(db, pPIWhere); |
| | sqlite3ExprListDelete(db, pList); |
| | sqlite3SrcListDelete(db, pTblName); |
| | sqlite3DbFree(db, zName); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | void sqlite3DefaultRowEst(Index *pIdx){ |
| | |
| | static const LogEst aVal[] = { 33, 32, 30, 28, 26 }; |
| | LogEst *a = pIdx->aiRowLogEst; |
| | LogEst x; |
| | int nCopy = MIN(ArraySize(aVal), pIdx->nKeyCol); |
| | int i; |
| |
|
| | |
| | assert( !pIdx->hasStat1 ); |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | x = pIdx->pTable->nRowLogEst; |
| | assert( 99==sqlite3LogEst(1000) ); |
| | if( x<99 ){ |
| | pIdx->pTable->nRowLogEst = x = 99; |
| | } |
| | if( pIdx->pPartIdxWhere!=0 ){ x -= 10; assert( 10==sqlite3LogEst(2) ); } |
| | a[0] = x; |
| |
|
| | |
| | |
| | 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; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | void sqlite3DropIndex(Parse *pParse, SrcList *pName, int ifExists){ |
| | Index *pIndex; |
| | Vdbe *v; |
| | sqlite3 *db = pParse->db; |
| | int iDb; |
| |
|
| | if( db->mallocFailed ){ |
| | goto exit_drop_index; |
| | } |
| | assert( pParse->nErr==0 ); |
| | assert( pName->nSrc==1 ); |
| | assert( pName->a[0].fg.fixedSchema==0 ); |
| | assert( pName->a[0].fg.isSubquery==0 ); |
| | if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){ |
| | goto exit_drop_index; |
| | } |
| | pIndex = sqlite3FindIndex(db, pName->a[0].zName, pName->a[0].u4.zDatabase); |
| | if( pIndex==0 ){ |
| | if( !ifExists ){ |
| | sqlite3ErrorMsg(pParse, "no such index: %S", pName->a); |
| | }else{ |
| | sqlite3CodeVerifyNamedSchema(pParse, pName->a[0].u4.zDatabase); |
| | sqlite3ForceNotReadOnly(pParse); |
| | } |
| | pParse->checkSchema = 1; |
| | goto exit_drop_index; |
| | } |
| | if( pIndex->idxType!=SQLITE_IDXTYPE_APPDEF ){ |
| | sqlite3ErrorMsg(pParse, "index associated with UNIQUE " |
| | "or PRIMARY KEY constraint cannot be dropped", 0); |
| | goto exit_drop_index; |
| | } |
| | iDb = sqlite3SchemaToIndex(db, pIndex->pSchema); |
| | #ifndef SQLITE_OMIT_AUTHORIZATION |
| | { |
| | int code = SQLITE_DROP_INDEX; |
| | Table *pTab = pIndex->pTable; |
| | const char *zDb = db->aDb[iDb].zDbSName; |
| | const char *zTab = SCHEMA_TABLE(iDb); |
| | if( sqlite3AuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb) ){ |
| | goto exit_drop_index; |
| | } |
| | if( !OMIT_TEMPDB && iDb==1 ) code = SQLITE_DROP_TEMP_INDEX; |
| | if( sqlite3AuthCheck(pParse, code, pIndex->zName, pTab->zName, zDb) ){ |
| | goto exit_drop_index; |
| | } |
| | } |
| | #endif |
| |
|
| | |
| | v = sqlite3GetVdbe(pParse); |
| | if( v ){ |
| | sqlite3BeginWriteOperation(pParse, 1, iDb); |
| | sqlite3NestedParse(pParse, |
| | "DELETE FROM %Q." LEGACY_SCHEMA_TABLE " WHERE name=%Q AND type='index'", |
| | db->aDb[iDb].zDbSName, 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); |
| | } |
| |
|
| | exit_drop_index: |
| | sqlite3SrcListDelete(db, pName); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | void *sqlite3ArrayAllocate( |
| | sqlite3 *db, |
| | void *pArray, |
| | int szEntry, |
| | int *pnEntry, |
| | int *pIdx |
| | ){ |
| | char *z; |
| | sqlite3_int64 n = *pIdx = *pnEntry; |
| | if( (n & (n-1))==0 ){ |
| | sqlite3_int64 sz = (n==0) ? 1 : 2*n; |
| | void *pNew = sqlite3DbRealloc(db, pArray, sz*szEntry); |
| | if( pNew==0 ){ |
| | *pIdx = -1; |
| | return pArray; |
| | } |
| | pArray = pNew; |
| | } |
| | z = (char*)pArray; |
| | memset(&z[n * szEntry], 0, szEntry); |
| | ++*pnEntry; |
| | return pArray; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | IdList *sqlite3IdListAppend(Parse *pParse, IdList *pList, Token *pToken){ |
| | sqlite3 *db = pParse->db; |
| | int i; |
| | if( pList==0 ){ |
| | pList = sqlite3DbMallocZero(db, SZ_IDLIST(1)); |
| | if( pList==0 ) return 0; |
| | }else{ |
| | IdList *pNew; |
| | pNew = sqlite3DbRealloc(db, pList, SZ_IDLIST(pList->nId+1)); |
| | if( pNew==0 ){ |
| | sqlite3IdListDelete(db, pList); |
| | return 0; |
| | } |
| | pList = pNew; |
| | } |
| | i = pList->nId++; |
| | pList->a[i].zName = sqlite3NameFromToken(db, pToken); |
| | if( IN_RENAME_OBJECT && pList->a[i].zName ){ |
| | sqlite3RenameTokenMap(pParse, (void*)pList->a[i].zName, pToken); |
| | } |
| | return pList; |
| | } |
| |
|
| | |
| | |
| | |
| | void sqlite3IdListDelete(sqlite3 *db, IdList *pList){ |
| | int i; |
| | assert( db!=0 ); |
| | if( pList==0 ) return; |
| | for(i=0; i<pList->nId; i++){ |
| | sqlite3DbFree(db, pList->a[i].zName); |
| | } |
| | sqlite3DbNNFreeNN(db, pList); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | int sqlite3IdListIndex(IdList *pList, const char *zName){ |
| | int i; |
| | assert( pList!=0 ); |
| | for(i=0; i<pList->nId; i++){ |
| | if( sqlite3StrICmp(pList->a[i].zName, zName)==0 ) return i; |
| | } |
| | return -1; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | #ifndef SQLITE_MAX_SRCLIST |
| | # define SQLITE_MAX_SRCLIST 200 |
| | #endif |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | SrcList *sqlite3SrcListEnlarge( |
| | Parse *pParse, |
| | SrcList *pSrc, |
| | int nExtra, |
| | int iStart |
| | ){ |
| | int i; |
| |
|
| | |
| | assert( iStart>=0 ); |
| | assert( nExtra>=1 ); |
| | assert( pSrc!=0 ); |
| | assert( iStart<=pSrc->nSrc ); |
| |
|
| | |
| | if( (u32)pSrc->nSrc+nExtra>pSrc->nAlloc ){ |
| | SrcList *pNew; |
| | sqlite3_int64 nAlloc = 2*(sqlite3_int64)pSrc->nSrc+nExtra; |
| | sqlite3 *db = pParse->db; |
| |
|
| | if( pSrc->nSrc+nExtra>=SQLITE_MAX_SRCLIST ){ |
| | sqlite3ErrorMsg(pParse, "too many FROM clause terms, max: %d", |
| | SQLITE_MAX_SRCLIST); |
| | return 0; |
| | } |
| | if( nAlloc>SQLITE_MAX_SRCLIST ) nAlloc = SQLITE_MAX_SRCLIST; |
| | pNew = sqlite3DbRealloc(db, pSrc, SZ_SRCLIST(nAlloc)); |
| | if( pNew==0 ){ |
| | assert( db->mallocFailed ); |
| | return 0; |
| | } |
| | pSrc = pNew; |
| | pSrc->nAlloc = nAlloc; |
| | } |
| |
|
| | |
| | |
| | for(i=pSrc->nSrc-1; i>=iStart; i--){ |
| | pSrc->a[i+nExtra] = pSrc->a[i]; |
| | } |
| | pSrc->nSrc += nExtra; |
| |
|
| | |
| | memset(&pSrc->a[iStart], 0, sizeof(pSrc->a[0])*nExtra); |
| | for(i=iStart; i<iStart+nExtra; i++){ |
| | pSrc->a[i].iCursor = -1; |
| | } |
| |
|
| | |
| | return pSrc; |
| | } |
| |
|
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | SrcList *sqlite3SrcListAppend( |
| | Parse *pParse, |
| | SrcList *pList, |
| | Token *pTable, |
| | Token *pDatabase |
| | ){ |
| | SrcItem *pItem; |
| | sqlite3 *db; |
| | assert( pDatabase==0 || pTable!=0 ); |
| | assert( pParse!=0 ); |
| | assert( pParse->db!=0 ); |
| | db = pParse->db; |
| | if( pList==0 ){ |
| | pList = sqlite3DbMallocRawNN(pParse->db, SZ_SRCLIST(1)); |
| | if( pList==0 ) return 0; |
| | pList->nAlloc = 1; |
| | pList->nSrc = 1; |
| | memset(&pList->a[0], 0, sizeof(pList->a[0])); |
| | pList->a[0].iCursor = -1; |
| | }else{ |
| | SrcList *pNew = sqlite3SrcListEnlarge(pParse, pList, 1, pList->nSrc); |
| | if( pNew==0 ){ |
| | sqlite3SrcListDelete(db, pList); |
| | return 0; |
| | }else{ |
| | pList = pNew; |
| | } |
| | } |
| | pItem = &pList->a[pList->nSrc-1]; |
| | if( pDatabase && pDatabase->z==0 ){ |
| | pDatabase = 0; |
| | } |
| | assert( pItem->fg.fixedSchema==0 ); |
| | assert( pItem->fg.isSubquery==0 ); |
| | if( pDatabase ){ |
| | pItem->zName = sqlite3NameFromToken(db, pDatabase); |
| | pItem->u4.zDatabase = sqlite3NameFromToken(db, pTable); |
| | }else{ |
| | pItem->zName = sqlite3NameFromToken(db, pTable); |
| | pItem->u4.zDatabase = 0; |
| | } |
| | return pList; |
| | } |
| |
|
| | |
| | |
| | |
| | void sqlite3SrcListAssignCursors(Parse *pParse, SrcList *pList){ |
| | int i; |
| | SrcItem *pItem; |
| | assert( pList || pParse->db->mallocFailed ); |
| | if( ALWAYS(pList) ){ |
| | for(i=0, pItem=pList->a; i<pList->nSrc; i++, pItem++){ |
| | if( pItem->iCursor>=0 ) continue; |
| | pItem->iCursor = pParse->nTab++; |
| | if( pItem->fg.isSubquery ){ |
| | assert( pItem->u4.pSubq!=0 ); |
| | assert( pItem->u4.pSubq->pSelect!=0 ); |
| | assert( pItem->u4.pSubq->pSelect->pSrc!=0 ); |
| | sqlite3SrcListAssignCursors(pParse, pItem->u4.pSubq->pSelect->pSrc); |
| | } |
| | } |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | void sqlite3SubqueryDelete(sqlite3 *db, Subquery *pSubq){ |
| | assert( pSubq!=0 && pSubq->pSelect!=0 ); |
| | sqlite3SelectDelete(db, pSubq->pSelect); |
| | sqlite3DbFree(db, pSubq); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | Select *sqlite3SubqueryDetach(sqlite3 *db, SrcItem *pItem){ |
| | Select *pSel; |
| | assert( pItem!=0 ); |
| | assert( pItem->fg.isSubquery ); |
| | pSel = pItem->u4.pSubq->pSelect; |
| | sqlite3DbFree(db, pItem->u4.pSubq); |
| | pItem->u4.pSubq = 0; |
| | pItem->fg.isSubquery = 0; |
| | return pSel; |
| | } |
| |
|
| | |
| | |
| | |
| | void sqlite3SrcListDelete(sqlite3 *db, SrcList *pList){ |
| | int i; |
| | SrcItem *pItem; |
| | assert( db!=0 ); |
| | if( pList==0 ) return; |
| | for(pItem=pList->a, i=0; i<pList->nSrc; i++, pItem++){ |
| | |
| | |
| | assert( !pItem->fg.isIndexedBy || !pItem->fg.isTabFunc ); |
| | assert( !pItem->fg.isCte || !pItem->fg.isIndexedBy ); |
| | assert( !pItem->fg.fixedSchema || !pItem->fg.isSubquery ); |
| | assert( !pItem->fg.isSubquery || (pItem->u4.pSubq!=0 && |
| | pItem->u4.pSubq->pSelect!=0) ); |
| |
|
| | if( pItem->zName ) sqlite3DbNNFreeNN(db, pItem->zName); |
| | if( pItem->zAlias ) sqlite3DbNNFreeNN(db, pItem->zAlias); |
| | if( pItem->fg.isSubquery ){ |
| | sqlite3SubqueryDelete(db, pItem->u4.pSubq); |
| | }else if( pItem->fg.fixedSchema==0 && pItem->u4.zDatabase!=0 ){ |
| | sqlite3DbNNFreeNN(db, pItem->u4.zDatabase); |
| | } |
| | if( pItem->fg.isIndexedBy ) sqlite3DbFree(db, pItem->u1.zIndexedBy); |
| | if( pItem->fg.isTabFunc ) sqlite3ExprListDelete(db, pItem->u1.pFuncArg); |
| | sqlite3DeleteTable(db, pItem->pSTab); |
| | if( pItem->fg.isUsing ){ |
| | sqlite3IdListDelete(db, pItem->u3.pUsing); |
| | }else if( pItem->u3.pOn ){ |
| | sqlite3ExprDelete(db, pItem->u3.pOn); |
| | } |
| | } |
| | sqlite3DbNNFreeNN(db, pList); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | int sqlite3SrcItemAttachSubquery( |
| | Parse *pParse, |
| | SrcItem *pItem, |
| | Select *pSelect, |
| | int dupSelect |
| | ){ |
| | Subquery *p; |
| | assert( pSelect!=0 ); |
| | assert( pItem->fg.isSubquery==0 ); |
| | if( pItem->fg.fixedSchema ){ |
| | pItem->u4.pSchema = 0; |
| | pItem->fg.fixedSchema = 0; |
| | }else if( pItem->u4.zDatabase!=0 ){ |
| | sqlite3DbFree(pParse->db, pItem->u4.zDatabase); |
| | pItem->u4.zDatabase = 0; |
| | } |
| | if( dupSelect ){ |
| | pSelect = sqlite3SelectDup(pParse->db, pSelect, 0); |
| | if( pSelect==0 ) return 0; |
| | } |
| | p = pItem->u4.pSubq = sqlite3DbMallocRawNN(pParse->db, sizeof(Subquery)); |
| | if( p==0 ){ |
| | sqlite3SelectDelete(pParse->db, pSelect); |
| | return 0; |
| | } |
| | pItem->fg.isSubquery = 1; |
| | p->pSelect = pSelect; |
| | assert( offsetof(Subquery, pSelect)==0 ); |
| | memset(((char*)p)+sizeof(p->pSelect), 0, sizeof(*p)-sizeof(p->pSelect)); |
| | return 1; |
| | } |
| |
|
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | SrcList *sqlite3SrcListAppendFromTerm( |
| | Parse *pParse, |
| | SrcList *p, |
| | Token *pTable, |
| | Token *pDatabase, |
| | Token *pAlias, |
| | Select *pSubquery, |
| | OnOrUsing *pOnUsing |
| | ){ |
| | SrcItem *pItem; |
| | sqlite3 *db = pParse->db; |
| | if( !p && pOnUsing!=0 && (pOnUsing->pOn || pOnUsing->pUsing) ){ |
| | sqlite3ErrorMsg(pParse, "a JOIN clause is required before %s", |
| | (pOnUsing->pOn ? "ON" : "USING") |
| | ); |
| | goto append_from_error; |
| | } |
| | p = sqlite3SrcListAppend(pParse, p, pTable, pDatabase); |
| | if( p==0 ){ |
| | goto append_from_error; |
| | } |
| | assert( p->nSrc>0 ); |
| | pItem = &p->a[p->nSrc-1]; |
| | assert( (pTable==0)==(pDatabase==0) ); |
| | assert( pItem->zName==0 || pDatabase!=0 ); |
| | if( IN_RENAME_OBJECT && pItem->zName ){ |
| | Token *pToken = (ALWAYS(pDatabase) && pDatabase->z) ? pDatabase : pTable; |
| | sqlite3RenameTokenMap(pParse, pItem->zName, pToken); |
| | } |
| | assert( pAlias!=0 ); |
| | if( pAlias->n ){ |
| | pItem->zAlias = sqlite3NameFromToken(db, pAlias); |
| | } |
| | assert( pSubquery==0 || pDatabase==0 ); |
| | if( pSubquery ){ |
| | if( sqlite3SrcItemAttachSubquery(pParse, pItem, pSubquery, 0) ){ |
| | if( pSubquery->selFlags & SF_NestedFrom ){ |
| | pItem->fg.isNestedFrom = 1; |
| | } |
| | } |
| | } |
| | assert( pOnUsing==0 || pOnUsing->pOn==0 || pOnUsing->pUsing==0 ); |
| | assert( pItem->fg.isUsing==0 ); |
| | if( pOnUsing==0 ){ |
| | pItem->u3.pOn = 0; |
| | }else if( pOnUsing->pUsing ){ |
| | pItem->fg.isUsing = 1; |
| | pItem->u3.pUsing = pOnUsing->pUsing; |
| | }else{ |
| | pItem->u3.pOn = pOnUsing->pOn; |
| | } |
| | return p; |
| |
|
| | append_from_error: |
| | assert( p==0 ); |
| | sqlite3ClearOnOrUsing(db, pOnUsing); |
| | sqlite3SelectDelete(db, pSubquery); |
| | return 0; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | void sqlite3SrcListIndexedBy(Parse *pParse, SrcList *p, Token *pIndexedBy){ |
| | assert( pIndexedBy!=0 ); |
| | if( p && pIndexedBy->n>0 ){ |
| | SrcItem *pItem; |
| | assert( p->nSrc>0 ); |
| | pItem = &p->a[p->nSrc-1]; |
| | assert( pItem->fg.notIndexed==0 ); |
| | assert( pItem->fg.isIndexedBy==0 ); |
| | assert( pItem->fg.isTabFunc==0 ); |
| | if( pIndexedBy->n==1 && !pIndexedBy->z ){ |
| | |
| | |
| | pItem->fg.notIndexed = 1; |
| | }else{ |
| | pItem->u1.zIndexedBy = sqlite3NameFromToken(pParse->db, pIndexedBy); |
| | pItem->fg.isIndexedBy = 1; |
| | assert( pItem->fg.isCte==0 ); |
| | } |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | SrcList *sqlite3SrcListAppendList(Parse *pParse, SrcList *p1, SrcList *p2){ |
| | assert( p1 ); |
| | assert( p2 || pParse->nErr ); |
| | assert( p2==0 || p2->nSrc>=1 ); |
| | testcase( p1->nSrc==0 ); |
| | if( p2 ){ |
| | int nOld = p1->nSrc; |
| | SrcList *pNew = sqlite3SrcListEnlarge(pParse, p1, p2->nSrc, nOld); |
| | if( pNew==0 ){ |
| | sqlite3SrcListDelete(pParse->db, p2); |
| | }else{ |
| | p1 = pNew; |
| | memcpy(&p1->a[nOld], p2->a, p2->nSrc*sizeof(SrcItem)); |
| | assert( nOld==1 || (p2->a[0].fg.jointype & JT_LTORJ)==0 ); |
| | assert( p1->nSrc>=1 ); |
| | p1->a[0].fg.jointype |= (JT_LTORJ & p2->a[0].fg.jointype); |
| | sqlite3DbFree(pParse->db, p2); |
| | } |
| | } |
| | return p1; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | void sqlite3SrcListFuncArgs(Parse *pParse, SrcList *p, ExprList *pList){ |
| | if( p ){ |
| | SrcItem *pItem = &p->a[p->nSrc-1]; |
| | assert( pItem->fg.notIndexed==0 ); |
| | assert( pItem->fg.isIndexedBy==0 ); |
| | assert( pItem->fg.isTabFunc==0 ); |
| | pItem->u1.pFuncArg = pList; |
| | pItem->fg.isTabFunc = 1; |
| | }else{ |
| | sqlite3ExprListDelete(pParse->db, pList); |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | void sqlite3SrcListShiftJoinType(Parse *pParse, SrcList *p){ |
| | (void)pParse; |
| | if( p && p->nSrc>1 ){ |
| | int i = p->nSrc-1; |
| | u8 allFlags = 0; |
| | do{ |
| | allFlags |= p->a[i].fg.jointype = p->a[i-1].fg.jointype; |
| | }while( (--i)>0 ); |
| | p->a[0].fg.jointype = 0; |
| |
|
| | |
| | |
| | if( allFlags & JT_RIGHT ){ |
| | for(i=p->nSrc-1; ALWAYS(i>0) && (p->a[i].fg.jointype&JT_RIGHT)==0; i--){} |
| | i--; |
| | assert( i>=0 ); |
| | do{ |
| | p->a[i].fg.jointype |= JT_LTORJ; |
| | }while( (--i)>=0 ); |
| | } |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | void sqlite3BeginTransaction(Parse *pParse, int type){ |
| | sqlite3 *db; |
| | Vdbe *v; |
| | int i; |
| |
|
| | assert( pParse!=0 ); |
| | db = pParse->db; |
| | assert( db!=0 ); |
| | if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, "BEGIN", 0, 0) ){ |
| | return; |
| | } |
| | v = sqlite3GetVdbe(pParse); |
| | if( !v ) return; |
| | if( type!=TK_DEFERRED ){ |
| | for(i=0; i<db->nDb; i++){ |
| | int eTxnType; |
| | Btree *pBt = db->aDb[i].pBt; |
| | if( pBt && sqlite3BtreeIsReadonly(pBt) ){ |
| | eTxnType = 0; |
| | }else if( type==TK_EXCLUSIVE ){ |
| | eTxnType = 2; |
| | }else{ |
| | eTxnType = 1; |
| | } |
| | sqlite3VdbeAddOp2(v, OP_Transaction, i, eTxnType); |
| | sqlite3VdbeUsesBtree(v, i); |
| | } |
| | } |
| | sqlite3VdbeAddOp0(v, OP_AutoCommit); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | void sqlite3EndTransaction(Parse *pParse, int eType){ |
| | Vdbe *v; |
| | int isRollback; |
| |
|
| | assert( pParse!=0 ); |
| | assert( pParse->db!=0 ); |
| | assert( eType==TK_COMMIT || eType==TK_END || eType==TK_ROLLBACK ); |
| | isRollback = eType==TK_ROLLBACK; |
| | if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, |
| | isRollback ? "ROLLBACK" : "COMMIT", 0, 0) ){ |
| | return; |
| | } |
| | v = sqlite3GetVdbe(pParse); |
| | if( v ){ |
| | sqlite3VdbeAddOp2(v, OP_AutoCommit, 1, isRollback); |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | void sqlite3Savepoint(Parse *pParse, int op, Token *pName){ |
| | char *zName = sqlite3NameFromToken(pParse->db, pName); |
| | if( zName ){ |
| | Vdbe *v = sqlite3GetVdbe(pParse); |
| | #ifndef SQLITE_OMIT_AUTHORIZATION |
| | static const char * const az[] = { "BEGIN", "RELEASE", "ROLLBACK" }; |
| | assert( !SAVEPOINT_BEGIN && SAVEPOINT_RELEASE==1 && SAVEPOINT_ROLLBACK==2 ); |
| | #endif |
| | if( !v || sqlite3AuthCheck(pParse, SQLITE_SAVEPOINT, az[op], zName, 0) ){ |
| | sqlite3DbFree(pParse->db, zName); |
| | return; |
| | } |
| | sqlite3VdbeAddOp4(v, OP_Savepoint, op, 0, 0, zName, P4_DYNAMIC); |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | int sqlite3OpenTempDatabase(Parse *pParse){ |
| | sqlite3 *db = pParse->db; |
| | if( db->aDb[1].pBt==0 && !pParse->explain ){ |
| | int rc; |
| | Btree *pBt; |
| | static const int flags = |
| | SQLITE_OPEN_READWRITE | |
| | SQLITE_OPEN_CREATE | |
| | SQLITE_OPEN_EXCLUSIVE | |
| | SQLITE_OPEN_DELETEONCLOSE | |
| | SQLITE_OPEN_TEMP_DB; |
| |
|
| | 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"); |
| | pParse->rc = rc; |
| | return 1; |
| | } |
| | db->aDb[1].pBt = pBt; |
| | assert( db->aDb[1].pSchema ); |
| | if( SQLITE_NOMEM==sqlite3BtreeSetPageSize(pBt, db->nextPagesize, 0, 0) ){ |
| | sqlite3OomFault(db); |
| | return 1; |
| | } |
| | } |
| | return 0; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | static void sqlite3CodeVerifySchemaAtToplevel(Parse *pToplevel, int iDb){ |
| | assert( iDb>=0 && iDb<pToplevel->db->nDb ); |
| | assert( pToplevel->db->aDb[iDb].pBt!=0 || iDb==1 ); |
| | assert( iDb<SQLITE_MAX_DB ); |
| | assert( sqlite3SchemaMutexHeld(pToplevel->db, iDb, 0) ); |
| | if( DbMaskTest(pToplevel->cookieMask, iDb)==0 ){ |
| | DbMaskSet(pToplevel->cookieMask, iDb); |
| | if( !OMIT_TEMPDB && iDb==1 ){ |
| | sqlite3OpenTempDatabase(pToplevel); |
| | } |
| | } |
| | } |
| | void sqlite3CodeVerifySchema(Parse *pParse, int iDb){ |
| | sqlite3CodeVerifySchemaAtToplevel(sqlite3ParseToplevel(pParse), iDb); |
| | } |
| |
|
| |
|
| | |
| | |
| | |
| | |
| | void sqlite3CodeVerifyNamedSchema(Parse *pParse, const char *zDb){ |
| | sqlite3 *db = pParse->db; |
| | int i; |
| | for(i=0; i<db->nDb; i++){ |
| | Db *pDb = &db->aDb[i]; |
| | if( pDb->pBt && (!zDb || 0==sqlite3StrICmp(zDb, pDb->zDbSName)) ){ |
| | sqlite3CodeVerifySchema(pParse, i); |
| | } |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | void sqlite3BeginWriteOperation(Parse *pParse, int setStatement, int iDb){ |
| | Parse *pToplevel = sqlite3ParseToplevel(pParse); |
| | sqlite3CodeVerifySchemaAtToplevel(pToplevel, iDb); |
| | DbMaskSet(pToplevel->writeMask, iDb); |
| | pToplevel->isMultiWrite |= setStatement; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | void sqlite3MultiWrite(Parse *pParse){ |
| | Parse *pToplevel = sqlite3ParseToplevel(pParse); |
| | pToplevel->isMultiWrite = 1; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | void sqlite3MayAbort(Parse *pParse){ |
| | Parse *pToplevel = sqlite3ParseToplevel(pParse); |
| | pToplevel->mayAbort = 1; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | void sqlite3HaltConstraint( |
| | Parse *pParse, |
| | int errCode, |
| | int onError, |
| | char *p4, |
| | i8 p4type, |
| | u8 p5Errmsg |
| | ){ |
| | Vdbe *v; |
| | assert( pParse->pVdbe!=0 ); |
| | v = sqlite3GetVdbe(pParse); |
| | assert( (errCode&0xff)==SQLITE_CONSTRAINT || pParse->nested ); |
| | if( onError==OE_Abort ){ |
| | sqlite3MayAbort(pParse); |
| | } |
| | sqlite3VdbeAddOp4(v, OP_Halt, errCode, onError, 0, p4, p4type); |
| | sqlite3VdbeChangeP5(v, p5Errmsg); |
| | } |
| |
|
| | |
| | |
| | |
| | void sqlite3UniqueConstraint( |
| | Parse *pParse, |
| | int onError, |
| | Index *pIdx |
| | ){ |
| | char *zErr; |
| | int j; |
| | StrAccum errMsg; |
| | Table *pTab = pIdx->pTable; |
| |
|
| | sqlite3StrAccumInit(&errMsg, pParse->db, 0, 0, |
| | pParse->db->aLimit[SQLITE_LIMIT_LENGTH]); |
| | if( pIdx->aColExpr ){ |
| | sqlite3_str_appendf(&errMsg, "index '%q'", pIdx->zName); |
| | }else{ |
| | for(j=0; j<pIdx->nKeyCol; j++){ |
| | char *zCol; |
| | assert( pIdx->aiColumn[j]>=0 ); |
| | zCol = pTab->aCol[pIdx->aiColumn[j]].zCnName; |
| | if( j ) sqlite3_str_append(&errMsg, ", ", 2); |
| | sqlite3_str_appendall(&errMsg, pTab->zName); |
| | sqlite3_str_append(&errMsg, ".", 1); |
| | sqlite3_str_appendall(&errMsg, zCol); |
| | } |
| | } |
| | zErr = sqlite3StrAccumFinish(&errMsg); |
| | sqlite3HaltConstraint(pParse, |
| | IsPrimaryKeyIndex(pIdx) ? SQLITE_CONSTRAINT_PRIMARYKEY |
| | : SQLITE_CONSTRAINT_UNIQUE, |
| | onError, zErr, P4_DYNAMIC, P5_ConstraintUnique); |
| | } |
| |
|
| |
|
| | |
| | |
| | |
| | void sqlite3RowidConstraint( |
| | Parse *pParse, |
| | int onError, |
| | Table *pTab |
| | ){ |
| | char *zMsg; |
| | int rc; |
| | if( pTab->iPKey>=0 ){ |
| | zMsg = sqlite3MPrintf(pParse->db, "%s.%s", pTab->zName, |
| | pTab->aCol[pTab->iPKey].zCnName); |
| | 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); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | #ifndef SQLITE_OMIT_REINDEX |
| | static int collationMatch(const char *zColl, Index *pIndex){ |
| | int i; |
| | assert( zColl!=0 ); |
| | for(i=0; i<pIndex->nColumn; i++){ |
| | const char *z = pIndex->azColl[i]; |
| | assert( z!=0 || pIndex->aiColumn[i]<0 ); |
| | if( pIndex->aiColumn[i]>=0 && 0==sqlite3StrICmp(z, zColl) ){ |
| | return 1; |
| | } |
| | } |
| | return 0; |
| | } |
| | #endif |
| |
|
| | |
| | |
| | |
| | |
| | #ifndef SQLITE_OMIT_REINDEX |
| | static void reindexTable(Parse *pParse, Table *pTab, char const *zColl){ |
| | if( !IsVirtual(pTab) ){ |
| | Index *pIndex; |
| |
|
| | for(pIndex=pTab->pIndex; pIndex; pIndex=pIndex->pNext){ |
| | if( zColl==0 || collationMatch(zColl, pIndex) ){ |
| | int iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); |
| | sqlite3BeginWriteOperation(pParse, 0, iDb); |
| | sqlite3RefillIndex(pParse, pIndex, -1); |
| | } |
| | } |
| | } |
| | } |
| | #endif |
| |
|
| | |
| | |
| | |
| | |
| | |
| | #ifndef SQLITE_OMIT_REINDEX |
| | static void reindexDatabases(Parse *pParse, char const *zColl){ |
| | Db *pDb; |
| | int iDb; |
| | sqlite3 *db = pParse->db; |
| | HashElem *k; |
| | Table *pTab; |
| |
|
| | assert( sqlite3BtreeHoldsAllMutexes(db) ); |
| | for(iDb=0, pDb=db->aDb; iDb<db->nDb; iDb++, pDb++){ |
| | assert( pDb!=0 ); |
| | for(k=sqliteHashFirst(&pDb->pSchema->tblHash); k; k=sqliteHashNext(k)){ |
| | pTab = (Table*)sqliteHashData(k); |
| | reindexTable(pParse, pTab, zColl); |
| | } |
| | } |
| | } |
| | #endif |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | #ifndef SQLITE_OMIT_REINDEX |
| | void sqlite3Reindex(Parse *pParse, Token *pName1, Token *pName2){ |
| | CollSeq *pColl; |
| | char *z; |
| | const char *zDb; |
| | Table *pTab; |
| | Index *pIndex; |
| | int iDb; |
| | sqlite3 *db = pParse->db; |
| | Token *pObjName; |
| |
|
| | |
| | |
| | if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){ |
| | return; |
| | } |
| |
|
| | if( pName1==0 ){ |
| | reindexDatabases(pParse, 0); |
| | return; |
| | }else if( NEVER(pName2==0) || pName2->z==0 ){ |
| | char *zColl; |
| | assert( pName1->z ); |
| | zColl = sqlite3NameFromToken(pParse->db, pName1); |
| | if( !zColl ) return; |
| | pColl = sqlite3FindCollSeq(db, ENC(db), zColl, 0); |
| | if( pColl ){ |
| | reindexDatabases(pParse, zColl); |
| | sqlite3DbFree(db, zColl); |
| | return; |
| | } |
| | sqlite3DbFree(db, zColl); |
| | } |
| | iDb = sqlite3TwoPartName(pParse, pName1, pName2, &pObjName); |
| | if( iDb<0 ) return; |
| | z = sqlite3NameFromToken(db, pObjName); |
| | if( z==0 ) return; |
| | zDb = pName2->n ? db->aDb[iDb].zDbSName : 0; |
| | pTab = sqlite3FindTable(db, z, zDb); |
| | if( pTab ){ |
| | reindexTable(pParse, pTab, 0); |
| | sqlite3DbFree(db, z); |
| | return; |
| | } |
| | pIndex = sqlite3FindIndex(db, z, zDb); |
| | sqlite3DbFree(db, z); |
| | if( pIndex ){ |
| | iDb = sqlite3SchemaToIndex(db, pIndex->pTable->pSchema); |
| | sqlite3BeginWriteOperation(pParse, 0, iDb); |
| | sqlite3RefillIndex(pParse, pIndex, -1); |
| | return; |
| | } |
| | sqlite3ErrorMsg(pParse, "unable to identify the object to be reindexed"); |
| | } |
| | #endif |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | KeyInfo *sqlite3KeyInfoOfIndex(Parse *pParse, Index *pIdx){ |
| | int i; |
| | int nCol = pIdx->nColumn; |
| | int nKey = pIdx->nKeyCol; |
| | KeyInfo *pKey; |
| | if( pParse->nErr ) return 0; |
| | 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++){ |
| | const char *zColl = pIdx->azColl[i]; |
| | pKey->aColl[i] = zColl==sqlite3StrBINARY ? 0 : |
| | sqlite3LocateCollSeq(pParse, zColl); |
| | pKey->aSortFlags[i] = pIdx->aSortOrder[i]; |
| | assert( 0==(pKey->aSortFlags[i] & KEYINFO_ORDER_BIGNULL) ); |
| | } |
| | if( pParse->nErr ){ |
| | assert( pParse->rc==SQLITE_ERROR_MISSING_COLLSEQ ); |
| | if( pIdx->bNoQuery==0 |
| | && sqlite3HashFind(&pIdx->pSchema->idxHash, pIdx->zName) |
| | ){ |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | pIdx->bNoQuery = 1; |
| | pParse->rc = SQLITE_ERROR_RETRY; |
| | } |
| | sqlite3KeyInfoUnref(pKey); |
| | pKey = 0; |
| | } |
| | } |
| | return pKey; |
| | } |
| |
|
| | #ifndef SQLITE_OMIT_CTE |
| | |
| | |
| | |
| | Cte *sqlite3CteNew( |
| | Parse *pParse, |
| | Token *pName, |
| | ExprList *pArglist, |
| | Select *pQuery, |
| | u8 eM10d |
| | ){ |
| | Cte *pNew; |
| | sqlite3 *db = pParse->db; |
| |
|
| | pNew = sqlite3DbMallocZero(db, sizeof(*pNew)); |
| | assert( pNew!=0 || db->mallocFailed ); |
| |
|
| | if( db->mallocFailed ){ |
| | sqlite3ExprListDelete(db, pArglist); |
| | sqlite3SelectDelete(db, pQuery); |
| | }else{ |
| | pNew->pSelect = pQuery; |
| | pNew->pCols = pArglist; |
| | pNew->zName = sqlite3NameFromToken(pParse->db, pName); |
| | pNew->eM10d = eM10d; |
| | } |
| | return pNew; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | static void cteClear(sqlite3 *db, Cte *pCte){ |
| | assert( pCte!=0 ); |
| | sqlite3ExprListDelete(db, pCte->pCols); |
| | sqlite3SelectDelete(db, pCte->pSelect); |
| | sqlite3DbFree(db, pCte->zName); |
| | } |
| |
|
| | |
| | |
| | |
| | void sqlite3CteDelete(sqlite3 *db, Cte *pCte){ |
| | assert( pCte!=0 ); |
| | cteClear(db, pCte); |
| | sqlite3DbFree(db, pCte); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | With *sqlite3WithAdd( |
| | Parse *pParse, |
| | With *pWith, |
| | Cte *pCte |
| | ){ |
| | sqlite3 *db = pParse->db; |
| | With *pNew; |
| | char *zName; |
| |
|
| | if( pCte==0 ){ |
| | return pWith; |
| | } |
| |
|
| | |
| | |
| | zName = pCte->zName; |
| | 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); |
| | } |
| | } |
| | } |
| |
|
| | if( pWith ){ |
| | pNew = sqlite3DbRealloc(db, pWith, SZ_WITH(pWith->nCte+1)); |
| | }else{ |
| | pNew = sqlite3DbMallocZero(db, SZ_WITH(1)); |
| | } |
| | assert( (pNew!=0 && zName!=0) || db->mallocFailed ); |
| |
|
| | if( db->mallocFailed ){ |
| | sqlite3CteDelete(db, pCte); |
| | pNew = pWith; |
| | }else{ |
| | pNew->a[pNew->nCte++] = *pCte; |
| | sqlite3DbFree(db, pCte); |
| | } |
| |
|
| | return pNew; |
| | } |
| |
|
| | |
| | |
| | |
| | void sqlite3WithDelete(sqlite3 *db, With *pWith){ |
| | if( pWith ){ |
| | int i; |
| | for(i=0; i<pWith->nCte; i++){ |
| | cteClear(db, &pWith->a[i]); |
| | } |
| | sqlite3DbFree(db, pWith); |
| | } |
| | } |
| | void sqlite3WithDeleteGeneric(sqlite3 *db, void *pWith){ |
| | sqlite3WithDelete(db, (With*)pWith); |
| | } |
| | #endif |
| |
|