alter-source.td 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425
  1. # Copyright Materialize, Inc. and contributors. All rights reserved.
  2. #
  3. # Use of this software is governed by the Business Source License
  4. # included in the LICENSE file at the root of this repository.
  5. #
  6. # As of the Change Date specified in that file, in accordance with
  7. # the Business Source License, use of this software will be governed
  8. # by the Apache License, Version 2.0.
  9. $ set-sql-timeout duration=60s
  10. > CREATE SECRET mysqlpass AS '${arg.mysql-root-password}'
  11. > CREATE CONNECTION mysql_conn TO MYSQL (
  12. HOST mysql,
  13. USER root,
  14. PASSWORD SECRET mysqlpass
  15. )
  16. $ mysql-connect name=mysql url=mysql://root@mysql password=${arg.mysql-root-password}
  17. $ mysql-execute name=mysql
  18. DROP DATABASE IF EXISTS public;
  19. CREATE DATABASE public;
  20. USE public;
  21. CREATE TABLE table_a (pk INTEGER PRIMARY KEY, f2 TEXT);
  22. INSERT INTO table_a VALUES (1, 'one');
  23. INSERT INTO table_a VALUES (2, 'two');
  24. > CREATE SOURCE mz_source FROM MYSQL CONNECTION mysql_conn;
  25. > CREATE TABLE table_a FROM SOURCE mz_source (REFERENCE public.table_a);
  26. > SELECT * FROM table_a;
  27. 1 one
  28. 2 two
  29. $ mysql-execute name=mysql
  30. DROP TABLE table_a CASCADE;
  31. # Adding a table with the same name as a running table does not allow you to add
  32. # the new table.
  33. $ mysql-execute name=mysql
  34. CREATE TABLE table_a (pk INTEGER PRIMARY KEY, f2 TEXT);
  35. INSERT INTO table_a VALUES (9, 'nine');
  36. ! SELECT * FROM table_a;
  37. contains:table was dropped
  38. # We are not aware that the new table_a is different
  39. ! CREATE TABLE table_a FROM SOURCE mz_source (REFERENCE public.table_a);
  40. contains:catalog item 'table_a' already exists
  41. > DROP SOURCE mz_source CASCADE;
  42. # Re-populate tables for rest of test.
  43. $ mysql-execute name=mysql
  44. DELETE FROM table_a;
  45. INSERT INTO table_a VALUES (1, 'one');
  46. INSERT INTO table_a VALUES (2, 'two');
  47. CREATE TABLE table_b (pk INTEGER PRIMARY KEY, f2 TEXT);
  48. INSERT INTO table_b VALUES (1, 'one');
  49. INSERT INTO table_b VALUES (2, 'two');
  50. CREATE TABLE table_c (pk INTEGER PRIMARY KEY, f2 TEXT);
  51. INSERT INTO table_c VALUES (1, 'one');
  52. INSERT INTO table_c VALUES (2, 'two');
  53. CREATE TABLE table_d (pk INTEGER PRIMARY KEY, f2 TEXT);
  54. INSERT INTO table_d VALUES (1, 'one');
  55. INSERT INTO table_d VALUES (2, 'two');
  56. CREATE TABLE table_e (pk INTEGER PRIMARY KEY, f2 TEXT);
  57. INSERT INTO table_e VALUES (1, 'one');
  58. INSERT INTO table_e VALUES (2, 'two');
  59. CREATE TABLE table_f (pk INTEGER PRIMARY KEY, f2 ENUM ('var0', 'var1'));
  60. INSERT INTO table_f VALUES (1, 'var0');
  61. INSERT INTO table_f VALUES (2, 'var1');
  62. CREATE TABLE table_g (pk INTEGER PRIMARY KEY, f2 TEXT);
  63. INSERT INTO table_g VALUES (1, 'one');
  64. INSERT INTO table_g VALUES (2, 'two');
  65. > CREATE SOURCE mz_source FROM MYSQL CONNECTION mysql_conn;
  66. > CREATE TABLE table_a FROM SOURCE mz_source (REFERENCE public.table_a);
  67. > CREATE TABLE table_b FROM SOURCE mz_source (REFERENCE public.table_b);
  68. > CREATE TABLE table_c FROM SOURCE mz_source (REFERENCE public.table_c);
  69. > CREATE TABLE table_d FROM SOURCE mz_source (REFERENCE public.table_d);
  70. > CREATE TABLE table_e FROM SOURCE mz_source (REFERENCE public.table_e);
  71. > CREATE TABLE table_f FROM SOURCE mz_source (REFERENCE public.table_f) WITH (TEXT COLUMNS (f2));
  72. > CREATE TABLE table_g FROM SOURCE mz_source (REFERENCE public.table_g);
  73. > SHOW SUBSOURCES ON mz_source
  74. mz_source_progress progress
  75. > SHOW TABLES
  76. table_a ""
  77. table_b ""
  78. table_c ""
  79. table_d ""
  80. table_e ""
  81. table_f ""
  82. table_g ""
  83. $ set-regex match="DETAILS = '[a-f0-9]+'" replacement=<DETAILS>
  84. > SHOW CREATE SOURCE mz_source;
  85. materialize.public.mz_source "CREATE SOURCE materialize.public.mz_source\nIN CLUSTER quickstart\nFROM MYSQL CONNECTION materialize.public.mysql_conn\nEXPOSE PROGRESS AS materialize.public.mz_source_progress;"
  86. > SHOW CREATE TABLE table_a;
  87. materialize.public.table_a "CREATE TABLE materialize.public.table_a (pk pg_catalog.int4 NOT NULL, f2 pg_catalog.text, CONSTRAINT \"PRIMARY\" PRIMARY KEY (pk)) FROM SOURCE materialize.public.mz_source (REFERENCE = public.table_a) WITH (<DETAILS>);"
  88. #
  89. # Error checking
  90. #
  91. > CREATE TABLE mz_table (a int);
  92. > DROP TABLE mz_table;
  93. > CREATE SOURCE "mz_source_too"
  94. FROM MYSQL CONNECTION mysql_conn;
  95. > CREATE TABLE t_a FROM SOURCE "mz_source_too" (REFERENCE public.table_a);
  96. > DROP SOURCE mz_source_too CASCADE;
  97. #
  98. # State checking
  99. #
  100. > DROP TABLE table_a
  101. > SELECT * FROM table_b;
  102. 1 one
  103. 2 two
  104. > SHOW SUBSOURCES ON mz_source
  105. mz_source_progress progress
  106. > SHOW TABLES
  107. table_b ""
  108. table_c ""
  109. table_d ""
  110. table_e ""
  111. table_f ""
  112. table_g ""
  113. ! SELECT * FROM table_a;
  114. contains: unknown catalog item 'table_a'
  115. # Makes progress after dropping subsources
  116. $ mysql-execute name=mysql
  117. INSERT INTO table_b VALUES (3, 'three');
  118. > SELECT * FROM table_b;
  119. 1 one
  120. 2 two
  121. 3 three
  122. # IF EXISTS works
  123. > DROP TABLE IF EXISTS table_a;
  124. # Multiple, repetitive tables work
  125. > DROP TABLE table_b, table_c, table_b, table_c, table_b, table_c;
  126. # IF EXISTS works with multiple tables
  127. > DROP TABLE IF EXISTS table_c, table_d;
  128. > CREATE MATERIALIZED VIEW mv_e AS SELECT pk + 1 FROM table_e;
  129. > CREATE MATERIALIZED VIEW mv_f AS SELECT pk + 1 FROM table_f;
  130. # Makes progress after dropping subsources
  131. $ mysql-execute name=mysql
  132. INSERT INTO table_e VALUES (3, 'three');
  133. > SELECT * FROM mv_e;
  134. 2
  135. 3
  136. 4
  137. > SHOW MATERIALIZED VIEWS
  138. mv_e quickstart ""
  139. mv_f quickstart ""
  140. # RESTRICT works
  141. ! DROP TABLE table_e RESTRICT;
  142. contains:cannot drop table "table_e": still depended upon by materialized view "mv_e"
  143. # CASCADE works
  144. > DROP TABLE table_e CASCADE;
  145. # IF NOT EXISTS + CASCADE works
  146. > DROP TABLE IF EXISTS table_e, table_f CASCADE;
  147. > SHOW SUBSOURCES ON mz_source
  148. mz_source_progress progress
  149. > SHOW TABLES
  150. table_g ""
  151. > SHOW MATERIALIZED VIEWS
  152. > DROP TABLE table_g;
  153. > SHOW SUBSOURCES ON mz_source
  154. mz_source_progress progress
  155. #
  156. # Add tables
  157. #
  158. > CREATE TABLE table_g FROM SOURCE mz_source (REFERENCE public.table_g);
  159. ! CREATE TABLE table_g FROM SOURCE mz_source (REFERENCE public.table_g);
  160. contains:catalog item 'table_g' already exists
  161. > CREATE TABLE table_a FROM SOURCE mz_source (REFERENCE public.table_a);
  162. > CREATE TABLE tb FROM SOURCE mz_source (REFERENCE public.table_b);
  163. > SELECT * FROM table_a;
  164. 1 one
  165. 2 two
  166. > SELECT * FROM tb;
  167. 1 one
  168. 2 two
  169. 3 three
  170. ! SELECT * FROM table_b;
  171. contains:unknown catalog item
  172. # We can add tables that didn't exist at the time of publication
  173. $ mysql-execute name=mysql
  174. CREATE TABLE table_h (pk INTEGER PRIMARY KEY, f2 TEXT);
  175. INSERT INTO table_h VALUES (1, 'one');
  176. INSERT INTO table_h VALUES (2, 'two');
  177. > CREATE TABLE table_h FROM SOURCE mz_source (REFERENCE public.table_h);
  178. > SELECT * FROM table_h;
  179. 1 one
  180. 2 two
  181. > SHOW SUBSOURCES ON mz_source
  182. mz_source_progress progress
  183. > SHOW TABLES
  184. table_a ""
  185. table_g ""
  186. table_h ""
  187. tb ""
  188. #
  189. # Complex subsource operations
  190. #
  191. # If your schema change breaks the subsource, you can fix it.
  192. $ mysql-execute name=mysql
  193. ALTER TABLE table_a DROP COLUMN f2;
  194. INSERT INTO table_a VALUES (3);
  195. ! SELECT * FROM table_a;
  196. contains:incompatible schema change
  197. > SELECT error ~~ '%incompatible schema change%' FROM mz_internal.mz_source_statuses WHERE name = 'table_a';
  198. true
  199. # Subsource errors not propagated to primary source
  200. > SELECT error IS NULL FROM mz_internal.mz_source_statuses WHERE name = 'mz_source';
  201. true
  202. > DROP TABLE table_a;
  203. > CREATE TABLE table_a FROM SOURCE mz_source (REFERENCE public.table_a);
  204. > SELECT * FROM table_a;
  205. 1
  206. 2
  207. 3
  208. # If you add columns you can re-ingest them
  209. $ mysql-execute name=mysql
  210. ALTER TABLE table_a ADD COLUMN f2 text;
  211. INSERT INTO table_a VALUES (4, 'four');
  212. > SELECT * FROM table_a;
  213. 1
  214. 2
  215. 3
  216. > DROP TABLE table_a;
  217. > CREATE TABLE table_a FROM SOURCE mz_source (REFERENCE public.table_a);
  218. > SELECT * FROM table_a;
  219. 1 <null>
  220. 2 <null>
  221. 3 <null>
  222. 4 four
  223. # If you add a NOT NULL constraint, you can propagate it.
  224. $ mysql-execute name=mysql
  225. ALTER TABLE table_a ADD COLUMN f3 int DEFAULT 1 NOT NULL;
  226. INSERT INTO table_a VALUES (5, 'five', 5);
  227. > DROP TABLE table_a;
  228. > CREATE TABLE table_a FROM SOURCE mz_source (REFERENCE public.table_a);
  229. > SELECT * FROM table_a;
  230. 1 <null> 1
  231. 2 <null> 1
  232. 3 <null> 1
  233. 4 four 1
  234. 5 five 5
  235. > EXPLAIN OPTIMIZED PLAN AS VERBOSE TEXT FOR SELECT * FROM table_a WHERE f3 IS NULL;
  236. "Explained Query (fast path):\n Constant <empty>\n\nTarget cluster: quickstart\n"
  237. #
  238. # Can add tables with text columns
  239. #
  240. ! CREATE TABLE table_f FROM SOURCE mz_source (REFERENCE public.table_f) WITH (TEXT COLUMNS [f2, f2]);
  241. contains: invalid TEXT COLUMNS option value: unexpected multiple references to public.table_f.f2
  242. > CREATE TABLE table_f FROM SOURCE mz_source (REFERENCE public.table_f) WITH (TEXT COLUMNS (f2));
  243. > SELECT * FROM table_f
  244. 1 var0
  245. 2 var1
  246. > SELECT regexp_match(create_sql, 'TEXT COLUMNS = \((.*?)\)')[1] FROM (SHOW CREATE TABLE table_f);
  247. f2
  248. # Drop a table, which shuffles the tables' output indexes, then add a table and ensure it can be added.
  249. $ mysql-execute name=mysql
  250. DROP TABLE table_c, table_d;
  251. CREATE TABLE table_i (pk INTEGER PRIMARY KEY, f2 ENUM ('var0', 'var1'));
  252. INSERT INTO table_i VALUES (1, 'var0');
  253. INSERT INTO table_i VALUES (2, 'var1');
  254. INSERT INTO table_f VALUES (3, 'var1');
  255. > CREATE TABLE table_i FROM SOURCE mz_source (REFERENCE public.table_i) WITH (TEXT COLUMNS [f2]);
  256. > SELECT regexp_match(create_sql, 'TEXT COLUMNS = \((.*?)\)')[1] FROM (SHOW CREATE TABLE table_i);
  257. f2
  258. > SELECT * FROM table_f
  259. 1 var0
  260. 2 var1
  261. 3 var1
  262. > DROP TABLE table_f, table_i;
  263. ! CREATE TABLE table_e FROM SOURCE mz_source (REFERENCE public.table_e) WITH (TEXT COLUMNS (xyz));
  264. contains:TEXT COLUMNS refers to table not currently being added
  265. # Test adding text cols w/o original text columns
  266. > CREATE SOURCE "mz_source_wo_init_text_cols"
  267. FROM MYSQL CONNECTION mysql_conn;
  268. > CREATE TABLE t_a FROM SOURCE "mz_source_wo_init_text_cols" (REFERENCE public.table_a);
  269. > SELECT regexp_match(create_sql, 'TEXT COLUMNS = \((.*?)\)')[1] FROM (SHOW CREATE TABLE t_a);
  270. <null>
  271. > CREATE TABLE t_f FROM SOURCE mz_source_wo_init_text_cols (REFERENCE public.table_f) WITH (TEXT COLUMNS [f2]);
  272. > SELECT regexp_match(create_sql, 'TEXT COLUMNS = \((.*?)\)')[1] FROM (SHOW CREATE TABLE t_f);
  273. f2
  274. #
  275. # Can add tables with exclude columns
  276. #
  277. ! CREATE TABLE table_f FROM SOURCE mz_source (REFERENCE public.table_f) WITH (EXCLUDE COLUMNS [f2, f2]);
  278. contains: invalid EXCLUDE COLUMNS option value: unexpected multiple references to public.table_f.f2
  279. > CREATE TABLE table_f FROM SOURCE mz_source (REFERENCE public.table_f) WITH (EXCLUDE COLUMNS [f2]);
  280. > SELECT * FROM table_f
  281. 1
  282. 2
  283. 3
  284. > CREATE TABLE table_i FROM SOURCE mz_source (REFERENCE public.table_i) WITH (EXCLUDE COLUMNS [f2]);
  285. > SELECT regexp_match(create_sql, 'EXCLUDE COLUMNS = \((.*?)\)')[1] FROM (SHOW CREATE TABLE table_i);
  286. f2
  287. > SELECT * FROM table_i
  288. 1
  289. 2
  290. > DROP TABLE table_f, table_i;
  291. ! CREATE TABLE table_e FROM SOURCE mz_source (REFERENCE public.table_e) WITH (EXCLUDE COLUMNS (a));
  292. contains:EXCLUDE COLUMNS refers to table not currently being added
  293. ! CREATE TABLE table_e FROM SOURCE mz_source (REFERENCE public.table_e) WITH (EXCLUDE COLUMNS [a]);
  294. contains:EXCLUDE COLUMNS refers to table not currently being added
  295. # Test adding exclude cols w/o original EXCLUDE COLUMNS
  296. > CREATE SOURCE "mz_source_wo_init_exclude_cols"
  297. FROM MYSQL CONNECTION mysql_conn;
  298. > CREATE TABLE t_a2 FROM SOURCE "mz_source_wo_init_exclude_cols" (REFERENCE public.table_a);
  299. > SELECT regexp_match(create_sql, 'EXCLUDE COLUMNS = \((.*?)\)')[1] FROM (SHOW CREATE TABLE t_a2);
  300. <null>
  301. > CREATE TABLE t_f2 FROM SOURCE mz_source_wo_init_exclude_cols (REFERENCE public.table_f) WITH (EXCLUDE COLUMNS [f2]);
  302. > SELECT regexp_match(create_sql, 'EXCLUDE COLUMNS = \((.*?)\)')[1] FROM (SHOW CREATE TABLE t_f2);
  303. f2
  304. # Add a table after having created the source
  305. $ mysql-execute name=mysql
  306. CREATE TABLE t2 (f1 BOOLEAN);
  307. ! SELECT COUNT(*) > 0 FROM t2;
  308. contains:unknown catalog item 't2'