Description:
A logic bug is exposed by Ternary Logic Partitioning (TLP) on a query involving multiple nested RIGHT JOINs and constant join conditions.
The original query returns a count of 25. However, when applying TLP by partitioning on the predicate (ref_4.status IS NULL) into three mutually exclusive conditions:
(ref_4.status IS NULL)
NOT (ref_4.status IS NULL)
(ref_4.status IS NULL) IS NULL
and summing the results of the three subqueries, the total result becomes 2525, which significantly deviates from the original result.
The query includes several unusual but valid constructs that may contribute to the issue:
Deeply nested RIGHT JOIN chains
Join conditions that are constant expressions (ON false, ON true)
EXISTS predicates independent of outer query columns
Mixed join types (LEFT, RIGHT, INNER) in the same join tree
According to TLP principles, the sum of the partitioned queries should be equal to the result of the original query. The observed discrepancy indicates a violation of logical equivalence, suggesting an error in query planning or execution, possibly related to join reordering, predicate pushdown, or null-handling in outer joins.
This demonstrates a correctness bug in handling complex join trees under three-valued logic semantics.
How to repeat:
```SQL
-- SCHEMA
CREATE TABLE users (
id INT,
username VARCHAR(100),
email VARCHAR(255),
age INT,
status VARCHAR(20),
created_at TIMESTAMP NULL,
score DOUBLE
);
CREATE TABLE posts (
id INT,
user_id INT,
title VARCHAR(255),
content VARCHAR(1000),
views INT,
likes INT,
created_at TIMESTAMP NULL,
rating DOUBLE
);
CREATE TABLE comments (
id INT,
post_id INT,
user_id INT,
content VARCHAR(1000),
is_spam INT,
created_at TIMESTAMP NULL
);
CREATE TABLE orders (
id INT,
user_id INT,
amount DOUBLE,
status VARCHAR(20),
created_at TIMESTAMP NULL
);
INSERT INTO users VALUES
(1, 'alice', 'alice@test.com', 20, 'active', '2022-01-01 10:00:00', 88.5),
(2, 'bob', 'bob@test.com', 30, 'active', '2022-01-02 11:00:00', 92.3),
(3, 'carol', NULL, NULL, 'banned','2022-01-03 12:00:00', NULL),
(4, 'dave', 'dave@test.com', 45, 'active', '2022-01-04 13:00:00', 65.2),
(5, NULL, 'null@test.com', 18, 'inactive','2022-01-05 14:00:00', 70.0);
INSERT INTO posts VALUES
(1, 1, 'Hello World', 'First post', 100, 10, '2022-01-10 10:00:00', 4.5),
(2, 1, 'Another Post', NULL, 150, 20, '2022-01-11 11:00:00', 3.0),
(3, 2, 'Bob Post', 'Content', NULL, 5, '2022-01-12 12:00:00', NULL),
(4, 3, NULL, 'Empty', 50, 2, '2022-01-13 13:00:00', 5.0),
(5, 4, 'Last Post', 'Last', 300, 30,'2022-01-14 14:00:00', 4.9);
INSERT INTO comments VALUES
(1, 1, 2, 'Nice post', 0, '2022-01-20 10:00:00'),
(2, 1, 3, 'Spam here', 1, '2022-01-21 11:00:00'),
(3, 2, 1, 'Thanks', 0, '2022-01-22 12:00:00'),
(4, 4, 5, NULL, 0, '2022-01-23 13:00:00');
INSERT INTO orders VALUES
(1, 1, 100.00, 'paid', '2022-02-01 09:00:00'),
(2, 1, 200.50, 'shipped', '2022-02-02 10:00:00'),
(3, 2, NULL, 'failed', '2022-02-03 11:00:00'),
(4, 3, 50.00, 'paid', '2022-02-04 12:00:00'),
(5, 5, 999.99, 'paid', '2022-02-05 13:00:00');
-- TRIGGER SQL
SELECT COUNT(*)
FROM (SELECT ref_0.id AS c0, ref_0.created_at AS c1, ref_0.id AS c2 FROM comments AS ref_0 WHERE 'x' >= 'rw') AS subq_0
RIGHT JOIN users AS ref_1
LEFT JOIN users AS ref_2
LEFT JOIN users AS ref_3 ON (ref_2.username = ref_3.username)
INNER JOIN orders AS ref_4 ON (ref_2.id <> 4)
ON (EXISTS (SELECT 1 FROM orders AS ref_5 WHERE TRUE))
LEFT JOIN users AS ref_6 ON (ref_4.id IS NOT NULL)
ON (subq_0.c0 = ref_1.id)
RIGHT JOIN posts AS ref_7
RIGHT JOIN posts AS ref_8
RIGHT JOIN orders AS ref_9
INNER JOIN comments AS ref_10 ON (false)
ON (true)
ON (false)
RIGHT JOIN users AS ref_16
ON (EXISTS (SELECT 1 FROM posts AS ref_17 WHERE '9lcg' <> '7u'))
ON (NULLIF('l6y6', 't6q6d6') != COALESCE(COALESCE('k', 'uac'), 'bj9'));
-- RESULT: {25}
SELECT
(
SELECT COUNT(*)
FROM (SELECT ref_0.id AS c0, ref_0.created_at AS c1, ref_0.id AS c2 FROM comments AS ref_0 WHERE 'x' >= 'rw') AS subq_0
RIGHT JOIN users AS ref_1
LEFT JOIN users AS ref_2
LEFT JOIN users AS ref_3 ON (ref_2.username = ref_3.username)
INNER JOIN orders AS ref_4 ON (ref_2.id <> 4)
ON (EXISTS (SELECT 1 FROM orders AS ref_5 WHERE TRUE))
LEFT JOIN users AS ref_6 ON (ref_4.id IS NOT NULL)
ON (subq_0.c0 = ref_1.id)
RIGHT JOIN posts AS ref_7
RIGHT JOIN posts AS ref_8
RIGHT JOIN orders AS ref_9
INNER JOIN comments AS ref_10 ON (false)
ON (true)
ON (false)
RIGHT JOIN users AS ref_16 ON (EXISTS (SELECT 1 FROM posts AS ref_17 WHERE '9lcg' <> '7u'))
ON (NULLIF('l6y6', 't6q6d6') != COALESCE(COALESCE('k', 'uac'), 'bj9'))
WHERE (ref_4.status IS NULL)
)
+
(
SELECT COUNT(*)
FROM (SELECT ref_0.id AS c0, ref_0.created_at AS c1, ref_0.id AS c2 FROM comments AS ref_0 WHERE 'x' >= 'rw') AS subq_0
RIGHT JOIN users AS ref_1
LEFT JOIN users AS ref_2
LEFT JOIN users AS ref_3 ON (ref_2.username = ref_3.username)
INNER JOIN orders AS ref_4 ON (ref_2.id <> 4)
ON (EXISTS (SELECT 1 FROM orders AS ref_5 WHERE TRUE))
LEFT JOIN users AS ref_6 ON (ref_4.id IS NOT NULL)
ON (subq_0.c0 = ref_1.id)
RIGHT JOIN posts AS ref_7
RIGHT JOIN posts AS ref_8
RIGHT JOIN orders AS ref_9
INNER JOIN comments AS ref_10 ON (false)
ON (true)
ON (false)
RIGHT JOIN users AS ref_16 ON (EXISTS (SELECT 1 FROM posts AS ref_17 WHERE '9lcg' <> '7u'))
ON (NULLIF('l6y6', 't6q6d6') != COALESCE(COALESCE('k', 'uac'), 'bj9'))
WHERE (NOT (ref_4.status IS NULL))
)
+
(
SELECT COUNT(*)
FROM (SELECT ref_0.id AS c0, ref_0.created_at AS c1, ref_0.id AS c2 FROM comments AS ref_0 WHERE 'x' >= 'rw') AS subq_0
RIGHT JOIN users AS ref_1
LEFT JOIN users AS ref_2
LEFT JOIN users AS ref_3 ON (ref_2.username = ref_3.username)
INNER JOIN orders AS ref_4 ON (ref_2.id <> 4)
ON (EXISTS (SELECT 1 FROM orders AS ref_5 WHERE TRUE))
LEFT JOIN users AS ref_6 ON (ref_4.id IS NOT NULL)
ON (subq_0.c0 = ref_1.id)
RIGHT JOIN posts AS ref_7
RIGHT JOIN posts AS ref_8
RIGHT JOIN orders AS ref_9
INNER JOIN comments AS ref_10 ON (false)
ON (true)
ON (false)
RIGHT JOIN users AS ref_16 ON (EXISTS (SELECT 1 FROM posts AS ref_17 WHERE '9lcg' <> '7u'))
ON (NULLIF('l6y6', 't6q6d6') != COALESCE(COALESCE('k', 'uac'), 'bj9'))
WHERE ((ref_4.status IS NULL) IS NULL)
);
-- RESULT: {2525}
```
Description: A logic bug is exposed by Ternary Logic Partitioning (TLP) on a query involving multiple nested RIGHT JOINs and constant join conditions. The original query returns a count of 25. However, when applying TLP by partitioning on the predicate (ref_4.status IS NULL) into three mutually exclusive conditions: (ref_4.status IS NULL) NOT (ref_4.status IS NULL) (ref_4.status IS NULL) IS NULL and summing the results of the three subqueries, the total result becomes 2525, which significantly deviates from the original result. The query includes several unusual but valid constructs that may contribute to the issue: Deeply nested RIGHT JOIN chains Join conditions that are constant expressions (ON false, ON true) EXISTS predicates independent of outer query columns Mixed join types (LEFT, RIGHT, INNER) in the same join tree According to TLP principles, the sum of the partitioned queries should be equal to the result of the original query. The observed discrepancy indicates a violation of logical equivalence, suggesting an error in query planning or execution, possibly related to join reordering, predicate pushdown, or null-handling in outer joins. This demonstrates a correctness bug in handling complex join trees under three-valued logic semantics. How to repeat: ```SQL -- SCHEMA CREATE TABLE users ( id INT, username VARCHAR(100), email VARCHAR(255), age INT, status VARCHAR(20), created_at TIMESTAMP NULL, score DOUBLE ); CREATE TABLE posts ( id INT, user_id INT, title VARCHAR(255), content VARCHAR(1000), views INT, likes INT, created_at TIMESTAMP NULL, rating DOUBLE ); CREATE TABLE comments ( id INT, post_id INT, user_id INT, content VARCHAR(1000), is_spam INT, created_at TIMESTAMP NULL ); CREATE TABLE orders ( id INT, user_id INT, amount DOUBLE, status VARCHAR(20), created_at TIMESTAMP NULL ); INSERT INTO users VALUES (1, 'alice', 'alice@test.com', 20, 'active', '2022-01-01 10:00:00', 88.5), (2, 'bob', 'bob@test.com', 30, 'active', '2022-01-02 11:00:00', 92.3), (3, 'carol', NULL, NULL, 'banned','2022-01-03 12:00:00', NULL), (4, 'dave', 'dave@test.com', 45, 'active', '2022-01-04 13:00:00', 65.2), (5, NULL, 'null@test.com', 18, 'inactive','2022-01-05 14:00:00', 70.0); INSERT INTO posts VALUES (1, 1, 'Hello World', 'First post', 100, 10, '2022-01-10 10:00:00', 4.5), (2, 1, 'Another Post', NULL, 150, 20, '2022-01-11 11:00:00', 3.0), (3, 2, 'Bob Post', 'Content', NULL, 5, '2022-01-12 12:00:00', NULL), (4, 3, NULL, 'Empty', 50, 2, '2022-01-13 13:00:00', 5.0), (5, 4, 'Last Post', 'Last', 300, 30,'2022-01-14 14:00:00', 4.9); INSERT INTO comments VALUES (1, 1, 2, 'Nice post', 0, '2022-01-20 10:00:00'), (2, 1, 3, 'Spam here', 1, '2022-01-21 11:00:00'), (3, 2, 1, 'Thanks', 0, '2022-01-22 12:00:00'), (4, 4, 5, NULL, 0, '2022-01-23 13:00:00'); INSERT INTO orders VALUES (1, 1, 100.00, 'paid', '2022-02-01 09:00:00'), (2, 1, 200.50, 'shipped', '2022-02-02 10:00:00'), (3, 2, NULL, 'failed', '2022-02-03 11:00:00'), (4, 3, 50.00, 'paid', '2022-02-04 12:00:00'), (5, 5, 999.99, 'paid', '2022-02-05 13:00:00'); -- TRIGGER SQL SELECT COUNT(*) FROM (SELECT ref_0.id AS c0, ref_0.created_at AS c1, ref_0.id AS c2 FROM comments AS ref_0 WHERE 'x' >= 'rw') AS subq_0 RIGHT JOIN users AS ref_1 LEFT JOIN users AS ref_2 LEFT JOIN users AS ref_3 ON (ref_2.username = ref_3.username) INNER JOIN orders AS ref_4 ON (ref_2.id <> 4) ON (EXISTS (SELECT 1 FROM orders AS ref_5 WHERE TRUE)) LEFT JOIN users AS ref_6 ON (ref_4.id IS NOT NULL) ON (subq_0.c0 = ref_1.id) RIGHT JOIN posts AS ref_7 RIGHT JOIN posts AS ref_8 RIGHT JOIN orders AS ref_9 INNER JOIN comments AS ref_10 ON (false) ON (true) ON (false) RIGHT JOIN users AS ref_16 ON (EXISTS (SELECT 1 FROM posts AS ref_17 WHERE '9lcg' <> '7u')) ON (NULLIF('l6y6', 't6q6d6') != COALESCE(COALESCE('k', 'uac'), 'bj9')); -- RESULT: {25} SELECT ( SELECT COUNT(*) FROM (SELECT ref_0.id AS c0, ref_0.created_at AS c1, ref_0.id AS c2 FROM comments AS ref_0 WHERE 'x' >= 'rw') AS subq_0 RIGHT JOIN users AS ref_1 LEFT JOIN users AS ref_2 LEFT JOIN users AS ref_3 ON (ref_2.username = ref_3.username) INNER JOIN orders AS ref_4 ON (ref_2.id <> 4) ON (EXISTS (SELECT 1 FROM orders AS ref_5 WHERE TRUE)) LEFT JOIN users AS ref_6 ON (ref_4.id IS NOT NULL) ON (subq_0.c0 = ref_1.id) RIGHT JOIN posts AS ref_7 RIGHT JOIN posts AS ref_8 RIGHT JOIN orders AS ref_9 INNER JOIN comments AS ref_10 ON (false) ON (true) ON (false) RIGHT JOIN users AS ref_16 ON (EXISTS (SELECT 1 FROM posts AS ref_17 WHERE '9lcg' <> '7u')) ON (NULLIF('l6y6', 't6q6d6') != COALESCE(COALESCE('k', 'uac'), 'bj9')) WHERE (ref_4.status IS NULL) ) + ( SELECT COUNT(*) FROM (SELECT ref_0.id AS c0, ref_0.created_at AS c1, ref_0.id AS c2 FROM comments AS ref_0 WHERE 'x' >= 'rw') AS subq_0 RIGHT JOIN users AS ref_1 LEFT JOIN users AS ref_2 LEFT JOIN users AS ref_3 ON (ref_2.username = ref_3.username) INNER JOIN orders AS ref_4 ON (ref_2.id <> 4) ON (EXISTS (SELECT 1 FROM orders AS ref_5 WHERE TRUE)) LEFT JOIN users AS ref_6 ON (ref_4.id IS NOT NULL) ON (subq_0.c0 = ref_1.id) RIGHT JOIN posts AS ref_7 RIGHT JOIN posts AS ref_8 RIGHT JOIN orders AS ref_9 INNER JOIN comments AS ref_10 ON (false) ON (true) ON (false) RIGHT JOIN users AS ref_16 ON (EXISTS (SELECT 1 FROM posts AS ref_17 WHERE '9lcg' <> '7u')) ON (NULLIF('l6y6', 't6q6d6') != COALESCE(COALESCE('k', 'uac'), 'bj9')) WHERE (NOT (ref_4.status IS NULL)) ) + ( SELECT COUNT(*) FROM (SELECT ref_0.id AS c0, ref_0.created_at AS c1, ref_0.id AS c2 FROM comments AS ref_0 WHERE 'x' >= 'rw') AS subq_0 RIGHT JOIN users AS ref_1 LEFT JOIN users AS ref_2 LEFT JOIN users AS ref_3 ON (ref_2.username = ref_3.username) INNER JOIN orders AS ref_4 ON (ref_2.id <> 4) ON (EXISTS (SELECT 1 FROM orders AS ref_5 WHERE TRUE)) LEFT JOIN users AS ref_6 ON (ref_4.id IS NOT NULL) ON (subq_0.c0 = ref_1.id) RIGHT JOIN posts AS ref_7 RIGHT JOIN posts AS ref_8 RIGHT JOIN orders AS ref_9 INNER JOIN comments AS ref_10 ON (false) ON (true) ON (false) RIGHT JOIN users AS ref_16 ON (EXISTS (SELECT 1 FROM posts AS ref_17 WHERE '9lcg' <> '7u')) ON (NULLIF('l6y6', 't6q6d6') != COALESCE(COALESCE('k', 'uac'), 'bj9')) WHERE ((ref_4.status IS NULL) IS NULL) ); -- RESULT: {2525} ```