Skip to content
Snippets Groups Projects
Commit 9c58958d authored by Mergen Imeev's avatar Mergen Imeev Committed by Nikita Pettik
Browse files

sql: fix INSTEAD OF DELETE trigger for VIEW

This patch makes the INSTEAD OF DELETE trigger work for every row
in VIEW. Prior to this patch, it worked only once for each group
of non-unique rows.

Also, this patch adds tests to check that the INSTEAD OF UPDATE
trigger work for every row in VIEW.

Closes #4740

(cherry picked from commit 6ddccda4)
parent 34cfb9a1
No related branches found
No related tags found
No related merge requests found
......@@ -240,7 +240,25 @@ sql_table_delete_from(struct Parse *parse, struct SrcList *tab_list,
int eph_cursor = parse->nTab++;
int addr_eph_open = sqlVdbeCurrentAddr(v);
if (is_view) {
pk_len = space->def->field_count;
/*
* At this stage SELECT is already materialized
* into ephemeral table, which has one additional
* tail field (except for ones specified in view
* format) which contains sequential ids. These ids
* are required since selected values may turn out to
* be non-unique. For instance:
* CREATE TABLE t (id INT PRIMARY KEY, a INT);
* INSERT INTO t VALUES (1, 1), (2, 1), (3, 1);
* CREATE VIEW v AS SELECT a FROM t;
* Meanwhile ephemeral tables feature PK covering ALL
* fields of format, so without id materialization
* processing is impossible. Then, results of
* materialization are transferred to the table being
* created below. So to fit tuples in it we must
* account that id field as well. That's why pk_len
* has one field more than view format.
*/
pk_len = space->def->field_count + 1;
parse->nMem += pk_len;
sqlVdbeAddOp2(v, OP_OpenTEphemeral, reg_eph,
pk_len);
......
......@@ -322,3 +322,82 @@ box.execute("DROP TABLE t1;");
---
- row_count: 1
...
--
-- gh-4740: make sure INSTEAD OF DELETE and INSTEAD OF UPDATE
-- triggers work for each row of view.
--
box.cfg{}
---
...
box.execute('CREATE TABLE t (i INT PRIMARY KEY AUTOINCREMENT, a INT);')
---
- row_count: 1
...
box.execute('CREATE TABLE t1 (i INT PRIMARY KEY AUTOINCREMENT, a INT);')
---
- row_count: 1
...
box.execute('CREATE VIEW v AS SELECT a FROM t;')
---
- row_count: 1
...
box.execute('CREATE TRIGGER r1 INSTEAD OF DELETE ON v FOR EACH ROW BEGIN INSERT INTO t1 VALUES (NULL, 1); END;')
---
- row_count: 1
...
box.execute('CREATE TRIGGER r2 INSTEAD OF UPDATE ON v FOR EACH ROW BEGIN INSERT INTO t1 VALUES (NULL, 2); END;')
---
- row_count: 1
...
box.execute('INSERT INTO t VALUES (NULL, 1), (NULL, 1), (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 3);')
---
- autoincrement_ids:
- 1
- 2
- 3
- 4
- 5
- 6
row_count: 6
...
box.execute('DELETE FROM v;')
---
- row_count: 0
...
box.execute('UPDATE v SET a = 10;')
---
- row_count: 0
...
box.execute('SELECT * FROM t1;')
---
- metadata:
- name: I
type: integer
- name: A
type: integer
rows:
- [1, 1]
- [2, 1]
- [3, 1]
- [4, 1]
- [5, 1]
- [6, 1]
- [7, 2]
- [8, 2]
- [9, 2]
- [10, 2]
- [11, 2]
- [12, 2]
...
box.execute('DROP VIEW v;')
---
- row_count: 1
...
box.execute('DROP TABLE t;')
---
- row_count: 1
...
box.execute('DROP TABLE t1;')
---
- row_count: 1
...
......@@ -120,3 +120,21 @@ box.space.T2:drop()
-- Cleanup
box.execute("DROP VIEW v1;");
box.execute("DROP TABLE t1;");
--
-- gh-4740: make sure INSTEAD OF DELETE and INSTEAD OF UPDATE
-- triggers work for each row of view.
--
box.cfg{}
box.execute('CREATE TABLE t (i INT PRIMARY KEY AUTOINCREMENT, a INT);')
box.execute('CREATE TABLE t1 (i INT PRIMARY KEY AUTOINCREMENT, a INT);')
box.execute('CREATE VIEW v AS SELECT a FROM t;')
box.execute('CREATE TRIGGER r1 INSTEAD OF DELETE ON v FOR EACH ROW BEGIN INSERT INTO t1 VALUES (NULL, 1); END;')
box.execute('CREATE TRIGGER r2 INSTEAD OF UPDATE ON v FOR EACH ROW BEGIN INSERT INTO t1 VALUES (NULL, 2); END;')
box.execute('INSERT INTO t VALUES (NULL, 1), (NULL, 1), (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 3);')
box.execute('DELETE FROM v;')
box.execute('UPDATE v SET a = 10;')
box.execute('SELECT * FROM t1;')
box.execute('DROP VIEW v;')
box.execute('DROP TABLE t;')
box.execute('DROP TABLE t1;')
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment