Index: src/build.c ================================================================== --- src/build.c +++ src/build.c @@ -1842,11 +1842,11 @@ return; } 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); } } iDb = sqlite3SchemaToIndex(db, p->pSchema); Index: src/parse.y ================================================================== --- src/parse.y +++ src/parse.y @@ -164,11 +164,11 @@ } %type table_options {u8} table_options(A) ::= . {A = 0;} table_options(A) ::= WITHOUT nm(X). { if( X.n==5 && sqlite3_strnicmp(X.z,"rowid",5)==0 ){ - A = TF_WithoutRowid; + A = TF_WithoutRowid | TF_NoVisibleRowid; }else{ A = 0; sqlite3ErrorMsg(pParse, "unknown table option: %.*s", X.n, X.z); } } Index: src/resolve.c ================================================================== --- src/resolve.c +++ src/resolve.c @@ -356,11 +356,11 @@ iCol = -1; } break; } } - if( iCol>=pTab->nCol && sqlite3IsRowid(zCol) && HasRowid(pTab) ){ + if( iCol>=pTab->nCol && sqlite3IsRowid(zCol) && VisibleRowid(pTab) ){ /* IMP: R-51414-32910 */ /* IMP: R-44911-55124 */ iCol = -1; } if( iColnCol ){ @@ -386,11 +386,11 @@ /* ** Perhaps the name is a reference to the ROWID */ if( cnt==0 && cntTab==1 && pMatch && sqlite3IsRowid(zCol) - && HasRowid(pMatch->pTab) ){ + && VisibleRowid(pMatch->pTab) ){ cnt = 1; pExpr->iColumn = -1; /* IMP: R-44911-55124 */ pExpr->affinity = SQLITE_AFF_INTEGER; } Index: src/select.c ================================================================== --- src/select.c +++ src/select.c @@ -3989,11 +3989,11 @@ if( pTab==0 ) return WRC_Abort; pTab->nRef = 1; pTab->zName = sqlite3DbStrDup(db, pCte->zName); pTab->iPKey = -1; pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) ); - pTab->tabFlags |= TF_Ephemeral; + pTab->tabFlags |= TF_Ephemeral | TF_NoVisibleRowid; pFrom->pSelect = sqlite3SelectDup(db, pCte->pSelect, 0); if( db->mallocFailed ) return SQLITE_NOMEM; assert( pFrom->pSelect ); /* Check if this is a recursive CTE. */ Index: src/sqliteInt.h ================================================================== --- src/sqliteInt.h +++ src/sqliteInt.h @@ -1632,12 +1632,13 @@ #define TF_Readonly 0x01 /* Read-only system table */ #define TF_Ephemeral 0x02 /* An ephemeral table */ #define TF_HasPrimaryKey 0x04 /* Table has a primary key */ #define TF_Autoincrement 0x08 /* Integer primary key is autoincrement */ #define TF_Virtual 0x10 /* Is a virtual table */ -#define TF_WithoutRowid 0x20 /* No rowid used. PRIMARY KEY is the key */ -#define TF_OOOHidden 0x40 /* Out-of-Order hidden columns */ +#define TF_WithoutRowid 0x20 /* No rowid. PRIMARY KEY is the key */ +#define TF_NoVisibleRowid 0x40 /* No user-visible "rowid" column */ +#define TF_OOOHidden 0x80 /* Out-of-Order hidden columns */ /* ** Test to see whether or not a table is a virtual table. This is ** done as a macro so that it will be optimized out when virtual @@ -1651,10 +1652,11 @@ # define IsHiddenColumn(X) 0 #endif /* Does the table have a rowid */ #define HasRowid(X) (((X)->tabFlags & TF_WithoutRowid)==0) +#define VisibleRowid(X) (((X)->tabFlags & TF_NoVisibleRowid)==0) /* ** Each foreign key constraint is an instance of the following structure. ** ** A foreign key is associated with two tables. The "from" table is Index: test/with1.test ================================================================== --- test/with1.test +++ test/with1.test @@ -846,7 +846,16 @@ # 2015-04-12 # do_execsql_test 14.1 { WITH x AS (SELECT * FROM t) SELECT 0 EXCEPT SELECT 0 ORDER BY 1 COLLATE binary; } {} + +# 2015-05-27: Do not allow rowid usage within a CTE +# +do_catchsql_test 15.1 { + WITH RECURSIVE + d(x) AS (VALUES(1) UNION ALL SELECT rowid+1 FROM d WHERE rowid<10) + SELECT x FROM d; +} {1 {no such column: rowid}} + finish_test Index: test/without_rowid1.test ================================================================== --- test/without_rowid1.test +++ test/without_rowid1.test @@ -306,8 +306,27 @@ SELECT name FROM sqlite_master WHERE tbl_name = 't48'; } { ok t48 sqlite_autoindex_t48_2 } +# 2015-05-28: CHECK constraints can refer to the rowid in a +# rowid table, but not in a WITHOUT ROWID table. +# +do_execsql_test 7.1 { + CREATE TABLE t70a( + a INT CHECK( rowid!=33 ), + b TEXT PRIMARY KEY + ); + INSERT INTO t70a(a,b) VALUES(99,'hello'); +} {} +do_catchsql_test 7.2 { + INSERT INTO t70a(rowid,a,b) VALUES(33,99,'xyzzy'); +} {1 {CHECK constraint failed: t70a}} +do_catchsql_test 7.3 { + CREATE TABLE t70b( + a INT CHECK( rowid!=33 ), + b TEXT PRIMARY KEY + ) WITHOUT ROWID; +} {1 {no such column: rowid}} finish_test