mirror of
https://github.com/sqlite/sqlite.git
synced 2025-07-30 19:03:16 +03:00
Fixed the support of UNIQUE and PRIMARY KEY. (CVS 268)
FossilOrigin-Name: 116fdad06868acf6aca9e75c2c3497c0511a42c3
This commit is contained in:
31
manifest
31
manifest
@ -1,5 +1,5 @@
|
||||
C Added\sbasic\ssupport\sfor\senforcement\sof\sUNIQUE\son\sindices\sand\sprimary\nkeys.\s\sSupport\sfor\saddition\sconstraints\sis\sto\sfollow.\s(CVS\s267)
|
||||
D 2001-09-27T03:22:33
|
||||
C Fixed\sthe\ssupport\sof\sUNIQUE\sand\sPRIMARY\sKEY.\s(CVS\s268)
|
||||
D 2001-09-27T15:11:54
|
||||
F Makefile.in fe9d96d6a7b04b3000a24692c2a3761840bbbf97
|
||||
F README 51f6a4e7408b34afa5bc1c0485f61b6a4efb6958
|
||||
F VERSION 17fadc361fb942d644f92116388409c937c9fa79
|
||||
@ -10,26 +10,26 @@ F doc/report1.txt a031aaf37b185e4fa540223cb516d3bccec7eeac
|
||||
F src/TODO af7f3cab0228e34149cf98e073aa83d45878e7e6
|
||||
F src/btree.c a4a88dfef2072cedfdac09f3a51b7d70b017b9b4
|
||||
F src/btree.h 57d653ef5137b91f2a068aaf71a2905468dd2cb7
|
||||
F src/build.c 501c96f8224f1dd6c87c53c1ca7de62c3a98d5bb
|
||||
F src/build.c 64a7325c1471087ada81588d6ace6d294b28cd1d
|
||||
F src/delete.c 81002d889aae874decf507627207c5d1b3599dc2
|
||||
F src/expr.c 343a515a4abaf60e9e26c7412aa8c43fd3eae97d
|
||||
F src/hash.c bf36fb4cba114015123b0050f137d2c4553778a1
|
||||
F src/hash.h 5f6e7c04c46ed015ab4e01797c2049b4af5b006d
|
||||
F src/insert.c 0552c2a4b5fd359e9ed5d1e314d5e89093802c8e
|
||||
F src/main.c 00ff61d82189ad23fe2f2e6c355951f514cb1b5c
|
||||
F src/main.c 87cabd64c99af66ba95f06a7dcd870eec65d89af
|
||||
F src/md5.c 52f677bfc590e09f71d07d7e327bd59da738d07c
|
||||
F src/os.c 45376582c41dc8829330816d56b8e9e6cd1b7972
|
||||
F src/os.h 0f478e2fef5ec1612f94b59b163d4807d4c77d6d
|
||||
F src/pager.c 0fe02b63a89d8eebb42ad30529d0c7cc918ecb94
|
||||
F src/pager.h a0d4c5ae271914aa07b62aee0707997d6932b6ca
|
||||
F src/parse.y a136e0a24ce434e52c79a7eaa669cf9c8249e4db
|
||||
F src/parse.y 7a61488cb52da8b3da094aadb391b42d59a25602
|
||||
F src/printf.c b1e22a47be8cdf707815647239991e08e8cb69f9
|
||||
F src/random.c 708a23f69f40d6f2ae5ce1a04e6a4055d4a6ecec
|
||||
F src/select.c 7d90a6464906419fde96c0707a4cf4f3280db318
|
||||
F src/shell.c 8e573138074e0b9526fca59b3eac22bdf18ecc03
|
||||
F src/shell.c 977ec6b6479c8b8b6e05323d5026a6f4bd73aa54
|
||||
F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e
|
||||
F src/sqlite.h.in 08151912b382ded315b5c8fc6288d9d7a9332aa4
|
||||
F src/sqliteInt.h 35f42e624f11924a56a5501e30a670e1b92f62bb
|
||||
F src/sqliteInt.h 3ead85324704b79b2ae6799d6af3e5fd710756d9
|
||||
F src/table.c abd0adbe0fee39d995287b3bcccd908d174dfcac
|
||||
F src/tclsqlite.c 04a35d04f06046acc3944121dc6c36717f7f36d5
|
||||
F src/test1.c e4b31f62ea71963cbae44338acf477a04fc8fc49
|
||||
@ -38,8 +38,8 @@ F src/test3.c 4a0d7b882fdae731dbb759f512ad867122452f96
|
||||
F src/tokenize.c 2ab07b85fde38d8fa2b4e73417b93e94f9cf8f5f
|
||||
F src/update.c 0449af173b5f2f0b26e2f0e4545ee0e0429763cb
|
||||
F src/util.c 4da3be37d0fd3c640d2d3033503768afdc8e5387
|
||||
F src/vdbe.c d3cf685bd9c823445a4b4a57f7cb01718169f464
|
||||
F src/vdbe.h dc1d441494ba560a1ff464e1c56beb8ca03844fc
|
||||
F src/vdbe.c 173892798e1698605fafb24d29e26e3a5644ddf5
|
||||
F src/vdbe.h c543a58f52fb654c90dd31d0d0c31309f4d838de
|
||||
F src/where.c cce952b6a2459ac2296e3432876a4252d2fe3b87
|
||||
F test/all.test a2320eb40b462f25bd3e33115b1cabf3791450dd
|
||||
F test/bigrow.test a35f2de9948b24e427fb292c35947795efe182d0
|
||||
@ -50,7 +50,7 @@ F test/delete.test 5ebb114582457428b3e0e30b21b477fedcb85609
|
||||
F test/expr.test b3475005ea19d53bf8c4573fb6e4a4498be5b434
|
||||
F test/func.test dfee65686b8ba06071c2f007243a25c96ce82cf2
|
||||
F test/in.test 9323681388be301dc73f370b4cd62c5a33f79d1e
|
||||
F test/index.test e43e952b482c2afe938f1f31b71e2b33d43893a9
|
||||
F test/index.test 6076f29d09a4f26a2efa38b03b8cc338b8662f0e
|
||||
F test/insert.test a5c122aa726f1cef6f07d6767e8fd6f220994c11
|
||||
F test/insert2.test 252d7130d8cc20f649b31a4f503cd87e660abda8
|
||||
F test/lock.test a9641cdc282214563a2fb0233735b09cc2fdd8f2
|
||||
@ -69,11 +69,12 @@ F test/select4.test 29a2ffb187f3d8b6ca42a0a6b619e9cabe12e228
|
||||
F test/select5.test 00a240e3311b6c4ff0f27a252ad33811211fa8d8
|
||||
F test/sort.test 462c1161eee1abaa7cc93990e0b34d5fdb70ce19
|
||||
F test/subselect.test 335d3dad8d585726c447dfee8d9c4f7383c76b78
|
||||
F test/table.test 52fdca1632580fb638c7b7dd14f4d37ecc09f994
|
||||
F test/table.test 3ef4254d62ece31a3872ab11cdaec846f6fa8fd1
|
||||
F test/tableapi.test 162840153191a91a7dce6395f2334f9aef713b37
|
||||
F test/tclsqlite.test a57bb478d7e9f0b2c927f92e161f391e2896631a
|
||||
F test/tester.tcl 957cd92fe8645b829da175d94b7ddb7ea68dac39
|
||||
F test/tester.tcl c7ddeebc14cc841abb37134cd5d40c1e3ad367c1
|
||||
F test/trans.test 855337b8a178c73c433fcf8ee88e4b2f5efff0d9
|
||||
F test/unique.test 23056f0705755bc503ff543e79b79a5c91d35850
|
||||
F test/update.test b320ea22899e80b32b4d21c54591eb7a6ba4d6bd
|
||||
F test/vacuum.test 8acf8669f3b627e54149b25165b034aa06c2432e
|
||||
F test/where.test 43d5ac94da3f3722375307f948884dc79b326a91
|
||||
@ -99,7 +100,7 @@ F www/speed.tcl 91b53f9403a62bb322dc1f85a81531309bcfb41c
|
||||
F www/sqlite.tcl cb0d23d8f061a80543928755ec7775da6e4f362f
|
||||
F www/tclsqlite.tcl 13d50723f583888fc80ae1a38247c0ab415066fa
|
||||
F www/vdbe.tcl 0c8aaa529dd216ccbf7daaabd80985e413d5f9ad
|
||||
P 0e9cfcd53e16f96fc181def1d0b2d0ea7f7df73f
|
||||
R d903e186383659ad85dc50397b26ad49
|
||||
P 34c42967f3d52dfb65d9f31db4f6995d098ec1f7
|
||||
R 738ff05ebc1672d0941631329247a92e
|
||||
U drh
|
||||
Z 4633481d5649b488b3df47e886de0708
|
||||
Z b9a4ce432fac1a7969450da73881d616
|
||||
|
@ -1 +1 @@
|
||||
34c42967f3d52dfb65d9f31db4f6995d098ec1f7
|
||||
116fdad06868acf6aca9e75c2c3497c0511a42c3
|
187
src/build.c
187
src/build.c
@ -25,7 +25,7 @@
|
||||
** ROLLBACK
|
||||
** PRAGMA
|
||||
**
|
||||
** $Id: build.c,v 1.42 2001/09/27 03:22:33 drh Exp $
|
||||
** $Id: build.c,v 1.43 2001/09/27 15:11:54 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <ctype.h>
|
||||
@ -343,6 +343,7 @@ void sqliteStartTable(Parse *pParse, Token *pStart, Token *pName){
|
||||
Table *pTable;
|
||||
char *zName;
|
||||
sqlite *db = pParse->db;
|
||||
Vdbe *v;
|
||||
|
||||
pParse->sFirstToken = *pStart;
|
||||
zName = sqliteTableNameFromToken(pName);
|
||||
@ -370,13 +371,13 @@ void sqliteStartTable(Parse *pParse, Token *pStart, Token *pName){
|
||||
pTable->pIndex = 0;
|
||||
if( pParse->pNewTable ) sqliteDeleteTable(db, pParse->pNewTable);
|
||||
pParse->pNewTable = pTable;
|
||||
if( !pParse->initFlag && (db->flags & SQLITE_InTrans)==0 ){
|
||||
Vdbe *v = sqliteGetVdbe(pParse);
|
||||
if( v ){
|
||||
if( !pParse->initFlag && (v = sqliteGetVdbe(pParse))!=0 ){
|
||||
if( (db->flags & SQLITE_InTrans)==0 ){
|
||||
sqliteVdbeAddOp(v, OP_Transaction, 0, 0, 0, 0);
|
||||
sqliteVdbeAddOp(v, OP_VerifyCookie, db->schema_cookie, 0, 0, 0);
|
||||
pParse->schemaVerified = 1;
|
||||
}
|
||||
sqliteVdbeAddOp(v, OP_OpenWrite, 0, 2, MASTER_NAME, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -491,47 +492,28 @@ void sqliteEndTable(Parse *pParse, Token *pEnd){
|
||||
*/
|
||||
if( pParse->initFlag ){
|
||||
p->tnum = pParse->newTnum;
|
||||
if( p->pIndex ){
|
||||
p->pIndex->tnum = pParse->newKnum;
|
||||
}
|
||||
}
|
||||
|
||||
/* If not initializing, then create a record for the new table
|
||||
** in the SQLITE_MASTER table of the database.
|
||||
*/
|
||||
if( !pParse->initFlag ){
|
||||
int n, base;
|
||||
int n, addr;
|
||||
Vdbe *v;
|
||||
|
||||
v = sqliteGetVdbe(pParse);
|
||||
if( v==0 ) return;
|
||||
n = (int)pEnd->z - (int)pParse->sFirstToken.z + 1;
|
||||
sqliteVdbeAddOp(v, OP_OpenWrite, 0, 2, MASTER_NAME, 0);
|
||||
sqliteVdbeAddOp(v, OP_NewRecno, 0, 0, 0, 0);
|
||||
sqliteVdbeAddOp(v, OP_String, 0, 0, "table", 0);
|
||||
sqliteVdbeAddOp(v, OP_String, 0, 0, p->zName, 0);
|
||||
sqliteVdbeAddOp(v, OP_String, 0, 0, p->zName, 0);
|
||||
sqliteVdbeAddOp(v, OP_CreateTable, 0, 0, 0, 0);
|
||||
sqliteVdbeTableRootAddr(v, &p->tnum);
|
||||
if( p->pIndex ){
|
||||
/* If the table has a primary key, create an index in the database
|
||||
** for that key and record the root page of the index in the "knum"
|
||||
** column of of the SQLITE_MASTER table.
|
||||
*/
|
||||
Index *pIndex = p->pIndex;
|
||||
assert( pIndex->pNext==0 );
|
||||
assert( pIndex->tnum==0 );
|
||||
sqliteVdbeAddOp(v, OP_CreateIndex, 0, 0, 0, 0),
|
||||
sqliteVdbeIndexRootAddr(v, &pIndex->tnum);
|
||||
}else{
|
||||
/* If the table does not have a primary key, the "knum" column is
|
||||
** fill with a NULL value.
|
||||
*/
|
||||
sqliteVdbeAddOp(v, OP_Null, 0, 0, 0, 0);
|
||||
}
|
||||
base = sqliteVdbeAddOp(v, OP_String, 0, 0, 0, 0);
|
||||
sqliteVdbeChangeP3(v, base, pParse->sFirstToken.z, n);
|
||||
sqliteVdbeAddOp(v, OP_MakeRecord, 6, 0, 0, 0);
|
||||
addr = sqliteVdbeAddOp(v, OP_CreateTable, 0, 0, 0, 0);
|
||||
sqliteVdbeChangeP3(v, addr, (char *)&p->tnum, -1);
|
||||
p->tnum = 0;
|
||||
addr = sqliteVdbeAddOp(v, OP_String, 0, 0, 0, 0);
|
||||
sqliteVdbeChangeP3(v, addr, pParse->sFirstToken.z, n);
|
||||
sqliteVdbeAddOp(v, OP_MakeRecord, 5, 0, 0, 0);
|
||||
sqliteVdbeAddOp(v, OP_Put, 0, 0, 0, 0);
|
||||
changeCookie(db);
|
||||
sqliteVdbeAddOp(v, OP_SetCookie, db->next_cookie, 0, 0, 0);
|
||||
@ -634,11 +616,13 @@ void sqliteDropTable(Parse *pParse, Token *pName){
|
||||
/*
|
||||
** Create a new index for an SQL table. pIndex is the name of the index
|
||||
** and pTable is the name of the table that is to be indexed. Both will
|
||||
** be NULL for a primary key. In that case, use pParse->pNewTable as the
|
||||
** table to be indexed.
|
||||
** be NULL for a primary key or an index that is created to satisfy a
|
||||
** UNIQUE constraint. If pTable and pIndex are NULL, use pParse->pNewTable
|
||||
** as the table to be indexed.
|
||||
**
|
||||
** pList is a list of columns to be indexed. pList will be NULL if the
|
||||
** most recently added column of the table is labeled as the primary key.
|
||||
** most recently added column of the table is the primary key or has
|
||||
** the UNIQUE constraint.
|
||||
*/
|
||||
void sqliteCreateIndex(
|
||||
Parse *pParse, /* All information about this parse */
|
||||
@ -679,8 +663,8 @@ void sqliteCreateIndex(
|
||||
/*
|
||||
** Find the name of the index. Make sure there is not already another
|
||||
** index or table with the same name. If pName==0 it means that we are
|
||||
** dealing with a primary key, which has no name, so this step can be
|
||||
** skipped.
|
||||
** dealing with a primary key or UNIQUE constraint. We have to invent our
|
||||
** own name.
|
||||
*/
|
||||
if( pName ){
|
||||
zName = sqliteTableNameFromToken(pName);
|
||||
@ -698,8 +682,13 @@ void sqliteCreateIndex(
|
||||
goto exit_create_index;
|
||||
}
|
||||
}else{
|
||||
char zBuf[30];
|
||||
int n;
|
||||
Index *pLoop;
|
||||
for(pLoop=pTab->pIndex, n=1; pLoop; pLoop=pLoop->pNext, n++){}
|
||||
sprintf(zBuf,"%d)",n);
|
||||
zName = 0;
|
||||
sqliteSetString(&zName, pTab->zName, " (primary key)", 0);
|
||||
sqliteSetString(&zName, "(", pTab->zName, " autoindex ", zBuf, 0);
|
||||
if( zName==0 ) goto exit_create_index;
|
||||
}
|
||||
|
||||
@ -746,16 +735,12 @@ void sqliteCreateIndex(
|
||||
}
|
||||
|
||||
/* Link the new Index structure to its table and to the other
|
||||
** in-memory database structures. Note that primary key indices
|
||||
** do not appear in the index hash table.
|
||||
** in-memory database structures.
|
||||
*/
|
||||
if( pParse->explain==0 ){
|
||||
if( pName!=0 ){
|
||||
char *zName = pIndex->zName;;
|
||||
sqliteHashInsert(&db->idxHash, zName, strlen(zName)+1, pIndex);
|
||||
}
|
||||
pIndex->pNext = pTab->pIndex;
|
||||
pTab->pIndex = pIndex;
|
||||
pIndex->pNext = pTab->pIndex;
|
||||
pTab->pIndex = pIndex;
|
||||
if( !pParse->explain ){
|
||||
sqliteHashInsert(&db->idxHash, pIndex->zName, strlen(zName)+1, pIndex);
|
||||
db->flags |= SQLITE_InternChanges;
|
||||
}
|
||||
|
||||
@ -763,7 +748,7 @@ void sqliteCreateIndex(
|
||||
** "sqlite_master" table on the disk. So do not write to the disk
|
||||
** again. Extract the table number from the pParse->newTnum field.
|
||||
*/
|
||||
if( pParse->initFlag ){
|
||||
if( pParse->initFlag && pTable!=0 ){
|
||||
pIndex->tnum = pParse->newTnum;
|
||||
}
|
||||
|
||||
@ -778,79 +763,75 @@ void sqliteCreateIndex(
|
||||
** we don't want to recreate it.
|
||||
**
|
||||
** If pTable==0 it means this index is generated as a primary key
|
||||
** and those does not have a CREATE INDEX statement to add to the
|
||||
** master table. Also, since primary keys are created at the same
|
||||
** time as tables, the table will be empty so there is no need to
|
||||
** initialize the index. Hence, skip all the code generation if
|
||||
** pTable==0.
|
||||
** or UNIQUE constraint of a CREATE TABLE statement. The code generator
|
||||
** for CREATE TABLE will have already opened cursor 0 for writing to
|
||||
** the sqlite_master table and will take care of closing that cursor
|
||||
** for us in the end. So those steps are skipped when pTable==0
|
||||
*/
|
||||
else if( pParse->initFlag==0 && pTable!=0 ){
|
||||
static VdbeOp addTable[] = {
|
||||
{ OP_OpenWrite, 2, 2, MASTER_NAME},
|
||||
{ OP_NewRecno, 2, 0, 0},
|
||||
{ OP_String, 0, 0, "index"},
|
||||
{ OP_String, 0, 0, 0}, /* 3 */
|
||||
{ OP_String, 0, 0, 0}, /* 4 */
|
||||
{ OP_CreateIndex, 1, 0, 0},
|
||||
{ OP_Dup, 0, 0, 0},
|
||||
{ OP_OpenWrite, 1, 0, 0}, /* 7 */
|
||||
{ OP_Null, 0, 0, 0},
|
||||
{ OP_String, 0, 0, 0}, /* 9 */
|
||||
{ OP_MakeRecord, 6, 0, 0},
|
||||
{ OP_Put, 2, 0, 0},
|
||||
{ OP_SetCookie, 0, 0, 0}, /* 12 */
|
||||
{ OP_Close, 2, 0, 0},
|
||||
};
|
||||
else if( pParse->initFlag==0 ){
|
||||
int n;
|
||||
Vdbe *v = pParse->pVdbe;
|
||||
Vdbe *v;
|
||||
int lbl1, lbl2;
|
||||
int i;
|
||||
int addr;
|
||||
|
||||
v = sqliteGetVdbe(pParse);
|
||||
if( v==0 ) goto exit_create_index;
|
||||
if( pTable!=0 && (db->flags & SQLITE_InTrans)==0 ){
|
||||
sqliteVdbeAddOp(v, OP_Transaction, 0, 0, 0, 0);
|
||||
sqliteVdbeAddOp(v, OP_VerifyCookie, db->schema_cookie, 0, 0, 0);
|
||||
pParse->schemaVerified = 1;
|
||||
if( pTable!=0 ){
|
||||
if( (db->flags & SQLITE_InTrans)==0 ){
|
||||
sqliteVdbeAddOp(v, OP_Transaction, 0, 0, 0, 0);
|
||||
sqliteVdbeAddOp(v, OP_VerifyCookie, db->schema_cookie, 0, 0, 0);
|
||||
pParse->schemaVerified = 1;
|
||||
}
|
||||
sqliteVdbeAddOp(v, OP_OpenWrite, 0, 2, MASTER_NAME, 0);
|
||||
}
|
||||
sqliteVdbeAddOp(v, OP_NewRecno, 0, 0, 0, 0);
|
||||
sqliteVdbeAddOp(v, OP_String, 0, 0, "index", 0);
|
||||
sqliteVdbeAddOp(v, OP_String, 0, 0, pIndex->zName, 0);
|
||||
sqliteVdbeAddOp(v, OP_String, 0, 0, pTab->zName, 0);
|
||||
addr = sqliteVdbeAddOp(v, OP_CreateIndex, 0, 0, 0, 0);
|
||||
sqliteVdbeChangeP3(v, addr, (char*)&pIndex->tnum, -1);
|
||||
pIndex->tnum = 0;
|
||||
if( pTable ){
|
||||
sqliteVdbeAddOp(v, OP_Dup, 0, 0, 0, 0);
|
||||
sqliteVdbeAddOp(v, OP_OpenWrite, 1, 0, 0, 0);
|
||||
}
|
||||
if( pStart && pEnd ){
|
||||
int base;
|
||||
n = (int)pEnd->z - (int)pStart->z + 1;
|
||||
base = sqliteVdbeAddOpList(v, ArraySize(addTable), addTable);
|
||||
sqliteVdbeChangeP3(v, base+3, pIndex->zName, 0);
|
||||
sqliteVdbeChangeP3(v, base+4, pTab->zName, 0);
|
||||
sqliteVdbeIndexRootAddr(v, &pIndex->tnum);
|
||||
sqliteVdbeChangeP3(v, base+7, pIndex->zName, 0);
|
||||
sqliteVdbeChangeP3(v, base+9, pStart->z, n);
|
||||
changeCookie(db);
|
||||
sqliteVdbeChangeP1(v, base+12, db->next_cookie);
|
||||
addr = sqliteVdbeAddOp(v, OP_String, 0, 0, "", 0);
|
||||
sqliteVdbeChangeP3(v, addr, pStart->z, n);
|
||||
}else{
|
||||
sqliteVdbeAddOp(v, OP_Null, 0, 0, 0, 0);
|
||||
}
|
||||
sqliteVdbeAddOp(v, OP_Open, 0, pTab->tnum, pTab->zName, 0);
|
||||
lbl1 = sqliteVdbeMakeLabel(v);
|
||||
lbl2 = sqliteVdbeMakeLabel(v);
|
||||
sqliteVdbeAddOp(v, OP_Rewind, 0, 0, 0, 0);
|
||||
sqliteVdbeAddOp(v, OP_Next, 0, lbl2, 0, lbl1);
|
||||
sqliteVdbeAddOp(v, OP_Recno, 0, 0, 0, 0);
|
||||
for(i=0; i<pIndex->nColumn; i++){
|
||||
sqliteVdbeAddOp(v, OP_Column, 0, pIndex->aiColumn[i], 0, 0);
|
||||
sqliteVdbeAddOp(v, OP_MakeRecord, 5, 0, 0, 0);
|
||||
sqliteVdbeAddOp(v, OP_Put, 0, 0, 0, 0);
|
||||
if( pTable ){
|
||||
sqliteVdbeAddOp(v, OP_Open, 2, pTab->tnum, pTab->zName, 0);
|
||||
lbl1 = sqliteVdbeMakeLabel(v);
|
||||
lbl2 = sqliteVdbeMakeLabel(v);
|
||||
sqliteVdbeAddOp(v, OP_Rewind, 2, 0, 0, 0);
|
||||
sqliteVdbeAddOp(v, OP_Next, 2, lbl2, 0, lbl1);
|
||||
sqliteVdbeAddOp(v, OP_Recno, 2, 0, 0, 0);
|
||||
for(i=0; i<pIndex->nColumn; i++){
|
||||
sqliteVdbeAddOp(v, OP_Column, 2, pIndex->aiColumn[i], 0, 0);
|
||||
}
|
||||
sqliteVdbeAddOp(v, OP_MakeIdxKey, pIndex->nColumn, 0, 0, 0);
|
||||
sqliteVdbeAddOp(v, OP_PutIdx, 1, pIndex->isUnique, 0, 0);
|
||||
sqliteVdbeAddOp(v, OP_Goto, 0, lbl1, 0, 0);
|
||||
sqliteVdbeAddOp(v, OP_Noop, 0, 0, 0, lbl2);
|
||||
sqliteVdbeAddOp(v, OP_Close, 2, 0, 0, 0);
|
||||
}
|
||||
sqliteVdbeAddOp(v, OP_MakeIdxKey, pIndex->nColumn, 0, 0, 0);
|
||||
sqliteVdbeAddOp(v, OP_PutIdx, 1, pIndex->isUnique, 0, 0);
|
||||
sqliteVdbeAddOp(v, OP_Goto, 0, lbl1, 0, 0);
|
||||
sqliteVdbeAddOp(v, OP_Noop, 0, 0, 0, lbl2);
|
||||
sqliteVdbeAddOp(v, OP_Close, 1, 0, 0, 0);
|
||||
sqliteVdbeAddOp(v, OP_Close, 0, 0, 0, 0);
|
||||
if( pTable!=0 && (db->flags & SQLITE_InTrans)==0 ){
|
||||
sqliteVdbeAddOp(v, OP_Commit, 0, 0, 0, 0);
|
||||
if( pTable!=0 ){
|
||||
changeCookie(db);
|
||||
sqliteVdbeAddOp(v, OP_SetCookie, db->next_cookie, 0, 0, 0);
|
||||
sqliteVdbeAddOp(v, OP_Close, 0, 0, 0, 0);
|
||||
if( (db->flags & SQLITE_InTrans)==0 ){
|
||||
sqliteVdbeAddOp(v, OP_Commit, 0, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Reclaim memory on an EXPLAIN call.
|
||||
*/
|
||||
if( pParse->explain ){
|
||||
sqliteFree(pIndex);
|
||||
}
|
||||
|
||||
/* Clean up before exiting */
|
||||
exit_create_index:
|
||||
sqliteIdListDelete(pList);
|
||||
|
80
src/main.c
80
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.41 2001/09/23 20:17:55 drh Exp $
|
||||
** $Id: main.c,v 1.42 2001/09/27 15:11:54 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "os.h"
|
||||
@ -26,8 +26,7 @@
|
||||
** argv[0] = "meta" 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] = root page number of primary key for tables or NULL.
|
||||
** argv[4] = SQL create statement for the table or index
|
||||
** argv[3] = SQL create statement for the table or index
|
||||
**
|
||||
*/
|
||||
static int sqliteOpenCb(void *pDb, int argc, char **argv, char **azColName){
|
||||
@ -38,25 +37,33 @@ static int sqliteOpenCb(void *pDb, int argc, char **argv, char **azColName){
|
||||
/* TODO: Do some validity checks on all fields. In particular,
|
||||
** make sure fields do not contain NULLs. */
|
||||
|
||||
assert( argc==5 );
|
||||
assert( argc==4 );
|
||||
switch( argv[0][0] ){
|
||||
case 'm': { /* Meta information */
|
||||
if( strcmp(argv[1],"file-format")==0 ){
|
||||
db->file_format = atoi(argv[4]);
|
||||
db->file_format = atoi(argv[3]);
|
||||
}else if( strcmp(argv[1],"schema-cookie")==0 ){
|
||||
db->schema_cookie = atoi(argv[4]);
|
||||
db->schema_cookie = atoi(argv[3]);
|
||||
db->next_cookie = db->schema_cookie;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'i':
|
||||
case 't': { /* CREATE TABLE and CREATE INDEX statements */
|
||||
memset(&sParse, 0, sizeof(sParse));
|
||||
sParse.db = db;
|
||||
sParse.initFlag = 1;
|
||||
sParse.newTnum = atoi(argv[2]);
|
||||
sParse.newKnum = argv[3] ? atoi(argv[3]) : 0;
|
||||
nErr = sqliteRunParser(&sParse, argv[4], 0);
|
||||
if( argv[3] && argv[3][0] ){
|
||||
memset(&sParse, 0, sizeof(sParse));
|
||||
sParse.db = db;
|
||||
sParse.initFlag = 1;
|
||||
sParse.newTnum = atoi(argv[2]);
|
||||
nErr = sqliteRunParser(&sParse, argv[3], 0);
|
||||
}else{
|
||||
Index *pIndex = sqliteFindIndex(db, argv[1]);
|
||||
if( pIndex==0 || pIndex->tnum!=0 ){
|
||||
nErr++;
|
||||
}else{
|
||||
pIndex->tnum = atoi(argv[2]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
@ -92,8 +99,7 @@ static int sqliteInit(sqlite *db, char **pzErrMsg){
|
||||
" type text,\n"
|
||||
" name text,\n"
|
||||
" tbl_name text,\n"
|
||||
" tnum integer,\n"
|
||||
" knum integer,\n"
|
||||
" rootpage integer,\n"
|
||||
" sql text\n"
|
||||
")"
|
||||
;
|
||||
@ -107,8 +113,7 @@ static int sqliteInit(sqlite *db, char **pzErrMsg){
|
||||
** type text, -- Either "table" or "index" or "meta"
|
||||
** name text, -- Name of table or index
|
||||
** tbl_name text, -- Associated table
|
||||
** tnum integer, -- The integer page number of root page
|
||||
** knum integer, -- Root page of primary key, or NULL
|
||||
** rootpage integer, -- The integer page number of root page
|
||||
** sql text -- The CREATE statement for this object
|
||||
** );
|
||||
**
|
||||
@ -136,47 +141,43 @@ static int sqliteInit(sqlite *db, char **pzErrMsg){
|
||||
static VdbeOp initProg[] = {
|
||||
{ OP_Open, 0, 2, 0},
|
||||
{ OP_Rewind, 0, 0, 0},
|
||||
{ OP_Next, 0, 13, 0}, /* 2 */
|
||||
{ OP_Next, 0, 12, 0}, /* 2 */
|
||||
{ OP_Column, 0, 0, 0},
|
||||
{ OP_String, 0, 0, "meta"},
|
||||
{ OP_Ne, 0, 2, 0},
|
||||
{ OP_Column, 0, 0, 0},
|
||||
{ OP_Column, 0, 1, 0},
|
||||
{ OP_Column, 0, 3, 0},
|
||||
{ OP_Null, 0, 0, 0},
|
||||
{ OP_Column, 0, 5, 0},
|
||||
{ OP_Callback, 5, 0, 0},
|
||||
{ OP_Column, 0, 4, 0},
|
||||
{ OP_Callback, 4, 0, 0},
|
||||
{ OP_Goto, 0, 2, 0},
|
||||
{ OP_Rewind, 0, 0, 0}, /* 13 */
|
||||
{ OP_Next, 0, 25, 0}, /* 14 */
|
||||
{ OP_Rewind, 0, 0, 0}, /* 12 */
|
||||
{ OP_Next, 0, 23, 0}, /* 13 */
|
||||
{ OP_Column, 0, 0, 0},
|
||||
{ OP_String, 0, 0, "table"},
|
||||
{ OP_Ne, 0, 14, 0},
|
||||
{ OP_Ne, 0, 13, 0},
|
||||
{ OP_Column, 0, 0, 0},
|
||||
{ OP_Column, 0, 1, 0},
|
||||
{ OP_Column, 0, 3, 0},
|
||||
{ OP_Column, 0, 4, 0},
|
||||
{ OP_Column, 0, 5, 0},
|
||||
{ OP_Callback, 5, 0, 0},
|
||||
{ OP_Goto, 0, 14, 0},
|
||||
{ OP_Rewind, 0, 0, 0}, /* 25 */
|
||||
{ OP_Next, 0, 37, 0}, /* 26 */
|
||||
{ OP_Callback, 4, 0, 0},
|
||||
{ OP_Goto, 0, 13, 0},
|
||||
{ OP_Rewind, 0, 0, 0}, /* 23 */
|
||||
{ OP_Next, 0, 34, 0}, /* 24 */
|
||||
{ OP_Column, 0, 0, 0},
|
||||
{ OP_String, 0, 0, "index"},
|
||||
{ OP_Ne, 0, 26, 0},
|
||||
{ OP_Ne, 0, 24, 0},
|
||||
{ OP_Column, 0, 0, 0},
|
||||
{ OP_Column, 0, 1, 0},
|
||||
{ OP_Column, 0, 3, 0},
|
||||
{ OP_Null, 0, 0, 0},
|
||||
{ OP_Column, 0, 5, 0},
|
||||
{ OP_Callback, 5, 0, 0},
|
||||
{ OP_Goto, 0, 26, 0},
|
||||
{ OP_String, 0, 0, "meta"}, /* 37 */
|
||||
{ OP_Column, 0, 4, 0},
|
||||
{ OP_Callback, 4, 0, 0},
|
||||
{ OP_Goto, 0, 24, 0},
|
||||
{ OP_String, 0, 0, "meta"}, /* 34 */
|
||||
{ OP_String, 0, 0, "schema-cookie"},
|
||||
{ OP_Null, 0, 0, 0},
|
||||
{ OP_Null, 0, 0, 0},
|
||||
{ OP_ReadCookie,0,0, 0},
|
||||
{ OP_Callback, 5, 0, 0},
|
||||
{ OP_Callback, 4, 0, 0},
|
||||
{ OP_Close, 0, 0, 0},
|
||||
{ OP_Halt, 0, 0, 0},
|
||||
};
|
||||
@ -203,10 +204,9 @@ static int sqliteInit(sqlite *db, char **pzErrMsg){
|
||||
azArg[0] = "table";
|
||||
azArg[1] = MASTER_NAME;
|
||||
azArg[2] = "2";
|
||||
azArg[3] = 0;
|
||||
azArg[4] = master_schema;
|
||||
azArg[5] = 0;
|
||||
sqliteOpenCb(db, 5, azArg, 0);
|
||||
azArg[3] = master_schema;
|
||||
azArg[4] = 0;
|
||||
sqliteOpenCb(db, 4, azArg, 0);
|
||||
pTab = sqliteFindTable(db, MASTER_NAME);
|
||||
if( pTab ){
|
||||
pTab->readOnly = 1;
|
||||
|
10
src/parse.y
10
src/parse.y
@ -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.31 2001/09/27 03:22:33 drh Exp $
|
||||
** @(#) $Id: parse.y,v 1.32 2001/09/27 15:11:54 drh Exp $
|
||||
*/
|
||||
%token_prefix TK_
|
||||
%token_type {Token}
|
||||
@ -125,7 +125,7 @@ carg ::= DEFAULT NULL.
|
||||
//
|
||||
ccons ::= NOT NULL.
|
||||
ccons ::= PRIMARY KEY sortorder. {sqliteCreateIndex(pParse,0,0,0,1,0,0);}
|
||||
ccons ::= UNIQUE.
|
||||
ccons ::= UNIQUE. {sqliteCreateIndex(pParse,0,0,0,1,0,0);}
|
||||
ccons ::= CHECK LP expr RP.
|
||||
|
||||
// For the time being, the only constraint we care about is the primary
|
||||
@ -138,10 +138,10 @@ conslist ::= conslist tcons.
|
||||
conslist ::= tcons.
|
||||
tcons ::= CONSTRAINT ids.
|
||||
tcons ::= PRIMARY KEY LP idxlist(X) RP. {sqliteCreateIndex(pParse,0,0,X,1,0,0);}
|
||||
tcons ::= UNIQUE LP idlist RP.
|
||||
tcons ::= UNIQUE LP idxlist(X) RP. {sqliteCreateIndex(pParse,0,0,X,1,0,0);}
|
||||
tcons ::= CHECK expr.
|
||||
idlist ::= idlist COMMA ids.
|
||||
idlist ::= ids.
|
||||
// idlist ::= idlist COMMA ids.
|
||||
// idlist ::= ids.
|
||||
|
||||
// The next command format is dropping tables.
|
||||
//
|
||||
|
@ -12,7 +12,7 @@
|
||||
** This file contains code to implement the "sqlite" command line
|
||||
** utility for accessing SQLite databases.
|
||||
**
|
||||
** $Id: shell.c,v 1.33 2001/09/16 00:13:27 drh Exp $
|
||||
** $Id: shell.c,v 1.34 2001/09/27 15:11:54 drh Exp $
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@ -648,6 +648,7 @@ static void do_meta_command(char *zLine, sqlite *db, struct callback_data *p){
|
||||
" type text,\n"
|
||||
" name text,\n"
|
||||
" tbl_name text,\n"
|
||||
" rootpage integer,\n"
|
||||
" sql text\n"
|
||||
")";
|
||||
new_argv[1] = 0;
|
||||
|
@ -11,7 +11,7 @@
|
||||
*************************************************************************
|
||||
** Internal interface definitions for SQLite.
|
||||
**
|
||||
** @(#) $Id: sqliteInt.h,v 1.55 2001/09/27 03:22:33 drh Exp $
|
||||
** @(#) $Id: sqliteInt.h,v 1.56 2001/09/27 15:11:54 drh Exp $
|
||||
*/
|
||||
#include "sqlite.h"
|
||||
#include "hash.h"
|
||||
@ -444,6 +444,7 @@ void sqliteExprCode(Parse*, Expr*);
|
||||
void sqliteExprIfTrue(Parse*, Expr*, int);
|
||||
void sqliteExprIfFalse(Parse*, Expr*, int);
|
||||
Table *sqliteFindTable(sqlite*,char*);
|
||||
Index *sqliteFindIndex(sqlite*,char*);
|
||||
void sqliteCopy(Parse*, Token*, Token*, Token*);
|
||||
void sqliteVacuum(Parse*, Token*);
|
||||
int sqliteGlobCompare(const unsigned char*,const unsigned char*);
|
||||
|
118
src/vdbe.c
118
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.78 2001/09/27 03:22:34 drh Exp $
|
||||
** $Id: vdbe.c,v 1.79 2001/09/27 15:11:54 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <ctype.h>
|
||||
@ -202,8 +202,6 @@ struct Vdbe {
|
||||
Agg agg; /* Aggregate information */
|
||||
int nSet; /* Number of sets allocated */
|
||||
Set *aSet; /* An array of sets */
|
||||
int *pTableRoot; /* Write root page no. for new tables to this addr */
|
||||
int *pIndexRoot; /* Write root page no. for new indices to this addr */
|
||||
int nFetch; /* Number of OP_Fetch instructions executed */
|
||||
};
|
||||
|
||||
@ -226,24 +224,6 @@ void sqliteVdbeTrace(Vdbe *p, FILE *trace){
|
||||
p->trace = trace;
|
||||
}
|
||||
|
||||
/*
|
||||
** Cause the next OP_CreateTable or OP_CreateIndex instruction that executes
|
||||
** to write the page number of the root page for the new table or index it
|
||||
** creates into the memory location *pAddr.
|
||||
**
|
||||
** The pointer to the place to write the page number is cleared after
|
||||
** the OP_Create* statement. If OP_Create* is executed and the pointer
|
||||
** is NULL, an error results. Hence the address can only be used once.
|
||||
** If the root address fields are set but OP_Create* operations never
|
||||
** execute, that too is an error.
|
||||
*/
|
||||
void sqliteVdbeTableRootAddr(Vdbe *p, int *pAddr){
|
||||
p->pTableRoot = pAddr;
|
||||
}
|
||||
void sqliteVdbeIndexRootAddr(Vdbe *p, int *pAddr){
|
||||
p->pIndexRoot = pAddr;
|
||||
}
|
||||
|
||||
/*
|
||||
** Add a new instruction to the list of instructions current in the
|
||||
** VDBE. Return the address of the new instruction.
|
||||
@ -288,6 +268,7 @@ int sqliteVdbeAddOp(Vdbe *p, int op, int p1, int p2, const char *p3, int lbl){
|
||||
p->aOp[i].p2 = p2;
|
||||
if( p3 && p3[0] ){
|
||||
p->aOp[i].p3 = sqliteStrDup(p3);
|
||||
p->aOp[i].p3dyn = 1;
|
||||
}else{
|
||||
p->aOp[i].p3 = 0;
|
||||
}
|
||||
@ -367,10 +348,28 @@ void sqliteVdbeChangeP1(Vdbe *p, int addr, int val){
|
||||
** This routine is useful when a large program is loaded from a
|
||||
** static array using sqliteVdbeAddOpList but we want to make a
|
||||
** few minor changes to the program.
|
||||
**
|
||||
** If n>=0 then the P3 operand is dynamic, meaning that a copy of
|
||||
** the string is made into memory obtained from sqliteMalloc().
|
||||
** A value of n==0 means copy bytes of zP3 up to and including the
|
||||
** first null byte. If n>0 then copy n+1 bytes of zP3.
|
||||
**
|
||||
** If n<0 then zP3 is assumed to be a pointer to a static string.
|
||||
** P3 is made to point directly to this string without any copying.
|
||||
*/
|
||||
void sqliteVdbeChangeP3(Vdbe *p, int addr, const char *zP3, int n){
|
||||
void sqliteVdbeChangeP3(Vdbe *p, int addr, char *zP3, int n){
|
||||
if( p && addr>=0 && p->nOp>addr && zP3 ){
|
||||
sqliteSetNString(&p->aOp[addr].p3, zP3, n, 0);
|
||||
Op *pOp = &p->aOp[addr];
|
||||
if( pOp->p3 && pOp->p3dyn ){
|
||||
sqliteFree(pOp->p3);
|
||||
}
|
||||
if( n<0 ){
|
||||
pOp->p3 = zP3;
|
||||
pOp->p3dyn = 0;
|
||||
}else{
|
||||
sqliteSetNString(&p->aOp[addr].p3, zP3, n, 0);
|
||||
pOp->p3dyn = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -384,10 +383,15 @@ void sqliteVdbeChangeP3(Vdbe *p, int addr, const char *zP3, int n){
|
||||
** resolve to be a single actual quote character within the string.
|
||||
*/
|
||||
void sqliteVdbeDequoteP3(Vdbe *p, int addr){
|
||||
char *z;
|
||||
Op *pOp;
|
||||
if( addr<0 || addr>=p->nOp ) return;
|
||||
z = p->aOp[addr].p3;
|
||||
if( z ) sqliteDequote(z);
|
||||
pOp = &p->aOp[addr];
|
||||
if( pOp->p3==0 || pOp->p3[0]==0 ) return;
|
||||
if( !pOp->p3dyn ){
|
||||
pOp->p3 = sqliteStrDup(pOp->p3);
|
||||
pOp->p3dyn = 1;
|
||||
}
|
||||
if( pOp->p3 ) sqliteDequote(pOp->p3);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -398,8 +402,14 @@ void sqliteVdbeDequoteP3(Vdbe *p, int addr){
|
||||
void sqliteVdbeCompressSpace(Vdbe *p, int addr){
|
||||
char *z;
|
||||
int i, j;
|
||||
Op *pOp;
|
||||
if( addr<0 || addr>=p->nOp ) return;
|
||||
z = p->aOp[addr].p3;
|
||||
pOp = &p->aOp[addr];
|
||||
if( !pOp->p3dyn ){
|
||||
pOp->p3 = sqliteStrDup(pOp->p3);
|
||||
pOp->p3dyn = 1;
|
||||
}
|
||||
z = pOp->p3;
|
||||
if( z==0 ) return;
|
||||
i = j = 0;
|
||||
while( isspace(z[i]) ){ i++; }
|
||||
@ -747,8 +757,6 @@ static void Cleanup(Vdbe *p){
|
||||
sqliteFree(p->aSet);
|
||||
p->aSet = 0;
|
||||
p->nSet = 0;
|
||||
p->pTableRoot = 0;
|
||||
p->pIndexRoot = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -763,7 +771,9 @@ void sqliteVdbeDelete(Vdbe *p){
|
||||
p->nOp = 0;
|
||||
}
|
||||
for(i=0; i<p->nOp; i++){
|
||||
sqliteFree(p->aOp[i].p3);
|
||||
if( p->aOp[i].p3dyn ){
|
||||
sqliteFree(p->aOp[i].p3);
|
||||
}
|
||||
}
|
||||
sqliteFree(p->aOp);
|
||||
sqliteFree(p->aLabel);
|
||||
@ -2618,7 +2628,7 @@ case OP_BeginIdx: {
|
||||
if( Stringify(p, tos) ) goto no_mem;
|
||||
if( pCrsr->zKey ) sqliteFree(pCrsr->zKey);
|
||||
pCrsr->nKey = aStack[tos].n;
|
||||
pCrsr->zKey = sqliteMalloc( pCrsr->nKey );
|
||||
pCrsr->zKey = sqliteMalloc( pCrsr->nKey+1 );
|
||||
if( pCrsr->zKey==0 ) goto no_mem;
|
||||
memcpy(pCrsr->zKey, zStack[tos], aStack[tos].n);
|
||||
pCrsr->zKey[aStack[tos].n] = 0;
|
||||
@ -2774,17 +2784,15 @@ case OP_Clear: {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: CreateTable * * *
|
||||
/* Opcode: CreateTable * * P3
|
||||
**
|
||||
** Allocate a new table in the main database file. Push the page number
|
||||
** for the root page of the new table onto the stack.
|
||||
**
|
||||
** The root page number is also written to a memory location which has
|
||||
** be set up by the parser. The difference between CreateTable and
|
||||
** CreateIndex is that each writes its root page number into a different
|
||||
** memory location. This writing of the page number into a memory location
|
||||
** is used by the SQL parser to record the page number in its internal
|
||||
** data structures.
|
||||
** The root page number is also written to a memory location that P3
|
||||
** points to. This is the mechanism is used to write the root page
|
||||
** number into the parser's internal data structures that describe the
|
||||
** new table.
|
||||
**
|
||||
** See also: CreateIndex
|
||||
*/
|
||||
@ -2792,31 +2800,26 @@ case OP_CreateTable: {
|
||||
int i = ++p->tos;
|
||||
int pgno;
|
||||
VERIFY( if( NeedStack(p, p->tos) ) goto no_mem; )
|
||||
if( p->pTableRoot==0 ){
|
||||
rc = SQLITE_INTERNAL;
|
||||
goto abort_due_to_error;
|
||||
}
|
||||
assert( pOp->p3!=0 && pOp->p3dyn==0 );
|
||||
rc = sqliteBtreeCreateTable(pBt, &pgno);
|
||||
if( rc==SQLITE_OK ){
|
||||
aStack[i].i = pgno;
|
||||
aStack[i].flags = STK_Int;
|
||||
*p->pTableRoot = pgno;
|
||||
p->pTableRoot = 0;
|
||||
*(u32*)pOp->p3 = pgno;
|
||||
pOp->p3 = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: CreateIndex P1 * *
|
||||
/* Opcode: CreateIndex * * P3
|
||||
**
|
||||
** Allocate a new Index in the main database file. Push the page number
|
||||
** for the root page of the new table onto the stack.
|
||||
**
|
||||
** The root page number is also written to a memory location which has
|
||||
** be set up by the parser. The difference between CreateTable and
|
||||
** CreateIndex is that each writes its root page number into a different
|
||||
** memory location. This writing of the page number into a memory location
|
||||
** is used by the SQL parser to record the page number in its internal
|
||||
** data structures.
|
||||
** The root page number is also written to a memory location that P3
|
||||
** points to. This is the mechanism is used to write the root page
|
||||
** number into the parser's internal data structures that describe the
|
||||
** new index.
|
||||
**
|
||||
** See also: CreateTable
|
||||
*/
|
||||
@ -2824,16 +2827,13 @@ case OP_CreateIndex: {
|
||||
int i = ++p->tos;
|
||||
int pgno;
|
||||
VERIFY( if( NeedStack(p, p->tos) ) goto no_mem; )
|
||||
if( p->pIndexRoot==0 ){
|
||||
rc = SQLITE_INTERNAL;
|
||||
goto abort_due_to_error;
|
||||
}
|
||||
assert( pOp->p3!=0 && pOp->p3dyn==0 );
|
||||
rc = sqliteBtreeCreateTable(pBt, &pgno);
|
||||
if( rc==SQLITE_OK ){
|
||||
aStack[i].i = pgno;
|
||||
aStack[i].flags = STK_Int;
|
||||
*p->pIndexRoot = pgno;
|
||||
p->pIndexRoot = 0;
|
||||
*(u32*)pOp->p3 = pgno;
|
||||
pOp->p3 = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -3865,10 +3865,6 @@ default: {
|
||||
|
||||
cleanup:
|
||||
Cleanup(p);
|
||||
if( (p->pTableRoot || p->pIndexRoot) && rc==SQLITE_OK ){
|
||||
rc = SQLITE_INTERNAL;
|
||||
sqliteSetString(pzErrMsg, "table or index root page not set", 0);
|
||||
}
|
||||
if( rc!=SQLITE_OK ){
|
||||
closeAllCursors(p);
|
||||
sqliteBtreeRollback(pBt);
|
||||
|
@ -15,7 +15,7 @@
|
||||
** or VDBE. The VDBE implements an abstract machine that runs a
|
||||
** simple program to access and modify the underlying database.
|
||||
**
|
||||
** $Id: vdbe.h,v 1.24 2001/09/23 02:35:53 drh Exp $
|
||||
** $Id: vdbe.h,v 1.25 2001/09/27 15:11:55 drh Exp $
|
||||
*/
|
||||
#ifndef _SQLITE_VDBE_H_
|
||||
#define _SQLITE_VDBE_H_
|
||||
@ -38,6 +38,7 @@ struct VdbeOp {
|
||||
int p1; /* First operand */
|
||||
int p2; /* Second parameter (often the jump destination) */
|
||||
char *p3; /* Third parameter */
|
||||
int p3dyn; /* True if p3 is malloced. False if it is static */
|
||||
};
|
||||
typedef struct VdbeOp VdbeOp;
|
||||
|
||||
@ -187,12 +188,10 @@ typedef struct VdbeOp VdbeOp;
|
||||
*/
|
||||
Vdbe *sqliteVdbeCreate(sqlite*);
|
||||
void sqliteVdbeCreateCallback(Vdbe*, int*);
|
||||
void sqliteVdbeTableRootAddr(Vdbe*, int*);
|
||||
void sqliteVdbeIndexRootAddr(Vdbe*, int*);
|
||||
int sqliteVdbeAddOp(Vdbe*,int,int,int,const char*,int);
|
||||
int sqliteVdbeAddOpList(Vdbe*, int nOp, VdbeOp const *aOp);
|
||||
void sqliteVdbeChangeP1(Vdbe*, int addr, int P1);
|
||||
void sqliteVdbeChangeP3(Vdbe*, int addr, const char *zP1, int N);
|
||||
void sqliteVdbeChangeP3(Vdbe*, int addr, char *zP1, int N);
|
||||
void sqliteVdbeDequoteP3(Vdbe*, int addr);
|
||||
int sqliteVdbeMakeLabel(Vdbe*);
|
||||
void sqliteVdbeDelete(Vdbe*);
|
||||
|
@ -11,7 +11,7 @@
|
||||
# This file implements regression tests for SQLite library. The
|
||||
# focus of this file is testing the CREATE INDEX statement.
|
||||
#
|
||||
# $Id: index.test,v 1.13 2001/09/17 20:25:58 drh Exp $
|
||||
# $Id: index.test,v 1.14 2001/09/27 15:11:55 drh Exp $
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
@ -203,9 +203,11 @@ do_test index-7.2 {
|
||||
execsql {SELECT f1 FROM test1 WHERE f2=65536}
|
||||
} {16}
|
||||
do_test index-7.3 {
|
||||
set code [execsql {EXPLAIN SELECT f1 FROM test1 WHERE f2=65536}]
|
||||
expr {[lsearch $code {test1 (primary key)}]>0}
|
||||
} {1}
|
||||
execsql {
|
||||
SELECT name FROM sqlite_master
|
||||
WHERE type='index' AND tbl_name='test1'
|
||||
}
|
||||
} {{(test1 autoindex 1)}}
|
||||
do_test index-7.4 {
|
||||
execsql {DROP table test1}
|
||||
execsql {SELECT name FROM sqlite_master WHERE type!='meta'}
|
||||
|
@ -11,7 +11,7 @@
|
||||
# This file implements regression tests for SQLite library. The
|
||||
# focus of this file is testing the CREATE TABLE statement.
|
||||
#
|
||||
# $Id: table.test,v 1.12 2001/09/16 00:13:28 drh Exp $
|
||||
# $Id: table.test,v 1.13 2001/09/27 15:11:55 drh Exp $
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
@ -163,7 +163,7 @@ set big_table \
|
||||
)}
|
||||
do_test table-3.1 {
|
||||
execsql $big_table
|
||||
execsql {SELECT sql FROM sqlite_master WHERE type!='meta'}
|
||||
execsql {SELECT sql FROM sqlite_master WHERE type=='table'}
|
||||
} \{$big_table\}
|
||||
do_test table-3.2 {
|
||||
set v [catch {execsql {CREATE TABLE BIG(xyz foo)}} msg]
|
||||
|
@ -11,7 +11,7 @@
|
||||
# This file implements some common TCL routines used for regression
|
||||
# testing the SQLite library
|
||||
#
|
||||
# $Id: tester.tcl,v 1.19 2001/09/20 01:44:43 drh Exp $
|
||||
# $Id: tester.tcl,v 1.20 2001/09/27 15:11:55 drh Exp $
|
||||
|
||||
# Make sure tclsqlite was compiled correctly. Abort now with an
|
||||
# error message if not.
|
||||
@ -174,6 +174,15 @@ proc execsql {sql {db db}} {
|
||||
return [$db eval $sql]
|
||||
}
|
||||
|
||||
# Execute SQL and catch exceptions.
|
||||
#
|
||||
proc catchsql {sql {db db}} {
|
||||
# puts "SQL = $sql"
|
||||
set r [catch {$db eval $sql} msg]
|
||||
lappend r $msg
|
||||
return $r
|
||||
}
|
||||
|
||||
# Another procedure to execute SQL. This one includes the field
|
||||
# names in the returned list.
|
||||
#
|
||||
|
33
test/unique.test
Normal file
33
test/unique.test
Normal file
@ -0,0 +1,33 @@
|
||||
# 2001 September 27
|
||||
#
|
||||
# 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. The
|
||||
# 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.1 2001/09/27 15:11:55 drh Exp $
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
# Try to create a table with two primary keys.
|
||||
# (This is allowed in SQLite even that it is not valid SQL)
|
||||
#
|
||||
do_test unique-1.1 {
|
||||
catchsql {
|
||||
CREATE TABLE t1(
|
||||
a int PRIMARY KEY,
|
||||
b int PRIMARY KEY,
|
||||
c text
|
||||
);
|
||||
}
|
||||
} {0 {}}
|
||||
|
||||
finish_test
|
Reference in New Issue
Block a user