#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;
}
}
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 = pParse->u1.pReturning;
int addrRewind;
int reg;
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);
#if SQLITE_USER_AUTHENTICATION
if( pParse->nTableLock>0 && db->init.busy==0 ){
sqlite3UserAuthInit(db);
if( db->auth.authLevel<UAUTH_User ){
sqlite3ErrorMsg(pParse, "user not authenticated");
pParse->rc = SQLITE_AUTH_USER;
return;
}
}
#endif
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
codeTableLocks(pParse);
sqlite3AutoincrementBegin(pParse);
if( pParse->pConstExpr ){
ExprList *pEL = pParse->pConstExpr;
pParse->okConstFactor = 0;
for(i=0; i<pEL->nExpr; i++){
int iReg = pEL->a[i].u.iConstExprReg;
sqlite3ExprCode(pParse, pEL->a[i].pExpr, iReg);
}
}
if( pParse->bReturning ){
Returning *pRet = pParse->u1.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--;
}
#if SQLITE_USER_AUTHENTICATION
int sqlite3UserAuthTable(const char *zTable){
return sqlite3_stricmp(zTable, "sqlite_user")==0;
}
#endif
Table *sqlite3FindTable(sqlite3 *db, const char *zName, const char *zDatabase){
Table *p = 0;
int i;
assert( zDatabase!=0 || sqlite3BtreeHoldsAllMutexes(db) );
#if SQLITE_USER_AUTHENTICATION
if( db->auth.authLevel<UAUTH_Admin && sqlite3UserAuthTable(zName)!=0 ){
return 0;
}
#endif
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);
}
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;
assert( p->pSchema==0 || p->zDatabase==0 );
if( p->pSchema ){
int iDb = sqlite3SchemaToIndex(pParse->db, p->pSchema);
zDb = pParse->db->aDb[iDb].zDbSName;
}else{
zDb = p->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( NEVER(!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 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;
}
i16 sqlite3TableColumnToIndex(Index *pIdx, i16 iCol){
int i;
for(i=0; i<pIdx->nColumn; i++){
if( iCol==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
reg1 = pParse->regRowid = ++pParse->nMem;
reg2 = pParse->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.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);
}
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
#define RETURNING_TRIGGER_NAME "sqlite_returning"
static void sqlite3DeleteReturning(sqlite3 *db, Returning *pRet){
Hash *pHash;
pHash = &(db->aDb[1].pSchema->trigHash);
sqlite3HashInsert(pHash, RETURNING_TRIGGER_NAME, 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;
}
pParse->u1.pReturning = pRet;
pRet->pParse = pParse;
pRet->pReturnEL = pList;
sqlite3ParserAddCleanup(pParse,
(void(*)(sqlite3*,void*))sqlite3DeleteReturning, pRet);
testcase( pParse->earlyCleanup );
if( db->mallocFailed ) return;
pRet->retTrig.zName = RETURNING_TRIGGER_NAME;
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, RETURNING_TRIGGER_NAME)==0
|| pParse->nErr || pParse->ifNotExists );
if( sqlite3HashInsert(pHash, RETURNING_TRIGGER_NAME, &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;
u8 hName;
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);
hName = sqlite3StrIHash(z);
for(i=0; i<p->nCol; i++){
if( p->aCol[i].hName==hName && sqlite3StrICmp(z, p->aCol[i].zCnName)==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 = hName;
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;
}
p->nCol++;
p->nNVCol++;
pParse->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] ){
h = (h<<8) + sqlite3UpperToLower[(*zIn)&0xff];
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 ){
const char *zCName;
assert( !ExprHasProperty(pCExpr, EP_IntValue) );
zCName = pCExpr->u.zToken;
for(iCol=0; iCol<pTab->nCol; iCol++){
if( sqlite3StrICmp(zCName, pTab->aCol[iCol].zCnName)==0 ){
pCol = &pTab->aCol[iCol];
makeColumnPartOfPrimaryKey(pParse, pCol);
break;
}
}
}
}
}
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);
if( pParse->constraintName.n ){
sqlite3ExprListSetName(pParse, pTab->pCheck, &pParse->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 int identLength(const char *z){
int 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, 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;
}
sqlite3_snprintf(n, zStmt, "CREATE TABLE ");
k = sqlite3Strlen30(zStmt);
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",
};
int len;
const char *zType;
sqlite3_snprintf(n-k, &zStmt[k], zSep);
k += sqlite3Strlen30(&zStmt[k]);
zSep = zSep2;
identPut(zStmt, &k, pCol->zCnName);
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) );
memcpy(&zStmt[k], zType, len);
k += len;
assert( k<=n );
}
sqlite3_snprintf(n-k, &zStmt[k], "%s", zEnd);
return zStmt;
}
static int resizeIndexObject(sqlite3 *db, Index *pIdx, int N){
char *zExtra;
int nByte;
if( pIdx->nColumn>=N ) return SQLITE_OK;
assert( pIdx->isResized==0 );
nByte = (sizeof(char*) + sizeof(LogEst) + sizeof(i16) + 1)*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 = 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.addrCrTab ){
assert( v );
sqlite3VdbeChangeP3(v, pParse->u1.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(db, 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(db, 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;
if( IN_SPECIAL_PARSE ){
pParse->rc = SQLITE_ERROR;
pParse->nErr++;
return;
}
regYield = ++pParse->nMem;
regRec = ++pParse->nMem;
regRowid = ++pParse->nMem;
assert(pParse->nTab==1);
sqlite3MayAbort(pParse);
sqlite3VdbeAddOp3(v, OP_OpenWrite, 1, pParse->regRoot, iDb);
sqlite3VdbeChangeP5(v, OPFLAG_P2ISREG);
pParse->nTab = 2;
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, 1, regRowid);
sqlite3VdbeAddOp3(v, OP_Insert, 1, regRec, regRowid);
sqlite3VdbeGoto(v, addrInsLoop);
sqlite3VdbeJumpHere(v, addrInsLoop);
sqlite3VdbeAddOp1(v, OP_Close, 1);
}
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
);
}
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->regRoot,
zStmt,
pParse->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( 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;
#ifndef SQLITE_ALLOW_ROWID_IN_VIEW
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;
}
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 );
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].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 = sizeof(*pFKey) + (nCol-1)*sizeof(pFKey->aCol[0]) + 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,
i16 nCol,
int nExtra,
char **ppExtra
){
Index *p;
int nByte;
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;
p->nColumn = nCol;
p->nKeyCol = 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
#if SQLITE_USER_AUTHENTICATION
&& sqlite3UserAuthTable(pTab->zName)==0
#endif
){
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 );
if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){
goto exit_drop_index;
}
pIndex = sqlite3FindIndex(db, pName->a[0].zName, pName->a[0].zDatabase);
if( pIndex==0 ){
if( !ifExists ){
sqlite3ErrorMsg(pParse, "no such index: %S", pName->a);
}else{
sqlite3CodeVerifyNamedSchema(pParse, pName->a[0].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, sizeof(IdList) );
if( pList==0 ) return 0;
}else{
IdList *pNew;
pNew = sqlite3DbRealloc(db, pList,
sizeof(IdList) + pList->nId*sizeof(pList->a));
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;
assert( pList->eU4!=EU4_EXPR );
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,
sizeof(*pSrc) + (nAlloc-1)*sizeof(pSrc->a[0]) );
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, sizeof(SrcList) );
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;
}
if( pDatabase ){
pItem->zName = sqlite3NameFromToken(db, pDatabase);
pItem->zDatabase = sqlite3NameFromToken(db, pTable);
}else{
pItem->zName = sqlite3NameFromToken(db, pTable);
pItem->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->pSelect ){
sqlite3SrcListAssignCursors(pParse, pItem->pSelect->pSrc);
}
}
}
}
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++){
if( pItem->zDatabase ) sqlite3DbNNFreeNN(db, pItem->zDatabase);
if( pItem->zName ) sqlite3DbNNFreeNN(db, pItem->zName);
if( pItem->zAlias ) sqlite3DbNNFreeNN(db, pItem->zAlias);
if( pItem->fg.isIndexedBy ) sqlite3DbFree(db, pItem->u1.zIndexedBy);
if( pItem->fg.isTabFunc ) sqlite3ExprListDelete(db, pItem->u1.pFuncArg);
sqlite3DeleteTable(db, pItem->pTab);
if( pItem->pSelect ) sqlite3SelectDelete(db, pItem->pSelect);
if( pItem->fg.isUsing ){
sqlite3IdListDelete(db, pItem->u3.pUsing);
}else if( pItem->u3.pOn ){
sqlite3ExprDelete(db, pItem->u3.pOn);
}
}
sqlite3DbNNFreeNN(db, pList);
}
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);
}
if( pSubquery ){
pItem->pSelect = pSubquery;
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 && p1->nSrc==1 );
if( p2 ){
SrcList *pNew = sqlite3SrcListEnlarge(pParse, p1, p2->nSrc, 1);
if( pNew==0 ){
sqlite3SrcListDelete(pParse->db, p2);
}else{
p1 = pNew;
memcpy(&p1->a[1], p2->a, p2->nSrc*sizeof(SrcItem));
sqlite3DbFree(pParse->db, p2);
p1->a[0].fg.jointype |= (JT_LTORJ & p1->a[1].fg.jointype);
}
}
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 = db->aDb[iDb].zDbSName;
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 ){
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 ){
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 ){
sqlite3_int64 nByte = sizeof(*pWith) + (sizeof(pWith->a[1]) * pWith->nCte);
pNew = sqlite3DbRealloc(db, pWith, nByte);
}else{
pNew = sqlite3DbMallocZero(db, sizeof(*pWith));
}
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);
}
}
#endif