@@ -1020,6 +1020,135 @@ SELECT COUNT(*) FROM (
10201020----
102110210
10221022
1023+ # A table function on the preserved side has no source delta of its own.
1024+ # LEFT JOIN MERGE cannot infer which zero-match generated groups must remain,
1025+ # so these aggregates use current-vs-stored affected-group recomputation.
1026+ statement ok
1027+ CREATE TABLE tf_customer (id INT, warehouse_id INT, balance INT);
1028+
1029+ statement ok
1030+ INSERT INTO tf_customer VALUES (1, 1, 10), (2, 1, 20), (3, 2, 30);
1031+
1032+ statement ok
1033+ CREATE MATERIALIZED VIEW mv_tf_customer_count AS
1034+ SELECT generated_id AS warehouse_id, COUNT(c.id) AS customer_count
1035+ FROM generate_series(1, 5) generated(generated_id)
1036+ LEFT JOIN tf_customer c ON c.warehouse_id = generated.generated_id
1037+ GROUP BY generated_id;
1038+
1039+ query I
1040+ SELECT type FROM openivm_views WHERE view_name = 'mv_tf_customer_count';
1041+ ----
1042+ 6
1043+
1044+ # Conflicting insert/delete/update operations are deliberately batched before
1045+ # one refresh. In particular, groups 3 and 5 must retain their generated
1046+ # zero-count rows.
1047+ statement ok
1048+ UPDATE tf_customer SET balance = 11 WHERE id = 1;
1049+
1050+ statement ok
1051+ UPDATE tf_customer SET warehouse_id = 2 WHERE id = 2;
1052+
1053+ statement ok
1054+ DELETE FROM tf_customer WHERE id = 3;
1055+
1056+ statement ok
1057+ INSERT INTO tf_customer VALUES (4, 1, 40), (5, 4, 50);
1058+
1059+ statement ok
1060+ UPDATE tf_customer SET balance = 41 WHERE id = 4;
1061+
1062+ statement ok
1063+ DELETE FROM tf_customer WHERE id = 5;
1064+
1065+ statement ok
1066+ PRAGMA refresh('mv_tf_customer_count');
1067+
1068+ query I
1069+ SELECT COUNT(*) FROM (
1070+ SELECT * FROM mv_tf_customer_count
1071+ EXCEPT ALL
1072+ SELECT generated_id, COUNT(c.id)
1073+ FROM generate_series(1, 5) generated(generated_id)
1074+ LEFT JOIN tf_customer c ON c.warehouse_id = generated.generated_id
1075+ GROUP BY generated_id
1076+ );
1077+ ----
1078+ 0
1079+
1080+ query I
1081+ SELECT COUNT(*) FROM (
1082+ SELECT generated_id, COUNT(c.id)
1083+ FROM generate_series(1, 5) generated(generated_id)
1084+ LEFT JOIN tf_customer c ON c.warehouse_id = generated.generated_id
1085+ GROUP BY generated_id
1086+ EXCEPT ALL
1087+ SELECT * FROM mv_tf_customer_count
1088+ );
1089+ ----
1090+ 0
1091+
1092+ statement ok
1093+ CREATE TABLE tf_stock (id INT, quantity INT);
1094+
1095+ statement ok
1096+ INSERT INTO tf_stock VALUES (1, 3), (2, 12), (3, 27);
1097+
1098+ statement ok
1099+ CREATE MATERIALIZED VIEW mv_tf_stock_thresholds AS
1100+ SELECT threshold, COUNT(s.id) AS low_stock_items
1101+ FROM range(5, 30, 5) generated(threshold)
1102+ LEFT JOIN tf_stock s ON s.quantity < generated.threshold
1103+ GROUP BY threshold;
1104+
1105+ query I
1106+ SELECT type FROM openivm_views WHERE view_name = 'mv_tf_stock_thresholds';
1107+ ----
1108+ 6
1109+
1110+ statement ok
1111+ UPDATE tf_stock SET quantity = 18 WHERE id = 1;
1112+
1113+ statement ok
1114+ DELETE FROM tf_stock WHERE id = 2;
1115+
1116+ statement ok
1117+ INSERT INTO tf_stock VALUES (4, 7), (5, 22);
1118+
1119+ statement ok
1120+ UPDATE tf_stock SET quantity = 2 WHERE id = 5;
1121+
1122+ statement ok
1123+ DELETE FROM tf_stock WHERE id = 4;
1124+
1125+ statement ok
1126+ PRAGMA refresh('mv_tf_stock_thresholds');
1127+
1128+ query I
1129+ SELECT COUNT(*) FROM (
1130+ SELECT * FROM mv_tf_stock_thresholds
1131+ EXCEPT ALL
1132+ SELECT threshold, COUNT(s.id)
1133+ FROM range(5, 30, 5) generated(threshold)
1134+ LEFT JOIN tf_stock s ON s.quantity < generated.threshold
1135+ GROUP BY threshold
1136+ );
1137+ ----
1138+ 0
1139+
1140+ query I
1141+ SELECT COUNT(*) FROM (
1142+ SELECT threshold, COUNT(s.id)
1143+ FROM range(5, 30, 5) generated(threshold)
1144+ LEFT JOIN tf_stock s ON s.quantity < generated.threshold
1145+ GROUP BY threshold
1146+ EXCEPT ALL
1147+ SELECT * FROM mv_tf_stock_thresholds
1148+ );
1149+ ----
1150+ 0
1151+
10231152# Delete from a deeper-right table: the matched MV row should
10241153# revert to NULL on that side.
10251154statement ok
0 commit comments