File: triggers.test.lua

package info (click to toggle)
tarantool 2.6.0-1
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 85,364 kB
  • sloc: ansic: 513,760; cpp: 69,489; sh: 25,650; python: 19,190; perl: 14,973; makefile: 4,173; yacc: 1,329; sql: 1,074; pascal: 620; ruby: 190; awk: 18; lisp: 7
file content (217 lines) | stat: -rw-r--r-- 8,855 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
env = require('test_run')
test_run = env.new()
engine = test_run:get_cfg('engine')
_ = box.space._session_settings:update('sql_default_engine', {{'=', 2, engine}})

-- Get invariant part of the tuple; name and opts don't change.
 function immutable_part(data) local r = {} for i, l in pairs(data) do table.insert(r, {l.name, l.opts}) end return r end

--
-- gh-3273: Move Triggers to server
--

box.execute("CREATE TABLE t1(x INTEGER PRIMARY KEY);")
box.execute("CREATE TABLE t2(x INTEGER PRIMARY KEY);")
box.execute([[CREATE TRIGGER t1t AFTER INSERT ON t1 FOR EACH ROW BEGIN INSERT INTO t2 VALUES(1); END; ]])
immutable_part(box.space._trigger:select())

space_id = box.space._space.index["name"]:get('T1').id

-- Checks for LUA tuples.
tuple = {"T1t", space_id, {sql = "CREATE TRIGGER t1t AFTER INSERT ON t1 FOR EACH ROW BEGIN INSERT INTO t2 VALUES(1); END;"}}
box.space._trigger:insert(tuple)

tuple = {"T1t", space_id, {sql = "CREATE TRIGGER t12t AFTER INSERT ON t1 FOR EACH ROW BEGIN INSERT INTO t2 VALUES(1); END;"}}
box.space._trigger:insert(tuple)

tuple = {"T2T", box.space.T1.id + 1, {sql = "CREATE TRIGGER t2t AFTER INSERT ON t1 FOR EACH ROW BEGIN INSERT INTO t2 VALUES(1); END;"}}
box.space._trigger:insert(tuple)
immutable_part(box.space._trigger:select())

box.execute("DROP TABLE T1;")
immutable_part(box.space._trigger:select())

box.execute("CREATE TABLE t1(x INTEGER PRIMARY KEY);")
box.execute([[CREATE TRIGGER t1t AFTER INSERT ON t1 FOR EACH ROW BEGIN INSERT INTO t2 VALUES(1); END; ]])
immutable_part(box.space._trigger:select())

space_id = box.space._space.index["name"]:get('T1').id

-- Test, didn't trigger t1t degrade.
box.execute("INSERT INTO t1 VALUES(1);")
box.execute("SELECT * FROM t2;")
box.execute("DELETE FROM t2;")


-- Test triggers.
tuple = {"T2T", space_id, {sql = "CREATE TRIGGER t2t AFTER INSERT ON t1 FOR EACH ROW BEGIN INSERT INTO t2 VALUES(2); END;"}}
_ = box.space._trigger:insert(tuple)
tuple = {"T3T", space_id, {sql = "CREATE TRIGGER t3t AFTER INSERT ON t1 FOR EACH ROW BEGIN INSERT INTO t2 VALUES(3); END;"}}
_ = box.space._trigger:insert(tuple)
immutable_part(box.space._trigger:select())
box.execute("INSERT INTO t1 VALUES(2);")
box.execute("SELECT * FROM t2;")
box.execute("DELETE FROM t2;")

-- Test t1t after t2t and t3t drop.
box.execute("DROP TRIGGER T2T;")
_ = box.space._trigger:delete("T3T")
immutable_part(box.space._trigger:select())
box.execute("INSERT INTO t1 VALUES(3);")
box.execute("SELECT * FROM t2;")
box.execute("DELETE FROM t2;")

-- Insert new SQL t2t and t3t.
box.execute([[CREATE TRIGGER t2t AFTER INSERT ON t1 FOR EACH ROW BEGIN INSERT INTO t2 VALUES(2); END; ]])
box.execute([[CREATE TRIGGER t3t AFTER INSERT ON t1 FOR EACH ROW BEGIN INSERT INTO t2 VALUES(3); END; ]])
immutable_part(box.space._trigger:select())
box.execute("INSERT INTO t1 VALUES(4);")
box.execute("SELECT * FROM t2;")

