Index: src/build.c
==================================================================
--- src/build.c
+++ src/build.c
@@ -20,11 +20,11 @@
** creating ID lists
** BEGIN TRANSACTION
** 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
/*
@@ -454,10 +454,13 @@
*/
sqliteResetColumnNames(pTable);
sqliteFree(pTable->zName);
sqliteFree(pTable->zColAff);
sqlite3SelectDelete(pTable->pSelect);
+#ifndef SQLITE_OMIT_CHECK
+ sqlite3ExprDelete(pTable->pCheck);
+#endif
sqliteFree(pTable);
}
/*
** Unlink the given table from the hash tables and the delete the
@@ -1044,10 +1047,29 @@
primary_key_exit:
sqlite3ExprListDelete(pList);
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.
*/
@@ -1268,10 +1290,31 @@
p = pParse->pNewTable;
if( p==0 ) return;
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
** for the table from the db->init.newTnum field. (The page number
** should have been put there by the sqliteOpenCb routine.)
Index: src/expr.c
==================================================================
--- src/expr.c
+++ src/expr.c
@@ -10,11 +10,11 @@
**
*************************************************************************
** 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
/*
@@ -800,11 +800,11 @@
**
** If the name cannot be resolved unambiguously, leave an error message
** 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. */
NameContext *pNC, /* The name context used to resolve the name */
Expr *pExpr /* Make this EXPR node point to the selected column */
@@ -828,14 +828,13 @@
goto lookupname_end;
}
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; inSrc; i++, pItem++){
Table *pTab = pItem->pTab;
Column *pCol;
@@ -950,11 +949,11 @@
** In cases like this, replace pExpr with a copy of the expression that
** forms the result set entry ("a+b" in the example) and return immediately.
** 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; jnExpr; j++){
char *zAs = pEList->a[j].zName;
if( zAs!=0 && sqlite3StrICmp(zAs, zCol)==0 ){
assert( pExpr->pLeft==0 && pExpr->pRight==0 );
pExpr->op = TK_AS;
@@ -1079,11 +1078,11 @@
pParse = pNC->pParse;
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; inSrc; i++){
assert( pSrcList->a[i].iCursor>=0 && pSrcList->a[i].iCursornTab);
}
}
@@ -1439,10 +1438,12 @@
** below verify that the numbers are aligned correctly.
*/
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);
return;
}
@@ -1460,11 +1461,15 @@
break;
}
/* 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{
sqlite3VdbeAddOp(v, OP_Rowid, pExpr->iTable, 0);
}
@@ -1523,10 +1528,11 @@
case SQLITE_AFF_NUMERIC: op = OP_ToNumeric; break;
case SQLITE_AFF_TEXT: op = OP_ToText; break;
case SQLITE_AFF_NONE: op = OP_ToBlob; break;
}
sqlite3VdbeAddOp(v, op, 0, 0);
+ stackChng = 0;
break;
}
#endif /* SQLITE_OMIT_CAST */
case TK_LT:
case TK_LE:
@@ -1541,10 +1547,11 @@
assert( TK_EQ==OP_Eq );
assert( TK_NE==OP_Ne );
sqlite3ExprCode(pParse, pExpr->pLeft);
sqlite3ExprCode(pParse, pExpr->pRight);
codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op, 0, 0);
+ stackChng = -1;
break;
}
case TK_AND:
case TK_OR:
case TK_PLUS:
@@ -1569,10 +1576,11 @@
assert( TK_RSHIFT==OP_ShiftRight );
assert( TK_CONCAT==OP_Concat );
sqlite3ExprCode(pParse, pExpr->pLeft);
sqlite3ExprCode(pParse, pExpr->pRight);
sqlite3VdbeAddOp(v, op, 0, 0);
+ stackChng = -1;
break;
}
case TK_UMINUS: {
Expr *pLeft = pExpr->pLeft;
assert( pLeft );
@@ -1594,10 +1602,11 @@
case TK_NOT: {
assert( TK_BITNOT==OP_BitNot );
assert( TK_NOT==OP_Not );
sqlite3ExprCode(pParse, pExpr->pLeft);
sqlite3VdbeAddOp(v, op, 0, 0);
+ stackChng = 0;
break;
}
case TK_ISNULL:
case TK_NOTNULL: {
int dest;
@@ -1606,10 +1615,11 @@
sqlite3VdbeAddOp(v, OP_Integer, 1, 0);
sqlite3ExprCode(pParse, pExpr->pLeft);
dest = sqlite3VdbeCurrentAddr(v) + 2;
sqlite3VdbeAddOp(v, op, 1, dest);
sqlite3VdbeAddOp(v, OP_AddImm, -1, 0);
+ stackChng = 0;
break;
}
case TK_AGG_FUNCTION: {
AggInfo *pInfo = pExpr->pAggInfo;
sqlite3VdbeAddOp(v, OP_MemLoad, pInfo->aFunc[pExpr->iAgg].iMem, 0);
@@ -1642,10 +1652,11 @@
if( pDef->needCollSeq ){
if( !pColl ) pColl = pParse->db->pDfltColl;
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
case TK_EXISTS:
case TK_SELECT: {
@@ -1700,10 +1711,11 @@
break;
}
case TK_UPLUS:
case TK_AS: {
sqlite3ExprCode(pParse, pExpr->pLeft);
+ stackChng = 0;
break;
}
case TK_CASE: {
int expr_end_label;
int jumpInst;
@@ -1765,13 +1777,19 @@
assert( pExpr->iColumn == OE_Ignore );
sqlite3VdbeAddOp(v, OP_ContextPop, 0, 0);
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 );
}
}
#ifndef SQLITE_OMIT_TRIGGER
/*
@@ -1835,10 +1853,11 @@
** below verify that the numbers are aligned correctly.
*/
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 ){
case TK_AND: {
int d2 = sqlite3VdbeMakeLabel(v);
@@ -1909,10 +1928,11 @@
sqlite3ExprCode(pParse, pExpr);
sqlite3VdbeAddOp(v, OP_If, jumpIfNull, dest);
break;
}
}
+ pParse->ckOffset = ckOffset;
}
/*
** Generate code for a boolean expression such that a jump is made
** to the label "dest" if the expression is false but execution
@@ -1922,10 +1942,11 @@
** jump if jumpIfNull is true or fall through if jumpIfNull is false.
*/
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:
**
** pExpr->op op
@@ -2018,10 +2039,11 @@
sqlite3ExprCode(pParse, pExpr);
sqlite3VdbeAddOp(v, OP_IfNot, jumpIfNull, dest);
break;
}
}
+ pParse->ckOffset = ckOffset;
}
/*
** Do a deep comparison of two expression trees. Return TRUE (non-zero)
** if they are identical and return FALSE if they differ in any way.
Index: src/insert.c
==================================================================
--- src/insert.c
+++ src/insert.c
@@ -10,11 +10,11 @@
**
*************************************************************************
** 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"
/*
** Set P3 of the most recently inserted opcode to a column affinity
@@ -866,11 +866,22 @@
sqlite3VdbeJumpHere(v, addr);
}
/* 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
** is an UPDATE and the primary key is not changing, that is OK.
*/
Index: src/parse.y
==================================================================
--- src/parse.y
+++ src/parse.y
@@ -12,11 +12,11 @@
** This file contains SQLite's grammar for SQL. Process this file
** using the lemon parser generator to generate C code that runs
** 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_"
%token_prefix TK_
@@ -266,11 +266,11 @@
ccons ::= NULL onconf.
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);}
ccons ::= COLLATE id(C). {sqlite3AddCollateType(pParse, C.z, C.n);}
Index: src/select.c
==================================================================
--- src/select.c
+++ src/select.c
@@ -10,11 +10,11 @@
**
*************************************************************************
** 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"
/*
@@ -2382,18 +2382,12 @@
}
/* 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;
}
Index: src/sqliteInt.h
==================================================================
--- src/sqliteInt.h
+++ src/sqliteInt.h
@@ -9,11 +9,11 @@
** May you share freely, never taking more than you give.
**
*************************************************************************
** 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_
/*
@@ -637,10 +637,13 @@
u8 autoInc; /* True if the integer primary key is autoincrement */
int nRef; /* Number of pointers to this 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
};
@@ -1170,10 +1173,11 @@
u8 nested; /* Number of nested calls to the parser/code generator */
int nErr; /* Number of errors seen */
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 */
int cookieValue[MAX_ATTACHED+2]; /* Values of cookies to verify */
@@ -1447,10 +1451,11 @@
void sqlite3OpenMasterTable(Vdbe *v, int);
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);
void sqlite3EndTable(Parse*,Token*,Token*,Select*);
Index: src/test1.c
==================================================================
--- src/test1.c
+++ src/test1.c
@@ -11,11 +11,11 @@
*************************************************************************
** Code for testing the printf() interface to SQLite. This code
** 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"
#include "os.h"
#include
@@ -2873,10 +2873,16 @@
#ifdef SQLITE_OMIT_CAST
Tcl_SetVar2(interp, "sqlite_options", "cast", "0", TCL_GLOBAL_ONLY);
#else
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
Tcl_SetVar2(interp, "sqlite_options", "complete", "1", TCL_GLOBAL_ONLY);
ADDED test/check.test
Index: test/check.test
==================================================================
--- /dev/null
+++ test/check.test
@@ -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
Index: www/lang.tcl
==================================================================
--- www/lang.tcl
+++ www/lang.tcl
@@ -1,9 +1,9 @@
#
# 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} {
set outputdir [lindex $argv 0]
} else {
@@ -509,17 +509,17 @@
( , )
} {column-constraint} {
NOT NULL [ ] |
PRIMARY KEY [] [ ] [AUTOINCREMENT] |
UNIQUE [ ] |
-CHECK ( ) [ ] |
+CHECK ( ) |
DEFAULT |
COLLATE
} {constraint} {
PRIMARY KEY ( ) [ ] |
UNIQUE ( ) [ ] |
-CHECK ( ) [ ]
+CHECK ( )
} {conflict-clause} {
ON CONFLICT
}
puts {
@@ -594,14 +594,12 @@
resolution algorithm, then that algorithm is used in place of the
default algorithm specified in the CREATE TABLE statement.
See the section titled
ON CONFLICT for additional information.
-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.
+CHECK constraints are supported as of version 3.3.0. Prior
+to version 3.3.0, CHECK constraints were parsed but not enforced.
There are no arbitrary limits on the number
of columns or on the number of constraints in a table.
The total amount of data in a single row is limited to about
1 megabytes in version 2.8. In version 3.0 there is no arbitrary
Index: www/omitted.tcl
==================================================================
--- www/omitted.tcl
+++ www/omitted.tcl
@@ -1,9 +1,9 @@
#
# 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 {
SQL Features That SQLite Does Not Implement
@@ -26,15 +26,10 @@
puts "$name | "
puts " "
puts " | $desc |
"
}
-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.
}
feature {Complete trigger support} {