| -- |
| -- Licensed to the Apache Software Foundation (ASF) under one or more |
| -- contributor license agreements. See the NOTICE file distributed with |
| -- this work for additional information regarding copyright ownership. |
| -- The ASF licenses this file to You under the Apache License, Version 2.0 |
| -- (the "License"); you may not use this file except in compliance with |
| -- the License. You may obtain a copy of the License at |
| -- |
| -- http://www.apache.org/licenses/LICENSE-2.0 |
| -- |
| -- Unless required by applicable law or agreed to in writing, software |
| -- distributed under the License is distributed on an "AS IS" BASIS, |
| -- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| -- See the License for the specific language governing permissions and |
| -- limitations under the License. |
| -- |
| -- ** insert positionedDelete.sql |
| -- |
| -- tests for positioned delete |
| -- |
| -- note that comments that begin '-- .' are test cases from the test plan |
| |
| -- assumed available in queries at time of initial writing: |
| -- subqueries. Additional tests will be needed once we have: |
| -- order by, group by, having, aggregates, distinct, views ... |
| |
| -- setup some tables for use in the tests |
| |
| create table t1 ( i int, v varchar(10), d double precision, t time ); |
| create table t1_copy ( i int, v varchar(10), d double precision, t time ); |
| |
| create table t2 ( s smallint, c char(10), r real, ts timestamp ); |
| |
| -- populate the first table and copy |
| insert into t1 values (1, '1111111111', 11e11, time('11:11:11')); |
| insert into t1_copy select * from t1; |
| |
| -- we need to turn autocommit off so that cursors aren't closed before |
| -- the positioned statements against them. |
| autocommit off; |
| |
| -- empty table tests |
| |
| -- .no table name given |
| -- this should fail with a syntax error |
| delete; |
| |
| -- this should succeed |
| get cursor c0 as 'select * from t1 for update'; |
| next c0; |
| delete from t1 where current of c0; |
| select * from t1; |
| close c0; |
| |
| -- restore t1 |
| delete from t1; |
| insert into t1 select * from t1_copy; |
| select * from t1; |
| |
| -- .same table name |
| -- .cursor before 1st row |
| get cursor c1 as 'select * from t2 for update'; |
| -- 'cursor not on a row' expected |
| delete from t2 where current of c1; |
| |
| -- .different table name |
| delete from t1 where current of c1; |
| -- restore t1 |
| delete from t1; |
| insert into t1 select * from t1_copy; |
| select * from t1; |
| |
| -- .non-existant table |
| delete from not_exists where current of c1; |
| close c1; |
| |
| -- .delete from base table, not exposed table name |
| -- (this one should work, since base table) |
| get cursor c2 as 'select * from t2 asdf for update'; |
| delete from t2 where current of c2; |
| |
| -- restore t1 |
| delete from t1; |
| insert into t1 select * from t1_copy; |
| select * from t1; |
| |
| -- .match correlation name |
| -- (this one should fail, since correlation name) |
| delete from asdf where current of c2; |
| close c2; |
| |
| -- .non-updatable cursor |
| -- NOTE - forupdate responsible for extensive tests |
| get cursor c3 as 'select * from t2 for read only'; |
| delete from t2 where current of c3; |
| close c3; |
| |
| -- .target cursor does not exist |
| delete from t2 where current of c44; |
| |
| -- .target cursor after last row |
| get cursor c4 as 'select * from t1 for update'; |
| next c4; |
| next c4; |
| next c4; |
| delete from t1 where current of c4; |
| close c4; |
| |
| -- .target cursor exists, closed |
| get cursor c5 as 'select * from t1'; |
| close c5; |
| delete from t1 where current of c5; |
| |
| -- .target cursor on row |
| get cursor c6 as 'select * from t1 for update'; |
| next c6; |
| delete from t1 where current of c6; |
| select * from t1; |
| close c6; |
| |
| -- restore t1 |
| delete from t1; |
| insert into t1 select * from t1_copy; |
| select * from t1; |
| |
| -- .target cursor on row deleted by another cursor |
| get cursor c7 as 'select * from t1 for update'; |
| next c7; |
| get cursor c8 as 'select * from t1 for update'; |
| next c8; |
| delete from t1 where current of c7; |
| delete from t1 where current of c8; |
| select * from t1; |
| close c7; |
| close c8; |
| |
| -- restore t1 |
| delete from t1; |
| insert into t1 select * from t1_copy; |
| select * from t1; |
| |
| -- .target cursor on already deleted row |
| get cursor c9 as 'select * from t1 for update'; |
| next c9; |
| delete from t1 where current of c9; |
| delete from t1 where current of c9; |
| select * from t1; |
| close c9; |
| |
| -- restore t1 |
| delete from t1; |
| insert into t1 select * from t1_copy; |
| select * from t1; |
| |
| -- delete to row which was subject to searched update |
| -- (row still within cursor qualification) |
| get cursor c10 as 'select * from t1 for update'; |
| next c10; |
| update t1 set i = i + 1; |
| select * from t1; |
| delete from t1 where current of c10; |
| select * from t1; |
| close c10; |
| |
| -- restore t1 |
| delete from t1; |
| insert into t1 select * from t1_copy; |
| select * from t1; |
| |
| -- delete to row which was subject to searched update |
| -- (row becomes outside of cursor qualification) |
| get cursor c10a as 'select * from t1 where i = 1 for update'; |
| next c10a; |
| update t1 set i = i + 1; |
| select * from t1; |
| delete from t1 where current of c10a; |
| select * from t1; |
| close c10a; |
| |
| -- restore t1 |
| delete from t1; |
| insert into t1 select * from t1_copy; |
| select * from t1; |
| |
| -- delete to row which was subject to positioned update |
| -- (row becomes outside of cursor qualification) |
| get cursor c11 as 'select * from t1 where i = 1 for update'; |
| next c11; |
| update t1 set i = i + 1 where current of c11; |
| select * from t1; |
| delete from t1 where current of c11; |
| select * from t1; |
| close c11; |
| |
| -- restore t1 |
| delete from t1; |
| insert into t1 select * from t1_copy; |
| select * from t1; |
| |
| -- delete to row which was subject to 2 searched updates |
| -- (1st puts row outside of cursor qualification, 2nd restores it) |
| get cursor c12 as 'select * from t1 where i = 1 for update'; |
| next c12; |
| update t1 set i = i + 1; |
| update t1 set i = 1; |
| select * from t1; |
| delete from t1 where current of c12; |
| select * from t1; |
| close c12; |
| |
| -- restore t1 |
| delete from t1; |
| insert into t1 select * from t1_copy; |
| select * from t1; |
| |
| -- positioned delete on table with index (#724) |
| create table t5 (c1 int, c2 int); |
| insert into t5 values (1, 1), (2, 2), (3, 3), (4, 4); |
| commit; |
| create index i5 on t5(c1); |
| get cursor c1 as 'select * from t5 where c1 > 1 for update of c2'; |
| next c1; |
| delete from t5 where current of c1; |
| next c1; |
| next c1; |
| delete from t5 where current of c1; |
| select * from t5; |
| close c1; |
| rollback; |
| create index i5 on t5(c2); |
| get cursor c1 as 'select * from t5 where c1 > 1 for update of c2'; |
| next c1; |
| delete from t5 where current of c1; |
| next c1; |
| next c1; |
| delete from t5 where current of c1; |
| select * from t5; |
| close c1; |
| rollback; |
| |
| -- reset autocommit |
| autocommit on; |
| |
| -- drop the tables |
| drop table t1; |
| drop table t2; |
| drop table t5; |
| drop table t1_copy; |
| |
| -- ** insert positionedUpdate.sql |
| -- |
| -- tests for positioned update |
| -- |
| -- note that comments that begin '-- .' are test cases from the test plan |
| |
| -- assumed available in queries at time of initial writing: |
| -- subqueries. Additional tests will be needed once we have: |
| -- order by, group by, having, aggregates, distinct, views ... |
| |
| -- setup some tables for use in the tests |
| |
| create table t1 ( i int, v varchar(10), d double precision, t time ); |
| create table t1_copy ( i int, v varchar(10), d double precision, t time ); |
| |
| create table t2 ( s smallint, c char(10), r real, ts timestamp ); |
| |
| -- populate the first table and copy |
| insert into t1 values (1, '1111111111', 11e11, time('11:11:11')); |
| insert into t1_copy select * from t1; |
| |
| -- we need to turn autocommit off so that cursors aren't closed before |
| -- the positioned statements against them. |
| autocommit off; |
| |
| -- empty table tests |
| |
| -- .no table name given |
| -- this should fail with a syntax error |
| update set c1 = c1; |
| |
| -- this should succeed |
| get cursor c0 as 'select * from t1 for update'; |
| next c0; |
| update t1 set i = 999 where current of c0; |
| select * from t1; |
| update t1 set i = 1 where current of c0; |
| select * from t1; |
| close c0; |
| |
| -- .same table name |
| -- .cursor before 1st row |
| get cursor c1 as 'select * from t2 for update'; |
| -- 'cursor not on a row' expected |
| update t2 set s = s where current of c1; |
| |
| -- .different table name |
| update t1 set i = i where current of c1; |
| |
| -- .non-existant table |
| update not_exists set i = i where current of c1; |
| close c1; |
| |
| -- .update base table, not exposed table name |
| -- (this one should work, since base table) |
| get cursor c2 as 'select * from t2 asdf for update'; |
| update t2 set s = s where current of c2; |
| |
| -- .match correlation name |
| -- (this one should fail, since correlation name) |
| update asdf set s = s where current of c2; |
| close c2; |
| |
| -- .non-updatable cursor |
| -- NOTE - forupdate responsible for extensive tests |
| get cursor c3 as 'select * from t2 for read only'; |
| update t2 set s = s where current of c3; |
| close c3; |
| |
| -- .target cursor does not exist |
| update t2 set s = s where current of c44; |
| |
| -- .target cursor after last row |
| get cursor c4 as 'select * from t1 for update'; |
| next c4; |
| next c4; |
| next c4; |
| update t1 set i = i where current of c4; |
| close c4; |
| |
| -- .target cursor exists, closed |
| get cursor c5 as 'select * from t1'; |
| close c5; |
| update t1 set i = i where current of c5; |
| |
| -- .target cursor on row |
| get cursor c6 as 'select * from t1 for update'; |
| next c6; |
| update t1 set i = i + 1 where current of c6; |
| select * from t1; |
| -- .consecutive updates to same row in cursor, keeping it in the cursor qual |
| update t1 set i = i + 1 where current of c6; |
| select * from t1; |
| close c6; |
| |
| -- restore t1 |
| delete from t1; |
| insert into t1 select * from t1_copy; |
| select * from t1; |
| |
| -- .target cursor on row deleted by another cursor |
| get cursor c7 as 'select * from t1 for update'; |
| next c7; |
| get cursor c8 as 'select * from t1 for update'; |
| next c8; |
| delete from t1 where current of c7; |
| update t1 set i = i + 1 where current of c8; |
| select * from t1; |
| close c7; |
| close c8; |
| |
| -- restore t1 |
| delete from t1; |
| insert into t1 select * from t1_copy; |
| select * from t1; |
| |
| -- .target cursor on already deleted row |
| get cursor c9 as 'select * from t1 for update'; |
| next c9; |
| delete from t1 where current of c9; |
| update t1 set i = i + 1 where current of c9; |
| select * from t1; |
| close c9; |
| |
| -- restore t1 |
| delete from t1; |
| insert into t1 select * from t1_copy; |
| select * from t1; |
| |
| -- update to row which was subject to searched update |
| -- (row still within cursor qualification) |
| get cursor c10 as 'select * from t1 for update'; |
| next c10; |
| update t1 set i = i + 1; |
| select * from t1; |
| update t1 set i = i + 2 where current of c10; |
| select * from t1; |
| close c10; |
| |
| -- restore t1 |
| delete from t1; |
| insert into t1 select * from t1_copy; |
| select * from t1; |
| |
| -- update to row which was subject to searched update |
| -- (row becomes outside of cursor qualification) |
| get cursor c10a as 'select * from t1 where i = 1 for update'; |
| next c10a; |
| update t1 set i = i + 1; |
| select * from t1; |
| update t1 set i = i + 2 where current of c10a; |
| select * from t1; |
| close c10a; |
| |
| -- restore t1 |
| delete from t1; |
| insert into t1 select * from t1_copy; |
| select * from t1; |
| |
| -- update to row which was subject to positioned update |
| -- (row becomes outside of cursor qualification) |
| get cursor c11 as 'select * from t1 where i = 1 for update'; |
| next c11; |
| update t1 set i = i + 1 where current of c11; |
| select * from t1; |
| update t1 set i = i + 2 where current of c11; |
| select * from t1; |
| close c11; |
| |
| -- restore t1 |
| delete from t1; |
| insert into t1 select * from t1_copy; |
| select * from t1; |
| |
| -- update to row which was subject to 2 searched updates |
| -- (1st puts row outside of cursor qualification, 2nd restores it) |
| get cursor c12 as 'select * from t1 where i = 1 for update'; |
| next c12; |
| update t1 set i = i + 1; |
| update t1 set i = 1; |
| select * from t1; |
| update t1 set i = i + 2 where current of c12; |
| select * from t1; |
| |
| -- negative test - try to update a non-existant column |
| update t1 set notacolumn = i + 1 where current of c12; |
| |
| close c12; |
| |
| -- restore t1 |
| delete from t1; |
| insert into t1 select * from t1_copy; |
| select * from t1; |
| |
| -- update column not in SELECT list, but in FOR UPDATE OF list |
| get cursor c13 as 'select i from t1 for update of v'; |
| next c13; |
| update t1 set v = '999' where current of c13; |
| select * from t1; |
| |
| -- update column not in FOR UPDATE OF list (negative test) |
| update t1 set i = 999 where current of c13; |
| select * from t1; |
| close c13; |
| |
| -- restore t1 |
| delete from t1; |
| insert into t1 select * from t1_copy; |
| select * from t1; |
| |
| -- update a non-referenced column |
| get cursor c14 as 'select i from t1 for update'; |
| next c14; |
| update t1 set v = '999' where current of c14; |
| select * from t1; |
| close c14; |
| |
| -- restore t1 |
| delete from t1; |
| insert into t1 select * from t1_copy; |
| select * from t1; |
| |
| -- .update columns in list in order different from the list's |
| get cursor c15 as 'select i, v from t1 for update of i, v'; |
| next c15; |
| update t1 set v = '999', i = 888 where current of c15; |
| select * from t1; |
| |
| -- . show that target table name must be used as qualifier, other names not allowed |
| update t1 set t1.v = '998' where current of c15; |
| update t1 set t2.v = '997' where current of c15; |
| select * from t1; |
| close c15; |
| |
| -- restore t1 |
| delete from t1; |
| insert into t1 select * from t1_copy; |
| select * from t1; |
| |
| -- .update only 1 column in the list |
| get cursor c16 as 'select i, v from t1 for update of i, v'; |
| next c16; |
| update t1 set v = '999' where current of c16; |
| select * from t1; |
| close c16; |
| |
| -- restore t1 |
| delete from t1; |
| insert into t1 select * from t1_copy; |
| select * from t1; |
| |
| -- .try to update through a closed cursor |
| get cursor c17 as 'select i, v from t1 for update of i, v'; |
| next c17; |
| close c17; |
| update t1 set v = '999' where current of c17; |
| select * from t1; |
| |
| -- a positioned update requires a named target table. |
| -- if we prepare the positioned update, close the underlying cursor |
| -- and reopen it on a different table, then the positioned update |
| -- should fail |
| |
| create table t3(c1 int, c2 int); |
| insert into t3 values (1,1), (2, 1), (3,3); |
| create table t4(c1 int, c2 int); |
| insert into t4 select * from t3; |
| |
| get cursor c1 as 'select c1 from t3 for update of c1'; |
| next c1; |
| prepare u1 as 'update t3 set c1 = c1 + 1 where current of c1'; |
| execute u1; |
| next c1; |
| select * from t3; |
| |
| close c1; |
| |
| get cursor c1 as 'select c1 from t4 for update of c1'; |
| next c1; |
| execute u1; |
| select * from t4; |
| select * from t3; |
| |
| close c1; |
| |
| -- now, reopen c1 on a table without column c1 and see |
| -- what happens on an attempted positioned update |
| get cursor c1 as 'select * from t1 for update'; |
| next c1; |
| execute u1; |
| |
| close c1; |
| |
| -- now, reopen c1 on t3, but as a read only cursor |
| select * from t3; |
| get cursor c1 as 'select c1 from t3 '; |
| next c1; |
| execute u1; |
| select * from t3; |
| |
| close c1; |
| |
| -- positioned update on table with index (#724) |
| create table t5 (c1 int, c2 int); |
| insert into t5 values (1, 1), (2, 2), (3, 3), (4, 4); |
| commit; |
| create index i5 on t5(c1); |
| get cursor c1 as 'select * from t5 where c1 > 1 for update of c2'; |
| next c1; |
| update t5 set c2 = 9 where current of c1; |
| next c1; |
| next c1; |
| update t5 set c2 = 9 where current of c1; |
| select * from t5; |
| close c1; |
| rollback; |
| create index i5 on t5(c2); |
| get cursor c1 as 'select * from t5 where c1 > 1 for update of c2'; |
| next c1; |
| update t5 set c2 = 9 where current of c1; |
| next c1; |
| next c1; |
| update t5 set c2 = 9 where current of c1; |
| select * from t5; |
| close c1; |
| rollback; |
| |
| |
| -- reset autocommit |
| autocommit on; |
| |
| -- drop the tables |
| drop table t1; |
| drop table t2; |
| drop table t3; |
| drop table t4; |
| drop table t5; |
| drop table t1_copy; |
| |
| -- tests for beetle 4417, schema and correlation name not working with |
| -- current of |
| create schema ejb; |
| create table ejb.test1 |
| (primarykey varchar(41) not null primary key, |
| name varchar(200), |
| parentkey varchar(41)); |
| insert into ejb.test1 values('0','jack','jill'); |
| autocommit off; |
| |
| -- test update with schema name |
| get cursor c1 as 'select primarykey, parentkey, name from ejb.test1 where primarykey = ''0'' for update'; |
| next c1; |
| prepare p1 as 'update ejb.test1 set name = ''john'' where current of c1'; |
| execute p1; |
| select primarykey, parentkey, name from ejb.test1; |
| close c1; |
| |
| -- test update with schema name and correlation name |
| get cursor c1 as 'select t1.primarykey, t1.parentkey, t1.name from ejb.test1 t1 where t1.primarykey = ''0'' for update'; |
| next c1; |
| prepare p1 as 'update ejb.test1 set name = ''joe'' where current of c1'; |
| execute p1; |
| select primarykey, parentkey, name from ejb.test1; |
| close c1; |
| |
| -- test update with set schema |
| set schema ejb; |
| get cursor c1 as 'select primarykey, parentkey, name from test1 where primarykey = ''0'' for update'; |
| next c1; |
| prepare p1 as 'update test1 set name = ''john'' where current of c1'; |
| execute p1; |
| select primarykey, parentkey, name from ejb.test1; |
| close c1; |
| |
| -- test update with set schema and correlation name |
| get cursor c1 as 'select t1.primarykey, t1.parentkey, t1.name from test1 t1 where t1.primarykey = ''0'' for update'; |
| next c1; |
| prepare p1 as 'update test1 set name = ''joe'' where current of c1'; |
| execute p1; |
| select primarykey, parentkey, name from ejb.test1; |
| close c1; |
| |
| -- test update with set schema and correlation name and schema name |
| get cursor c1 as 'select t1.primarykey, t1.parentkey, t1.name from ejb.test1 t1 where t1.primarykey = ''0'' for update'; |
| next c1; |
| prepare p1 as 'update ejb.test1 set name = ''joe'' where current of c1'; |
| execute p1; |
| select primarykey, parentkey, name from ejb.test1; |
| close c1; |
| |
| -- |
| -- reset schema name |
| set schema app; |
| |
| -- test delete with schema name |
| get cursor c1 as 'select primarykey, parentkey, name from ejb.test1 where primarykey = ''0'' for update'; |
| next c1; |
| prepare p2 as 'delete from ejb.test1 where current of c1'; |
| execute p2; |
| select primarykey, parentkey, name from ejb.test1; |
| close c1; |
| -- test delete with schema name and correlation name |
| insert into ejb.test1 values('0','jack','jill'); |
| get cursor c1 as 'select t1.primarykey, t1.parentkey, t1.name from ejb.test1 t1 where t1.primarykey = ''0'' for update'; |
| next c1; |
| prepare p2 as 'delete from ejb.test1 where current of c1'; |
| execute p2; |
| select primarykey, parentkey, name from ejb.test1; |
| close c1; |
| |
| -- test delete with set schema |
| set schema ejb; |
| insert into test1 values('0','jack','jill'); |
| get cursor c1 as 'select primarykey, parentkey, name from test1 where primarykey = ''0'' for update'; |
| next c1; |
| prepare p2 as 'delete from test1 where current of c1'; |
| execute p2; |
| select primarykey, parentkey, name from ejb.test1; |
| close c1; |
| |
| -- test delete with set schema and correlation name |
| insert into test1 values('0','jack','jill'); |
| get cursor c1 as 'select t1.primarykey, t1.parentkey, t1.name from test1 t1 where t1.primarykey = ''0'' for update'; |
| next c1; |
| prepare p2 as 'delete from test1 where current of c1'; |
| execute p2; |
| select primarykey, parentkey, name from ejb.test1; |
| close c1; |
| -- test delete with set schema and correlation name and schema name |
| insert into test1 values('0','jack','jill'); |
| get cursor c1 as 'select t1.primarykey, t1.parentkey, t1.name from ejb.test1 t1 where t1.primarykey = ''0'' for update'; |
| next c1; |
| prepare p2 as 'delete from ejb.test1 where current of c1'; |
| execute p2; |
| select primarykey, parentkey, name from ejb.test1; |
| close c1; |
| commit; |
| |
| -- clean up |
| autocommit on; |
| set schema app; |
| drop table ejb.test1; |
| --drop schema ejb restrict; - can't drop this because it will fail SPS tests since |
| --statements are created and would need to be dropped |
| |
| -- test correlation on select in current of cursor in current schema |
| -- this was also broken |
| create table test1 |
| (primarykey varchar(41) not null primary key, |
| name varchar(200), |
| parentkey varchar(41)); |
| -- make sure a cursor will work fine in this situation |
| insert into test1 values('0','jack','jill'); |
| autocommit off; |
| get cursor c1 as 'select t1.primarykey, t1.parentkey, t1.name from test1 t1 where t1.primarykey = ''0'' for update'; |
| next c1; |
| prepare p2 as 'delete from test1 where current of c1'; |
| execute p2; |
| select primarykey, parentkey, name from test1; |
| close c1; |
| commit; |
| |
| -- clean up |
| autocommit on; |
| drop table test1; |