mirror of
https://github.com/sqlite/sqlite.git
synced 2025-07-29 08:01:23 +03:00
Added support for the INTEGER PRIMARY KEY column type. (CVS 333)
FossilOrigin-Name: 236a54d289e858a1e0505a20d907a2a40c01b521
This commit is contained in:
33
manifest
33
manifest
@ -1,9 +1,9 @@
|
||||
C Added\sthe\sability\sto\ssay\sthings\slike\s"SELECT\srowid,\s*\sFROM\stable1;"\s(CVS\s332)
|
||||
D 2001-12-16T20:05:05
|
||||
C Added\ssupport\sfor\sthe\sINTEGER\sPRIMARY\sKEY\scolumn\stype.\s(CVS\s333)
|
||||
D 2001-12-21T14:30:43
|
||||
F Makefile.in 352fed589f09dd94347e0bb391d047118ebd6105
|
||||
F Makefile.template 0fbf0ee1fe38183d760170a13e91fffec64e73f5
|
||||
F README a4c0ba11354ef6ba0776b400d057c59da47a4cc0
|
||||
F VERSION 380c16915706a90410eb148b6266d51f0d49ad8b
|
||||
F VERSION 353ee68ca2468dce6464d331044643d350fd256f
|
||||
F aclocal.m4 11faa843caa38fd451bc6aeb43e248d1723a269d
|
||||
F config.guess f38b1e93d1e0fa6f5a6913e9e7b12774b9232588
|
||||
F config.log 6a73d03433669b10a3f0c221198c3f26b9413914
|
||||
@ -21,35 +21,35 @@ F publish.sh cb0f8f7bcb65b8360d0f6668a216a9ac9d5da892
|
||||
F src/TODO af7f3cab0228e34149cf98e073aa83d45878e7e6
|
||||
F src/btree.c c3c36b3b5f07c3efdabf76df9ea423086b1ce142
|
||||
F src/btree.h 8767bd4ecf841c4999b7aee6876906bd607546e7
|
||||
F src/build.c 5127f737837a9d2a8cb4b998dbab505c08b8f06a
|
||||
F src/delete.c 5d93a21c1388cfb1359bda01c072f25583a2f4f2
|
||||
F src/expr.c 6b25c5bb1e750af2e2217c0134a7aa1fc0b11444
|
||||
F src/build.c 36b3bf95bb2f0bdf1d19436b8af5125997c95735
|
||||
F src/delete.c f7690efc09ad6a2f1f3f0490e1b0cbb676bb95cf
|
||||
F src/expr.c ef1c365c5d558fa691878830501d3c36ed7edb25
|
||||
F src/hash.c 6f1a7712ae3aac8351662969aec5693740a2fbf7
|
||||
F src/hash.h a5f5b3ce2d086a172c5879b0b06a27a82eac9fac
|
||||
F src/insert.c 3526be771a01035198bef28d8f370cbcab94f46d
|
||||
F src/main.c e5fa4773e6684b81fc0bcd9d9ae4578d56660c0c
|
||||
F src/insert.c 18353ee08ee29241e147187c63ade3669b0af007
|
||||
F src/main.c 00a9f5603e130fc0b1a05f731731c9c99ebdc2dc
|
||||
F src/md5.c 52f677bfc590e09f71d07d7e327bd59da738d07c
|
||||
F src/os.c 07882cde5c61f26751b8ee76fd84726c1f7e453c
|
||||
F src/os.h 00a18e0ae1139a64f1d3ead465ae2b9ff43f3db2
|
||||
F src/pager.c dde0eb5bf9af0ac0ff8a4429b2bee2aec2194ec9
|
||||
F src/pager.h f78d064c780855ff70beacbeba0e2324471b26fe
|
||||
F src/parse.y 23ff6728eb2f5d3052fe8b1c311bfd55d9fb0944
|
||||
F src/parse.y c62f32e332c291612a3a2e856ab48b636c82ee03
|
||||
F src/printf.c 300a90554345751f26e1fc0c0333b90a66110a1d
|
||||
F src/random.c 2a9cc2c9716d14815fd4c2accf89d87a1143e46b
|
||||
F src/select.c 76a8fafb29935865ddbef263ee90f1398d950d8b
|
||||
F src/shell.c 407095aaeeae78f42deb3e846b1ad77f8ed3b4ef
|
||||
F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e
|
||||
F src/sqlite.h.in 934de9112747ad8d8e7d5fec44876246b24ca5a3
|
||||
F src/sqliteInt.h 3990eeee362d1fb48dff841b56b7fe39577ea590
|
||||
F src/sqliteInt.h 0b1e8ba2738440e2f06a4e01bb89230492bc203b
|
||||
F src/table.c c89698bd5bb4b8d14722d6ee7e9be014c383d24a
|
||||
F src/tclsqlite.c b82e4faeae89fdb7304b3c970979ade299336a1f
|
||||
F src/test1.c 41eabe255970ef947263b94145c9b2766bab8675
|
||||
F src/test2.c e9f99aa5ee73872819259d6612c11e55e1644321
|
||||
F src/test3.c d6775f95fd91f5b3cf0e2382a28e5aaeb68f745b
|
||||
F src/tokenize.c 830e9ef684334070a26583d94770bb869e2727bf
|
||||
F src/update.c 365f6fafe75f6816a598e76031b0a757d91c003d
|
||||
F src/update.c 9c266e5c9d1beba74475fd2fb8078dc3d5b23182
|
||||
F src/util.c 13dcd870ee0e424f5427e8178480ca1b1833a706
|
||||
F src/vdbe.c f1afb7a82016be2cb4cea24cf98dbb5af0ea7214
|
||||
F src/vdbe.c 49227b52911dcc6811d5c71d36024172feb22195
|
||||
F src/vdbe.h cd4c8647051a0c22c0e133c375f1cd17bb8b1e06
|
||||
F src/where.c 05d27a01e53c20b8cd10589b7e789b2a64367988
|
||||
F test/all.test 2a51e5395ac7c2c539689b123b9782a05e3837fe
|
||||
@ -65,6 +65,7 @@ F test/in.test 9323681388be301dc73f370b4cd62c5a33f79d1e
|
||||
F test/index.test c8a471243bbf878974b99baf5badd59407237cf3
|
||||
F test/insert.test a5c122aa726f1cef6f07d6767e8fd6f220994c11
|
||||
F test/insert2.test d6901ca931e308fea7fca8c95ebe7dc957cc9fc2
|
||||
F test/intpkey.test 79be8360e6f0a5506b513f3ab4399da797cd8b3e
|
||||
F test/ioerr.test 57d9bffaca18b34f9e976f786eadc2591d6efc6a
|
||||
F test/limit.test a930f3eba2a7691c8397ccab33710b931589566a
|
||||
F test/lock.test 19593689260c419efe7ced55b1418653a4b7bcd1
|
||||
@ -89,7 +90,7 @@ F test/tclsqlite.test feca0f2b23ba51d202d67d71e10ba7a8a1621f82
|
||||
F test/temptable.test 37acd9e39781c2ff7cff2ba741b6b27ce020a44a
|
||||
F test/tester.tcl 96db1b49157388edb57e11bf33285e3811a897e4
|
||||
F test/trans.test 855337b8a178c73c433fcf8ee88e4b2f5efff0d9
|
||||
F test/unique.test ef1f67607a7109e9c0842cd8557550fb121d7ec6
|
||||
F test/unique.test 07776624b82221a80c8b4138ce0dd8b0853bb3ea
|
||||
F test/update.test 3cf1ca0565f678063c2dfa9a7948d2d66ae1a778
|
||||
F test/vacuum.test 8acf8669f3b627e54149b25165b034aa06c2432e
|
||||
F test/where.test 20b19475fe894b86b06d2979592260dd16beeb17
|
||||
@ -117,7 +118,7 @@ F www/speed.tcl 83457b2bf6bb430900bd48ca3dd98264d9a916a5
|
||||
F www/sqlite.tcl 8b5884354cb615049aed83039f8dfe1552a44279
|
||||
F www/tclsqlite.tcl 880ef67cb4f2797b95bf1368fc4e0d8ca0fda956
|
||||
F www/vdbe.tcl 2013852c27a02a091d39a766bc87cff329f21218
|
||||
P e8595579a5218aa3f344f967a23ac52ea89daca1
|
||||
R 0e3b3ee92605e01cba0081d64199478c
|
||||
P ffbdd43f5de62e7bf81631c83473aca29c3a6c98
|
||||
R 56465183b3eaba81097d58ab4fff365b
|
||||
U drh
|
||||
Z 9f8a16e7e900ed26b3f50785c874bb79
|
||||
Z 8ca8d028861bf23d8008c82aec39ab1e
|
||||
|
@ -1 +1 @@
|
||||
ffbdd43f5de62e7bf81631c83473aca29c3a6c98
|
||||
236a54d289e858a1e0505a20d907a2a40c01b521
|
62
src/build.c
62
src/build.c
@ -25,7 +25,7 @@
|
||||
** ROLLBACK
|
||||
** PRAGMA
|
||||
**
|
||||
** $Id: build.c,v 1.59 2001/12/15 02:35:59 drh Exp $
|
||||
** $Id: build.c,v 1.60 2001/12/21 14:30:43 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <ctype.h>
|
||||
@ -268,7 +268,7 @@ void sqliteCommitInternalChanges(sqlite *db){
|
||||
}
|
||||
sqliteHashClear(&toDelete);
|
||||
for(pElem=sqliteHashFirst(&db->idxHash); pElem; pElem=sqliteHashNext(pElem)){
|
||||
Table *pIndex = sqliteHashData(pElem);
|
||||
Index *pIndex = sqliteHashData(pElem);
|
||||
if( pIndex->isDelete ){
|
||||
sqliteHashInsert(&toDelete, pIndex, 0, pIndex);
|
||||
}else{
|
||||
@ -311,7 +311,7 @@ void sqliteRollbackInternalChanges(sqlite *db){
|
||||
}
|
||||
sqliteHashClear(&toDelete);
|
||||
for(pElem=sqliteHashFirst(&db->idxHash); pElem; pElem=sqliteHashNext(pElem)){
|
||||
Table *pIndex = sqliteHashData(pElem);
|
||||
Index *pIndex = sqliteHashData(pElem);
|
||||
if( !pIndex->isCommit ){
|
||||
sqliteHashInsert(&toDelete, pIndex, 0, pIndex);
|
||||
}else{
|
||||
@ -425,6 +425,7 @@ void sqliteStartTable(Parse *pParse, Token *pStart, Token *pName, int isTemp){
|
||||
pTable->zName = zName;
|
||||
pTable->nCol = 0;
|
||||
pTable->aCol = 0;
|
||||
pTable->iPKey = -1;
|
||||
pTable->pIndex = 0;
|
||||
pTable->isTemp = isTemp;
|
||||
if( pParse->pNewTable ) sqliteDeleteTable(db, pParse->pNewTable);
|
||||
@ -436,6 +437,7 @@ void sqliteStartTable(Parse *pParse, Token *pStart, Token *pName, int isTemp){
|
||||
pParse->schemaVerified = 1;
|
||||
}
|
||||
if( !isTemp ){
|
||||
sqliteVdbeAddOp(v, OP_SetCookie, db->file_format, 1);
|
||||
sqliteVdbeAddOp(v, OP_OpenWrite, 0, 2);
|
||||
sqliteVdbeChangeP3(v, -1, MASTER_NAME, P3_STATIC);
|
||||
}
|
||||
@ -534,6 +536,56 @@ void sqliteAddDefaultValue(Parse *pParse, Token *pVal, int minusFlag){
|
||||
sqliteDequote(*pz);
|
||||
}
|
||||
|
||||
/*
|
||||
** 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.
|
||||
**
|
||||
** A table can have at most one primary key. If the table already has
|
||||
** a primary key (and this is the second primary key) then create an
|
||||
** error.
|
||||
**
|
||||
** If the PRIMARY KEY is on a single column whose datatype is INTEGER,
|
||||
** then we will try to use that column as the row id. (Exception:
|
||||
** For backwards compatibility with older databases, do not do this
|
||||
** if the file format version number is less than 1.) Set the Table.iPKey
|
||||
** field of the table under construction to be the index of the
|
||||
** INTEGER PRIMARY KEY column. Table.iPKey is set to -1 if there is
|
||||
** no INTEGER PRIMARY KEY.
|
||||
**
|
||||
** If the key is not an INTEGER PRIMARY KEY, then create a unique
|
||||
** index for the key. No index is created for INTEGER PRIMARY KEYs.
|
||||
*/
|
||||
void sqliteAddPrimaryKey(Parse *pParse, IdList *pList){
|
||||
Table *pTab = pParse->pNewTable;
|
||||
char *zType = 0;
|
||||
int iCol = -1;
|
||||
if( pTab==0 ) return;
|
||||
if( pTab->hasPrimKey ){
|
||||
sqliteSetString(&pParse->zErrMsg, "table \"", pTab->zName,
|
||||
"\" has more than one primary key", 0);
|
||||
pParse->nErr++;
|
||||
return;
|
||||
}
|
||||
pTab->hasPrimKey = 1;
|
||||
if( pList==0 ){
|
||||
iCol = pTab->nCol - 1;
|
||||
}else if( pList->nId==1 ){
|
||||
for(iCol=0; iCol<pTab->nCol; iCol++){
|
||||
if( sqliteStrICmp(pList->a[0].zName, pTab->aCol[iCol].zName)==0 ) break;
|
||||
}
|
||||
}
|
||||
if( iCol>=0 && iCol<pTab->nCol ){
|
||||
zType = pTab->aCol[iCol].zType;
|
||||
}
|
||||
if( pParse->db->file_format>=1 &&
|
||||
zType && sqliteStrICmp(zType, "INTEGER")==0 ){
|
||||
pTab->iPKey = iCol;
|
||||
}else{
|
||||
sqliteCreateIndex(pParse, 0, 0, pList, 1, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Come up with a new random value for the schema cookie. Make sure
|
||||
** the new value is different from the old.
|
||||
@ -787,8 +839,8 @@ void sqliteCreateIndex(
|
||||
|
||||
/* If this index is created while re-reading the schema from sqlite_master
|
||||
** but the table associated with this index is a temporary table, it can
|
||||
** only mean that the table this index is really associated with is one
|
||||
** whose name is hidden behind a temporary table with the same name.
|
||||
** only mean that the table that this index is really associated with is
|
||||
** one whose name is hidden behind a temporary table with the same name.
|
||||
** Since its table has been suppressed, we need to also suppress the
|
||||
** index.
|
||||
*/
|
||||
|
@ -12,7 +12,7 @@
|
||||
** This file contains C code routines that are called by the parser
|
||||
** to handle DELETE FROM statements.
|
||||
**
|
||||
** $Id: delete.c,v 1.21 2001/11/07 16:48:27 drh Exp $
|
||||
** $Id: delete.c,v 1.22 2001/12/21 14:30:43 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
@ -157,7 +157,12 @@ void sqliteDeleteFrom(
|
||||
int j;
|
||||
sqliteVdbeAddOp(v, OP_Recno, base, 0);
|
||||
for(j=0; j<pIdx->nColumn; j++){
|
||||
sqliteVdbeAddOp(v, OP_Column, base, pIdx->aiColumn[j]);
|
||||
int idx = pIdx->aiColumn[j];
|
||||
if( idx==pTab->iPKey ){
|
||||
sqliteVdbeAddOp(v, OP_Dup, j, 0);
|
||||
}else{
|
||||
sqliteVdbeAddOp(v, OP_Column, base, idx);
|
||||
}
|
||||
}
|
||||
sqliteVdbeAddOp(v, OP_MakeIdxKey, pIdx->nColumn, 0);
|
||||
sqliteVdbeAddOp(v, OP_IdxDelete, base+i, 0);
|
||||
|
16
src/expr.c
16
src/expr.c
@ -12,7 +12,7 @@
|
||||
** This file contains routines used for analyzing expressions and
|
||||
** for generating VDBE code that evaluates expressions in SQLite.
|
||||
**
|
||||
** $Id: expr.c,v 1.34 2001/11/24 00:31:46 drh Exp $
|
||||
** $Id: expr.c,v 1.35 2001/12/21 14:30:43 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
@ -127,7 +127,12 @@ int sqliteExprResolveIds(Parse *pParse, IdList *pTabList, Expr *pExpr){
|
||||
if( sqliteStrICmp(pTab->aCol[j].zName, z)==0 ){
|
||||
cnt++;
|
||||
pExpr->iTable = i + pParse->nTab;
|
||||
pExpr->iColumn = j;
|
||||
if( j==pTab->iPKey ){
|
||||
/* Substitute the record number for the INTEGER PRIMARY KEY */
|
||||
pExpr->iColumn = -1;
|
||||
}else{
|
||||
pExpr->iColumn = j;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -190,7 +195,12 @@ int sqliteExprResolveIds(Parse *pParse, IdList *pTabList, Expr *pExpr){
|
||||
if( sqliteStrICmp(pTab->aCol[j].zName, zRight)==0 ){
|
||||
cnt++;
|
||||
pExpr->iTable = i + pParse->nTab;
|
||||
pExpr->iColumn = j;
|
||||
if( j==pTab->iPKey ){
|
||||
/* Substitute the record number for the INTEGER PRIMARY KEY */
|
||||
pExpr->iColumn = -1;
|
||||
}else{
|
||||
pExpr->iColumn = j;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
58
src/insert.c
58
src/insert.c
@ -12,7 +12,7 @@
|
||||
** This file contains C code routines that are called by the parser
|
||||
** to handle INSERT statements in SQLite.
|
||||
**
|
||||
** $Id: insert.c,v 1.26 2001/11/07 16:48:27 drh Exp $
|
||||
** $Id: insert.c,v 1.27 2001/12/21 14:30:43 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
@ -49,6 +49,7 @@ void sqliteInsert(
|
||||
int iCont, iBreak; /* Beginning and end of the loop over srcTab */
|
||||
sqlite *db; /* The main database structure */
|
||||
int openOp; /* Opcode used to open cursors */
|
||||
int keyColumn = -1; /* Column that is the INTEGER PRIMARY KEY */
|
||||
|
||||
if( pParse->nErr || sqlite_malloc_failed ) goto insert_cleanup;
|
||||
db = pParse->db;
|
||||
@ -140,6 +141,9 @@ void sqliteInsert(
|
||||
for(j=0; j<pTab->nCol; j++){
|
||||
if( sqliteStrICmp(pColumn->a[i].zName, pTab->aCol[j].zName)==0 ){
|
||||
pColumn->a[i].idx = j;
|
||||
if( j==pTab->iPKey ){
|
||||
keyColumn = j;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -152,6 +156,13 @@ void sqliteInsert(
|
||||
}
|
||||
}
|
||||
|
||||
/* If there is not IDLIST term but the table has an integer primary
|
||||
** key, the set the keyColumn variable to the primary key column.
|
||||
*/
|
||||
if( pColumn==0 ){
|
||||
keyColumn = pTab->iPKey;
|
||||
}
|
||||
|
||||
/* Open cursors into the table that is received the new data and
|
||||
** all indices of that table.
|
||||
*/
|
||||
@ -178,13 +189,41 @@ void sqliteInsert(
|
||||
iCont = sqliteVdbeCurrentAddr(v);
|
||||
}
|
||||
|
||||
/* Create a new entry in the table and fill it with data.
|
||||
/* Push the record number for the new entry onto the stack. The
|
||||
** record number is a randomly generate integer created by NewRecno
|
||||
** except when the table has an INTEGER PRIMARY KEY column, in which
|
||||
** case the record number is the same as that column.
|
||||
*/
|
||||
if( keyColumn>=0 ){
|
||||
if( srcTab>=0 ){
|
||||
sqliteVdbeAddOp(v, OP_Column, srcTab, keyColumn);
|
||||
}else{
|
||||
sqliteExprCode(pParse, pList->a[keyColumn].pExpr);
|
||||
}
|
||||
sqliteVdbeAddOp(v, OP_AddImm, 0, 0); /* Make sure ROWID is an integer */
|
||||
}else{
|
||||
sqliteVdbeAddOp(v, OP_NewRecno, base, 0);
|
||||
}
|
||||
|
||||
/* If there are indices, we'll need this record number again, so make
|
||||
** a copy.
|
||||
*/
|
||||
sqliteVdbeAddOp(v, OP_NewRecno, base, 0);
|
||||
if( pTab->pIndex ){
|
||||
sqliteVdbeAddOp(v, OP_Dup, 0, 0);
|
||||
}
|
||||
|
||||
/* Push onto the stack data for all columns of the new entry, beginning
|
||||
** with the first column.
|
||||
*/
|
||||
for(i=0; i<pTab->nCol; i++){
|
||||
if( i==pTab->iPKey ){
|
||||
/* The value of the INTEGER PRIMARY KEY column is always a NULL.
|
||||
** Whenever this column is used, the record number will be substituted
|
||||
** in its place, so there is no point it it taking up space in
|
||||
** the data record. */
|
||||
sqliteVdbeAddOp(v, OP_String, 0, 0);
|
||||
continue;
|
||||
}
|
||||
if( pColumn==0 ){
|
||||
j = i;
|
||||
}else{
|
||||
@ -201,10 +240,12 @@ void sqliteInsert(
|
||||
sqliteExprCode(pParse, pList->a[j].pExpr);
|
||||
}
|
||||
}
|
||||
sqliteVdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0);
|
||||
sqliteVdbeAddOp(v, OP_Put, base, 0);
|
||||
|
||||
|
||||
/* Create the new record and put it into the database.
|
||||
*/
|
||||
sqliteVdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0);
|
||||
sqliteVdbeAddOp(v, OP_Put, base, keyColumn>=0);
|
||||
|
||||
/* Create appropriate entries for the new data row in all indices
|
||||
** of the table.
|
||||
*/
|
||||
@ -214,6 +255,11 @@ void sqliteInsert(
|
||||
}
|
||||
for(i=0; i<pIdx->nColumn; i++){
|
||||
int idx = pIdx->aiColumn[i];
|
||||
if( idx==pTab->iPKey ){
|
||||
/* Copy the record number in place of the INTEGER PRIMARY KEY column */
|
||||
sqliteVdbeAddOp(v, OP_Dup, i, 0);
|
||||
continue;
|
||||
}
|
||||
if( pColumn==0 ){
|
||||
j = idx;
|
||||
}else{
|
||||
|
97
src/main.c
97
src/main.c
@ -14,7 +14,7 @@
|
||||
** other files are for internal use by SQLite and should not be
|
||||
** accessed by users of the library.
|
||||
**
|
||||
** $Id: main.c,v 1.51 2001/12/05 00:21:20 drh Exp $
|
||||
** $Id: main.c,v 1.52 2001/12/21 14:30:43 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "os.h"
|
||||
@ -25,7 +25,7 @@
|
||||
**
|
||||
** Each callback contains the following information:
|
||||
**
|
||||
** argv[0] = "meta" or "table" or "index"
|
||||
** argv[0] = "file-format" or "schema-cookie" or "table" or "index"
|
||||
** argv[1] = table or index name or meta statement type.
|
||||
** argv[2] = root page number for table or index. NULL for meta.
|
||||
** argv[3] = SQL create statement for the table or index
|
||||
@ -42,13 +42,13 @@ static int sqliteOpenCb(void *pDb, int argc, char **argv, char **azColName){
|
||||
|
||||
assert( argc==4 );
|
||||
switch( argv[0][0] ){
|
||||
case 'm': { /* Meta information */
|
||||
if( strcmp(argv[1],"file-format")==0 ){
|
||||
db->file_format = atoi(argv[3]);
|
||||
}else if( strcmp(argv[1],"schema-cookie")==0 ){
|
||||
db->schema_cookie = atoi(argv[3]);
|
||||
db->next_cookie = db->schema_cookie;
|
||||
}
|
||||
case 'f': { /* File format */
|
||||
db->file_format = atoi(argv[3]);
|
||||
break;
|
||||
}
|
||||
case 's': { /* Schema cookie */
|
||||
db->schema_cookie = atoi(argv[3]);
|
||||
db->next_cookie = db->schema_cookie;
|
||||
break;
|
||||
}
|
||||
case 'i':
|
||||
@ -156,44 +156,39 @@ static int sqliteInit(sqlite *db, char **pzErrMsg){
|
||||
** database scheme.
|
||||
*/
|
||||
static VdbeOp initProg[] = {
|
||||
{ OP_Open, 0, 2, 0},
|
||||
{ OP_Rewind, 0, 31, 0},
|
||||
{ OP_Column, 0, 0, 0}, /* 2 */
|
||||
{ OP_String, 0, 0, "meta"},
|
||||
{ OP_Ne, 0, 10, 0},
|
||||
{ OP_Column, 0, 0, 0},
|
||||
{ OP_Column, 0, 1, 0},
|
||||
{ OP_Column, 0, 3, 0},
|
||||
{ OP_Column, 0, 4, 0},
|
||||
{ OP_Callback, 4, 0, 0},
|
||||
{ OP_Next, 0, 2, 0}, /* 10 */
|
||||
{ OP_Rewind, 0, 31, 0}, /* 11 */
|
||||
{ OP_Column, 0, 0, 0}, /* 12 */
|
||||
{ OP_String, 0, 0, "table"},
|
||||
{ OP_Ne, 0, 20, 0},
|
||||
{ OP_Column, 0, 0, 0},
|
||||
{ OP_Column, 0, 1, 0},
|
||||
{ OP_Column, 0, 3, 0},
|
||||
{ OP_Column, 0, 4, 0},
|
||||
{ OP_Callback, 4, 0, 0},
|
||||
{ OP_Next, 0, 12, 0}, /* 20 */
|
||||
{ OP_Rewind, 0, 31, 0}, /* 21 */
|
||||
{ OP_Column, 0, 0, 0}, /* 22 */
|
||||
{ OP_String, 0, 0, "index"},
|
||||
{ OP_Ne, 0, 30, 0},
|
||||
{ OP_Column, 0, 0, 0},
|
||||
{ OP_Column, 0, 1, 0},
|
||||
{ OP_Column, 0, 3, 0},
|
||||
{ OP_Column, 0, 4, 0},
|
||||
{ OP_Callback, 4, 0, 0},
|
||||
{ OP_Next, 0, 22, 0}, /* 30 */
|
||||
{ OP_String, 0, 0, "meta"}, /* 31 */
|
||||
{ OP_String, 0, 0, "schema-cookie"},
|
||||
{ OP_String, 0, 0, 0},
|
||||
{ OP_ReadCookie,0,0, 0},
|
||||
{ OP_Callback, 4, 0, 0},
|
||||
{ OP_Close, 0, 0, 0},
|
||||
{ OP_Halt, 0, 0, 0},
|
||||
{ OP_Open, 0, 2, 0},
|
||||
{ OP_String, 0, 0, "file-format"},
|
||||
{ OP_String, 0, 0, 0},
|
||||
{ OP_String, 0, 0, 0},
|
||||
{ OP_ReadCookie, 0, 1, 0},
|
||||
{ OP_Callback, 4, 0, 0},
|
||||
{ OP_String, 0, 0, "schema_cookie"},
|
||||
{ OP_String, 0, 0, 0},
|
||||
{ OP_String, 0, 0, 0},
|
||||
{ OP_ReadCookie, 0, 0, 0},
|
||||
{ OP_Callback, 4, 0, 0},
|
||||
{ OP_Rewind, 0, 31, 0},
|
||||
{ OP_Column, 0, 0, 0}, /* 12 */
|
||||
{ OP_String, 0, 0, "table"},
|
||||
{ OP_Ne, 0, 20, 0},
|
||||
{ OP_Column, 0, 0, 0},
|
||||
{ OP_Column, 0, 1, 0},
|
||||
{ OP_Column, 0, 3, 0},
|
||||
{ OP_Column, 0, 4, 0},
|
||||
{ OP_Callback, 4, 0, 0},
|
||||
{ OP_Next, 0, 12, 0}, /* 20 */
|
||||
{ OP_Rewind, 0, 31, 0}, /* 21 */
|
||||
{ OP_Column, 0, 0, 0}, /* 22 */
|
||||
{ OP_String, 0, 0, "index"},
|
||||
{ OP_Ne, 0, 30, 0},
|
||||
{ OP_Column, 0, 0, 0},
|
||||
{ OP_Column, 0, 1, 0},
|
||||
{ OP_Column, 0, 3, 0},
|
||||
{ OP_Column, 0, 4, 0},
|
||||
{ OP_Callback, 4, 0, 0},
|
||||
{ OP_Next, 0, 22, 0}, /* 30 */
|
||||
{ OP_Close, 0, 0, 0}, /* 31 */
|
||||
{ OP_Halt, 0, 0, 0},
|
||||
};
|
||||
|
||||
/* Create a virtual machine to run the initialization program. Run
|
||||
@ -208,7 +203,10 @@ static int sqliteInit(sqlite *db, char **pzErrMsg){
|
||||
rc = sqliteVdbeExec(vdbe, sqliteOpenCb, db, pzErrMsg,
|
||||
db->pBusyArg, db->xBusyCallback);
|
||||
sqliteVdbeDelete(vdbe);
|
||||
if( rc==SQLITE_OK && db->file_format>1 && db->nTable>0 ){
|
||||
if( rc==SQLITE_OK && db->nTable==0 ){
|
||||
db->file_format = FILE_FORMAT;
|
||||
}
|
||||
if( rc==SQLITE_OK && db->file_format>FILE_FORMAT ){
|
||||
sqliteSetString(pzErrMsg, "unsupported file format", 0);
|
||||
rc = SQLITE_ERROR;
|
||||
}
|
||||
@ -282,9 +280,6 @@ sqlite *sqlite_open(const char *zFilename, int mode, char **pzErrMsg){
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Assume file format 1 unless the database says otherwise */
|
||||
db->file_format = 1;
|
||||
|
||||
/* Attempt to read the schema */
|
||||
rc = sqliteInit(db, pzErrMsg);
|
||||
if( sqlite_malloc_failed ){
|
||||
|
@ -14,7 +14,7 @@
|
||||
** the parser. Lemon will also generate a header file containing
|
||||
** numeric codes for all of the tokens.
|
||||
**
|
||||
** @(#) $Id: parse.y,v 1.39 2001/12/16 20:05:06 drh Exp $
|
||||
** @(#) $Id: parse.y,v 1.40 2001/12/21 14:30:43 drh Exp $
|
||||
*/
|
||||
%token_prefix TK_
|
||||
%token_type {Token}
|
||||
@ -138,7 +138,7 @@ carg ::= DEFAULT NULL.
|
||||
// UNIQUE constraints.
|
||||
//
|
||||
ccons ::= NOT NULL. {sqliteAddNotNull(pParse);}
|
||||
ccons ::= PRIMARY KEY sortorder. {sqliteCreateIndex(pParse,0,0,0,1,0,0);}
|
||||
ccons ::= PRIMARY KEY sortorder. {sqliteAddPrimaryKey(pParse, 0);}
|
||||
ccons ::= UNIQUE. {sqliteCreateIndex(pParse,0,0,0,1,0,0);}
|
||||
ccons ::= CHECK LP expr RP.
|
||||
|
||||
@ -151,7 +151,7 @@ conslist ::= conslist COMMA tcons.
|
||||
conslist ::= conslist tcons.
|
||||
conslist ::= tcons.
|
||||
tcons ::= CONSTRAINT ids.
|
||||
tcons ::= PRIMARY KEY LP idxlist(X) RP. {sqliteCreateIndex(pParse,0,0,X,1,0,0);}
|
||||
tcons ::= PRIMARY KEY LP idxlist(X) RP. {sqliteAddPrimaryKey(pParse,X);}
|
||||
tcons ::= UNIQUE LP idxlist(X) RP. {sqliteCreateIndex(pParse,0,0,X,1,0,0);}
|
||||
tcons ::= CHECK expr.
|
||||
|
||||
|
@ -11,7 +11,7 @@
|
||||
*************************************************************************
|
||||
** Internal interface definitions for SQLite.
|
||||
**
|
||||
** @(#) $Id: sqliteInt.h,v 1.72 2001/12/05 00:21:20 drh Exp $
|
||||
** @(#) $Id: sqliteInt.h,v 1.73 2001/12/21 14:30:43 drh Exp $
|
||||
*/
|
||||
#include "sqlite.h"
|
||||
#include "hash.h"
|
||||
@ -30,6 +30,11 @@
|
||||
#define MAX_PAGES 100
|
||||
#define TEMP_PAGES 25
|
||||
|
||||
/*
|
||||
** File format version number
|
||||
*/
|
||||
#define FILE_FORMAT 1
|
||||
|
||||
/*
|
||||
** Integers of known sizes. These typedefs might change for architectures
|
||||
** where the sizes very. Preprocessor macros are available so that the
|
||||
@ -213,7 +218,8 @@ struct Column {
|
||||
char *zName; /* Name of this column */
|
||||
char *zDflt; /* Default value of this column */
|
||||
char *zType; /* Data type for this column */
|
||||
int notNull; /* True if there is a NOT NULL constraint */
|
||||
u8 notNull; /* True if there is a NOT NULL constraint */
|
||||
u8 isPrimKey; /* True if this column is an INTEGER PRIMARY KEY */
|
||||
};
|
||||
|
||||
/*
|
||||
@ -224,12 +230,14 @@ struct Table {
|
||||
char *zName; /* Name of the table */
|
||||
int nCol; /* Number of columns in this table */
|
||||
Column *aCol; /* Information about each column */
|
||||
int iPKey; /* Use this column as the record-number for each row */
|
||||
Index *pIndex; /* List of SQL indexes on this table. */
|
||||
int tnum; /* Page containing root for this table */
|
||||
u8 readOnly; /* True if this table should not be written by the user */
|
||||
u8 isCommit; /* True if creation of this table has been committed */
|
||||
u8 isDelete; /* True if this table is being deleted */
|
||||
u8 isTemp; /* True if stored in db->pBeTemp instead of db->pBe */
|
||||
u8 hasPrimKey; /* True if there exists a primary key */
|
||||
};
|
||||
|
||||
/*
|
||||
|
52
src/update.c
52
src/update.c
@ -12,7 +12,7 @@
|
||||
** This file contains C code routines that are called by the parser
|
||||
** to handle UPDATE statements.
|
||||
**
|
||||
** $Id: update.c,v 1.22 2001/11/21 02:21:12 drh Exp $
|
||||
** $Id: update.c,v 1.23 2001/12/21 14:30:43 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
@ -40,6 +40,8 @@ void sqliteUpdate(
|
||||
** an expression for the i-th column of the table.
|
||||
** aXRef[i]==-1 if the i-th column is not changed. */
|
||||
int openOp; /* Opcode used to open tables */
|
||||
int chngRecno; /* True if the record number is being changed */
|
||||
Expr *pRecnoExpr; /* Expression defining the new record number */
|
||||
|
||||
if( pParse->nErr || sqlite_malloc_failed ) goto update_cleanup;
|
||||
db = pParse->db;
|
||||
@ -89,6 +91,7 @@ void sqliteUpdate(
|
||||
goto update_cleanup;
|
||||
}
|
||||
}
|
||||
chngRecno = 0;
|
||||
for(i=0; i<pChanges->nExpr; i++){
|
||||
if( sqliteExprResolveIds(pParse, pTabList, pChanges->a[i].pExpr) ){
|
||||
goto update_cleanup;
|
||||
@ -98,6 +101,10 @@ void sqliteUpdate(
|
||||
}
|
||||
for(j=0; j<pTab->nCol; j++){
|
||||
if( sqliteStrICmp(pTab->aCol[j].zName, pChanges->a[i].zName)==0 ){
|
||||
if( i==pTab->iPKey ){
|
||||
chngRecno = 1;
|
||||
pRecnoExpr = pChanges->a[i].pExpr;
|
||||
}
|
||||
aXRef[j] = i;
|
||||
break;
|
||||
}
|
||||
@ -115,8 +122,12 @@ void sqliteUpdate(
|
||||
** key includes one of the columns named in pChanges.
|
||||
*/
|
||||
for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
||||
for(i=0; i<pIdx->nColumn; i++){
|
||||
if( aXRef[pIdx->aiColumn[i]]>=0 ) break;
|
||||
if( chngRecno ){
|
||||
i = 0;
|
||||
}else {
|
||||
for(i=0; i<pIdx->nColumn; i++){
|
||||
if( aXRef[pIdx->aiColumn[i]]>=0 ) break;
|
||||
}
|
||||
}
|
||||
if( i<pIdx->nColumn ) nIdx++;
|
||||
}
|
||||
@ -125,8 +136,12 @@ void sqliteUpdate(
|
||||
if( apIdx==0 ) goto update_cleanup;
|
||||
}
|
||||
for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
||||
for(i=0; i<pIdx->nColumn; i++){
|
||||
if( aXRef[pIdx->aiColumn[i]]>=0 ) break;
|
||||
if( chngRecno ){
|
||||
i = 0;
|
||||
}else{
|
||||
for(i=0; i<pIdx->nColumn; i++){
|
||||
if( aXRef[pIdx->aiColumn[i]]>=0 ) break;
|
||||
}
|
||||
}
|
||||
if( i<pIdx->nColumn ) apIdx[nIdx++] = pIdx;
|
||||
}
|
||||
@ -175,6 +190,7 @@ void sqliteUpdate(
|
||||
** the old data for each record to be updated because some columns
|
||||
** might not change and we will need to copy the old value.
|
||||
** Also, the old data is needed to delete the old index entires.
|
||||
** So make the cursor point at the old record.
|
||||
*/
|
||||
end = sqliteVdbeMakeLabel(v);
|
||||
addr = sqliteVdbeAddOp(v, OP_ListRead, 0, end);
|
||||
@ -193,9 +209,22 @@ void sqliteUpdate(
|
||||
sqliteVdbeAddOp(v, OP_IdxDelete, base+i+1, 0);
|
||||
}
|
||||
|
||||
/* If changing the record number, remove the old record number
|
||||
** from the top of the stack and replace it with the new one.
|
||||
*/
|
||||
if( chngRecno ){
|
||||
sqliteVdbeAddOp(v, OP_Pop, 1, 0);
|
||||
sqliteExprCode(pParse, pRecnoExpr);
|
||||
sqliteVdbeAddOp(v, OP_AddImm, 0, 0);
|
||||
}
|
||||
|
||||
/* Compute new data for this record.
|
||||
*/
|
||||
for(i=0; i<pTab->nCol; i++){
|
||||
if( i==pTab->iPKey ){
|
||||
sqliteVdbeAddOp(v, OP_Dup, i, 0);
|
||||
continue;
|
||||
}
|
||||
j = aXRef[i];
|
||||
if( j<0 ){
|
||||
sqliteVdbeAddOp(v, OP_Column, base, i);
|
||||
@ -204,13 +233,24 @@ void sqliteUpdate(
|
||||
}
|
||||
}
|
||||
|
||||
/* If changing the record number, delete the hold record.
|
||||
*/
|
||||
if( chngRecno ){
|
||||
sqliteVdbeAddOp(v, OP_Delete, 0, 0);
|
||||
}
|
||||
|
||||
/* Insert new index entries that correspond to the new data
|
||||
*/
|
||||
for(i=0; i<nIdx; i++){
|
||||
sqliteVdbeAddOp(v, OP_Dup, pTab->nCol, 0); /* The KEY */
|
||||
pIdx = apIdx[i];
|
||||
for(j=0; j<pIdx->nColumn; j++){
|
||||
sqliteVdbeAddOp(v, OP_Dup, j+pTab->nCol-pIdx->aiColumn[j], 0);
|
||||
int idx = pIdx->aiColumn[j];
|
||||
if( idx==pTab->iPKey ){
|
||||
sqliteVdbeAddOp(v, OP_Dup, j, 0);
|
||||
}else{
|
||||
sqliteVdbeAddOp(v, OP_Dup, j+pTab->nCol-idx, 0);
|
||||
}
|
||||
}
|
||||
sqliteVdbeAddOp(v, OP_MakeIdxKey, pIdx->nColumn, 0);
|
||||
sqliteVdbeAddOp(v, OP_IdxPut, base+i+1, pIdx->isUnique);
|
||||
|
59
src/vdbe.c
59
src/vdbe.c
@ -30,7 +30,7 @@
|
||||
** But other routines are also provided to help in building up
|
||||
** a program instruction by instruction.
|
||||
**
|
||||
** $Id: vdbe.c,v 1.100 2001/11/13 19:35:15 drh Exp $
|
||||
** $Id: vdbe.c,v 1.101 2001/12/21 14:30:43 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <ctype.h>
|
||||
@ -1654,7 +1654,10 @@ case OP_ShiftRight: {
|
||||
|
||||
/* Opcode: AddImm P1 * *
|
||||
**
|
||||
** Add the value P1 to whatever is on top of the stack.
|
||||
** Add the value P1 to whatever is on top of the stack. The result
|
||||
** is always an integer.
|
||||
**
|
||||
** To force the top of the stack to be an integer, just add 0.
|
||||
*/
|
||||
case OP_AddImm: {
|
||||
int tos = p->tos;
|
||||
@ -2269,15 +2272,20 @@ case OP_Rollback: {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: ReadCookie * * *
|
||||
/* Opcode: ReadCookie * P2 *
|
||||
**
|
||||
** Read the schema cookie from the database file and push it onto the
|
||||
** When P2==0,
|
||||
** read the schema cookie from the database file and push it onto the
|
||||
** stack. The schema cookie is an integer that is used like a version
|
||||
** number for the database schema. Everytime the schema changes, the
|
||||
** cookie changes to a new random value. This opcode is used during
|
||||
** initialization to read the initial cookie value so that subsequent
|
||||
** database accesses can verify that the cookie has not changed.
|
||||
**
|
||||
** If P2>0, then read global database parameter number P2. There is
|
||||
** a small fixed number of global database parameters. P2==1 is the
|
||||
** database version number. Other parameters are currently unused.
|
||||
**
|
||||
** There must be a read-lock on the database (either a transaction
|
||||
** must be started or there must be an open cursor) before
|
||||
** executing this instruction.
|
||||
@ -2285,17 +2293,21 @@ case OP_Rollback: {
|
||||
case OP_ReadCookie: {
|
||||
int i = ++p->tos;
|
||||
int aMeta[SQLITE_N_BTREE_META];
|
||||
assert( pOp->p2<SQLITE_N_BTREE_META );
|
||||
VERIFY( if( NeedStack(p, p->tos) ) goto no_mem; )
|
||||
rc = sqliteBtreeGetMeta(pBt, aMeta);
|
||||
aStack[i].i = aMeta[1];
|
||||
aStack[i].i = aMeta[1+pOp->p2];
|
||||
aStack[i].flags = STK_Int;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: SetCookie P1 * *
|
||||
/* Opcode: SetCookie P1 P2 *
|
||||
**
|
||||
** This operation changes the value of the schema cookie on the database.
|
||||
** The new value is P1.
|
||||
** When P2==0,
|
||||
** this operation changes the value of the schema cookie on the database.
|
||||
** The new value is P1. When P2>0, the value of global database parameter
|
||||
** number P2 is changed. See ReadCookie for more information about
|
||||
** global database parametes.
|
||||
**
|
||||
** The schema cookie changes its value whenever the database schema changes.
|
||||
** That way, other processes can recognize when the schema has changed
|
||||
@ -2305,18 +2317,21 @@ case OP_ReadCookie: {
|
||||
*/
|
||||
case OP_SetCookie: {
|
||||
int aMeta[SQLITE_N_BTREE_META];
|
||||
assert( pOp->p2<SQLITE_N_BTREE_META );
|
||||
rc = sqliteBtreeGetMeta(pBt, aMeta);
|
||||
if( rc==SQLITE_OK ){
|
||||
aMeta[1] = pOp->p1;
|
||||
aMeta[1+pOp->p2] = pOp->p1;
|
||||
rc = sqliteBtreeUpdateMeta(pBt, aMeta);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: VerifyCookie P1 * *
|
||||
/* Opcode: VerifyCookie P1 P2 *
|
||||
**
|
||||
** Check the current value of the schema cookie and make sure it is
|
||||
** equal to P1. If it is not, abort with an SQLITE_SCHEMA error.
|
||||
** Check the value of global database parameter number P2 and make
|
||||
** sure it is equal to P1. P2==0 is the schema cookie. P1==1 is
|
||||
** the database version. If the values do not match, abort with
|
||||
** an SQLITE_SCHEMA error.
|
||||
**
|
||||
** The cookie changes its value whenever the database schema changes.
|
||||
** This operation is used to detect when that the cookie has changed
|
||||
@ -2328,8 +2343,9 @@ case OP_SetCookie: {
|
||||
*/
|
||||
case OP_VerifyCookie: {
|
||||
int aMeta[SQLITE_N_BTREE_META];
|
||||
assert( pOp->p2<SQLITE_N_BTREE_META );
|
||||
rc = sqliteBtreeGetMeta(pBt, aMeta);
|
||||
if( rc==SQLITE_OK && aMeta[1]!=pOp->p1 ){
|
||||
if( rc==SQLITE_OK && aMeta[1+pOp->p2]!=pOp->p1 ){
|
||||
sqliteSetString(pzErrMsg, "database schema has changed", 0);
|
||||
rc = SQLITE_SCHEMA;
|
||||
}
|
||||
@ -2613,7 +2629,7 @@ case OP_Found: {
|
||||
**
|
||||
** Get a new integer record number used as the key to a table.
|
||||
** The record number is not previously used as a key in the database
|
||||
** table that cursor P1 points to. The new record number pushed
|
||||
** table that cursor P1 points to. The new record number is pushed
|
||||
** onto the stack.
|
||||
*/
|
||||
case OP_NewRecno: {
|
||||
@ -2666,13 +2682,16 @@ case OP_NewRecno: {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: Put P1 * *
|
||||
/* Opcode: Put P1 P2 *
|
||||
**
|
||||
** Write an entry into the database file P1. A new entry is
|
||||
** created if it doesn't already exist or the data for an existing
|
||||
** entry is overwritten. The data is the value on the top of the
|
||||
** stack. The key is the next value down on the stack. The stack
|
||||
** is popped twice by this instruction.
|
||||
**
|
||||
** If P2==1 then overwriting is prohibited. If a prior entry with
|
||||
** the same key exists, an SQLITE_CONSTRAINT exception is raised.
|
||||
*/
|
||||
case OP_Put: {
|
||||
int tos = p->tos;
|
||||
@ -2691,6 +2710,16 @@ case OP_Put: {
|
||||
iKey = bigEndian(aStack[nos].i);
|
||||
zKey = (char*)&iKey;
|
||||
}
|
||||
if( pOp->p2 ){
|
||||
int res;
|
||||
rc = sqliteBtreeMoveto(p->aCsr[i].pCursor, zKey, nKey, &res);
|
||||
if( res==0 && rc==SQLITE_OK ){
|
||||
rc = SQLITE_CONSTRAINT;
|
||||
}
|
||||
if( rc!=SQLITE_OK ){
|
||||
goto abort_due_to_error;
|
||||
}
|
||||
}
|
||||
rc = sqliteBtreeInsert(p->aCsr[i].pCursor, zKey, nKey,
|
||||
zStack[tos], aStack[tos].n);
|
||||
}
|
||||
|
125
test/intpkey.test
Normal file
125
test/intpkey.test
Normal file
@ -0,0 +1,125 @@
|
||||
# 2001 September 15
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
# This file implements regression tests for SQLite library.
|
||||
#
|
||||
# This file implements tests for the special processing associated
|
||||
# with INTEGER PRIMARY KEY columns.
|
||||
#
|
||||
# $Id: intpkey.test,v 1.1 2001/12/21 14:30:44 drh Exp $
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
# Create a table with a primary key and a datatype other than
|
||||
# integer
|
||||
#
|
||||
do_test intpkey-1.0 {
|
||||
execsql {
|
||||
CREATE TABLE t1(a TEXT PRIMARY KEY, b, c);
|
||||
}
|
||||
} {}
|
||||
|
||||
# There should be an index associated with the primary key
|
||||
#
|
||||
do_test intpkey-1.1 {
|
||||
execsql {
|
||||
SELECT name FROM sqlite_master
|
||||
WHERE type='index' AND tbl_name='t1';
|
||||
}
|
||||
} {{(t1 autoindex 1)}}
|
||||
|
||||
# Now create a table with an integer primary key and verify that
|
||||
# there is no associated index.
|
||||
#
|
||||
do_test intpkey-1.2 {
|
||||
execsql {
|
||||
DROP TABLE t1;
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
|
||||
SELECT name FROM sqlite_master
|
||||
WHERE type='index' AND tbl_name='t1';
|
||||
}
|
||||
} {}
|
||||
|
||||
# Insert some records into the new table. Specify the primary key
|
||||
# and verify that the key is used as the record number.
|
||||
#
|
||||
do_test intpkey-1.3 {
|
||||
execsql {
|
||||
INSERT INTO t1 VALUES(5,'hello','world');
|
||||
}
|
||||
} {}
|
||||
do_test intpkey-1.4 {
|
||||
execsql {
|
||||
SELECT * FROM t1;
|
||||
}
|
||||
} {5 hello world}
|
||||
do_test intpkey-1.5 {
|
||||
execsql {
|
||||
SELECT rowid, * FROM t1;
|
||||
}
|
||||
} {5 5 hello world}
|
||||
|
||||
# Attempting to insert a duplicate primary key should give a constraint
|
||||
# failure.
|
||||
#
|
||||
do_test intpkey-1.6 {
|
||||
set r [catch {execsql {
|
||||
INSERT INTO t1 VALUES(5,'second','entry');
|
||||
}} msg]
|
||||
lappend r $msg
|
||||
} {1 {constraint failed}}
|
||||
do_test intpkey-1.7 {
|
||||
execsql {
|
||||
SELECT rowid, * FROM t1;
|
||||
}
|
||||
} {5 5 hello world}
|
||||
do_test intpkey-1.8 {
|
||||
set r [catch {execsql {
|
||||
INSERT INTO t1 VALUES(6,'second','entry');
|
||||
}} msg]
|
||||
lappend r $msg
|
||||
} {0 {}}
|
||||
do_test intpkey-1.9 {
|
||||
execsql {
|
||||
SELECT rowid, * FROM t1;
|
||||
}
|
||||
} {5 5 hello world 6 6 second entry}
|
||||
|
||||
# A ROWID is automatically generated for new records that do not specify
|
||||
# the integer primary key.
|
||||
#
|
||||
do_test intpkey-1.10 {
|
||||
execsql {
|
||||
INSERT INTO t1(b,c) VALUES('one','two');
|
||||
SELECT b FROM t1 ORDER BY b;
|
||||
}
|
||||
} {hello one second}
|
||||
|
||||
# Try to change the ROWID for the new entry.
|
||||
#
|
||||
do_test intpkey-1.11 {
|
||||
execsql {
|
||||
UPDATE t1 SET a=7 WHERE b='one';
|
||||
SELECT * FROM t1;
|
||||
}
|
||||
} {5 hello world 6 second entry 7 one two}
|
||||
|
||||
# Make sure SELECT statements are able to use the primary key column
|
||||
# as an index.
|
||||
#
|
||||
do_test intpkey-1.12 {
|
||||
execsql {
|
||||
SELECT * FROM t1 WHERE a==7;
|
||||
}
|
||||
} {7 one two}
|
||||
|
||||
|
||||
finish_test
|
@ -12,7 +12,7 @@
|
||||
# focus of this file is testing the CREATE UNIQUE INDEX statement,
|
||||
# and primary keys, and the UNIQUE constraint on table columns
|
||||
#
|
||||
# $Id: unique.test,v 1.2 2001/09/27 23:57:06 drh Exp $
|
||||
# $Id: unique.test,v 1.3 2001/12/21 14:30:44 drh Exp $
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
@ -28,6 +28,15 @@ do_test unique-1.1 {
|
||||
c text
|
||||
);
|
||||
}
|
||||
} {1 {table "t1" has more than one primary key}}
|
||||
do_test unique-1.1b {
|
||||
catchsql {
|
||||
CREATE TABLE t1(
|
||||
a int PRIMARY KEY,
|
||||
b int UNIQUE,
|
||||
c text
|
||||
);
|
||||
}
|
||||
} {0 {}}
|
||||
do_test unique-1.2 {
|
||||
catchsql {
|
||||
|
Reference in New Issue
Block a user