First cut at supporting CHECK constraints. Everything appears to work,

but much more testing is needed as well as documentation. (CVS 2754)

FossilOrigin-Name: 2313d912baeca0fd516d524f16708953de483729
This commit is contained in:
drh 2005-11-03 00:41:17 +00:00
parent 8df447f0e6
commit ffe07b2dc1
12 changed files with 279 additions and 51 deletions

View File

@ -1,5 +1,5 @@
C Omit\sthe\sSQLITE_AFF_INTEGER\stype\saffinity.\s\sAll\snumeric\svalues\sare\snow\nof\stype\sreal,\sthough\san\sinteger\srepresentation\sis\sstill\ssometimes\sused\ninternally\sfor\sefficiency.\s(CVS\s2753)
D 2005-11-01T15:48:24
C First\scut\sat\ssupporting\sCHECK\sconstraints.\s\sEverything\sappears\sto\swork,\nbut\smuch\smore\stesting\sis\sneeded\sas\swell\sas\sdocumentation.\s(CVS\s2754)
D 2005-11-03T00:41:17
F Makefile.in 12784cdce5ffc8dfb707300c34e4f1eb3b8a14f1
F Makefile.linux-gcc aee18d8a05546dcf1888bd4547e442008a49a092
F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028
@ -35,17 +35,17 @@ F src/attach.c 4b21689700a72ae281fa85dbaff06b2a62bd49ee
F src/auth.c 31e2304bef67f44d635655f44234387ea7d21454
F src/btree.c 1ccc3b3931774a68ee0d6a8e2c8ea83f27b853fb
F src/btree.h 1ed561263ca0e335bc3e81d761c9d5ff8c22f61e
F src/build.c a9dc62b900e83d70ff4a065e760064ded379c5bf
F src/build.c 5441ae700097557051c40a1d7a67d170f19d94f3
F src/callback.c 90ab4f235a2603c4cb8e6a2497091a71fb732bfa
F src/complete.c 4de937dfdd4c79a501772ab2035b26082f337a79
F src/date.c 7444b0900a28da77e57e3337a636873cff0ae940
F src/delete.c 29dac493f4d83b05f91233b116827c133bcdab72
F src/experimental.c 50c1e3b34f752f4ac10c36f287db095c2b61766d
F src/expr.c acf80a3ce4a668f4b7ae40c064049befa2f83d91
F src/expr.c e74e9c265c3572f71ab9d8f795cb656469209bb6
F src/func.c 7d81dccd9c440c6c4e761056333e629192814af0
F src/hash.c 8747cf51d12de46512880dfcf1b68b4e24072863
F src/hash.h 1b0c445e1c89ff2aaad9b4605ba61375af001e84
F src/insert.c b7757ac308a7ea8124f2d6d1a6821ea4ae045a29
F src/insert.c b814e8d73b725cf34ff9328573ea052226c290bd
F src/legacy.c d58ea507bce885298a2c8c3cbb0f4bff5d47830b
F src/main.c 97bb830cdbd378d1f87469618471f52d9d263d09
F src/md5.c 7ae1c39044b95de2f62e066f47bb1deb880a1070
@ -59,18 +59,18 @@ F src/os_win.c fbccc85e7011174068c27d54256746321a1f0059
F src/os_win.h 41a946bea10f61c158ce8645e7646b29d44f122b
F src/pager.c adbb27f13ac75cd5bc29a3d84803e0cab1edfa88
F src/pager.h e7b41ce8e7b5f629d456708b7ad9a8c8ede37140
F src/parse.y 5602d5cb894dda2932bf50b7e88782a4440ae3ae
F src/parse.y 416bc5ed6239356173d7283881750f6b7ed2b899
F src/pragma.c 9ec219dc4ee2d4e78f4ec5c9d1422089758af13f
F src/prepare.c fc098db25d2a121affb08686cf04833fd50452d4
F src/printf.c 3ea3a17d25d7ac498efc18007c70371a42c968f8
F src/random.c 90adff4e73a3b249eb4f1fc2a6ff9cf78c7233a4
F src/select.c 80c95f3cebd6f7096cdcad1968316e4bb96b18b2
F src/select.c be02f123e8651bee22beb07d89dcfa75bcc2e291
F src/shell.c 3596c1e559b82663057940d19ba533ad421c7dd3
F src/sqlite.h.in 8e648e1f386e4509f2f96c09ded7c07b0df0c9a2
F src/sqliteInt.h 922d71882bbfc64a3e7ca0f3e173a5f5ef8d00ed
F src/sqliteInt.h d4f226034a9f1b2414aed408908984008db5c44f
F src/table.c e03b60eaabaeb54a00d7e931566d77302dfc19b0
F src/tclsqlite.c 4f274fae3d4a1863451a553dd8e5015747a5d91d
F src/test1.c 0f1a66f65a54fba029f7e93b7500d49443dc959b
F src/test1.c 77506b6b88125c26f00a11bf3ff5c8dc824e837e
F src/test2.c 4196848c845626e7df894470f27329e80bfe92aa
F src/test3.c f4e6a16a602091696619a1171bda25c0e3df49f7
F src/test4.c a8fd681e139e1c61f22a77d07fc3a99cb28fff3f
@ -124,6 +124,7 @@ F test/capi2.test f897209386fb21cfdc9267595e0c667ebaca9164
F test/capi3.test fc8e573467049add3bfaf81f53827e8ff153cf8f
F test/capi3b.test 5b6a66f9f295f79f443b5d3f33187fa5ef6cf336
F test/cast.test 2543165ced4249c89ce5f0352222df503a98b9e5
F test/check.test 073a4b542793e4acb7bcfa2abb838586a3462625
F test/collate1.test add9454cef160677bb8b34148b8f277ce7f9f1c4
F test/collate2.test 224a632ba04907c049804b08162efd234aa7871f
F test/collate3.test 947a77f5b8227e037a7094d0e338a5504f155cc4
@ -295,12 +296,12 @@ F www/fullscanb.gif f7c94cb227f060511f8909e10f570157263e9a25
F www/index-ex1-x-b.gif f9b1d85c3fa2435cf38b15970c7e3aa1edae23a3
F www/index.tcl 2fff45565fd52fba6746b27eb60ea1d7834042ec
F www/indirect1b1.gif adfca361d2df59e34f9c5cac52a670c2bfc303a1
F www/lang.tcl b04a87ce05cdbd8d356d6b760a9a0b6f6fce927e
F www/lang.tcl 6ec7f6f3250e7f671cf8ada7c765e56b0cc1f169
F www/lockingv3.tcl f59b19d6c8920a931f096699d6faaf61c05db55f
F www/mingw.tcl d96b451568c5d28545fefe0c80bee3431c73f69c
F www/nulls.tcl ec35193f92485b87b90a994a01d0171b58823fcf
F www/oldnews.tcl 1a808d86882621557774bf7741ed81c7f4ef9f19
F www/omitted.tcl 658ebdc83781ac419dc8a08b3f6cf93929023470
F www/omitted.tcl ee6b46f83d513b2187869740da829a700e1a355e
F www/opcode.tcl 5bd68059416b223515a680d410a9f7cb6736485f
F www/optimizer.tcl d6812a10269bd0d7c488987aac0ad5036cace9dc
F www/optimizing.tcl f0b2538988d1bbad16cbfe63ec6e8f48c9eb04e5
@ -315,7 +316,7 @@ F www/tclsqlite.tcl ddcf912ea48695603c8ed7efb29f0812ef8d1b49
F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
F www/version3.tcl a99cf5f6d8bd4d5537584a2b342f0fb9fa601d8b
F www/whentouse.tcl 97e2b5cd296f7d8057e11f44427dea8a4c2db513
P 0d3357b5f65887f7db03db2ae021f28f480f90e4
R 129a42da3960f8ddb76cd0aa7a6f3c7c
P e0d6f61c7de2c03b8fd17ef37cf1a0add36ee618
R 1ff7e911d1dc61bef39e78e87be5de02
U drh
Z 4057f17a6edfdde3a8a1c1ea6fb897b0
Z c4af40f7e2f1f1ea9a28a66e94a942b3

