truncate.sql 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  1. -- Test basic TRUNCATE functionality.
  2. CREATE TABLE truncate_a (col1 integer primary key);
  3. INSERT INTO truncate_a VALUES (1);
  4. INSERT INTO truncate_a VALUES (2);
  5. SELECT * FROM truncate_a;
  6. -- Roll truncate back
  7. BEGIN;
  8. TRUNCATE truncate_a;
  9. ROLLBACK;
  10. SELECT * FROM truncate_a;
  11. -- Commit the truncate this time
  12. BEGIN;
  13. TRUNCATE truncate_a;
  14. COMMIT;
  15. SELECT * FROM truncate_a;
  16. -- Test foreign-key checks
  17. CREATE TABLE trunc_b (a int REFERENCES truncate_a);
  18. CREATE TABLE trunc_c (a serial PRIMARY KEY);
  19. CREATE TABLE trunc_d (a int REFERENCES trunc_c);
  20. CREATE TABLE trunc_e (a int REFERENCES truncate_a, b int REFERENCES trunc_c);
  21. TRUNCATE TABLE truncate_a; -- fail
  22. TRUNCATE TABLE truncate_a,trunc_b; -- fail
  23. TRUNCATE TABLE truncate_a,trunc_b,trunc_e; -- ok
  24. TRUNCATE TABLE truncate_a,trunc_e; -- fail
  25. TRUNCATE TABLE trunc_c; -- fail
  26. TRUNCATE TABLE trunc_c,trunc_d; -- fail
  27. TRUNCATE TABLE trunc_c,trunc_d,trunc_e; -- ok
  28. TRUNCATE TABLE trunc_c,trunc_d,trunc_e,truncate_a; -- fail
  29. TRUNCATE TABLE trunc_c,trunc_d,trunc_e,truncate_a,trunc_b; -- ok
  30. TRUNCATE TABLE truncate_a RESTRICT; -- fail
  31. TRUNCATE TABLE truncate_a CASCADE; -- ok
  32. -- circular references
  33. ALTER TABLE truncate_a ADD FOREIGN KEY (col1) REFERENCES trunc_c;
  34. -- Add some data to verify that truncating actually works ...
  35. INSERT INTO trunc_c VALUES (1);
  36. INSERT INTO truncate_a VALUES (1);
  37. INSERT INTO trunc_b VALUES (1);
  38. INSERT INTO trunc_d VALUES (1);
  39. INSERT INTO trunc_e VALUES (1,1);
  40. TRUNCATE TABLE trunc_c;
  41. TRUNCATE TABLE trunc_c,truncate_a;
  42. TRUNCATE TABLE trunc_c,truncate_a,trunc_d;
  43. TRUNCATE TABLE trunc_c,truncate_a,trunc_d,trunc_e;
  44. TRUNCATE TABLE trunc_c,truncate_a,trunc_d,trunc_e,trunc_b;
  45. -- Verify that truncating did actually work
  46. SELECT * FROM truncate_a
  47. UNION ALL
  48. SELECT * FROM trunc_c
  49. UNION ALL
  50. SELECT * FROM trunc_b
  51. UNION ALL
  52. SELECT * FROM trunc_d;
  53. SELECT * FROM trunc_e;
  54. -- Add data again to test TRUNCATE ... CASCADE
  55. INSERT INTO trunc_c VALUES (1);
  56. INSERT INTO truncate_a VALUES (1);
  57. INSERT INTO trunc_b VALUES (1);
  58. INSERT INTO trunc_d VALUES (1);
  59. INSERT INTO trunc_e VALUES (1,1);
  60. TRUNCATE TABLE trunc_c CASCADE; -- ok
  61. SELECT * FROM truncate_a
  62. UNION ALL
  63. SELECT * FROM trunc_c
  64. UNION ALL
  65. SELECT * FROM trunc_b
  66. UNION ALL
  67. SELECT * FROM trunc_d;
  68. SELECT * FROM trunc_e;
  69. DROP TABLE truncate_a,trunc_c,trunc_b,trunc_d,trunc_e CASCADE;
  70. -- Test TRUNCATE with inheritance
  71. CREATE TABLE trunc_f (col1 integer primary key);
  72. INSERT INTO trunc_f VALUES (1);
  73. INSERT INTO trunc_f VALUES (2);
  74. CREATE TABLE trunc_fa (col2a text) INHERITS (trunc_f);
  75. INSERT INTO trunc_fa VALUES (3, 'three');
  76. CREATE TABLE trunc_fb (col2b int) INHERITS (trunc_f);
  77. INSERT INTO trunc_fb VALUES (4, 444);
  78. CREATE TABLE trunc_faa (col3 text) INHERITS (trunc_fa);
  79. INSERT INTO trunc_faa VALUES (5, 'five', 'FIVE');
  80. BEGIN;
  81. SELECT * FROM trunc_f;
  82. TRUNCATE trunc_f;
  83. SELECT * FROM trunc_f;
  84. ROLLBACK;
  85. BEGIN;
  86. SELECT * FROM trunc_f;
  87. TRUNCATE ONLY trunc_f;
  88. SELECT * FROM trunc_f;
  89. ROLLBACK;
  90. BEGIN;
  91. SELECT * FROM trunc_f;
  92. SELECT * FROM trunc_fa;
  93. SELECT * FROM trunc_faa;
  94. TRUNCATE ONLY trunc_fb, ONLY trunc_fa;
  95. SELECT * FROM trunc_f;
  96. SELECT * FROM trunc_fa;
  97. SELECT * FROM trunc_faa;
  98. ROLLBACK;
  99. BEGIN;
  100. SELECT * FROM trunc_f;
  101. SELECT * FROM trunc_fa;
  102. SELECT * FROM trunc_faa;
  103. TRUNCATE ONLY trunc_fb, trunc_fa;
  104. SELECT * FROM trunc_f;
  105. SELECT * FROM trunc_fa;
  106. SELECT * FROM trunc_faa;
  107. ROLLBACK;
  108. DROP TABLE trunc_f CASCADE;
  109. -- Test ON TRUNCATE triggers
  110. CREATE TABLE trunc_trigger_test (f1 int, f2 text, f3 text);
  111. CREATE TABLE trunc_trigger_log (tgop text, tglevel text, tgwhen text,
  112. tgargv text, tgtable name, rowcount bigint);
  113. CREATE FUNCTION trunctrigger() RETURNS trigger as $$
  114. declare c bigint;
  115. begin
  116. execute 'select count(*) from ' || quote_ident(tg_table_name) into c;
  117. insert into trunc_trigger_log values
  118. (TG_OP, TG_LEVEL, TG_WHEN, TG_ARGV[0], tg_table_name, c);
  119. return null;
  120. end;
  121. $$ LANGUAGE plpgsql;
  122. -- basic before trigger
  123. INSERT INTO trunc_trigger_test VALUES(1, 'foo', 'bar'), (2, 'baz', 'quux');
  124. CREATE TRIGGER t
  125. BEFORE TRUNCATE ON trunc_trigger_test
  126. FOR EACH STATEMENT
  127. EXECUTE PROCEDURE trunctrigger('before trigger truncate');
  128. SELECT count(*) as "Row count in test table" FROM trunc_trigger_test;
  129. SELECT * FROM trunc_trigger_log;
  130. TRUNCATE trunc_trigger_test;
  131. SELECT count(*) as "Row count in test table" FROM trunc_trigger_test;
  132. SELECT * FROM trunc_trigger_log;
  133. DROP TRIGGER t ON trunc_trigger_test;
  134. truncate trunc_trigger_log;
  135. -- same test with an after trigger
  136. INSERT INTO trunc_trigger_test VALUES(1, 'foo', 'bar'), (2, 'baz', 'quux');
  137. CREATE TRIGGER tt
  138. AFTER TRUNCATE ON trunc_trigger_test
  139. FOR EACH STATEMENT
  140. EXECUTE PROCEDURE trunctrigger('after trigger truncate');
  141. SELECT count(*) as "Row count in test table" FROM trunc_trigger_test;
  142. SELECT * FROM trunc_trigger_log;
  143. TRUNCATE trunc_trigger_test;
  144. SELECT count(*) as "Row count in test table" FROM trunc_trigger_test;
  145. SELECT * FROM trunc_trigger_log;
  146. DROP TABLE trunc_trigger_test;
  147. DROP TABLE trunc_trigger_log;
  148. DROP FUNCTION trunctrigger();
  149. -- test TRUNCATE ... RESTART IDENTITY
  150. CREATE SEQUENCE truncate_a_id1 START WITH 33;
  151. CREATE TABLE truncate_a (id serial,
  152. id1 integer default nextval('truncate_a_id1'));
  153. ALTER SEQUENCE truncate_a_id1 OWNED BY truncate_a.id1;
  154. INSERT INTO truncate_a DEFAULT VALUES;
  155. INSERT INTO truncate_a DEFAULT VALUES;
  156. SELECT * FROM truncate_a;
  157. TRUNCATE truncate_a;
  158. INSERT INTO truncate_a DEFAULT VALUES;
  159. INSERT INTO truncate_a DEFAULT VALUES;
  160. SELECT * FROM truncate_a;
  161. TRUNCATE truncate_a RESTART IDENTITY;
  162. INSERT INTO truncate_a DEFAULT VALUES;
  163. INSERT INTO truncate_a DEFAULT VALUES;
  164. SELECT * FROM truncate_a;
  165. CREATE TABLE truncate_b (id int GENERATED ALWAYS AS IDENTITY (START WITH 44));
  166. INSERT INTO truncate_b DEFAULT VALUES;
  167. INSERT INTO truncate_b DEFAULT VALUES;
  168. SELECT * FROM truncate_b;
  169. TRUNCATE truncate_b;
  170. INSERT INTO truncate_b DEFAULT VALUES;
  171. INSERT INTO truncate_b DEFAULT VALUES;
  172. SELECT * FROM truncate_b;
  173. TRUNCATE truncate_b RESTART IDENTITY;
  174. INSERT INTO truncate_b DEFAULT VALUES;
  175. INSERT INTO truncate_b DEFAULT VALUES;
  176. SELECT * FROM truncate_b;
  177. -- check rollback of a RESTART IDENTITY operation
  178. BEGIN;
  179. TRUNCATE truncate_a RESTART IDENTITY;
  180. INSERT INTO truncate_a DEFAULT VALUES;
  181. SELECT * FROM truncate_a;
  182. ROLLBACK;
  183. INSERT INTO truncate_a DEFAULT VALUES;
  184. INSERT INTO truncate_a DEFAULT VALUES;
  185. SELECT * FROM truncate_a;
  186. DROP TABLE truncate_a;
  187. SELECT nextval('truncate_a_id1'); -- fail, seq should have been dropped
  188. -- partitioned table
  189. CREATE TABLE truncparted (a int, b char) PARTITION BY LIST (a);
  190. -- error, can't truncate a partitioned table
  191. TRUNCATE ONLY truncparted;
  192. CREATE TABLE truncparted1 PARTITION OF truncparted FOR VALUES IN (1);
  193. INSERT INTO truncparted VALUES (1, 'a');
  194. -- error, must truncate partitions
  195. TRUNCATE ONLY truncparted;
  196. TRUNCATE truncparted;
  197. DROP TABLE truncparted;
  198. -- foreign key on partitioned table: partition key is referencing column.
  199. -- Make sure truncate did execute on all tables
  200. CREATE FUNCTION tp_ins_data() RETURNS void LANGUAGE plpgsql AS $$
  201. BEGIN
  202. INSERT INTO truncprim VALUES (1), (100), (150);
  203. INSERT INTO truncpart VALUES (1), (100), (150);
  204. END
  205. $$;
  206. CREATE FUNCTION tp_chk_data(OUT pktb regclass, OUT pkval int, OUT fktb regclass, OUT fkval int)
  207. RETURNS SETOF record LANGUAGE plpgsql AS $$
  208. BEGIN
  209. RETURN QUERY SELECT
  210. pk.tableoid::regclass, pk.a, fk.tableoid::regclass, fk.a
  211. FROM truncprim pk FULL JOIN truncpart fk USING (a)
  212. ORDER BY 2, 4;
  213. END
  214. $$;
  215. CREATE TABLE truncprim (a int PRIMARY KEY);
  216. CREATE TABLE truncpart (a int REFERENCES truncprim)
  217. PARTITION BY RANGE (a);
  218. CREATE TABLE truncpart_1 PARTITION OF truncpart FOR VALUES FROM (0) TO (100);
  219. CREATE TABLE truncpart_2 PARTITION OF truncpart FOR VALUES FROM (100) TO (200)
  220. PARTITION BY RANGE (a);
  221. CREATE TABLE truncpart_2_1 PARTITION OF truncpart_2 FOR VALUES FROM (100) TO (150);
  222. CREATE TABLE truncpart_2_d PARTITION OF truncpart_2 DEFAULT;
  223. TRUNCATE TABLE truncprim; -- should fail
  224. select tp_ins_data();
  225. -- should truncate everything
  226. TRUNCATE TABLE truncprim, truncpart;
  227. select * from tp_chk_data();
  228. select tp_ins_data();
  229. -- should truncate everything
  230. TRUNCATE TABLE truncprim CASCADE;
  231. SELECT * FROM tp_chk_data();
  232. SELECT tp_ins_data();
  233. -- should truncate all partitions
  234. TRUNCATE TABLE truncpart;
  235. SELECT * FROM tp_chk_data();
  236. DROP TABLE truncprim, truncpart;
  237. DROP FUNCTION tp_ins_data(), tp_chk_data();
  238. -- test cascade when referencing a partitioned table
  239. CREATE TABLE trunc_a (a INT PRIMARY KEY) PARTITION BY RANGE (a);
  240. CREATE TABLE trunc_a1 PARTITION OF trunc_a FOR VALUES FROM (0) TO (10);
  241. CREATE TABLE trunc_a2 PARTITION OF trunc_a FOR VALUES FROM (10) TO (20)
  242. PARTITION BY RANGE (a);
  243. CREATE TABLE trunc_a21 PARTITION OF trunc_a2 FOR VALUES FROM (10) TO (12);
  244. CREATE TABLE trunc_a22 PARTITION OF trunc_a2 FOR VALUES FROM (12) TO (16);
  245. CREATE TABLE trunc_a2d PARTITION OF trunc_a2 DEFAULT;
  246. CREATE TABLE trunc_a3 PARTITION OF trunc_a FOR VALUES FROM (20) TO (30);
  247. INSERT INTO trunc_a VALUES (0), (5), (10), (15), (20), (25);
  248. -- truncate a partition cascading to a table
  249. CREATE TABLE ref_b (
  250. b INT PRIMARY KEY,
  251. a INT REFERENCES trunc_a(a) ON DELETE CASCADE
  252. );
  253. INSERT INTO ref_b VALUES (10, 0), (50, 5), (100, 10), (150, 15);
  254. TRUNCATE TABLE trunc_a1 CASCADE;
  255. SELECT a FROM ref_b;
  256. DROP TABLE ref_b;
  257. -- truncate a partition cascading to a partitioned table
  258. CREATE TABLE ref_c (
  259. c INT PRIMARY KEY,
  260. a INT REFERENCES trunc_a(a) ON DELETE CASCADE
  261. ) PARTITION BY RANGE (c);
  262. CREATE TABLE ref_c1 PARTITION OF ref_c FOR VALUES FROM (100) TO (200);
  263. CREATE TABLE ref_c2 PARTITION OF ref_c FOR VALUES FROM (200) TO (300);
  264. INSERT INTO ref_c VALUES (100, 10), (150, 15), (200, 20), (250, 25);
  265. TRUNCATE TABLE trunc_a21 CASCADE;
  266. SELECT a as "from table ref_c" FROM ref_c;
  267. SELECT a as "from table trunc_a" FROM trunc_a ORDER BY a;
  268. DROP TABLE trunc_a, ref_c;