aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/build.c5
-rw-r--r--src/insert.c24
-rw-r--r--src/prepare.c11
-rw-r--r--src/sqliteInt.h4
-rw-r--r--src/where.c30
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;