Added ON CONFLICT support to COPY. Updates to documentation. Bug fixes. (CVS 359)

FossilOrigin-Name: cf1538d71c9ce12d5e59f367e03642cbcaf6b717
This commit is contained in:
drh
2002-01-30 16:17:23 +00:00
parent ef6764a1d9
commit b419a926d4
15 changed files with 493 additions and 107 deletions
+9
View File
@@ -17,6 +17,15 @@ proc chng {date desc} {
puts "<DD><P><UL>$desc</UL></P></DD>"
}
chng {2002 Jan 30 (2.3.0 beta)} {
<li>Added the ability to resolve constraint conflicts is ways other than
an abort and rollback. See the documentation on the "ON CONFLICT"
clause for details.</li>
<li>NOT NULL constraints are honored.</li>
<li>The COPY command puts NULLs in columns whose data is '\N'.</li>
<li>In the COPY command, backslash can now be used to escape a newline.</li>
}
chng {2002 Jan 28 (2.2.5)} {
<li>Important bug fix: the IN operator was not working if either the
left-hand or right-hand side was derived from an INTEGER PRIMARY KEY.</li>
+191
View File
@@ -0,0 +1,191 @@
#
# Run this Tcl script to generate the constraint.html file.
#
set rcsid {$Id: conflict.tcl,v 1.1 2002/01/30 16:17:25 drh Exp $ }
puts {<html>
<head>
<title>Constraint Conflict Resolution in SQLite</title>
</head>
<body bgcolor=white>
<h1 align=center>
Constraint Conflict Resolution in SQLite
</h1>}
puts "<p align=center>
(This page was last modified on [lrange $rcsid 3 4] UTC)
</p>"
puts {
<h2>Introduction</h2>
<p>
In most SQL databases, if you have a UNIQUE constraint on
a table and you try to do an UPDATE or INSERT that violates
that constraint, the database will aborts the operation in
progress and rolls back the current transaction.
This is the default behavior of SQLite.
Beginning with version 2.3.0, though, SQLite allows you to
define alternative ways for dealing with constraint violations.
This article describes those alternatives and how to use them.
</p>
<h2>Conflict Resolution Algorithms</h2>
<p>
The default conflict resolution algorithm is to abort the
operation in progress, rollback all changes, and cancel the
current transaction. Call this algorithm "ABORT". Abort
is the standard way of dealing with a constraint error
in most SQL databases.
</p>
<p>
Sometimes ABORT is not the most helpful way of dealing
with constraint violations. Suppose, for example, you are
inserting 1000 records into a database, all within a single
transaction, but one of those records is malformed and causes
a constraint error. With the default ABORT behavior, none
of the 1000 records gets inserted. But sometimes it is
desirable to just omit the single malformed insert and
finish the other 999.
</p>
<p>
SQLite defines two addition conflict resolution algorithms
called "IGNORE" and "REPLACE".
If you are trying to do multiple INSERTs or UPDATEs when a constraint
fails for a single row and the conflict behavior is IGNORE, then
that row remains uninserted or unmodified. But the overall operation
is not aborted and no rollback occurs. If a constraint
fails and the behavior is REPLACE, then SQLite tries to
delete other rows in the table in order to eliminate the
constraint problem. Again, the overall operation continues
and no rollback occurs.
</p>
<p>
The default conflict resolution algorithm is always ABORT
but you can specify an alternative algorithm using special
(non-standard) syntax on the INSERT and UPDATE commands.
You can add the clause "ON CONFLICT <algorithm>" immediately
after the "INSERT" or "UPDATE" keywords to specify the
conflict resolution algorithm to use for that one operation.
(Substitute "ABORT", "IGNORE", or "REPLACE" for <algorithm>,
of course.)
</p>
Consider this example:
<blockquote><pre>
BEGIN;
CREATE TABLE t1(
a INTEGER,
b INTEGER,
c INTEGER,
UNIQUE(a,b)
);
INSERT INTO a VALUES(1,2,3);
COMMIT;
BEGIN;
INSERT INTO a VALUES(2,3,4);
INSERT INTO a VALUES(1,2,5);
</pre></blockquote>
<p>
In the last instruction, the UNIQUE constraint fails
and the entire transaction is rolled back. The database
now contains a single entry: {1,2,3}.
</p>
<blockquote><pre>
BEGIN;
INSERT ON CONFLICT IGNORE INTO a VALUES(2,3,4);
INSERT ON CONFLICT IGNORE INTO a VALUES(1,2,5);
COMMIT;
</pre></blockquote>
<p>This time the "ON CONFLICT IGNORE" clause tells SQLite to use
IGNORE semantics when a constraint fails. The second
INSERT statement fails, but the database is
not rolled back and there is no failure. The database
now contains two rows: {1,2,3} and {2,3,4}.</p>
<blockquote><pre>
BEGIN;
INSERT ON CONFLICT REPLACE INTO a VALUES(1,2,5);
COMMIT;
</pre></blockquote>
<p>Here the "ON CONFLICT REPLACE" clause tells SQLite to use REPLACE
semantics. The {1,2,3} is deleted when the {1,2,5} row
is inserted in order to satisfy the constraint. After
the above, the database contains {1,2,5} and {2,3,4}.</p>
<h2>A Syntactic Shortcut</h2>
<p>On an INSERT, the "ON CONFLICT" keywords may be omitted for brevity.
So you can say</p>
<blockquote><pre>
INSERT IGNORE INTO a VALUES(1,2,5);
</pre></blockquote>
<p>Instead of the more wordy:</p>
<blockquote><pre>
INSERT ON CONFLICT IGNORE INTO a VALUES(1,2,5);
</pre></blockquote>
<p>Unfortunately, you cannot do this with an UPDATE.</p>
<h2>Changing The Default Conflict Resolution Algorithm</h2>
<p>You can change the default conflict resolution algorithm
on a constraint-by-constraint basis using special (non-standard)
syntax in CREATE TABLE and CREATE INDEX statements. The
same "ON CONFLICT" clause that appears in INSERT and UPDATE
statements is used but the clause is attached to the constraint
in the CREATE TABLE statement. Like this:
<blockquote><pre>
CREATE TABLE t1 (
a INTEGER,
b INTEGER,
c INTEGER,
UNIQUE(a,b) ON CONFLICT REPLACE
);
</pre></blockquote>
<p>The ON CONFLICT clause in the above table definition says that
the default conflict resolution algorithm is REPLACE instead
of ABORT. REPLACE will always be used unless you override
this by saying "INSERT IGNORE" or "INSERT ABORT".</p>
<p>The ON CONFLICT clause can also appear on a NOT NULL constraint,
a PRIMARY KEY constraint, and a CHECK constraint.
(Note, however, that CHECK constraints are not currently enforced
so the ON CONFLICT clause has no effect there.)</p>
<p>A NOT NULL constraint will normally ABORT if you try to insert
a NULL. But if you substitute the REPLACE algorithm, it tries to insert
the default value in place of the NULL. If there is no default value,
then REPLACE is the same as ABORT for NOT NULL constraints.
With the IGNORE algorithm on a NOT NULL, the INSERT or UPDATE
is suppressed if the value is NULL.</p>
<h2>Portability</h2>
<p>The ON CONFLICT syntax is not standard SQL and will not
(as far as is known) work on any other database product. Furthermore,
the syntax might change in future versions of SQLite. So use it
with appropriate discretion.</p>
}
puts {
<p><hr /></p>
<p><a href="index.html"><img src="/goback.jpg" border=0 />
Back to the SQLite Home Page</a>
</p>
</body></html>}
+11 -1
View File
@@ -1,7 +1,7 @@
#
# Run this Tcl script to generate the formatchng.html file.
#
set rcsid {$Id: formatchng.tcl,v 1.1 2001/12/22 19:27:41 drh Exp $ }
set rcsid {$Id: formatchng.tcl,v 1.2 2002/01/30 16:17:25 drh Exp $ }
puts {<html>
<head>
@@ -81,6 +81,16 @@ occurred since version 1.0.0:
and version 2.2.x database files will be identical and completely
interchangeable.</p>
</tr>
<tr>
<td valign="top">2.2.5 to 2.3.0</td>
<td valign="top">2002-Jan-30</td>
<td>Beginning with version 2.3.0, SQLite supports some additional syntax
(the "ON CONFLICT" clause) in the CREATE TABLE and CREATE INDEX statements
that are stored in the SQLITE_MASTER table. If you create a database that
contains this new syntax, then try to read that database using version 2.2.5
or earlier, the parser will not understand the new syntax and you will get
an error. Otherwise, databases for 2.2.x and 2.3.x are interchangeable.</p>
</tr>
</table>
</blockquote>
+96 -16
View File
@@ -1,7 +1,7 @@
#
# Run this Tcl script to generate the sqlite.html file.
#
set rcsid {$Id: lang.tcl,v 1.18 2001/12/22 19:27:41 drh Exp $}
set rcsid {$Id: lang.tcl,v 1.19 2002/01/30 16:17:25 drh Exp $}
puts {<html>
<head>
@@ -31,7 +31,7 @@ by SQLite. Many low-level productions are omitted. For detailed information
on the language that SQLite understands, refer to the source code.</p>
<p>SQLite implements the follow SQL commands:</p>
<p>SQLite implements the follow syntax:</p>
<p><ul>
}
@@ -50,6 +50,7 @@ foreach {section} [lsort -index 0 -dictionary {
{expression expr}
{{BEGIN TRANSACTION} transaction}
{PRAGMA pragma}
{{ON CONFLICT clause} conflict}
}] {
puts "<li><a href=\"#[lindex $section 1]\">[lindex $section 0]</a></li>"
}
@@ -140,12 +141,47 @@ a alias for COMMIT.
</p>
}
Section {ON CONFLICT clause} conflict
Syntax {conflict-clause} {
ON CONFLICT <algorithm>
} {algorithm} {
ABORT | IGNORE | REPLACE
}
puts {
<p>The ON CONFLICT clause is not a separate SQL command. It is a
non-standard clause that can appear in many other SQL commands.
It is given its own section in this document because it is not
part of standard SQL and therefore might not be familiar.</p>
<p>The ON CONFLICT clause specifies an algorithm used to resolve
constraint conflicts. The default algorithm is ABORT. When the
ABORT algorithm is in use, any constraint violation causes the
command to abort and the current transaction to be rolled back.
This is the only behavior exhibited by most SQL engines. But
SQLite allows two alternative behaviors: IGNORE and REPLACE.
The IGNORE algorithm means that when a constraint violation occurs
on a COPY, INSERT or UPDATE, the particular row that caused the constraint
violation is not inserted or changed, but other rows effected by the
COPY, INSERT, or UPDATE are insert or changed as usual.
The command is not aborted and no rollback occurs.
If the algorithm is REPLACE, then SQLite tries to
delete preexisting rows from the table to remove the constraint
violation before inserting or changing the row.</p>
<p>For additional information, see
<a href="conflict.html">conflict.html</a>.</p>
}
Section COPY copy
Syntax {sql-statement} {
COPY <table-name> FROM <filename>
COPY [ <conflict-clause> ] <table-name> FROM <filename>
[ USING DELIMITERS <delim> ]
}
puts {
<p>The COPY command is an extension used to load large amounts of
data into a table. It is modeled after a similar command found
@@ -163,7 +199,16 @@ the <b>STDIN</b> to read data from standard input.<p>
in the table. Columns are separated by tabs. If a tab occurs as
data within a column, then that tab is preceded by a baskslash "\"
character. A baskslash in the data appears as two backslashes in
a row.</p>
a row. The optional USING DELIMITERS clause can specify a delimiter
other than tab.</p>
<p>If a column consists of the character "\N", that column is filled
with the value NULL.</p>
<p>The optional conflict-clause allows the specification of an alternative
constraint conflict resolution algorithm to use for this one command.
See the section titled
<a href="#conflict">ON CONFLICT</a> for additional information.</p>
<p>When the input data source is STDIN, the input can be terminated
by a line that contains only a baskslash and a dot:}
@@ -174,10 +219,12 @@ Section {CREATE INDEX} createindex
Syntax {sql-statement} {
CREATE [UNIQUE] INDEX <index-name>
ON <table-name> ( <column-name> [, <column-name>]* )
[ <conflict-clause> ]
} {column-name} {
<name> [ ASC | DESC ]
}
puts {
<p>The CREATE INDEX command consists of the keywords "CREATE INDEX" followed
by the name of the new index, the keyword "ON", the name of a previously
@@ -194,6 +241,16 @@ attached to a single table, nor on the number of columns in an index.</p>
index entries are not allowed. Any attempt to insert a duplicate entry
will result in a rollback and an error message.</p>
<p>The optional conflict-clause allows the specification of al alternative
default constraint conflict resolution algorithm for this index.
This only makes sense if the UNIQUE keyword is used since otherwise
there are not constraints on the index. The default algorithm is
ABORT. If a COPY, INSERT, or UPDATE statement specifies a particular
conflict resolution algorithm, that algorithm is used in place of
the default algorithm specified here.
See the section titled
<a href="#conflict">ON CONFLICT</a> for additional information.</p>
<p>The exact text
of each CREATE INDEX statement is stored in the <b>sqlite_master</b>
table. Everytime the database is opened, all CREATE INDEX statements
@@ -216,15 +273,15 @@ CREATE [TEMP | TEMPORARY] TABLE <table-name> (
<typename> ( <number> ) |
<typename> ( <number> , <number> )
} {column-constraint} {
NOT NULL |
PRIMARY KEY [<sort-order>] |
UNIQUE |
CHECK ( <expr> ) |
NOT NULL [ <conflict-clause> ] |
PRIMARY KEY [<sort-order>] [ <conflict-clause> ] |
UNIQUE [ <conflict-clause> ] |
CHECK ( <expr> ) [ <conflict-clause> ] |
DEFAULT <value>
} {constraint} {
PRIMARY KEY ( <name> [, <name>]* ) |
UNIQUE ( <name> [, <name>]* ) |
CHECK ( <expr> )
PRIMARY KEY ( <name> [, <name>]* ) [ <conflict-clause> ]|
UNIQUE ( <name> [, <name>]* ) [ <conflict-clause> ] |
CHECK ( <expr> ) [ <conflict-clause> ]
}
puts {
@@ -265,6 +322,17 @@ the database is closed. Any indices created on a temporary table
are also temporary. Temporary tables and indices are stored in a
separate file distinct from the main database file.</p>
<p>The optional conflict-clause following each constraint
allows the specification of an alternative default
constraint conflict resolution algorithm for that constraint.
The default is abort ABORT. Different constraints within the same
table may have different default conflict resolution algorithms.
If an COPY, INSERT, or UPDATE command specifies a different conflict
resolution algorithm, then that algorithm is used in place of the
default algorithm specified in the CREATE TABLE statement.
See the section titled
<a href="#conflict">ON CONFLICT</a> for additional information.</p>
<p>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
@@ -363,7 +431,7 @@ LIKE | GLOB | NOT LIKE | NOT GLOB
}
puts {
<p>This section is different from the others. Every other section of
<p>This section is different from the others. Most other sections of
this document talks about a particular SQL command. This section does
not talk about a standalone command but about "expressions" which are
subcomponent of most other commands.</p>
@@ -490,8 +558,8 @@ The "<b>count(*)</b>" syntax is supported but
Section INSERT insert
Syntax {sql-statement} {
INSERT INTO <table-name> [( <column-list> )] VALUES ( <value-list> ) |
INSERT INTO <table-name> [( <column-list> )] <select-statement>
INSERT [ <conflict-clause> ] INTO <table-name> [( <column-list> )] VALUES ( <value-list> ) |
INSERT [ <conflict-clause> ] INTO <table-name> [( <column-list> )] <select-statement>
}
puts {
@@ -513,6 +581,11 @@ name in the column list. A new entry is made in the table
for every row of the SELECT result. The SELECT may be simple
or compound. If the SELECT statement has an ORDER BY clause,
the ORDER BY is ignored.</p>
<p>The optional conflict-clause allows the specification of an alternative
constraint conflict resolution algorithm to use during this one command.
See the section titled
<a href="#conflict">ON CONFLICT</a> for additional information.</p>
}
Section SELECT select
@@ -597,7 +670,9 @@ are connected into a compound, they group from left to right.</p>
Section UPDATE update
Syntax {sql-statement} {
UPDATE <table-name> SET <assignment> [, <assignment>] [WHERE <expression>]
UPDATE [ <conflict-clause> ] <table-name>
SET <assignment> [, <assignment>]
[WHERE <expression>]
} {assignment} {
<column-name> = <expression>
}
@@ -608,7 +683,12 @@ selected rows of a table. Each assignment in an UPDATE specifies
a column name to the left of the equals sign and an arbitrary expression
to the right. The expressions may use the values of other columns.
All expressions are evaluated before any assignments are made.
A WHERE clause can be used to restrict which rows are updated.
A WHERE clause can be used to restrict which rows are updated.</p>
<p>The optional conflict-clause allows the specification of an alternative
constraint conflict resolution algorithm to use during this one command.
See the section titled
<a href="#conflict">ON CONFLICT</a> for additional information.</p>
}
Section VACUUM vacuum