Index: third_party/sqlite/src/src/build.c |
diff --git a/third_party/sqlite/src/src/build.c b/third_party/sqlite/src/src/build.c |
index b897494db3c2e478402917cfbe724de567177ac7..63e30046578470c705fe0cc3eed84f865c821e71 100644 |
--- a/third_party/sqlite/src/src/build.c |
+++ b/third_party/sqlite/src/src/build.c |
@@ -142,9 +142,11 @@ void sqlite3FinishCoding(Parse *pParse){ |
assert( pParse->pToplevel==0 ); |
db = pParse->db; |
- if( db->mallocFailed ) return; |
if( pParse->nested ) return; |
- if( pParse->nErr ) return; |
+ if( db->mallocFailed || pParse->nErr ){ |
+ if( pParse->rc==SQLITE_OK ) pParse->rc = SQLITE_ERROR; |
+ return; |
+ } |
/* Begin by generating some termination code at the end of the |
** vdbe program |
@@ -190,6 +192,8 @@ void sqlite3FinishCoding(Parse *pParse){ |
db->aDb[iDb].pSchema->iGeneration /* P4 */ |
); |
if( db->init.busy==0 ) sqlite3VdbeChangeP5(v, 1); |
+ VdbeComment((v, |
+ "usesStmtJournal=%d", pParse->mayAbort && pParse->isMultiWrite)); |
} |
#ifndef SQLITE_OMIT_VIRTUALTABLE |
for(i=0; i<pParse->nVtabLock; i++){ |
@@ -219,14 +223,14 @@ void sqlite3FinishCoding(Parse *pParse){ |
} |
/* Finally, jump back to the beginning of the executable code. */ |
- sqlite3VdbeAddOp2(v, OP_Goto, 0, 1); |
+ sqlite3VdbeGoto(v, 1); |
} |
} |
/* Get the VDBE program ready for execution |
*/ |
- if( v && ALWAYS(pParse->nErr==0) && !db->mallocFailed ){ |
+ if( v && pParse->nErr==0 && !db->mallocFailed ){ |
assert( pParse->iCacheLevel==0 ); /* Disables and re-enables match */ |
/* A minimum of one cursor is required if autoincrement is used |
* See ticket [a696379c1f08866] */ |
@@ -307,7 +311,7 @@ int sqlite3UserAuthTable(const char *zTable){ |
Table *sqlite3FindTable(sqlite3 *db, const char *zName, const char *zDatabase){ |
Table *p = 0; |
int i; |
- assert( zName!=0 ); |
+ |
/* All mutexes are required for schema access. Make sure we hold them. */ |
assert( zDatabase!=0 || sqlite3BtreeHoldsAllMutexes(db) ); |
#if SQLITE_USER_AUTHENTICATION |
@@ -354,6 +358,17 @@ Table *sqlite3LocateTable( |
p = sqlite3FindTable(pParse->db, zName, zDbase); |
if( p==0 ){ |
const char *zMsg = isView ? "no such view" : "no such table"; |
+#ifndef SQLITE_OMIT_VIRTUALTABLE |
+ if( sqlite3FindDbName(pParse->db, zDbase)<1 ){ |
+ /* If zName is the not the name of a table in the schema created using |
+ ** CREATE, then check to see if it is the name of an virtual table that |
+ ** can be an eponymous virtual table. */ |
+ Module *pMod = (Module*)sqlite3HashFind(&pParse->db->aModule, zName); |
+ if( pMod && sqlite3VtabEponymousTableInit(pParse, pMod) ){ |
+ return pMod->pEpoTab; |
+ } |
+ } |
+#endif |
if( zDbase ){ |
sqlite3ErrorMsg(pParse, "%s: %s.%s", zMsg, zDbase, zName); |
}else{ |
@@ -361,12 +376,7 @@ Table *sqlite3LocateTable( |
} |
pParse->checkSchema = 1; |
} |
-#if SQLITE_USER_AUTHENICATION |
- else if( pParse->db->auth.authLevel<UAUTH_User ){ |
- sqlite3ErrorMsg(pParse, "user not authenticated"); |
- p = 0; |
- } |
-#endif |
+ |
return p; |
} |
@@ -431,10 +441,10 @@ static void freeIndex(sqlite3 *db, Index *p){ |
#ifndef SQLITE_OMIT_ANALYZE |
sqlite3DeleteIndexSamples(db, p); |
#endif |
- if( db==0 || db->pnBytesFreed==0 ) sqlite3KeyInfoUnref(p->pKeyInfo); |
sqlite3ExprDelete(db, p->pPartIdxWhere); |
+ sqlite3ExprListDelete(db, p->aColExpr); |
sqlite3DbFree(db, p->zColAff); |
- if( p->isResized ) sqlite3DbFree(db, p->azColl); |
+ if( p->isResized ) sqlite3DbFree(db, (void *)p->azColl); |
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 |
sqlite3_free(p->aiRowEst); |
#endif |
@@ -559,7 +569,7 @@ void sqlite3CommitInternalChanges(sqlite3 *db){ |
** Delete memory allocated for the column names of a table or view (the |
** Table.aCol[] array). |
*/ |
-static void sqliteDeleteColumnNames(sqlite3 *db, Table *pTable){ |
+void sqlite3DeleteColumnNames(sqlite3 *db, Table *pTable){ |
int i; |
Column *pCol; |
assert( pTable!=0 ); |
@@ -626,13 +636,11 @@ void sqlite3DeleteTable(sqlite3 *db, Table *pTable){ |
/* Delete the Table structure itself. |
*/ |
- sqliteDeleteColumnNames(db, pTable); |
+ sqlite3DeleteColumnNames(db, pTable); |
sqlite3DbFree(db, pTable->zName); |
sqlite3DbFree(db, pTable->zColAff); |
sqlite3SelectDelete(db, pTable->pSelect); |
-#ifndef SQLITE_OMIT_CHECK |
sqlite3ExprListDelete(db, pTable->pCheck); |
-#endif |
#ifndef SQLITE_OMIT_VIRTUALTABLE |
sqlite3VtabClear(db, pTable); |
#endif |
@@ -762,14 +770,12 @@ int sqlite3TwoPartName( |
if( ALWAYS(pName2!=0) && pName2->n>0 ){ |
if( db->init.busy ) { |
sqlite3ErrorMsg(pParse, "corrupt database"); |
- pParse->nErr++; |
return -1; |
} |
*pUnqual = pName2; |
iDb = sqlite3FindDb(db, pName1); |
if( iDb<0 ){ |
sqlite3ErrorMsg(pParse, "unknown database %T", pName1); |
- pParse->nErr++; |
return -1; |
} |
}else{ |
@@ -928,7 +934,7 @@ void sqlite3StartTable( |
if( !noErr ){ |
sqlite3ErrorMsg(pParse, "table %T already exists", pName); |
}else{ |
- assert( !db->init.busy ); |
+ assert( !db->init.busy || CORRUPT_DB ); |
sqlite3CodeVerifySchema(pParse, iDb); |
} |
goto begin_table_error; |
@@ -974,10 +980,12 @@ void sqlite3StartTable( |
** now. |
*/ |
if( !db->init.busy && (v = sqlite3GetVdbe(pParse))!=0 ){ |
- int j1; |
+ int addr1; |
int fileFormat; |
int reg1, reg2, reg3; |
- sqlite3BeginWriteOperation(pParse, 0, iDb); |
+ /* nullRow[] is an OP_Record encoding of a row containing 5 NULLs */ |
+ static const char nullRow[] = { 6, 0, 0, 0, 0, 0 }; |
+ sqlite3BeginWriteOperation(pParse, 1, iDb); |
#ifndef SQLITE_OMIT_VIRTUALTABLE |
if( isVirtual ){ |
@@ -993,14 +1001,14 @@ void sqlite3StartTable( |
reg3 = ++pParse->nMem; |
sqlite3VdbeAddOp3(v, OP_ReadCookie, iDb, reg3, BTREE_FILE_FORMAT); |
sqlite3VdbeUsesBtree(v, iDb); |
- j1 = sqlite3VdbeAddOp1(v, OP_If, reg3); VdbeCoverage(v); |
+ addr1 = sqlite3VdbeAddOp1(v, OP_If, reg3); VdbeCoverage(v); |
fileFormat = (db->flags & SQLITE_LegacyFileFmt)!=0 ? |
1 : SQLITE_MAX_FILE_FORMAT; |
sqlite3VdbeAddOp2(v, OP_Integer, fileFormat, reg3); |
sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_FILE_FORMAT, reg3); |
sqlite3VdbeAddOp2(v, OP_Integer, ENC(db), reg3); |
sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_TEXT_ENCODING, reg3); |
- sqlite3VdbeJumpHere(v, j1); |
+ sqlite3VdbeJumpHere(v, addr1); |
/* This just creates a place-holder record in the sqlite_master table. |
** The record created does not contain anything yet. It will be replaced |
@@ -1021,7 +1029,7 @@ void sqlite3StartTable( |
} |
sqlite3OpenMasterTable(pParse, iDb); |
sqlite3VdbeAddOp2(v, OP_NewRowid, 0, reg1); |
- sqlite3VdbeAddOp2(v, OP_Null, 0, reg3); |
+ 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); |
@@ -1036,18 +1044,19 @@ begin_table_error: |
return; |
} |
-/* |
-** This macro is used to compare two strings in a case-insensitive manner. |
-** It is slightly faster than calling sqlite3StrICmp() directly, but |
-** produces larger code. |
-** |
-** WARNING: This macro is not compatible with the strcmp() family. It |
-** returns true if the two strings are equal, otherwise false. |
+/* Set properties of a table column based on the (magical) |
+** name of the column. |
*/ |
-#define STRICMP(x, y) (\ |
-sqlite3UpperToLower[*(unsigned char *)(x)]== \ |
-sqlite3UpperToLower[*(unsigned char *)(y)] \ |
-&& sqlite3StrICmp((x)+1,(y)+1)==0 ) |
+#if SQLITE_ENABLE_HIDDEN_COLUMNS |
+void sqlite3ColumnPropertiesFromName(Table *pTab, Column *pCol){ |
+ if( sqlite3_strnicmp(pCol->zName, "__hidden__", 10)==0 ){ |
+ pCol->colFlags |= COLFLAG_HIDDEN; |
+ }else if( pTab && pCol!=pTab->aCol && (pCol[-1].colFlags & COLFLAG_HIDDEN) ){ |
+ pTab->tabFlags |= TF_OOOHidden; |
+ } |
+} |
+#endif |
+ |
/* |
** Add a new column to the table currently being constructed. |
@@ -1073,7 +1082,7 @@ void sqlite3AddColumn(Parse *pParse, Token *pName){ |
z = sqlite3NameFromToken(db, pName); |
if( z==0 ) return; |
for(i=0; i<p->nCol; i++){ |
- if( STRICMP(z, p->aCol[i].zName) ){ |
+ if( sqlite3_stricmp(z, p->aCol[i].zName)==0 ){ |
sqlite3ErrorMsg(pParse, "duplicate column name: %s", z); |
sqlite3DbFree(db, z); |
return; |
@@ -1091,12 +1100,13 @@ void sqlite3AddColumn(Parse *pParse, Token *pName){ |
pCol = &p->aCol[p->nCol]; |
memset(pCol, 0, sizeof(p->aCol[0])); |
pCol->zName = z; |
+ sqlite3ColumnPropertiesFromName(p, pCol); |
/* If there is no type specified, columns have the default affinity |
- ** 'NONE'. If there is a type specified, then sqlite3AddColumnType() will |
+ ** 'BLOB'. If there is a type specified, then sqlite3AddColumnType() will |
** be called next to set pCol->affinity correctly. |
*/ |
- pCol->affinity = SQLITE_AFF_NONE; |
+ pCol->affinity = SQLITE_AFF_BLOB; |
pCol->szEst = 1; |
p->nCol++; |
} |
@@ -1131,7 +1141,7 @@ void sqlite3AddNotNull(Parse *pParse, int onError){ |
** 'CHAR' | SQLITE_AFF_TEXT |
** 'CLOB' | SQLITE_AFF_TEXT |
** 'TEXT' | SQLITE_AFF_TEXT |
-** 'BLOB' | SQLITE_AFF_NONE |
+** 'BLOB' | SQLITE_AFF_BLOB |
** 'REAL' | SQLITE_AFF_REAL |
** 'FLOA' | SQLITE_AFF_REAL |
** 'DOUB' | SQLITE_AFF_REAL |
@@ -1157,7 +1167,7 @@ char sqlite3AffinityType(const char *zIn, u8 *pszEst){ |
aff = SQLITE_AFF_TEXT; |
}else if( h==(('b'<<24)+('l'<<16)+('o'<<8)+'b') /* BLOB */ |
&& (aff==SQLITE_AFF_NUMERIC || aff==SQLITE_AFF_REAL) ){ |
- aff = SQLITE_AFF_NONE; |
+ aff = SQLITE_AFF_BLOB; |
if( zIn[0]=='(' ) zChar = zIn; |
#ifndef SQLITE_OMIT_FLOATING_POINT |
}else if( h==(('r'<<24)+('e'<<16)+('a'<<8)+'l') /* REAL */ |
@@ -1217,7 +1227,8 @@ void sqlite3AddColumnType(Parse *pParse, Token *pType){ |
p = pParse->pNewTable; |
if( p==0 || NEVER(p->nCol<1) ) return; |
pCol = &p->aCol[p->nCol-1]; |
- assert( pCol->zType==0 ); |
+ assert( pCol->zType==0 || CORRUPT_DB ); |
+ sqlite3DbFree(pParse->db, pCol->zType); |
pCol->zType = sqlite3NameFromToken(pParse->db, pType); |
pCol->affinity = sqlite3AffinityType(pCol->zType, &pCol->szEst); |
} |
@@ -1258,6 +1269,30 @@ void sqlite3AddDefaultValue(Parse *pParse, ExprSpan *pSpan){ |
} |
/* |
+** Backwards Compatibility Hack: |
+** |
+** Historical versions of SQLite accepted strings as column names in |
+** indexes and PRIMARY KEY constraints and in UNIQUE constraints. Example: |
+** |
+** CREATE TABLE xyz(a,b,c,d,e,PRIMARY KEY('a'),UNIQUE('b','c' COLLATE trim) |
+** CREATE INDEX abc ON xyz('c','d' DESC,'e' COLLATE nocase DESC); |
+** |
+** This is goofy. But to preserve backwards compatibility we continue to |
+** accept it. This routine does the necessary conversion. It converts |
+** the expression given in its argument from a TK_STRING into a TK_ID |
+** if the expression is just a TK_STRING with an optional COLLATE clause. |
+** If the epxression is anything other than TK_STRING, the expression is |
+** unchanged. |
+*/ |
+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; |
+ } |
+} |
+ |
+/* |
** Designate the PRIMARY KEY for the table. pList is a list of names |
** of columns that form the primary key. If pList is NULL, then the |
** most recently added column of the table is the primary key. |
@@ -1301,18 +1336,24 @@ void sqlite3AddPrimaryKey( |
}else{ |
nTerm = pList->nExpr; |
for(i=0; i<nTerm; i++){ |
- for(iCol=0; iCol<pTab->nCol; iCol++){ |
- if( sqlite3StrICmp(pList->a[i].zName, pTab->aCol[iCol].zName)==0 ){ |
- pTab->aCol[iCol].colFlags |= COLFLAG_PRIMKEY; |
- zType = pTab->aCol[iCol].zType; |
- break; |
+ Expr *pCExpr = sqlite3ExprSkipCollate(pList->a[i].pExpr); |
+ assert( pCExpr!=0 ); |
+ sqlite3StringToId(pCExpr); |
+ if( pCExpr->op==TK_ID ){ |
+ const char *zCName = pCExpr->u.zToken; |
+ for(iCol=0; iCol<pTab->nCol; iCol++){ |
+ if( sqlite3StrICmp(zCName, pTab->aCol[iCol].zName)==0 ){ |
+ pTab->aCol[iCol].colFlags |= COLFLAG_PRIMKEY; |
+ zType = pTab->aCol[iCol].zType; |
+ break; |
+ } |
} |
} |
} |
} |
if( nTerm==1 |
&& zType && sqlite3StrICmp(zType, "INTEGER")==0 |
- && sortOrder==SQLITE_SO_ASC |
+ && sortOrder!=SQLITE_SO_DESC |
){ |
pTab->iPKey = iCol; |
pTab->keyConf = (u8)onError; |
@@ -1325,14 +1366,11 @@ void sqlite3AddPrimaryKey( |
"INTEGER PRIMARY KEY"); |
#endif |
}else{ |
- Vdbe *v = pParse->pVdbe; |
Index *p; |
- if( v ) pParse->addrSkipPK = sqlite3VdbeAddOp0(v, OP_Noop); |
p = sqlite3CreateIndex(pParse, 0, 0, 0, pList, onError, 0, |
0, sortOrder, 0); |
if( p ){ |
p->idxType = SQLITE_IDXTYPE_PRIMARYKEY; |
- if( v ) sqlite3VdbeJumpHere(v, pParse->addrSkipPK); |
} |
pList = 0; |
} |
@@ -1551,7 +1589,7 @@ static char *createTableStmt(sqlite3 *db, Table *p){ |
zStmt[k++] = '('; |
for(pCol=p->aCol, i=0; i<p->nCol; i++, pCol++){ |
static const char * const azType[] = { |
- /* SQLITE_AFF_NONE */ "", |
+ /* SQLITE_AFF_BLOB */ "", |
/* SQLITE_AFF_TEXT */ " TEXT", |
/* SQLITE_AFF_NUMERIC */ " NUM", |
/* SQLITE_AFF_INTEGER */ " INT", |
@@ -1564,17 +1602,17 @@ static char *createTableStmt(sqlite3 *db, Table *p){ |
k += sqlite3Strlen30(&zStmt[k]); |
zSep = zSep2; |
identPut(zStmt, &k, pCol->zName); |
- assert( pCol->affinity-SQLITE_AFF_NONE >= 0 ); |
- assert( pCol->affinity-SQLITE_AFF_NONE < ArraySize(azType) ); |
- testcase( pCol->affinity==SQLITE_AFF_NONE ); |
+ 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 ); |
- zType = azType[pCol->affinity - SQLITE_AFF_NONE]; |
+ zType = azType[pCol->affinity - SQLITE_AFF_BLOB]; |
len = sqlite3Strlen30(zType); |
- assert( pCol->affinity==SQLITE_AFF_NONE |
+ assert( pCol->affinity==SQLITE_AFF_BLOB |
|| pCol->affinity==sqlite3AffinityType(zType, 0) ); |
memcpy(&zStmt[k], zType, len); |
k += len; |
@@ -1597,7 +1635,7 @@ static int resizeIndexObject(sqlite3 *db, Index *pIdx, int N){ |
zExtra = sqlite3DbMallocZero(db, nByte); |
if( zExtra==0 ) return SQLITE_NOMEM; |
memcpy(zExtra, pIdx->azColl, sizeof(char*)*pIdx->nColumn); |
- pIdx->azColl = (char**)zExtra; |
+ pIdx->azColl = (const char**)zExtra; |
zExtra += sizeof(char*)*N; |
memcpy(zExtra, pIdx->aiColumn, sizeof(i16)*pIdx->nColumn); |
pIdx->aiColumn = (i16*)zExtra; |
@@ -1682,15 +1720,7 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){ |
*/ |
if( pParse->addrCrTab ){ |
assert( v ); |
- sqlite3VdbeGetOp(v, pParse->addrCrTab)->opcode = OP_CreateIndex; |
- } |
- |
- /* Bypass the creation of the PRIMARY KEY btree and the sqlite_master |
- ** table entry. |
- */ |
- if( pParse->addrSkipPK ){ |
- assert( v ); |
- sqlite3VdbeGetOp(v, pParse->addrSkipPK)->opcode = OP_Goto; |
+ sqlite3VdbeChangeOpcode(v, pParse->addrCrTab, OP_CreateIndex); |
} |
/* Locate the PRIMARY KEY index. Or, if this table was originally |
@@ -1698,10 +1728,12 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){ |
*/ |
if( pTab->iPKey>=0 ){ |
ExprList *pList; |
- pList = sqlite3ExprListAppend(pParse, 0, 0); |
+ Token ipkToken; |
+ ipkToken.z = pTab->aCol[pTab->iPKey].zName; |
+ ipkToken.n = sqlite3Strlen30(ipkToken.z); |
+ pList = sqlite3ExprListAppend(pParse, 0, |
+ sqlite3ExprAlloc(db, TK_ID, &ipkToken, 0)); |
if( pList==0 ) return; |
- pList->a[0].zName = sqlite3DbStrDup(pParse->db, |
- pTab->aCol[pTab->iPKey].zName); |
pList->a[0].sortOrder = pParse->iPkSortOrder; |
assert( pParse->pNewTable==pTab ); |
pPk = sqlite3CreateIndex(pParse, 0, 0, 0, pList, pTab->keyConf, 0, 0, 0, 0); |
@@ -1710,16 +1742,42 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){ |
pTab->iPKey = -1; |
}else{ |
pPk = sqlite3PrimaryKeyIndex(pTab); |
+ |
+ /* Bypass the creation of the PRIMARY KEY btree and the sqlite_master |
+ ** table entry. This is only required if currently generating VDBE |
+ ** code for a CREATE TABLE (not when parsing one as part of reading |
+ ** a database schema). */ |
+ if( v ){ |
+ assert( db->init.busy==0 ); |
+ sqlite3VdbeChangeOpcode(v, pPk->tnum, OP_Goto); |
+ } |
+ |
+ /* |
+ ** Remove all redundant columns from the PRIMARY KEY. For example, change |
+ ** "PRIMARY KEY(a,b,a,b,c,b,c,d)" into just "PRIMARY KEY(a,b,c,d)". Later |
+ ** code assumes the PRIMARY KEY contains no repeated columns. |
+ */ |
+ for(i=j=1; i<pPk->nKeyCol; i++){ |
+ if( hasColumn(pPk->aiColumn, j, pPk->aiColumn[i]) ){ |
+ pPk->nColumn--; |
+ }else{ |
+ pPk->aiColumn[j++] = pPk->aiColumn[i]; |
+ } |
+ } |
+ pPk->nKeyCol = j; |
} |
pPk->isCovering = 1; |
assert( pPk!=0 ); |
nPk = pPk->nKeyCol; |
- /* Make sure every column of the PRIMARY KEY is NOT NULL */ |
- for(i=0; i<nPk; i++){ |
- pTab->aCol[pPk->aiColumn[i]].notNull = 1; |
+ /* Make sure every column of the PRIMARY KEY is NOT NULL. (Except, |
+ ** do not enforce this for imposter tables.) */ |
+ if( !db->init.imposterTable ){ |
+ for(i=0; i<nPk; i++){ |
+ pTab->aCol[pPk->aiColumn[i]].notNull = OE_Abort; |
+ } |
+ pPk->uniqNotNull = 1; |
} |
- pPk->uniqNotNull = 1; |
/* The root page of the PRIMARY KEY is the table root page */ |
pPk->tnum = pTab->tnum; |
@@ -1758,7 +1816,7 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){ |
if( !hasColumn(pPk->aiColumn, j, i) ){ |
assert( j<pPk->nColumn ); |
pPk->aiColumn[j] = i; |
- pPk->azColl[j] = "BINARY"; |
+ pPk->azColl[j] = sqlite3StrBINARY; |
j++; |
} |
} |
@@ -1801,9 +1859,10 @@ void sqlite3EndTable( |
int iDb; /* Database in which the table lives */ |
Index *pIdx; /* An implied index of the table */ |
- if( (pEnd==0 && pSelect==0) || db->mallocFailed ){ |
+ if( pEnd==0 && pSelect==0 ){ |
return; |
} |
+ assert( !db->mallocFailed ); |
p = pParse->pNewTable; |
if( p==0 ) return; |
@@ -1829,7 +1888,7 @@ void sqlite3EndTable( |
if( (p->tabFlags & TF_HasPrimaryKey)==0 ){ |
sqlite3ErrorMsg(pParse, "PRIMARY KEY missing on table %s", p->zName); |
}else{ |
- p->tabFlags |= TF_WithoutRowid; |
+ p->tabFlags |= TF_WithoutRowid | TF_NoVisibleRowid; |
convertToWithoutRowidTable(pParse, p); |
} |
} |
@@ -1897,26 +1956,46 @@ void sqlite3EndTable( |
** be redundant. |
*/ |
if( pSelect ){ |
- SelectDest dest; |
- Table *pSelTab; |
- |
+ SelectDest dest; /* Where the SELECT should store results */ |
+ int regYield; /* Register holding co-routine entry-point */ |
+ int addrTop; /* Top of the co-routine */ |
+ int regRec; /* A record to be insert into the new table */ |
+ int regRowid; /* Rowid of the next row to insert */ |
+ int addrInsLoop; /* Top of the loop for inserting rows */ |
+ Table *pSelTab; /* A table that describes the SELECT results */ |
+ |
+ 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; |
- sqlite3SelectDestInit(&dest, SRT_Table, 1); |
+ addrTop = sqlite3VdbeCurrentAddr(v) + 1; |
+ sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, addrTop); |
+ sqlite3SelectDestInit(&dest, SRT_Coroutine, regYield); |
sqlite3Select(pParse, pSelect, &dest); |
+ sqlite3VdbeAddOp1(v, OP_EndCoroutine, regYield); |
+ sqlite3VdbeJumpHere(v, addrTop - 1); |
+ if( pParse->nErr ) return; |
+ pSelTab = sqlite3ResultSetOfSelect(pParse, pSelect); |
+ if( pSelTab==0 ) return; |
+ assert( p->aCol==0 ); |
+ p->nCol = pSelTab->nCol; |
+ p->aCol = pSelTab->aCol; |
+ pSelTab->nCol = 0; |
+ pSelTab->aCol = 0; |
+ sqlite3DeleteTable(db, pSelTab); |
+ 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( pParse->nErr==0 ){ |
- pSelTab = sqlite3ResultSetOfSelect(pParse, pSelect); |
- if( pSelTab==0 ) return; |
- assert( p->aCol==0 ); |
- p->nCol = pSelTab->nCol; |
- p->aCol = pSelTab->aCol; |
- pSelTab->nCol = 0; |
- pSelTab->aCol = 0; |
- sqlite3DeleteTable(db, pSelTab); |
- } |
} |
/* Compute the complete text of the CREATE statement */ |
@@ -2011,6 +2090,7 @@ void sqlite3CreateView( |
Token *pBegin, /* The CREATE token that begins the statement */ |
Token *pName1, /* The token that holds the name of the view */ |
Token *pName2, /* The token that holds the name of the view */ |
+ ExprList *pCNames, /* Optional list of view column names */ |
Select *pSelect, /* A SELECT statement that will become the new view */ |
int isTemp, /* TRUE for a TEMPORARY view */ |
int noErr /* Suppress error messages if VIEW already exists */ |
@@ -2026,22 +2106,15 @@ void sqlite3CreateView( |
if( pParse->nVar>0 ){ |
sqlite3ErrorMsg(pParse, "parameters are not allowed in views"); |
- sqlite3SelectDelete(db, pSelect); |
- return; |
+ goto create_view_fail; |
} |
sqlite3StartTable(pParse, pName1, pName2, isTemp, 1, 0, noErr); |
p = pParse->pNewTable; |
- if( p==0 || pParse->nErr ){ |
- sqlite3SelectDelete(db, pSelect); |
- return; |
- } |
+ if( p==0 || pParse->nErr ) goto create_view_fail; |
sqlite3TwoPartName(pParse, pName1, pName2, &pName); |
iDb = sqlite3SchemaToIndex(db, p->pSchema); |
sqlite3FixInit(&sFix, pParse, iDb, "view", pName); |
- if( sqlite3FixSelect(&sFix, pSelect) ){ |
- sqlite3SelectDelete(db, pSelect); |
- return; |
- } |
+ if( sqlite3FixSelect(&sFix, pSelect) ) goto create_view_fail; |
/* Make a copy of the entire SELECT statement that defines the view. |
** This will force all the Expr.token.z values to be dynamically |
@@ -2049,30 +2122,31 @@ void sqlite3CreateView( |
** they will persist after the current sqlite3_exec() call returns. |
*/ |
p->pSelect = sqlite3SelectDup(db, pSelect, EXPRDUP_REDUCE); |
- sqlite3SelectDelete(db, pSelect); |
- if( db->mallocFailed ){ |
- return; |
- } |
- if( !db->init.busy ){ |
- sqlite3ViewGetColumnNames(pParse, p); |
- } |
+ p->pCheck = sqlite3ExprListDup(db, pCNames, EXPRDUP_REDUCE); |
+ if( db->mallocFailed ) goto create_view_fail; |
/* Locate the end of the CREATE VIEW statement. Make sEnd point to |
** the end. |
*/ |
sEnd = pParse->sLastToken; |
- if( ALWAYS(sEnd.z[0]!=0) && sEnd.z[0]!=';' ){ |
+ assert( sEnd.z[0]!=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( ALWAYS(n>0) && sqlite3Isspace(z[n-1]) ){ n--; } |
+ while( sqlite3Isspace(z[n-1]) ){ n--; } |
sEnd.z = &z[n-1]; |
sEnd.n = 1; |
/* Use sqlite3EndTable() to add the view to the SQLITE_MASTER table */ |
sqlite3EndTable(pParse, 0, &sEnd, 0, 0); |
+ |
+create_view_fail: |
+ sqlite3SelectDelete(db, pSelect); |
+ sqlite3ExprListDelete(db, pCNames); |
return; |
} |
#endif /* SQLITE_OMIT_VIEW */ |
@@ -2090,6 +2164,7 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){ |
int n; /* Temporarily holds the number of cursors assigned */ |
sqlite3 *db = pParse->db; /* Database connection for malloc errors */ |
sqlite3_xauth xAuth; /* Saved xAuth pointer */ |
+ u8 bEnabledLA; /* Saved db->lookaside.bEnabled state */ |
assert( pTable ); |
@@ -2135,40 +2210,46 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){ |
** statement that defines the view. |
*/ |
assert( pTable->pSelect ); |
- pSel = sqlite3SelectDup(db, pTable->pSelect, 0); |
- if( pSel ){ |
- u8 enableLookaside = db->lookaside.bEnabled; |
- n = pParse->nTab; |
- sqlite3SrcListAssignCursors(pParse, pSel->pSrc); |
- pTable->nCol = -1; |
+ bEnabledLA = db->lookaside.bEnabled; |
+ if( pTable->pCheck ){ |
db->lookaside.bEnabled = 0; |
+ sqlite3ColumnsFromExprList(pParse, pTable->pCheck, |
+ &pTable->nCol, &pTable->aCol); |
+ }else{ |
+ pSel = sqlite3SelectDup(db, pTable->pSelect, 0); |
+ if( pSel ){ |
+ n = pParse->nTab; |
+ sqlite3SrcListAssignCursors(pParse, pSel->pSrc); |
+ pTable->nCol = -1; |
+ db->lookaside.bEnabled = 0; |
#ifndef SQLITE_OMIT_AUTHORIZATION |
- xAuth = db->xAuth; |
- db->xAuth = 0; |
- pSelTab = sqlite3ResultSetOfSelect(pParse, pSel); |
- db->xAuth = xAuth; |
+ xAuth = db->xAuth; |
+ db->xAuth = 0; |
+ pSelTab = sqlite3ResultSetOfSelect(pParse, pSel); |
+ db->xAuth = xAuth; |
#else |
- pSelTab = sqlite3ResultSetOfSelect(pParse, pSel); |
+ pSelTab = sqlite3ResultSetOfSelect(pParse, pSel); |
#endif |
- db->lookaside.bEnabled = enableLookaside; |
- pParse->nTab = n; |
- if( pSelTab ){ |
- assert( pTable->aCol==0 ); |
- pTable->nCol = pSelTab->nCol; |
- pTable->aCol = pSelTab->aCol; |
- pSelTab->nCol = 0; |
- pSelTab->aCol = 0; |
- sqlite3DeleteTable(db, pSelTab); |
- assert( sqlite3SchemaMutexHeld(db, 0, pTable->pSchema) ); |
- pTable->pSchema->schemaFlags |= DB_UnresetViews; |
- }else{ |
- pTable->nCol = 0; |
+ pParse->nTab = n; |
+ if( pSelTab ){ |
+ assert( pTable->aCol==0 ); |
+ pTable->nCol = pSelTab->nCol; |
+ pTable->aCol = pSelTab->aCol; |
+ pSelTab->nCol = 0; |
+ pSelTab->aCol = 0; |
+ sqlite3DeleteTable(db, pSelTab); |
+ assert( sqlite3SchemaMutexHeld(db, 0, pTable->pSchema) ); |
+ }else{ |
+ pTable->nCol = 0; |
+ nErr++; |
+ } |
+ sqlite3SelectDelete(db, pSel); |
+ } else { |
nErr++; |
} |
- sqlite3SelectDelete(db, pSel); |
- } else { |
- nErr++; |
} |
+ db->lookaside.bEnabled = bEnabledLA; |
+ pTable->pSchema->schemaFlags |= DB_UnresetViews; |
#endif /* SQLITE_OMIT_VIEW */ |
return nErr; |
} |
@@ -2185,7 +2266,7 @@ static void sqliteViewResetAll(sqlite3 *db, int idx){ |
for(i=sqliteHashFirst(&db->aDb[idx].pSchema->tblHash); i;i=sqliteHashNext(i)){ |
Table *pTab = sqliteHashData(i); |
if( pTab->pSelect ){ |
- sqliteDeleteColumnNames(db, pTab); |
+ sqlite3DeleteColumnNames(db, pTab); |
pTab->aCol = 0; |
pTab->nCol = 0; |
} |
@@ -2435,6 +2516,7 @@ void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, int noErr){ |
} |
assert( pParse->nErr==0 ); |
assert( pName->nSrc==1 ); |
+ if( sqlite3ReadSchema(pParse) ) goto exit_drop_table; |
if( noErr ) db->suppressErr++; |
pTab = sqlite3LocateTableItem(pParse, isView, &pName->a[0]); |
if( noErr ) db->suppressErr--; |
@@ -2739,7 +2821,7 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){ |
assert( pKey!=0 || db->mallocFailed || pParse->nErr ); |
if( IsUniqueIndex(pIndex) && pKey!=0 ){ |
int j2 = sqlite3VdbeCurrentAddr(v) + 3; |
- sqlite3VdbeAddOp2(v, OP_Goto, 0, j2); |
+ sqlite3VdbeGoto(v, j2); |
addr2 = sqlite3VdbeCurrentAddr(v); |
sqlite3VdbeAddOp4Int(v, OP_SorterCompare, iSorter, j2, regRecord, |
pIndex->nKeyCol); VdbeCoverage(v); |
@@ -2748,7 +2830,8 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){ |
addr2 = sqlite3VdbeCurrentAddr(v); |
} |
sqlite3VdbeAddOp3(v, OP_SorterData, iSorter, regRecord, iIdx); |
- sqlite3VdbeAddOp3(v, OP_IdxInsert, iIdx, regRecord, 1); |
+ sqlite3VdbeAddOp3(v, OP_Last, iIdx, 0, -1); |
+ sqlite3VdbeAddOp3(v, OP_IdxInsert, iIdx, regRecord, 0); |
sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT); |
sqlite3ReleaseTempReg(pParse, regRecord); |
sqlite3VdbeAddOp2(v, OP_SorterNext, iSorter, addr2); VdbeCoverage(v); |
@@ -2783,7 +2866,7 @@ Index *sqlite3AllocateIndexObject( |
p = sqlite3DbMallocZero(db, nByte + nExtra); |
if( p ){ |
char *pExtra = ((char*)p)+ROUND8(sizeof(Index)); |
- p->azColl = (char**)pExtra; pExtra += ROUND8(sizeof(char*)*nCol); |
+ 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; |
@@ -2835,14 +2918,12 @@ Index *sqlite3CreateIndex( |
int iDb; /* Index of the database that is being written */ |
Token *pName = 0; /* Unqualified name of the index to create */ |
struct ExprList_item *pListItem; /* For looping over pList */ |
- const Column *pTabCol; /* A column in the table */ |
int nExtra = 0; /* Space allocated for zExtra[] */ |
int nExtraCol; /* Number of extra columns needed */ |
char *zExtra = 0; /* Extra space after the Index object */ |
Index *pPk = 0; /* PRIMARY KEY index for WITHOUT ROWID tables */ |
- assert( pParse->nErr==0 ); /* Never called with prior errors */ |
- if( db->mallocFailed || IN_DECLARE_VTAB ){ |
+ if( db->mallocFailed || IN_DECLARE_VTAB || pParse->nErr>0 ){ |
goto exit_create_index; |
} |
if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){ |
@@ -2991,11 +3072,16 @@ Index *sqlite3CreateIndex( |
** So create a fake list to simulate this. |
*/ |
if( pList==0 ){ |
- pList = sqlite3ExprListAppend(pParse, 0, 0); |
+ Token prevCol; |
+ prevCol.z = pTab->aCol[pTab->nCol-1].zName; |
+ prevCol.n = sqlite3Strlen30(prevCol.z); |
+ pList = sqlite3ExprListAppend(pParse, 0, |
+ sqlite3ExprAlloc(db, TK_ID, &prevCol, 0)); |
if( pList==0 ) goto exit_create_index; |
- pList->a[0].zName = sqlite3DbStrDup(pParse->db, |
- pTab->aCol[pTab->nCol-1].zName); |
- pList->a[0].sortOrder = (u8)sortOrder; |
+ assert( pList->nExpr==1 ); |
+ sqlite3ExprListSetSortOrder(pList, sortOrder); |
+ }else{ |
+ sqlite3ExprListCheckLength(pParse, pList, "index"); |
} |
/* Figure out how many bytes of space are required to store explicitly |
@@ -3003,8 +3089,8 @@ Index *sqlite3CreateIndex( |
*/ |
for(i=0; i<pList->nExpr; i++){ |
Expr *pExpr = pList->a[i].pExpr; |
- if( pExpr ){ |
- assert( pExpr->op==TK_COLLATE ); |
+ assert( pExpr!=0 ); |
+ if( pExpr->op==TK_COLLATE ){ |
nExtra += (1 + sqlite3Strlen30(pExpr->u.zToken)); |
} |
} |
@@ -3045,35 +3131,54 @@ Index *sqlite3CreateIndex( |
sortOrderMask = 0; /* Ignore DESC */ |
} |
- /* Scan the names of the columns of the table to be indexed and |
- ** load the column indices into the Index structure. Report an error |
- ** if any column is not found. |
+ /* Analyze the list of expressions that form the terms of the index and |
+ ** report any errors. In the common case where the expression is exactly |
+ ** a table column, store that column in aiColumn[]. For general expressions, |
+ ** populate pIndex->aColExpr and store XN_EXPR (-2) in aiColumn[]. |
** |
- ** TODO: Add a test to make sure that the same column is not named |
- ** more than once within the same index. Only the first instance of |
- ** the column will ever be used by the optimizer. Note that using the |
- ** same column more than once cannot be an error because that would |
- ** break backwards compatibility - it needs to be a warning. |
+ ** TODO: Issue a warning if two or more columns of the index are identical. |
+ ** TODO: Issue a warning if the table primary key is used as part of the |
+ ** index key. |
*/ |
for(i=0, pListItem=pList->a; i<pList->nExpr; i++, pListItem++){ |
- const char *zColName = pListItem->zName; |
- int requestedSortOrder; |
- char *zColl; /* Collation sequence name */ |
- |
- for(j=0, pTabCol=pTab->aCol; j<pTab->nCol; j++, pTabCol++){ |
- if( sqlite3StrICmp(zColName, pTabCol->zName)==0 ) break; |
- } |
- if( j>=pTab->nCol ){ |
- sqlite3ErrorMsg(pParse, "table %s has no column named %s", |
- pTab->zName, zColName); |
- pParse->checkSchema = 1; |
- goto exit_create_index; |
+ Expr *pCExpr; /* The i-th index expression */ |
+ int requestedSortOrder; /* ASC or DESC on the i-th expression */ |
+ const char *zColl; /* Collation sequence name */ |
+ |
+ 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 ){ |
+ ExprList *pCopy = sqlite3ExprListDup(db, pList, 0); |
+ pIndex->aColExpr = pCopy; |
+ if( !db->mallocFailed ){ |
+ assert( pCopy!=0 ); |
+ pListItem = &pCopy->a[i]; |
+ } |
+ } |
+ j = XN_EXPR; |
+ pIndex->aiColumn[i] = XN_EXPR; |
+ pIndex->uniqNotNull = 0; |
+ }else{ |
+ j = pCExpr->iColumn; |
+ assert( j<=0x7fff ); |
+ if( j<0 ){ |
+ j = pTab->iPKey; |
+ }else if( pTab->aCol[j].notNull==0 ){ |
+ pIndex->uniqNotNull = 0; |
+ } |
+ pIndex->aiColumn[i] = (i16)j; |
} |
- assert( j<=0x7fff ); |
- pIndex->aiColumn[i] = (i16)j; |
- if( pListItem->pExpr ){ |
+ zColl = 0; |
+ if( pListItem->pExpr->op==TK_COLLATE ){ |
int nColl; |
- assert( pListItem->pExpr->op==TK_COLLATE ); |
zColl = pListItem->pExpr->u.zToken; |
nColl = sqlite3Strlen30(zColl) + 1; |
assert( nExtra>=nColl ); |
@@ -3081,21 +3186,26 @@ Index *sqlite3CreateIndex( |
zColl = zExtra; |
zExtra += nColl; |
nExtra -= nColl; |
- }else{ |
+ }else if( j>=0 ){ |
zColl = pTab->aCol[j].zColl; |
- if( !zColl ) zColl = "BINARY"; |
} |
+ if( !zColl ) zColl = sqlite3StrBINARY; |
if( !db->init.busy && !sqlite3LocateCollSeq(pParse, zColl) ){ |
goto exit_create_index; |
} |
pIndex->azColl[i] = zColl; |
requestedSortOrder = pListItem->sortOrder & sortOrderMask; |
pIndex->aSortOrder[i] = (u8)requestedSortOrder; |
- if( pTab->aCol[j].notNull==0 ) pIndex->uniqNotNull = 0; |
} |
+ |
+ /* Append the table key to the end of the index. For WITHOUT ROWID |
+ ** tables (when pPk!=0) this will be the declared PRIMARY KEY. For |
+ ** normal tables (when pPk==0) this will be the rowid. |
+ */ |
if( pPk ){ |
for(j=0; j<pPk->nKeyCol; j++){ |
int x = pPk->aiColumn[j]; |
+ assert( x>=0 ); |
if( hasColumn(pIndex->aiColumn, pIndex->nKeyCol, x) ){ |
pIndex->nColumn--; |
}else{ |
@@ -3107,8 +3217,8 @@ Index *sqlite3CreateIndex( |
} |
assert( i==pIndex->nColumn ); |
}else{ |
- pIndex->aiColumn[i] = -1; |
- pIndex->azColl[i] = "BINARY"; |
+ pIndex->aiColumn[i] = XN_ROWID; |
+ pIndex->azColl[i] = sqlite3StrBINARY; |
} |
sqlite3DefaultRowEst(pIndex); |
if( pParse->pNewTable==0 ) estimateIndexWidth(pIndex); |
@@ -3146,6 +3256,7 @@ Index *sqlite3CreateIndex( |
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]; |
@@ -3168,6 +3279,7 @@ Index *sqlite3CreateIndex( |
pIdx->onError = pIndex->onError; |
} |
} |
+ pRet = pIdx; |
goto exit_create_index; |
} |
} |
@@ -3176,6 +3288,7 @@ Index *sqlite3CreateIndex( |
/* Link the new Index structure to its table and to the other |
** in-memory database structures. |
*/ |
+ assert( pParse->nErr==0 ); |
if( db->init.busy ){ |
Index *p; |
assert( sqlite3SchemaMutexHeld(db, 0, pIndex->pSchema) ); |
@@ -3205,7 +3318,7 @@ Index *sqlite3CreateIndex( |
** has just been created, it contains no data and the index initialization |
** step can be skipped. |
*/ |
- else if( pParse->nErr==0 && (HasRowid(pTab) || pTblName!=0) ){ |
+ else if( HasRowid(pTab) || pTblName!=0 ){ |
Vdbe *v; |
char *zStmt; |
int iMem = ++pParse->nMem; |
@@ -3213,10 +3326,15 @@ Index *sqlite3CreateIndex( |
v = sqlite3GetVdbe(pParse); |
if( v==0 ) goto exit_create_index; |
- |
- /* Create the rootpage for the index |
- */ |
sqlite3BeginWriteOperation(pParse, 1, iDb); |
+ |
+ /* Create the rootpage for the index using CreateIndex. But before |
+ ** doing so, code a Noop instruction and store its address in |
+ ** Index.tnum. This is required in case this index is actually a |
+ ** PRIMARY KEY and the table is actually a WITHOUT ROWID table. In |
+ ** that case the convertToWithoutRowidTable() routine will replace |
+ ** the Noop with a Goto to jump over the VDBE code generated below. */ |
+ pIndex->tnum = sqlite3VdbeAddOp0(v, OP_Noop); |
sqlite3VdbeAddOp2(v, OP_CreateIndex, iDb, iMem); |
/* Gather the complete text of the CREATE INDEX statement into |
@@ -3256,6 +3374,8 @@ Index *sqlite3CreateIndex( |
sqlite3MPrintf(db, "name='%q' AND type='index'", pIndex->zName)); |
sqlite3VdbeAddOp1(v, OP_Expire, 0); |
} |
+ |
+ sqlite3VdbeJumpHere(v, pIndex->tnum); |
} |
/* When adding an index to the list of indices for a table, make |
@@ -3658,7 +3778,8 @@ void sqlite3SrcListDelete(sqlite3 *db, SrcList *pList){ |
sqlite3DbFree(db, pItem->zDatabase); |
sqlite3DbFree(db, pItem->zName); |
sqlite3DbFree(db, pItem->zAlias); |
- sqlite3DbFree(db, pItem->zIndex); |
+ if( pItem->fg.isIndexedBy ) sqlite3DbFree(db, pItem->u1.zIndexedBy); |
+ if( pItem->fg.isTabFunc ) sqlite3ExprListDelete(db, pItem->u1.pFuncArg); |
sqlite3DeleteTable(db, pItem->pTab); |
sqlite3SelectDelete(db, pItem->pSelect); |
sqlite3ExprDelete(db, pItem->pOn); |
@@ -3731,18 +3852,38 @@ void sqlite3SrcListIndexedBy(Parse *pParse, SrcList *p, Token *pIndexedBy){ |
assert( pIndexedBy!=0 ); |
if( p && ALWAYS(p->nSrc>0) ){ |
struct SrcList_item *pItem = &p->a[p->nSrc-1]; |
- assert( pItem->notIndexed==0 && pItem->zIndex==0 ); |
+ assert( pItem->fg.notIndexed==0 ); |
+ assert( pItem->fg.isIndexedBy==0 ); |
+ assert( pItem->fg.isTabFunc==0 ); |
if( pIndexedBy->n==1 && !pIndexedBy->z ){ |
/* A "NOT INDEXED" clause was supplied. See parse.y |
** construct "indexed_opt" for details. */ |
- pItem->notIndexed = 1; |
+ pItem->fg.notIndexed = 1; |
}else{ |
- pItem->zIndex = sqlite3NameFromToken(pParse->db, pIndexedBy); |
+ pItem->u1.zIndexedBy = sqlite3NameFromToken(pParse->db, pIndexedBy); |
+ pItem->fg.isIndexedBy = (pItem->u1.zIndexedBy!=0); |
} |
} |
} |
/* |
+** Add the list of function arguments to the SrcList entry for a |
+** table-valued-function. |
+*/ |
+void sqlite3SrcListFuncArgs(Parse *pParse, SrcList *p, ExprList *pList){ |
+ if( p ){ |
+ struct SrcList_item *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); |
+ } |
+} |
+ |
+/* |
** When building up a FROM clause in the parser, the join operator |
** is initially attached to the left operand. But the code generator |
** expects the join operator to be on the right operand. This routine |
@@ -3760,11 +3901,10 @@ void sqlite3SrcListIndexedBy(Parse *pParse, SrcList *p, Token *pIndexedBy){ |
void sqlite3SrcListShiftJoinType(SrcList *p){ |
if( p ){ |
int i; |
- assert( p->a || p->nSrc==0 ); |
for(i=p->nSrc-1; i>0; i--){ |
- p->a[i].jointype = p->a[i-1].jointype; |
+ p->a[i].fg.jointype = p->a[i-1].fg.jointype; |
} |
- p->a[0].jointype = 0; |
+ p->a[0].fg.jointype = 0; |
} |
} |
@@ -4007,14 +4147,17 @@ void sqlite3UniqueConstraint( |
StrAccum errMsg; |
Table *pTab = pIdx->pTable; |
- sqlite3StrAccumInit(&errMsg, 0, 0, 200); |
- errMsg.db = pParse->db; |
- for(j=0; j<pIdx->nKeyCol; j++){ |
- char *zCol = pTab->aCol[pIdx->aiColumn[j]].zName; |
- if( j ) sqlite3StrAccumAppend(&errMsg, ", ", 2); |
- sqlite3StrAccumAppendAll(&errMsg, pTab->zName); |
- sqlite3StrAccumAppend(&errMsg, ".", 1); |
- sqlite3StrAccumAppendAll(&errMsg, zCol); |
+ sqlite3StrAccumInit(&errMsg, pParse->db, 0, 0, 200); |
+ if( pIdx->aColExpr ){ |
+ sqlite3XPrintf(&errMsg, 0, "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]].zName; |
+ if( j ) sqlite3StrAccumAppend(&errMsg, ", ", 2); |
+ sqlite3XPrintf(&errMsg, 0, "%s.%s", pTab->zName, zCol); |
+ } |
} |
zErr = sqlite3StrAccumFinish(&errMsg); |
sqlite3HaltConstraint(pParse, |
@@ -4186,40 +4329,30 @@ void sqlite3Reindex(Parse *pParse, Token *pName1, Token *pName2){ |
** when it has finished using it. |
*/ |
KeyInfo *sqlite3KeyInfoOfIndex(Parse *pParse, Index *pIdx){ |
+ int i; |
+ int nCol = pIdx->nColumn; |
+ int nKey = pIdx->nKeyCol; |
+ KeyInfo *pKey; |
if( pParse->nErr ) return 0; |
-#ifndef SQLITE_OMIT_SHARED_CACHE |
- if( pIdx->pKeyInfo && pIdx->pKeyInfo->db!=pParse->db ){ |
- sqlite3KeyInfoUnref(pIdx->pKeyInfo); |
- pIdx->pKeyInfo = 0; |
+ if( pIdx->uniqNotNull ){ |
+ pKey = sqlite3KeyInfoAlloc(pParse->db, nKey, nCol-nKey); |
+ }else{ |
+ pKey = sqlite3KeyInfoAlloc(pParse->db, nCol, 0); |
} |
-#endif |
- if( pIdx->pKeyInfo==0 ){ |
- int i; |
- int nCol = pIdx->nColumn; |
- int nKey = pIdx->nKeyCol; |
- KeyInfo *pKey; |
- if( pIdx->uniqNotNull ){ |
- pKey = sqlite3KeyInfoAlloc(pParse->db, nKey, nCol-nKey); |
- }else{ |
- pKey = sqlite3KeyInfoAlloc(pParse->db, nCol, 0); |
+ if( pKey ){ |
+ assert( sqlite3KeyInfoIsWriteable(pKey) ); |
+ for(i=0; i<nCol; i++){ |
+ const char *zColl = pIdx->azColl[i]; |
+ pKey->aColl[i] = zColl==sqlite3StrBINARY ? 0 : |
+ sqlite3LocateCollSeq(pParse, zColl); |
+ pKey->aSortOrder[i] = pIdx->aSortOrder[i]; |
} |
- if( pKey ){ |
- assert( sqlite3KeyInfoIsWriteable(pKey) ); |
- for(i=0; i<nCol; i++){ |
- char *zColl = pIdx->azColl[i]; |
- assert( zColl!=0 ); |
- pKey->aColl[i] = strcmp(zColl,"BINARY")==0 ? 0 : |
- sqlite3LocateCollSeq(pParse, zColl); |
- pKey->aSortOrder[i] = pIdx->aSortOrder[i]; |
- } |
- if( pParse->nErr ){ |
- sqlite3KeyInfoUnref(pKey); |
- }else{ |
- pIdx->pKeyInfo = pKey; |
- } |
+ if( pParse->nErr ){ |
+ sqlite3KeyInfoUnref(pKey); |
+ pKey = 0; |
} |
} |
- return sqlite3KeyInfoRef(pIdx->pKeyInfo); |
+ return pKey; |
} |
#ifndef SQLITE_OMIT_CTE |
@@ -4268,7 +4401,7 @@ With *sqlite3WithAdd( |
pNew->a[pNew->nCte].pSelect = pQuery; |
pNew->a[pNew->nCte].pCols = pArglist; |
pNew->a[pNew->nCte].zName = zName; |
- pNew->a[pNew->nCte].zErr = 0; |
+ pNew->a[pNew->nCte].zCteErr = 0; |
pNew->nCte++; |
} |