mirror of
https://github.com/sqlite/sqlite.git
synced 2025-11-11 01:42:22 +03:00
Some simple inserts and queries working on WITHOUT ROWID tables.
FossilOrigin-Name: 3f8016dee24213ec83a02d71ad2698789cc3a818
This commit is contained in:
22
manifest
22
manifest
@@ -1,5 +1,5 @@
|
||||
C Build\sinternal\sdata\sstructures\sappropriately\sfor\sWITHOUT\sROWID\stables.
|
||||
D 2013-10-23T00:32:58.135
|
||||
C Some\ssimple\sinserts\sand\squeries\sworking\son\sWITHOUT\sROWID\stables.
|
||||
D 2013-10-23T01:57:32.661
|
||||
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
||||
F Makefile.in 0522b53cdc1fcfc18f3a98e0246add129136c654
|
||||
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
||||
@@ -168,7 +168,7 @@ F src/btmutex.c 976f45a12e37293e32cae0281b15a21d48a8aaa7
|
||||
F src/btree.c 509722ce305471b626d3401c0631a808fd33237b
|
||||
F src/btree.h bfe0e8c5759b4ec77b0d18390064a6ef3cdffaaf
|
||||
F src/btreeInt.h f038e818bfadf75afbd09819ed93c26a333d39e0
|
||||
F src/build.c fbc70ed499d86a5a004ea097e509175229826e8b
|
||||
F src/build.c 2b8af1054c5db8dd78675c847adcbe4999af0403
|
||||
F src/callback.c f99a8957ba2adf369645fac0db09ad8adcf1caa2
|
||||
F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac
|
||||
F src/ctime.c ea4b7f3623a0fcb1146e7f245d7410033e86859c
|
||||
@@ -182,7 +182,7 @@ F src/global.c 5caf4deab621abb45b4c607aad1bd21c20aac759
|
||||
F src/hash.c ac3470bbf1ca4ae4e306a8ecb0fdf1731810ffe4
|
||||
F src/hash.h 8890a25af81fb85a9ad7790d32eedab4b994da22
|
||||
F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08
|
||||
F src/insert.c c9db86093430946d08186117dab197fddf621a75
|
||||
F src/insert.c e8aeca40de34d936118157e3afc5a0551cda9c66
|
||||
F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d
|
||||
F src/legacy.c 0df0b1550b9cc1f58229644735e317ac89131f12
|
||||
F src/lempar.c cdf0a000315332fc9b50b62f3b5e22e080a0952b
|
||||
@@ -213,7 +213,7 @@ F src/pcache.c f8043b433a57aba85384a531e3937a804432a346
|
||||
F src/pcache.h a5e4f5d9f5d592051d91212c5949517971ae6222
|
||||
F src/pcache1.c a467393909a4ed7ca9de066d85ba5c5b04a5be63
|
||||
F src/pragma.c ab815d27690d24e87c953355a765edb546c47708
|
||||
F src/prepare.c b1a3393b6c71b270921451ac43072d0c46711575
|
||||
F src/prepare.c f47ba2bba7ac5650881ab6c41f6d33a6de1a8d52
|
||||
F src/printf.c da9119eb31a187a4b99f60aa4a225141c0ebb74b
|
||||
F src/random.c 0b2dbc37fdfbfa6bd455b091dfcef5bdb32dba68
|
||||
F src/resolve.c 572585a96bf282bb9c3d9e08785ec3cae21dc488
|
||||
@@ -223,7 +223,7 @@ F src/shell.c 6f11f0e9ded63d48e306f2c6858c521e568a47bb
|
||||
F src/sqlite.h.in 547a44dd4ff4d975e92a645ea2d609e543a83d0f
|
||||
F src/sqlite3.rc 11094cc6a157a028b301a9f06b3d03089ea37c3e
|
||||
F src/sqlite3ext.h 886f5a34de171002ad46fae8c36a7d8051c190fc
|
||||
F src/sqliteInt.h a60fca7b3f2a8d5a69f4b49e63224b92140207cf
|
||||
F src/sqliteInt.h 7cde277316177b00d1daeb6e4a3eebbcb1aff4ea
|
||||
F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
|
||||
F src/status.c 7ac05a5c7017d0b9f0b4bcd701228b784f987158
|
||||
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
|
||||
@@ -292,13 +292,13 @@ F src/vtab.c 5a423b042eb1402ef77697d03d6a67378d97bc8d
|
||||
F src/wal.c 7dc3966ef98b74422267e7e6e46e07ff6c6eb1b4
|
||||
F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4
|
||||
F src/walker.c e9e593d5bb798c3e67fc3893dfe7055c9e7d8d74
|
||||
F src/where.c 32b6e99b4343958f5ca641e3d62fe3da072f7128
|
||||
F src/where.c f9e7662714d776a929683d813a2496fbca8b9087
|
||||
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
|
||||
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
|
||||
F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6
|
||||
F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87
|
||||
F test/all.test 6ff7b43c2b4b905c74dc4a813d201d0fa64c5783
|
||||
F test/alter.test e88dfa77e020c2b48e52a8020c70171ab828e079
|
||||
F test/alter.test b955ec265bca952bd23aa80a2d9bf6e69688694b
|
||||
F test/alter2.test 7ea05c7d92ac99349a802ef7ada17294dd647060
|
||||
F test/alter3.test 49c9d9fba2b8fcdce2dedeca97bbf1f369cc548d
|
||||
F test/alter4.test 8e93bf7a7e6919b14b0c9a6c1e4908bcf21b0165
|
||||
@@ -1127,7 +1127,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381
|
||||
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
|
||||
F tool/warnings.sh d1a6de74685f360ab718efda6265994b99bbea01
|
||||
F tool/win/sqlite.vsix 030f3eeaf2cb811a3692ab9c14d021a75ce41fff
|
||||
P a106ce86cd4afd1f81603826de77df1fb25e9ab5
|
||||
R 3388bfdb8db93d8349e384ecbd431368
|
||||
P 35a3606071685aa5196951f4bdddb136589ea216
|
||||
R 7bad51a408f97a3987f0c85c7f87eccd
|
||||
U drh
|
||||
Z b769ffc4c966dfcb9185c08b7ad2538c
|
||||
Z 6da9ec3dec29a9e1ff505c84577a827e
|
||||
|
||||
@@ -1 +1 @@
|
||||
35a3606071685aa5196951f4bdddb136589ea216
|
||||
3f8016dee24213ec83a02d71ad2698789cc3a818
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
24
src/insert.c
24
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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 */
|
||||
|
||||
30
src/where.c
30
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;
|
||||
|
||||
@@ -863,6 +863,7 @@ foreach {tn tbl} $system_table_list {
|
||||
#------------------------------------------------------------------------
|
||||
# Verify that ALTER TABLE works on tables with the WITHOUT rowid option.
|
||||
#
|
||||
if 0 {
|
||||
do_execsql_test alter-16.1 {
|
||||
CREATE TABLE t16a(a TEXT, b REAL, c INT, PRIMARY KEY(a,b)) WITHOUT rowid;
|
||||
INSERT INTO t16a VALUES('abc',1.25,99);
|
||||
@@ -874,5 +875,6 @@ do_execsql_test alter-16.2 {
|
||||
ALTER TABLE t16a RENAME TO t16a_rn;
|
||||
SELECT * FROM t16a_rn ORDER BY a;
|
||||
} {abc 1.25 99 xyzzy cba 5.5 98 fizzle}
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
Reference in New Issue
Block a user