-- Clean up.
box.execute("DROP TABLE t1;")
box.execute("DROP TABLE t2;")
immutable_part(box.space._trigger:select())

-- Test target tables restricts.
box.execute("CREATE TABLE t1(a INT PRIMARY KEY,b INT);")
space_id = box.space.T1.id

tuple = {"T1T", space_id, {sql = [[create trigger t1t instead of update on t1 for each row begin delete from t1 WHERE a=old.a+2; end;]]}}
box.space._trigger:insert(tuple)

box.execute("CREATE VIEW V1 AS SELECT * FROM t1;")
space_id = box.space.V1.id

tuple = {"V1T", space_id, {sql = [[create trigger v1t before update on v1 for each row begin delete from t1 WHERE a=old.a+2; end;]]}}
box.space._trigger:insert(tuple)

tuple = {"V1T", space_id, {sql = [[create trigger v1t AFTER update on v1 for each row begin delete from t1 WHERE a=old.a+2; end;]]}}
box.space._trigger:insert(tuple)

space_id =  box.space._fk_constraint.id
tuple = {"T1T", space_id, {sql = [[create trigger t1t instead of update on "_fk_constraint" for each row begin delete from t1 WHERE a=old.a+2; end;]]}}
box.space._trigger:insert(tuple)

box.execute("DROP VIEW V1;")
box.execute("DROP TABLE T1;")

--
-- gh-3531: Assertion with trigger and two storage engines
--
-- Case 1: Src 'vinyl' table; Dst 'memtx' table
box.space._session_settings:update('sql_default_engine', {{'=', 2, 'vinyl'}})
box.execute("CREATE TABLE m (s0 INT PRIMARY KEY, s1 TEXT UNIQUE);")
box.execute("CREATE TRIGGER m1 BEFORE UPDATE ON m FOR EACH ROW BEGIN UPDATE n SET s2 = 'now'; END;")
box.space._session_settings:update('sql_default_engine', {{'=', 2, 'memtx'}})
box.execute("CREATE TABLE n (s0 INT PRIMARY KEY, s1 TEXT UNIQUE, s2 NUMBER);")
box.execute("INSERT INTO m VALUES (0, '0');")
box.execute("INSERT INTO n VALUES (0, '',null);")
box.execute("UPDATE m SET s1 = 'The Rain In Spain';")

-- ANALYZE banned in gh-4069
-- box.sql.execute("ANALYZE m;")
box.execute("DROP TABLE m;")
box.execute("DROP TABLE n;")


-- Case 2: Src 'memtx' table; Dst 'vinyl' table
box.space._session_settings:update('sql_default_engine', {{'=', 2, 'memtx'}})
box.execute("CREATE TABLE m (s0 INT PRIMARY KEY, s1 TEXT UNIQUE);")
box.execute("CREATE TRIGGER m1 BEFORE UPDATE ON m FOR EACH ROW BEGIN UPDATE n SET s2 = 'now'; END;")
box.space._session_settings:update('sql_default_engine', {{'=', 2, 'vinyl'}})
box.execute("CREATE TABLE n (s0 INT PRIMARY KEY, s1 TEXT UNIQUE, s2 NUMBER);")
box.execute("INSERT INTO m VALUES (0, '0');")
box.execute("INSERT INTO n VALUES (0, '',null);")
box.execute("UPDATE m SET s1 = 'The Rain In Spain';")

-- ANALYZE banned in gh-4069
-- box.sql.execute("ANALYZE n;")
box.execute("DROP TABLE m;")
box.execute("DROP TABLE n;")

-- Test SQL Transaction with LUA
box.space._session_settings:update('sql_default_engine', {{'=', 2, 'memtx'}})
box.execute("CREATE TABLE test (id INT PRIMARY KEY)")
box.space._session_settings:update('sql_default_engine', {{'=', 2, 'vinyl'}})
box.execute("CREATE TABLE test2 (id INT PRIMARY KEY)")
box.execute("INSERT INTO test2 VALUES (2)")
box.execute("START TRANSACTION")
box.execute("INSERT INTO test VALUES (1)")
box.execute("SELECT * FROM test2")
box.execute("ROLLBACK;")
box.execute("DROP TABLE test;")
box.execute("DROP TABLE test2;")

