| Index: third_party/sqlite/sqlite-src-3100200/src/build.c
|
| diff --git a/third_party/sqlite/sqlite-src-3080704/src/build.c b/third_party/sqlite/sqlite-src-3100200/src/build.c
|
| similarity index 90%
|
| copy from third_party/sqlite/sqlite-src-3080704/src/build.c
|
| copy to third_party/sqlite/sqlite-src-3100200/src/build.c
|
| index b897494db3c2e478402917cfbe724de567177ac7..63e30046578470c705fe0cc3eed84f865c821e71 100644
|
| --- a/third_party/sqlite/sqlite-src-3080704/src/build.c
|
| +++ b/third_party/sqlite/sqlite-src-3100200/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++;
|
| }
|
|
|
|
|