View File

@ -1 +1 @@
e0d6f61c7de2c03b8fd17ef37cf1a0add36ee618
2313d912baeca0fd516d524f16708953de483729

View File

@ -22,7 +22,7 @@
** COMMIT
** ROLLBACK
**
** $Id: build.c,v 1.352 2005/11/01 15:48:24 drh Exp $
** $Id: build.c,v 1.353 2005/11/03 00:41:17 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
@ -456,6 +456,9 @@ void sqlite3DeleteTable(sqlite3 *db, Table *pTable){
sqliteFree(pTable->zName);
sqliteFree(pTable->zColAff);
sqlite3SelectDelete(pTable->pSelect);
#ifndef SQLITE_OMIT_CHECK
sqlite3ExprDelete(pTable->pCheck);
#endif
sqliteFree(pTable);
}
@ -1047,6 +1050,25 @@ primary_key_exit:
return;
}
/*
** Add a new CHECK constraint to the table currently under construction.
*/
void sqlite3AddCheckConstraint(
Parse *pParse, /* Parsing context */
Expr *pCheckExpr /* The check expression */
){
#ifndef SQLITE_OMIT_CHECK
Table *pTab = pParse->pNewTable;
if( pTab ){
/* The CHECK expression must be duplicated so that tokens refer
** to malloced space and not the (ephemeral) text of the CREATE TABLE
** statement */
pTab->pCheck = sqlite3ExprAnd(pTab->pCheck, sqlite3ExprDup(pCheckExpr));
}
#endif
sqlite3ExprDelete(pCheckExpr);
}
/*
** Set the collation function of the most recently parsed table column
** to the CollSeq given.
@ -1270,6 +1292,27 @@ void sqlite3EndTable(
assert( !db->init.busy || !pSelect );
#ifndef SQLITE_OMIT_CHECK
/* Resolve names in all CHECK constraint expressions.
*/
if( p->pCheck ){
SrcList sSrc; /* Fake SrcList for pParse->pNewTable */
NameContext sNC; /* Name context for pParse->pNewTable */
memset(&sNC, 0, sizeof(sNC));
memset(&sSrc, 0, sizeof(sSrc));
sSrc.nSrc = 1;
sSrc.a[0].zName = p->zName;
sSrc.a[0].pTab = p;
sSrc.a[0].iCursor = -1;
sNC.pParse = pParse;
sNC.pSrcList = &sSrc;
if( sqlite3ExprResolveNames(&sNC, p->pCheck) ){
return;
}
}
#endif /* !defined(SQLITE_OMIT_CHECK) */
/* If the db->init.busy is 1 it means we are reading the SQL off the
** "sqlite_master" or "sqlite_temp_master" table on the disk.
** So do not write to the disk again. Extract the root page number

View File

@ -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.232 2005/11/01 15:48:24 drh Exp $
** $Id: expr.c,v 1.233 2005/11/03 00:41:17 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
@ -802,7 +802,7 @@ int sqlite3IsRowid(const char *z){
** in pParse and return non-zero. Return zero on success.
*/
static int lookupName(
Parse *pParse, /* The parsing context */
Parse *pParse, /* The parsing context */
Token *pDbToken, /* Name of the database containing table, or NULL */
Token *pTableToken, /* Name of table containing column, or NULL */
Token *pColumnToken, /* Name of the column. */
@ -830,10 +830,9 @@ static int lookupName(
pExpr->iTable = -1;
while( pNC && cnt==0 ){
ExprList *pEList;
SrcList *pSrcList = pNC->pSrcList;
ExprList *pEList = pNC->pEList;
/* assert( zTab==0 || pEList==0 ); */
if( pSrcList ){
for(i=0, pItem=pSrcList->a; i<pSrcList->nSrc; i++, pItem++){
Table *pTab = pItem->pTab;
@ -952,7 +951,7 @@ static int lookupName(
** Note that the expression in the result set should have already been
** resolved by the time the WHERE clause is resolved.
*/
if( cnt==0 && pEList!=0 && zTab==0 ){
if( cnt==0 && (pEList = pNC->pEList)!=0 && zTab==0 ){
for(j=0; j<pEList->nExpr; j++){
char *zAs = pEList->a[j].zName;
if( zAs!=0 && sqlite3StrICmp(zAs, zCol)==0 ){
@ -1081,7 +1080,7 @@ static int nameResolverStep(void *pArg, Expr *pExpr){
if( ExprHasAnyProperty(pExpr, EP_Resolved) ) return 1;
ExprSetProperty(pExpr, EP_Resolved);
#ifndef NDEBUG
if( pSrcList ){
if( pSrcList && pSrcList->nAlloc>0 ){
int i;
for(i=0; i<pSrcList->nSrc; i++){
assert( pSrcList->a[i].iCursor>=0 && pSrcList->a[i].iCursor<pParse->nTab);
@ -1441,6 +1440,8 @@ static void codeInteger(Vdbe *v, const char *z, int n){
void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
Vdbe *v = pParse->pVdbe;
int op;
int stackChng = 1; /* Amount of change to stack depth */
if( v==0 ) return;
if( pExpr==0 ){
sqlite3VdbeAddOp(v, OP_Null, 0, 0);
@ -1462,7 +1463,11 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
/* Otherwise, fall thru into the TK_COLUMN case */
}
case TK_COLUMN: {
if( pExpr->iColumn>=0 ){
if( pExpr->iTable<0 ){
/* This only happens when coding check constraints */
assert( pParse->ckOffset>0 );
sqlite3VdbeAddOp(v, OP_Dup, pParse->ckOffset-pExpr->iColumn-1, 1);
}else if( pExpr->iColumn>=0 ){
sqlite3VdbeAddOp(v, OP_Column, pExpr->iTable, pExpr->iColumn);
sqlite3ColumnDefault(v, pExpr->pTab, pExpr->iColumn);
}else{
@ -1525,6 +1530,7 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
case SQLITE_AFF_NONE: op = OP_ToBlob; break;
}
sqlite3VdbeAddOp(v, op, 0, 0);
stackChng = 0;
break;
}
#endif /* SQLITE_OMIT_CAST */
@ -1543,6 +1549,7 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
sqlite3ExprCode(pParse, pExpr->pLeft);
sqlite3ExprCode(pParse, pExpr->pRight);
codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op, 0, 0);
stackChng = -1;
break;
}
case TK_AND:
@ -1571,6 +1578,7 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
sqlite3ExprCode(pParse, pExpr->pLeft);
sqlite3ExprCode(pParse, pExpr->pRight);
sqlite3VdbeAddOp(v, op, 0, 0);
stackChng = -1;
break;
}
case TK_UMINUS: {
@ -1596,6 +1604,7 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
assert( TK_NOT==OP_Not );
sqlite3ExprCode(pParse, pExpr->pLeft);
sqlite3VdbeAddOp(v, op, 0, 0);
stackChng = 0;
break;
}
case TK_ISNULL:
@ -1608,6 +1617,7 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
dest = sqlite3VdbeCurrentAddr(v) + 2;
sqlite3VdbeAddOp(v, op, 1, dest);
sqlite3VdbeAddOp(v, OP_AddImm, -1, 0);
stackChng = 0;
break;
}
case TK_AGG_FUNCTION: {
@ -1644,6 +1654,7 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
sqlite3VdbeOp3(v, OP_CollSeq, 0, 0, (char *)pColl, P3_COLLSEQ);
}
sqlite3VdbeOp3(v, OP_Function, constMask, nExpr, (char*)pDef, P3_FUNCDEF);
stackChng = 1-nExpr;
break;
}
#ifndef SQLITE_OMIT_SUBQUERY
@ -1702,6 +1713,7 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
case TK_UPLUS:
case TK_AS: {
sqlite3ExprCode(pParse, pExpr->pLeft);
stackChng = 0;
break;
}
case TK_CASE: {
@ -1767,9 +1779,15 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
sqlite3VdbeAddOp(v, OP_Goto, 0, pParse->trigStack->ignoreJump);
VdbeComment((v, "# raise(IGNORE)"));
}
stackChng = 0;
break;
}
#endif
break;
}
if( pParse->ckOffset ){
pParse->ckOffset += stackChng;
assert( pParse->ckOffset );
}
}
@ -1837,6 +1855,7 @@ int sqlite3ExprCodeExprList(
void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
Vdbe *v = pParse->pVdbe;
int op = 0;
int ckOffset = pParse->ckOffset;
if( v==0 || pExpr==0 ) return;
op = pExpr->op;
switch( op ){
@ -1911,6 +1930,7 @@ void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
break;
}
}
pParse->ckOffset = ckOffset;
}
/*
@ -1924,6 +1944,7 @@ void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
Vdbe *v = pParse->pVdbe;
int op = 0;
int ckOffset = pParse->ckOffset;
if( v==0 || pExpr==0 ) return;
/* The value of pExpr->op and op are related as follows:
@ -2020,6 +2041,7 @@ void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
break;
}
}
pParse->ckOffset = ckOffset;
}
/*

View File

@ -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.144 2005/11/01 15:48:24 drh Exp $
** $Id: insert.c,v 1.145 2005/11/03 00:41:17 drh Exp $
*/
#include "sqliteInt.h"
@ -868,7 +868,18 @@ void sqlite3GenerateConstraintChecks(
/* Test all CHECK constraints
*/
/**** TBD ****/
#ifndef SQLITE_OMIT_CHECK
if( pTab->pCheck ){
int allOk = sqlite3VdbeMakeLabel(v);
assert( pParse->ckOffset==0 );
pParse->ckOffset = nCol;
sqlite3ExprIfTrue(pParse, pTab->pCheck, allOk, 0);
assert( pParse->ckOffset==nCol );
pParse->ckOffset = 0;
sqlite3VdbeAddOp(v, OP_Halt, SQLITE_CONSTRAINT, OE_Abort);
sqlite3VdbeResolveLabel(v, allOk);
}
#endif /* !defined(SQLITE_OMIT_CHECK) */
/* If we have an INTEGER PRIMARY KEY, make sure the primary key
** of the new record does not previously exist. Except, if this

View File

@ -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.180 2005/09/16 02:38:10 drh Exp $
** @(#) $Id: parse.y,v 1.181 2005/11/03 00:41:17 drh Exp $
*/
// All token codes are small integers with #defines that begin with "TK_"
@ -268,7 +268,7 @@ ccons ::= NOT NULL onconf(R). {sqlite3AddNotNull(pParse, R);}
ccons ::= PRIMARY KEY sortorder onconf(R) autoinc(I).
{sqlite3AddPrimaryKey(pParse,0,R,I);}
ccons ::= UNIQUE onconf(R). {sqlite3CreateIndex(pParse,0,0,0,0,R,0,0);}
ccons ::= CHECK LP expr(X) RP onconf. {sqlite3ExprDelete(X);}
ccons ::= CHECK LP expr(X) RP. {sqlite3AddCheckConstraint(pParse, X);}
ccons ::= REFERENCES nm(T) idxlist_opt(TA) refargs(R).
{sqlite3CreateForeignKey(pParse,0,&T,TA,R);}
ccons ::= defer_subclause(D). {sqlite3DeferForeignKey(pParse,D);}

View File

@ -12,7 +12,7 @@
** This file contains C code routines that are called by the parser
** to handle SELECT statements in SQLite.
**
** $Id: select.c,v 1.277 2005/10/06 16:53:15 drh Exp $
** $Id: select.c,v 1.278 2005/11/03 00:41:17 drh Exp $
*/
#include "sqliteInt.h"
@ -2384,14 +2384,8 @@ int sqlite3SelectResolve(
/* Resolve the expressions in the LIMIT and OFFSET clauses. These
** are not allowed to refer to any names, so pass an empty NameContext.
*/
memset(&sNC, 0, sizeof(sNC));
sNC.pParse = pParse;
sNC.hasAgg = 0;
sNC.nErr = 0;
sNC.nRef = 0;
sNC.pEList = 0;
sNC.allowAgg = 0;
sNC.pSrcList = 0;
sNC.pNext = 0;
if( sqlite3ExprResolveNames(&sNC, p->pLimit) ||
sqlite3ExprResolveNames(&sNC, p->pOffset) ){
return SQLITE_ERROR;

View File

@ -11,7 +11,7 @@
*************************************************************************
** Internal interface definitions for SQLite.
**
** @(#) $Id: sqliteInt.h,v 1.424 2005/11/01 15:48:24 drh Exp $
** @(#) $Id: sqliteInt.h,v 1.425 2005/11/03 00:41:17 drh Exp $
*/
#ifndef _SQLITEINT_H_
#define _SQLITEINT_H_
@ -639,6 +639,9 @@ struct Table {
Trigger *pTrigger; /* List of SQL triggers on this table */
FKey *pFKey; /* Linked list of all foreign keys in this table */
char *zColAff; /* String defining the affinity of each column */
#ifndef SQLITE_OMIT_CHECK
Expr *pCheck; /* The AND of all CHECK constraints */
#endif
#ifndef SQLITE_OMIT_ALTERTABLE
int addColOffset; /* Offset in CREATE TABLE statement to add a new column */
#endif
@ -1172,6 +1175,7 @@ struct Parse {
int nTab; /* Number of previously allocated VDBE cursors */
int nMem; /* Number of memory cells used so far */
int nSet; /* Number of sets used so far */
int ckOffset; /* Stack offset to data used by CHECK constraints */
u32 writeMask; /* Start a write transaction on these databases */
u32 cookieMask; /* Bitmask of schema verified databases */
int cookieGoto; /* Address of OP_Goto to cookie verifier subroutine */
@ -1449,6 +1453,7 @@ void sqlite3StartTable(Parse*,Token*,Token*,Token*,int,int);
void sqlite3AddColumn(Parse*,Token*);
void sqlite3AddNotNull(Parse*, int);
void sqlite3AddPrimaryKey(Parse*, ExprList*, int, int);
void sqlite3AddCheckConstraint(Parse*, Expr*);
void sqlite3AddColumnType(Parse*,Token*);
void sqlite3AddDefaultValue(Parse*,Expr*);
void sqlite3AddCollateType(Parse*, const char*, int);

View File

@ -13,7 +13,7 @@
** is not included in the SQLite library. It is used for automated
** testing of the SQLite library.
**
** $Id: test1.c,v 1.162 2005/09/19 13:15:23 drh Exp $
** $Id: test1.c,v 1.163 2005/11/03 00:41:17 drh Exp $
*/
#include "sqliteInt.h"
#include "tcl.h"
@ -2876,6 +2876,12 @@ static void set_options(Tcl_Interp *interp){
Tcl_SetVar2(interp, "sqlite_options", "cast", "1", TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_OMIT_CHECK
Tcl_SetVar2(interp, "sqlite_options", "check", "0", TCL_GLOBAL_ONLY);
#else
Tcl_SetVar2(interp, "sqlite_options", "check", "1", TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_OMIT_COMPLETE
Tcl_SetVar2(interp, "sqlite_options", "complete", "0", TCL_GLOBAL_ONLY);
#else

153
test/check.test Normal file
View File

@ -0,0 +1,153 @@
# 2005 November 2
#
# 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 CHECK constraints
#
# $Id: check.test,v 1.1 2005/11/03 00:41:18 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# Only run these tests if the build includes support for CHECK constraints
ifcapable !check {
finish_test
return
}
do_test check-1.1 {
execsql {
CREATE TABLE t1(
x INTEGER CHECK( x<5 ),
y REAL CHECK( y>x )
);
}
} {}
do_test check-1.2 {
execsql {
INSERT INTO t1 VALUES(3,4);
SELECT * FROM t1;
}
} {3 4}
do_test check-1.3 {
catchsql {
INSERT INTO t1 VALUES(6,7);
}
} {1 {constraint failed}}
do_test check-1.4 {
execsql {
SELECT * FROM t1;
}
} {3 4}
do_test check-1.5 {
catchsql {
INSERT INTO t1 VALUES(4,3);
}
} {1 {constraint failed}}
do_test check-1.6 {
execsql {
SELECT * FROM t1;
}
} {3 4}
do_test check-1.7 {
catchsql {
INSERT INTO t1 VALUES(NULL,6);
}
} {1 {constraint failed}}
do_test check-1.8 {
execsql {
SELECT * FROM t1;
}
} {3 4}
do_test check-1.9 {
catchsql {
INSERT INTO t1 VALUES(2,NULL);
}
} {1 {constraint failed}}
do_test check-1.10 {
execsql {
SELECT * FROM t1;
}
} {3 4}
do_test check-1.11 {
execsql {
UPDATE t1 SET x=2 WHERE x==3;
SELECT * FROM t1;
}
} {2 4}
do_test check-1.12 {
catchsql {
UPDATE t1 SET x=7 WHERE x==2
}
} {1 {constraint failed}}
do_test check-1.13 {
execsql {
SELECT * FROM t1;
}
} {2 4}
do_test check-1.14 {
catchsql {
UPDATE t1 SET x=5 WHERE x==2
}
} {1 {constraint failed}}
do_test check-1.15 {
execsql {
SELECT * FROM t1;
}
} {2 4}
do_test check-1.16 {
catchsql {
UPDATE t1 SET x=4, y=11 WHERE x==2
}
} {0 {}}
do_test check-1.17 {
execsql {
SELECT * FROM t1;
}
} {4 11}
do_test check-2.1 {
execsql {
CREATE TABLE t2(
x INTEGER CHECK( typeof(coalesce(x,0))=="integer" ),
y REAL CHECK( typeof(coalesce(y,0.1))=="real" ),
z TEXT CHECK( typeof(coalesce(z,''))=="text" )
);
}
} {}
do_test check-2.2 {
execsql {
INSERT INTO t2 VALUES(1,2.2,'three');
SELECT * FROM t2;
}
} {1 2.2 three}
do_test check-2.3 {
execsql {
INSERT INTO t2 VALUES(NULL, NULL, NULL);
SELECT * FROM t2;
}
} {1 2.2 three {} {} {}}
do_test check-2.4 {
catchsql {
INSERT INTO t2 VALUES(1.1, NULL, NULL);
}
} {1 {constraint failed}}
do_test check-2.5 {
catchsql {
INSERT INTO t2 VALUES(NULL, 5, NULL);
}
} {1 {constraint failed}}
do_test check-2.6 {
catchsql {
INSERT INTO t2 VALUES(NULL, NULL, 3.14159);
}
} {1 {constraint failed}}
finish_test

View File

@ -1,7 +1,7 @@
#
# Run this Tcl script to generate the lang-*.html files.
#
set rcsid {$Id: lang.tcl,v 1.100 2005/09/11 11:56:28 drh Exp $}
set rcsid {$Id: lang.tcl,v 1.101 2005/11/03 00:41:18 drh Exp $}
source common.tcl
if {[llength $argv]>0} {
@ -511,13 +511,13 @@ CREATE [TEMP | TEMPORARY] TABLE [<database-name>.] <table-name> AS <select-state
NOT NULL [ <conflict-clause> ] |
PRIMARY KEY [<sort-order>] [ <conflict-clause> ] [AUTOINCREMENT] |
UNIQUE [ <conflict-clause> ] |
CHECK ( <expr> ) [ <conflict-clause> ] |
CHECK ( <expr> ) |
DEFAULT <value> |
COLLATE <collation-name>
} {constraint} {
PRIMARY KEY ( <column-list> ) [ <conflict-clause> ] |
UNIQUE ( <column-list> ) [ <conflict-clause> ] |
CHECK ( <expr> ) [ <conflict-clause> ]
CHECK ( <expr> )
} {conflict-clause} {
ON CONFLICT <conflict-algorithm>
}
@ -596,10 +596,8 @@ default algorithm specified in the CREATE TABLE statement.
See the section titled
<a href="#conflict">ON CONFLICT</a> for additional information.</p>
<p>CHECK constraints are ignored in the current implementation.
Support for CHECK constraints may be added in the future. As of
version 2.3.0, NOT NULL, PRIMARY KEY, and UNIQUE constraints all
work.</p>
<p>CHECK constraints are supported as of version 3.3.0. Prior
to version 3.3.0, CHECK constraints were parsed but not enforced.</p>
<p>There are no arbitrary limits on the number
of columns or on the number of constraints in a table.

View File

@ -1,7 +1,7 @@
#
# Run this script to generated a omitted.html output file
#
set rcsid {$Id: omitted.tcl,v 1.9 2005/09/11 11:56:28 drh Exp $}
set rcsid {$Id: omitted.tcl,v 1.10 2005/11/03 00:41:18 drh Exp $}
source common.tcl
header {SQL Features That SQLite Does Not Implement}
puts {
@ -28,11 +28,6 @@ proc feature {name desc} {
puts "<td valign=\"top\">$desc</td></tr>"
}
feature {CHECK constraints} {
CHECK constraints are parsed but they are not enforced.
NOT NULL and UNIQUE constraints are enforced, however.
}
feature {FOREIGN KEY constraints} {
FOREIGN KEY constraints are parsed but are not enforced.
}