Add test cases and fixes for UPDATE...FROM statements that modify primary key columns.
FossilOrigin-Name: 47c87af3e52bce10fbcc2cbe832d659b0c204bfb3368d9314fa1b01120129254
This commit is contained in:
parent
a7f82d9f47
commit
be952c11dc
@ -1 +1 @@
|
|||||||
5ee3c27e20d12a126fb773b428bb864102b949a5b26a8d5c523753dcedf4be10
|
47c87af3e52bce10fbcc2cbe832d659b0c204bfb3368d9314fa1b01120129254
|
@ -756,10 +756,10 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
|
|||||||
#endif
|
#endif
|
||||||
switch( pExpr->op ){
|
switch( pExpr->op ){
|
||||||
|
|
||||||
#if defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) && !defined(SQLITE_OMIT_SUBQUERY)
|
|
||||||
/* The special operator TK_ROW means use the rowid for the first
|
/* The special operator TK_ROW means use the rowid for the first
|
||||||
** column in the FROM clause. This is used by the LIMIT and ORDER BY
|
** column in the FROM clause. This is used by the LIMIT and ORDER BY
|
||||||
** clause processing on UPDATE and DELETE statements.
|
** clause processing on UPDATE and DELETE statements, and by
|
||||||
|
** UPDATE ... FROM statement processing.
|
||||||
*/
|
*/
|
||||||
case TK_ROW: {
|
case TK_ROW: {
|
||||||
SrcList *pSrcList = pNC->pSrcList;
|
SrcList *pSrcList = pNC->pSrcList;
|
||||||
@ -774,8 +774,6 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
|
|||||||
pExpr->affExpr = SQLITE_AFF_INTEGER;
|
pExpr->affExpr = SQLITE_AFF_INTEGER;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#endif /* defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT)
|
|
||||||
&& !defined(SQLITE_OMIT_SUBQUERY) */
|
|
||||||
|
|
||||||
/* A column name: ID
|
/* A column name: ID
|
||||||
** Or table name and column name: ID.ID
|
** Or table name and column name: ID.ID
|
||||||
|
@ -637,7 +637,13 @@ void sqlite3Update(
|
|||||||
iEph = pParse->nTab++;
|
iEph = pParse->nTab++;
|
||||||
if( pPk ) sqlite3VdbeAddOp3(v, OP_Null, 0, iPk, iPk+nPk-1);
|
if( pPk ) sqlite3VdbeAddOp3(v, OP_Null, 0, iPk, iPk+nPk-1);
|
||||||
addrOpen = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, iEph, nEphCol);
|
addrOpen = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, iEph, nEphCol);
|
||||||
if( pPk ) sqlite3VdbeSetP4KeyInfo(pParse, pPk);
|
if( pPk ){
|
||||||
|
KeyInfo *pKeyInfo = sqlite3KeyInfoOfIndex(pParse, pPk);
|
||||||
|
if( pKeyInfo ){
|
||||||
|
pKeyInfo->nAllField = nEphCol;
|
||||||
|
sqlite3VdbeAppendP4(v, pKeyInfo, P4_KEYINFO);
|
||||||
|
}
|
||||||
|
}
|
||||||
if( nChangeFrom ){
|
if( nChangeFrom ){
|
||||||
updatePopulateEphTable(
|
updatePopulateEphTable(
|
||||||
pParse, iEph, pPk, pChanges, pTabList, pWhere, pOrderBy, pLimit
|
pParse, iEph, pPk, pChanges, pTabList, pWhere, pOrderBy, pLimit
|
||||||
|
@ -25,6 +25,7 @@ ifcapable !fts3 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
foreach {tn create_table} {
|
foreach {tn create_table} {
|
||||||
|
0 { CREATE VIRTUAL TABLE ft USING fts5(a, b, c) }
|
||||||
1 { CREATE VIRTUAL TABLE ft USING fts3(a, b, c) }
|
1 { CREATE VIRTUAL TABLE ft USING fts3(a, b, c) }
|
||||||
2 { CREATE TABLE ft(a, b, c) }
|
2 { CREATE TABLE ft(a, b, c) }
|
||||||
3 {
|
3 {
|
||||||
@ -40,6 +41,7 @@ foreach {tn create_table} {
|
|||||||
END;
|
END;
|
||||||
}
|
}
|
||||||
} {
|
} {
|
||||||
|
if {$tn==0} { ifcapable !fts5 { continue } }
|
||||||
catchsql { DROP VIEW IF EXISTS changes }
|
catchsql { DROP VIEW IF EXISTS changes }
|
||||||
catchsql { DROP TABLE IF EXISTS ft }
|
catchsql { DROP TABLE IF EXISTS ft }
|
||||||
catchsql { DROP VIEW IF EXISTS ft }
|
catchsql { DROP VIEW IF EXISTS ft }
|
||||||
@ -92,12 +94,45 @@ foreach {tn create_table} {
|
|||||||
}
|
}
|
||||||
|
|
||||||
do_execsql_test 1.$tn.7 {
|
do_execsql_test 1.$tn.7 {
|
||||||
SELECT a, b, c FROM ft ORDER BY rowid;
|
SELECT rowid, a, b, c FROM ft ORDER BY rowid;
|
||||||
} {
|
} {
|
||||||
a {} apricot
|
1 a {} apricot
|
||||||
b apple blueberry
|
2 b apple blueberry
|
||||||
c banana clementine
|
3 c banana clementine
|
||||||
d cherry dewberry
|
4 d cherry dewberry
|
||||||
|
}
|
||||||
|
|
||||||
|
do_execsql_test 1.$tn.8 "
|
||||||
|
WITH x1(o, n) AS (
|
||||||
|
VALUES(1, 11) UNION ALL
|
||||||
|
VALUES(2, 12) UNION ALL
|
||||||
|
VALUES(3, 13) UNION ALL
|
||||||
|
VALUES(4, 14)
|
||||||
|
)
|
||||||
|
SELECT ft.rowid, a, b, c, o, n FROM ft, x1 WHERE ft.rowid = o;
|
||||||
|
" {
|
||||||
|
1 a {} apricot 1 11
|
||||||
|
2 b apple blueberry 2 12
|
||||||
|
3 c banana clementine 3 13
|
||||||
|
4 d cherry dewberry 4 14
|
||||||
|
}
|
||||||
|
|
||||||
|
set ROWID rowid
|
||||||
|
if {$tn==1} { set ROWID docid }
|
||||||
|
do_execsql_test 1.$tn.9 "
|
||||||
|
WITH x1(o, n) AS (
|
||||||
|
VALUES(1, 11) UNION ALL
|
||||||
|
VALUES(2, 12) UNION ALL
|
||||||
|
VALUES(3, 13) UNION ALL
|
||||||
|
VALUES(4, 14)
|
||||||
|
)
|
||||||
|
UPDATE ft SET $ROWID = n FROM x1 WHERE ft.rowid = o;
|
||||||
|
SELECT rowid, a, b, c FROM ft ORDER BY rowid;
|
||||||
|
" {
|
||||||
|
11 a {} apricot
|
||||||
|
12 b apple blueberry
|
||||||
|
13 c banana clementine
|
||||||
|
14 d cherry dewberry
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
166
test/upfrom3.test
Normal file
166
test/upfrom3.test
Normal file
@ -0,0 +1,166 @@
|
|||||||
|
# 2020 July 14
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
#
|
||||||
|
#***********************************************************************
|
||||||
|
#
|
||||||
|
|
||||||
|
set testdir [file dirname $argv0]
|
||||||
|
source $testdir/tester.tcl
|
||||||
|
set testprefix upfrom3
|
||||||
|
|
||||||
|
foreach {tn wo} {
|
||||||
|
1 ""
|
||||||
|
2 "WITHOUT ROWID"
|
||||||
|
} {
|
||||||
|
reset_db
|
||||||
|
eval [string map [list %WO% $wo %TN% $tn] {
|
||||||
|
|
||||||
|
do_execsql_test 1.%TN%.0 {
|
||||||
|
CREATE TABLE log(t TEXT);
|
||||||
|
CREATE TABLE t1(x INTEGER PRIMARY KEY, y, z UNIQUE) %WO%;
|
||||||
|
CREATE INDEX t1y ON t1(y);
|
||||||
|
|
||||||
|
INSERT INTO t1 VALUES(1, 'i', 'one');
|
||||||
|
INSERT INTO t1 VALUES(2, 'ii', 'two');
|
||||||
|
INSERT INTO t1 VALUES(3, 'iii', 'three');
|
||||||
|
INSERT INTO t1 VALUES(4, 'iv', 'four');
|
||||||
|
}
|
||||||
|
|
||||||
|
do_execsql_test 1.%TN%.1 {
|
||||||
|
CREATE TABLE x1(o, n);
|
||||||
|
INSERT INTO x1 VALUES(1, 11);
|
||||||
|
INSERT INTO x1 VALUES(2, 12);
|
||||||
|
INSERT INTO x1 VALUES(3, 13);
|
||||||
|
INSERT INTO x1 VALUES(4, 14);
|
||||||
|
UPDATE t1 SET x=n FROM x1 WHERE x=o;
|
||||||
|
SELECT x, y, z FROM t1 ORDER BY 1;
|
||||||
|
} {
|
||||||
|
11 i one
|
||||||
|
12 ii two
|
||||||
|
13 iii three
|
||||||
|
14 iv four
|
||||||
|
}
|
||||||
|
|
||||||
|
do_test 1.%TN%.2 { db changes } 4
|
||||||
|
|
||||||
|
do_execsql_test 1.%TN%.3 {
|
||||||
|
INSERT INTO x1 VALUES(11, 21);
|
||||||
|
INSERT INTO x1 VALUES(12, 22);
|
||||||
|
INSERT INTO x1 VALUES(13, 23);
|
||||||
|
INSERT INTO x1 VALUES(14, 24);
|
||||||
|
|
||||||
|
INSERT INTO x1 VALUES(21, 31);
|
||||||
|
INSERT INTO x1 VALUES(22, 32);
|
||||||
|
INSERT INTO x1 VALUES(23, 33);
|
||||||
|
INSERT INTO x1 VALUES(24, 34);
|
||||||
|
UPDATE t1 SET x=n FROM x1 WHERE x=o;
|
||||||
|
SELECT x, y, z FROM t1 ORDER BY 1;
|
||||||
|
} {
|
||||||
|
21 i one
|
||||||
|
22 ii two
|
||||||
|
23 iii three
|
||||||
|
24 iv four
|
||||||
|
}
|
||||||
|
|
||||||
|
do_execsql_test 1.%TN%.4 {
|
||||||
|
UPDATE t1 SET x=n FROM x1 WHERE x=o;
|
||||||
|
SELECT x, y, z FROM t1 ORDER BY 1;
|
||||||
|
} {
|
||||||
|
31 i one
|
||||||
|
32 ii two
|
||||||
|
33 iii three
|
||||||
|
34 iv four
|
||||||
|
}
|
||||||
|
|
||||||
|
do_execsql_test 1.%TN%.5 {
|
||||||
|
INSERT INTO x1 VALUES(31, 32);
|
||||||
|
INSERT INTO x1 VALUES(33, 34);
|
||||||
|
UPDATE OR REPLACE t1 SET x=n FROM x1 WHERE x=o;
|
||||||
|
SELECT x, y, z FROM t1 ORDER BY 1;
|
||||||
|
} {
|
||||||
|
32 i one
|
||||||
|
34 iii three
|
||||||
|
}
|
||||||
|
|
||||||
|
do_execsql_test 1.%TN%.6 {
|
||||||
|
INSERT INTO t1 VALUES(33, 'ii', 'two');
|
||||||
|
INSERT INTO t1 VALUES(35, 'iv', 'four');
|
||||||
|
}
|
||||||
|
|
||||||
|
do_execsql_test 1.%TN%.7 {
|
||||||
|
CREATE TABLE x2(o, n, zz);
|
||||||
|
INSERT INTO x2 VALUES(32, 41, 'four');
|
||||||
|
INSERT INTO x2 VALUES(33, 42, 'three');
|
||||||
|
UPDATE OR IGNORE t1 SET x=n, z=zz FROM x2 WHERE x=o;
|
||||||
|
SELECT x, y, z FROM t1 ORDER BY 1;
|
||||||
|
} {
|
||||||
|
32 i one
|
||||||
|
33 ii two
|
||||||
|
34 iii three
|
||||||
|
35 iv four
|
||||||
|
}
|
||||||
|
|
||||||
|
do_execsql_test 1.%TN%.8 {
|
||||||
|
UPDATE OR REPLACE t1 SET x=n, z=zz FROM x2 WHERE x=o;
|
||||||
|
SELECT x, y, z FROM t1 ORDER BY 1;
|
||||||
|
} {
|
||||||
|
41 i four
|
||||||
|
42 ii three
|
||||||
|
}
|
||||||
|
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
|
||||||
|
do_execsql_test 2.1.1 {
|
||||||
|
CREATE TABLE u1(a, b, c, PRIMARY KEY(b, c)) WITHOUT ROWID;
|
||||||
|
INSERT INTO u1 VALUES(0, 0, 0);
|
||||||
|
INSERT INTO u1 VALUES(1, 0, 1);
|
||||||
|
INSERT INTO u1 VALUES(2, 1, 0);
|
||||||
|
INSERT INTO u1 VALUES(3, 1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
do_execsql_test 2.1.2 {
|
||||||
|
CREATE TABLE map(f, t);
|
||||||
|
INSERT INTO map VALUES(0, 10);
|
||||||
|
INSERT INTO map VALUES(1, 11);
|
||||||
|
UPDATE u1 SET c=t FROM map WHERE c=f;
|
||||||
|
SELECT * FROM u1 ORDER BY a;
|
||||||
|
} {
|
||||||
|
0 0 10
|
||||||
|
1 0 11
|
||||||
|
2 1 10
|
||||||
|
3 1 11
|
||||||
|
}
|
||||||
|
|
||||||
|
do_execsql_test 2.1.3 {
|
||||||
|
UPDATE u1 SET b=t FROM map WHERE b=f;
|
||||||
|
SELECT * FROM u1 ORDER BY a;
|
||||||
|
} {
|
||||||
|
0 10 10
|
||||||
|
1 10 11
|
||||||
|
2 11 10
|
||||||
|
3 11 11
|
||||||
|
}
|
||||||
|
|
||||||
|
do_execsql_test 2.1.4 {
|
||||||
|
CREATE TABLE map2(o1, o2, n1, n2);
|
||||||
|
INSERT INTO map2 VALUES
|
||||||
|
(10, 10, 50, 50), (10, 11, 50, 60),
|
||||||
|
(11, 10, 60, 50), (11, 11, 60, 60);
|
||||||
|
UPDATE u1 SET b=n1, c=n2 FROM map2 WHERE b=o1 AND c=o2;
|
||||||
|
SELECT * FROM u1 ORDER BY a;
|
||||||
|
} {
|
||||||
|
0 50 50
|
||||||
|
1 50 60
|
||||||
|
2 60 50
|
||||||
|
3 60 60
|
||||||
|
}
|
||||||
|
|
||||||
|
finish_test
|
||||||
|
|
Loading…
Reference in New Issue
Block a user