--
-- gh-3536: Some triggers cause error messages and/or half-finished updates
--
box.execute("CREATE TABLE t (s1 INT, s2 INT, s3 INT, s4 INT PRIMARY KEY);")
box.execute("CREATE VIEW v AS SELECT s1, s2 FROM t;")
box.execute("CREATE TRIGGER tv INSTEAD OF UPDATE ON v FOR EACH ROW BEGIN UPDATE t SET s3 = new.s1 WHERE s1 = old.s1; END;")
box.execute("INSERT INTO t VALUES (1,1,1,1);")
box.execute("UPDATE v SET s2 = s1 + 1;")
box.execute("UPDATE v SET s1 = s1 + 5;")
box.execute("SELECT * FROM t;")
box.execute("DROP VIEW v;")
box.execute("DROP TABLE t;")

--
-- gh-3653: Dissallow bindings for DDL
--
box.execute("CREATE TABLE t1(a INT PRIMARY KEY, b INT);")
space_id = box.space.T1.id
box.execute("CREATE TRIGGER tr1 AFTER INSERT ON t1 FOR EACH ROW WHEN new.a = ? BEGIN SELECT 1; END;")
tuple = {"TR1", space_id, {sql = [[CREATE TRIGGER tr1 AFTER INSERT ON t1 FOR EACH ROW WHEN new.a = ? BEGIN SELECT 1; END;]]}}
box.space._trigger:insert(tuple)
box.execute("DROP TABLE t1;")

-- 
-- Check that FOR EACH ROW clause is moandatory
--
box.execute("CREATE TABLE t1(a INT PRIMARY KEY, b INT);")
space_id = box.space.T1.id
box.execute("CREATE TRIGGER tr1 AFTER INSERT ON t1 BEGIN ; END;")
box.execute("DROP TABLE t1;")

--
-- gh-3570: Use box_space_id_by_name() instead of schema_find_id()
-- in SQL
--
box.schema.user.create('tester')
box.schema.user.grant('tester','read,write,create,execute', 'space', '_trigger')
box.execute("CREATE TABLE t1(x INTEGER PRIMARY KEY AUTOINCREMENT);")
box.session.su('tester')
--
-- Ensure that the CREATE TRIGGER statement cannot be executed if
-- the user does not have enough rights. In this case, the user
-- does not have rights to read from _space.
--
box.execute([[CREATE TRIGGER r1 AFTER INSERT ON t1 FOR EACH ROW BEGIN SELECT 1; END; ]])
box.session.su('admin')
box.schema.user.drop('tester')
box.execute("DROP TABLE t1;")

--
-- gh-4188: make sure that the identifiers that were generated
-- during the INSERT performed by the triggers are not returned.
--
box.execute('CREATE TABLE t1 (i INT PRIMARY KEY AUTOINCREMENT);')
box.execute('CREATE TABLE t2 (i INT PRIMARY KEY AUTOINCREMENT);')
box.execute('CREATE TABLE t3 (i INT PRIMARY KEY AUTOINCREMENT);')

box.execute('CREATE TRIGGER r1 AFTER INSERT ON t2 FOR EACH ROW BEGIN INSERT INTO t1 VALUES (null); END')
box.execute('INSERT INTO t1 VALUES (100);')
box.execute('INSERT INTO t2 VALUES (NULL), (NULL), (NULL);')
box.execute('SELECT * FROM t1;')
box.execute('SELECT * FROM t2;')

box.execute('CREATE TRIGGER r2 AFTER INSERT ON t3 FOR EACH ROW BEGIN INSERT INTO t2 VALUES (null); END')
box.execute('INSERT INTO t3 VALUES (NULL), (NULL), (NULL);')
box.execute('SELECT * FROM t1;')
box.execute('SELECT * FROM t2;')
box.execute('SELECT * FROM t3;')

box.execute('DROP TABLE t1;')
box.execute('DROP TABLE t2;')
box.execute('DROP TABLE t3;')