diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/build.c | 5 | ||||
-rw-r--r-- | src/insert.c | 24 | ||||
-rw-r--r-- | src/prepare.c | 11 | ||||
-rw-r--r-- | src/sqliteInt.h | 4 | ||||
-rw-r--r-- | src/where.c | 30 |
5 files changed, 51 insertions, 23 deletions
diff --git a/src/build.c b/src/build.c index 091498fc5..f1ef19b38 100644 --- a/src/build.c +++ b/src/build.c @@ -1615,6 +1615,11 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){ 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; + } + /* Update the in-memory representation of all UNIQUE indices by converting ** the final rowid column into one or more columns of the PRIMARY KEY. */ diff --git a/src/insert.c b/src/insert.c index c662a52e7..d9bf67216 100644 --- a/src/insert.c +++ b/src/insert.c @@ -29,9 +29,11 @@ void sqlite3OpenTable( v = sqlite3GetVdbe(p); assert( opcode==OP_OpenWrite || opcode==OP_OpenRead ); sqlite3TableLock(p, iDb, pTab->tnum, (opcode==OP_OpenWrite)?1:0, pTab->zName); - sqlite3VdbeAddOp3(v, opcode, iCur, pTab->tnum, iDb); - sqlite3VdbeChangeP4(v, -1, SQLITE_INT_TO_PTR(pTab->nCol), P4_INT32); - VdbeComment((v, "%s", pTab->zName)); + if( HasRowid(pTab) ){ + sqlite3VdbeAddOp3(v, opcode, iCur, pTab->tnum, iDb); + sqlite3VdbeChangeP4(v, -1, SQLITE_INT_TO_PTR(pTab->nCol), P4_INT32); + VdbeComment((v, "%s", pTab->zName)); + } } /* @@ -441,7 +443,7 @@ static int xferOptimization( ** the "1st template"): ** ** open write cursor to <table> and its indices -** puts VALUES clause expressions onto the stack +** put VALUES clause expressions into registers ** write the resulting record into <table> ** cleanup ** @@ -551,6 +553,7 @@ void sqlite3Insert( int iDb; /* Index of database holding TABLE */ Db *pDb; /* The database containing table being inserted into */ int appendFlag = 0; /* True if the insert is likely to be an append */ + int withoutRowid; /* 0 for normal table. 1 for WITHOUT ROWID table */ /* Register allocations */ int regFromSelect = 0;/* Base register for data coming from SELECT */ @@ -590,6 +593,7 @@ void sqlite3Insert( if( sqlite3AuthCheck(pParse, SQLITE_INSERT, pTab->zName, 0, zDb) ){ goto insert_cleanup; } + withoutRowid = !HasRowid(pTab); /* Figure out if we have any triggers and if the table being ** inserted into is a view @@ -770,13 +774,13 @@ void sqlite3Insert( if( sqlite3StrICmp(pColumn->a[i].zName, pTab->aCol[j].zName)==0 ){ pColumn->a[i].idx = j; if( j==pTab->iPKey ){ - keyColumn = i; + keyColumn = i; assert( !withoutRowid ); } break; } } if( j>=pTab->nCol ){ - if( sqlite3IsRowid(pColumn->a[i].zName) ){ + if( sqlite3IsRowid(pColumn->a[i].zName) && !withoutRowid ){ keyColumn = i; }else{ sqlite3ErrorMsg(pParse, "table %S has no column named %s", @@ -807,7 +811,7 @@ void sqlite3Insert( if( !isView ){ int nIdx; - baseCur = pParse->nTab; + baseCur = pParse->nTab - withoutRowid; nIdx = sqlite3OpenTableAndIndices(pParse, pTab, baseCur, OP_OpenWrite); aRegIdx = sqlite3DbMallocRaw(db, sizeof(int)*(nIdx+1)); if( aRegIdx==0 ){ @@ -872,6 +876,7 @@ void sqlite3Insert( sqlite3VdbeAddOp2(v, OP_Integer, -1, regCols); }else{ int j1; + assert( !withoutRowid ); if( useTempTable ){ sqlite3VdbeAddOp3(v, OP_Column, srcTab, keyColumn, regCols); }else{ @@ -968,7 +973,7 @@ void sqlite3Insert( } sqlite3VdbeAddOp1(v, OP_MustBeInt, regRowid); } - }else if( IsVirtual(pTab) ){ + }else if( IsVirtual(pTab) || withoutRowid ){ sqlite3VdbeAddOp2(v, OP_Null, 0, regRowid); }else{ sqlite3VdbeAddOp3(v, OP_NewRowid, baseCur, regRowid, regAutoinc); @@ -1065,7 +1070,7 @@ void sqlite3Insert( if( !IsVirtual(pTab) && !isView ){ /* Close all tables opened */ - sqlite3VdbeAddOp1(v, OP_Close, baseCur); + if( !withoutRowid ) sqlite3VdbeAddOp1(v, OP_Close, baseCur); for(idx=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, idx++){ sqlite3VdbeAddOp1(v, OP_Close, idx+baseCur); } @@ -1528,6 +1533,7 @@ void sqlite3CompleteInsertion( sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT); } } + if( !HasRowid(pTab) ) return; regData = regRowid + 1; regRec = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp3(v, OP_MakeRecord, regData, pTab->nCol, regRec); diff --git a/src/prepare.c b/src/prepare.c index 542d0bf8b..5205f07e5 100644 --- a/src/prepare.c +++ b/src/prepare.c @@ -65,9 +65,7 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){ assert( iDb>=0 && iDb<db->nDb ); if( argv==0 ) return 0; /* Might happen if EMPTY_RESULT_CALLBACKS are on */ - if( argv[1]==0 ){ - /* NULL root page for a WITHOUT ROWID table */ - }else if( argv[2] && argv[2][0] ){ + if( argv[2] && argv[2][0] ){ /* Call the parser to process a CREATE TABLE, INDEX or VIEW. ** But because db->init.busy is set to 1, no VDBE code is generated ** or executed. All the parser does is build the internal data @@ -79,7 +77,7 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){ assert( db->init.busy ); db->init.iDb = iDb; - db->init.newTnum = sqlite3Atoi(argv[1]); + db->init.newTnum = argv[1] ? sqlite3Atoi(argv[1]) : 0; db->init.orphanTrigger = 0; TESTONLY(rcp = ) sqlite3_prepare(db, argv[2], -1, &pStmt, 0); rc = db->errCode; @@ -119,6 +117,11 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){ }else if( sqlite3GetInt32(argv[1], &pIndex->tnum)==0 ){ corruptSchema(pData, argv[0], "invalid rootpage"); } + if( pIndex->autoIndex==2 + && (pIndex->pTable->tabFlags & TF_WithoutRowid)!=0 + ){ + pIndex->pTable->tnum = pIndex->tnum; + } } return 0; } diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 8ff95e361..43cf27436 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -1427,6 +1427,9 @@ struct Table { # define IsHiddenColumn(X) 0 #endif +/* Does the table have a rowid */ +#define HasRowid(X) (((X)->tabFlags & TF_WithoutRowid)==0) + /* ** Each foreign key constraint is an instance of the following structure. ** @@ -1595,6 +1598,7 @@ struct Index { unsigned bUnordered:1; /* Use this index for == or IN queries only */ unsigned uniqNotNull:1; /* True if UNIQUE and NOT NULL for all columns */ unsigned isResized:1; /* True if resizeIndexObject() has been called */ + unsigned isCovering:1; /* True if this is a covering index */ #ifdef SQLITE_ENABLE_STAT3_OR_STAT4 int nSample; /* Number of elements in aSample[] */ int nSampleCol; /* Size of IndexSample.anEq[] and so on */ diff --git a/src/where.c b/src/where.c index b9036c924..bccb980b7 100644 --- a/src/where.c +++ b/src/where.c @@ -4421,12 +4421,13 @@ static int indexMightHelpWithOrderBy( static Bitmask columnsInIndex(Index *pIdx){ Bitmask m = 0; int j; - for(j=pIdx->nKeyCol-1; j>=0; j--){ + for(j=pIdx->nColumn-1; j>=0; j--){ int x = pIdx->aiColumn[j]; - assert( x>=0 ); - testcase( x==BMS-1 ); - testcase( x==BMS-2 ); - if( x<BMS-1 ) m |= MASKBIT(x); + if( x>=0 ){ + testcase( x==BMS-1 ); + testcase( x==BMS-2 ); + if( x<BMS-1 ) m |= MASKBIT(x); + } } return m; } @@ -4479,6 +4480,8 @@ static int whereLoopAddBtree( if( pSrc->pIndex ){ /* An INDEXED BY clause specifies a particular index to use */ pProbe = pSrc->pIndex; + }else if( !HasRowid(pTab) ){ + pProbe = pTab->pIndex; }else{ /* There is no INDEXED BY clause. Create a fake Index object in local ** variable sPk to represent the rowid primary key index. Make this @@ -4511,6 +4514,7 @@ static int whereLoopAddBtree( && pSrc->pIndex==0 && !pSrc->viaCoroutine && !pSrc->notIndexed + && HasRowid(pTab) && !pSrc->isCorrelated ){ /* Generate auto-index WhereLoops */ @@ -4573,8 +4577,14 @@ static int whereLoopAddBtree( pNew->nOut = rSize; if( rc ) break; }else{ - Bitmask m = pSrc->colUsed & ~columnsInIndex(pProbe); - pNew->wsFlags = (m==0) ? (WHERE_IDX_ONLY|WHERE_INDEXED) : WHERE_INDEXED; + Bitmask m; + if( pProbe->isCovering ){ + pNew->wsFlags = WHERE_IDX_ONLY | WHERE_INDEXED; + m = 0; + }else{ + m = pSrc->colUsed & ~columnsInIndex(pProbe); + pNew->wsFlags = (m==0) ? (WHERE_IDX_ONLY|WHERE_INDEXED) : WHERE_INDEXED; + } /* Full scan via index */ if( b @@ -5522,7 +5532,7 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){ } if( j!=pIdx->nKeyCol ) continue; pLoop->wsFlags = WHERE_COLUMN_EQ|WHERE_ONEROW|WHERE_INDEXED; - if( (pItem->colUsed & ~columnsInIndex(pIdx))==0 ){ + if( pIdx->isCovering || (pItem->colUsed & ~columnsInIndex(pIdx))==0 ){ pLoop->wsFlags |= WHERE_IDX_ONLY; } pLoop->nLTerm = j; @@ -6112,14 +6122,14 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){ for(; k<last; k++, pOp++){ if( pOp->p1!=pLevel->iTabCur ) continue; if( pOp->opcode==OP_Column ){ - for(j=0; j<pIdx->nKeyCol; j++){ + for(j=0; j<pIdx->nColumn; j++){ if( pOp->p2==pIdx->aiColumn[j] ){ pOp->p2 = j; pOp->p1 = pLevel->iIdxCur; break; } } - assert( (pLoop->wsFlags & WHERE_IDX_ONLY)==0 || j<pIdx->nKeyCol ); + assert( (pLoop->wsFlags & WHERE_IDX_ONLY)==0 || j<pIdx->nColumn ); }else if( pOp->opcode==OP_Rowid ){ pOp->p1 = pLevel->iIdxCur; pOp->opcode = OP_IdxRowid; |