diff --git a/include/my_base.h b/include/my_base.h index 9528bbbad47..bf40e8dcf5c 100644 --- a/include/my_base.h +++ b/include/my_base.h @@ -428,6 +428,7 @@ enum ha_extra_function { */ HA_EXTRA_IGNORE_TTL, HA_EXTRA_NO_IGNORE_TTL, + HA_EXTRA_FK_TTL }; /* Compatible option, to be deleted in 6.0 */ diff --git a/mysql-test/ttl_test.py b/mysql-test/ttl_test.py index 06a4e3ec6c4..ffc490714dc 100644 --- a/mysql-test/ttl_test.py +++ b/mysql-test/ttl_test.py @@ -1592,7 +1592,159 @@ def case_27_thdB(conn): B_succ = True +def case_28_pre(A_conn, B_conn): + try: + cur = A_conn.cursor() + cur.execute("DROP TABLE IF EXISTS sz1") + cur.execute("CREATE TABLE test.sz1 (" + "col_a INT, " + "col_b TIMESTAMP, " + "col_c INT, " + "PRIMARY KEY(col_a), " + "KEY(col_c))" + "ENGINE = NDB, " + "COMMENT=\"NDB_TABLE=FULLY_REPLICATED=1,TTL=10@col_b\"") + except Exception as e: + print(f"PRE Create DB/TABLE failed: {e}") + A_conn.close() + B_conn.close() + exit (-1) + def case_28_thdA(conn): + global A_succ + try: + cur = conn.cursor() + cur.execute("BEGIN") + cur.execute("INSERT INTO sz1 VALUES(1, sysdate(), 1), (2, sysdate(), 2), (3, sysdate(), 3), (4, sysdate(), 4), (5, sysdate(), 5), (6, sysdate(), 6), (7, sysdate(), 7), (8, sysdate(), 8), (9, sysdate(), 9), (10, sysdate(), 10)") + cur.execute("COMMIT") + time.sleep(2) + cur.execute("BEGIN") + cur.execute("SELECT * FROM sz1") + results = cur.fetchall() + assert len(results) == 10, "ASSERT 1" + cur.execute("SELECT * FROM sz1 where col_a = 6") + results = cur.fetchall() + assert len(results) == 1, "ASSERT 2" + cur.execute("SELECT * FROM sz1 where col_a >= 6") + results = cur.fetchall() + assert len(results) == 5, "ASSERT 3" + cur.execute("SELECT * FROM sz1 where col_c = 8") + results = cur.fetchall() + assert len(results) == 1, "ASSERT 4" + cur.execute("SELECT * FROM sz1 where col_c <= 8") + results = cur.fetchall() + assert len(results) == 8, "ASSERT 5" + time.sleep(9) + cur.execute("SELECT * FROM sz1") + results = cur.fetchall() + assert len(results) == 0, "ASSERT 6" + cur.execute("COMMIT") + + cur.execute("BEGIN") + cur.execute("INSERT INTO sz1 VALUES(1, sysdate(), 1), (2, sysdate(), 2), (3, sysdate(), 3), (4, sysdate(), 4), (5, sysdate(), 5), (6, sysdate(), 6), (7, sysdate(), 7), (8, sysdate(), 8), (9, sysdate(), 9), (10, sysdate(), 10)") + cur.execute("COMMIT") + time.sleep(2) + + except Exception as e: + print(f"Thd A failed: {e}") + cur.close() + return + cur.close() + A_succ = True + +def case_28_thdB(conn): + global B_succ + try: + time.sleep(15) + cur = conn.cursor() + cur.execute("BEGIN") + cur.execute("SELECT * FROM sz1 WHERE col_a <= 5 FOR SHARE") + results = cur.fetchall() + assert len(results) == 5, "ASSERT 1" + time.sleep(6) + cur.execute("SELECT * FROM sz1") + results = cur.fetchall() + assert len(results) == 5, "ASSERT 2" + cur.execute("SELECT * FROM sz1 WHERE col_a = 3") + results = cur.fetchall() + assert len(results) == 1, "ASSERT 3" + cur.execute("SELECT * FROM sz1 WHERE col_a = 8") + results = cur.fetchall() + assert len(results) == 0, "ASSERT 4" + cur.execute("SELECT * FROM sz1 WHERE col_a >= 3") + results = cur.fetchall() + assert len(results) == 3, "ASSERT 5" + cur.execute("SELECT * FROM sz1 WHERE col_a <= 9") + results = cur.fetchall() + assert len(results) == 5, "ASSERT 6" + + cur.execute("SELECT * FROM sz1 WHERE col_c = 3") + results = cur.fetchall() + assert len(results) == 1, "ASSERT 7" + cur.execute("SELECT * FROM sz1 WHERE col_c = 8") + results = cur.fetchall() + assert len(results) == 0, "ASSERT 8" + cur.execute("SELECT * FROM sz1 WHERE col_c >= 3") + results = cur.fetchall() + assert len(results) == 3, "ASSERT 9" + cur.execute("SELECT * FROM sz1 WHERE col_c <= 9") + results = cur.fetchall() + assert len(results) == 5, "ASSERT 10" + cur.execute("COMMIT") + + cur.execute("BEGIN") + cur.execute("SELECT * FROM sz1") + results = cur.fetchall() + assert len(results) == 0, "ASSERT 11" + cur.execute("SELECT * FROM sz1 WHERE col_a = 3") + results = cur.fetchall() + assert len(results) == 0, "ASSERT 12" + cur.execute("SELECT * FROM sz1 WHERE col_a = 8") + results = cur.fetchall() + assert len(results) == 0, "ASSERT 13" + cur.execute("SELECT * FROM sz1 WHERE col_a >= 3") + results = cur.fetchall() + assert len(results) == 0, "ASSERT 14" + cur.execute("SELECT * FROM sz1 WHERE col_a <= 9") + results = cur.fetchall() + assert len(results) == 0, "ASSERT 15" + + cur.execute("SELECT * FROM sz1 WHERE col_c = 3") + results = cur.fetchall() + assert len(results) == 0, "ASSERT 16" + cur.execute("SELECT * FROM sz1 WHERE col_c = 8") + results = cur.fetchall() + assert len(results) == 0, "ASSERT 17" + cur.execute("SELECT * FROM sz1 WHERE col_c >= 3") + results = cur.fetchall() + assert len(results) == 0, "ASSERT 18" + cur.execute("SELECT * FROM sz1 WHERE col_c <= 9") + results = cur.fetchall() + assert len(results) == 0, "ASSERT 19" + cur.execute("COMMIT") + + except Exception as e: + print(f"Thd B failed: {e}") + time.sleep(2) + cur.close() + return + + cur.close() + B_succ = True + +def case_28_post(A_conn, B_conn): + try: + cur = A_conn.cursor() + cur.execute("DROP TABLE IF EXISTS sz1") + except Exception as e: + print(f"POST Drop DB/TABLE failed: {e}") + A_conn.close() + B_conn.close() + exit (-1) + + +def case_48_thdA(conn): + # Notice: this case has unique index on col_c global A_succ try: cur = conn.cursor() @@ -1603,23 +1755,28 @@ def case_28_thdA(conn): cur.execute("BEGIN") cur.execute("SELECT * FROM sz") results = cur.fetchall() - assert len(results) == 10, "ASSERT" + assert len(results) == 10, "ASSERT 1" cur.execute("SELECT * FROM sz where col_a = 6") results = cur.fetchall() - assert len(results) == 1, "ASSERT" + assert len(results) == 1, "ASSERT 2" cur.execute("SELECT * FROM sz where col_a >= 6") results = cur.fetchall() - assert len(results) == 5, "ASSERT" + assert len(results) == 5, "ASSERT 3" + # = condition here will use the unique index on col_c + # which acquires lock on the row implicitly. cur.execute("SELECT * FROM sz where col_c = 8") results = cur.fetchall() - assert len(results) == 1, "ASSERT" + assert len(results) == 1, "ASSERT 4" + # <= condition here won't use the unique index on col_c... + # so no lock acquires cur.execute("SELECT * FROM sz where col_c <= 8") results = cur.fetchall() - assert len(results) == 8, "ASSERT" + assert len(results) == 8, "ASSERT 5" time.sleep(9) cur.execute("SELECT * FROM sz") results = cur.fetchall() - assert len(results) == 0, "ASSERT" + # Here is different with the case_28 + assert len(results) == 1, "ASSERT 6" cur.execute("COMMIT") cur.execute("BEGIN") @@ -1634,7 +1791,7 @@ def case_28_thdA(conn): cur.close() A_succ = True -def case_28_thdB(conn): +def case_48_thdB(conn): global B_succ try: time.sleep(15) @@ -1642,67 +1799,67 @@ def case_28_thdB(conn): cur.execute("BEGIN") cur.execute("SELECT * FROM sz WHERE col_a <= 5 FOR SHARE") results = cur.fetchall() - assert len(results) == 5, "ASSERT" + assert len(results) == 5, "ASSERT 1" time.sleep(6) cur.execute("SELECT * FROM sz") results = cur.fetchall() - assert len(results) == 5, "ASSERT" + assert len(results) == 5, "ASSERT 2" cur.execute("SELECT * FROM sz WHERE col_a = 3") results = cur.fetchall() - assert len(results) == 1, "ASSERT" + assert len(results) == 1, "ASSERT 3" cur.execute("SELECT * FROM sz WHERE col_a = 8") results = cur.fetchall() - assert len(results) == 0, "ASSERT" + assert len(results) == 0, "ASSERT 4" cur.execute("SELECT * FROM sz WHERE col_a >= 3") results = cur.fetchall() - assert len(results) == 3, "ASSERT" + assert len(results) == 3, "ASSERT 5" cur.execute("SELECT * FROM sz WHERE col_a <= 9") results = cur.fetchall() - assert len(results) == 5, "ASSERT" + assert len(results) == 5, "ASSERT 6" cur.execute("SELECT * FROM sz WHERE col_c = 3") results = cur.fetchall() - assert len(results) == 1, "ASSERT" + assert len(results) == 1, "ASSERT 7" cur.execute("SELECT * FROM sz WHERE col_c = 8") results = cur.fetchall() - assert len(results) == 0, "ASSERT" + assert len(results) == 0, "ASSERT 8" cur.execute("SELECT * FROM sz WHERE col_c >= 3") results = cur.fetchall() - assert len(results) == 3, "ASSERT" + assert len(results) == 3, "ASSERT 9" cur.execute("SELECT * FROM sz WHERE col_c <= 9") results = cur.fetchall() - assert len(results) == 5, "ASSERT" + assert len(results) == 5, "ASSERT 10" cur.execute("COMMIT") cur.execute("BEGIN") cur.execute("SELECT * FROM sz") results = cur.fetchall() - assert len(results) == 0, "ASSERT" + assert len(results) == 0, "ASSERT 11" cur.execute("SELECT * FROM sz WHERE col_a = 3") results = cur.fetchall() - assert len(results) == 0, "ASSERT" + assert len(results) == 0, "ASSERT 12" cur.execute("SELECT * FROM sz WHERE col_a = 8") results = cur.fetchall() - assert len(results) == 0, "ASSERT" + assert len(results) == 0, "ASSERT 13" cur.execute("SELECT * FROM sz WHERE col_a >= 3") results = cur.fetchall() - assert len(results) == 0, "ASSERT" + assert len(results) == 0, "ASSERT 14" cur.execute("SELECT * FROM sz WHERE col_a <= 9") results = cur.fetchall() - assert len(results) == 0, "ASSERT" + assert len(results) == 0, "ASSERT 15" cur.execute("SELECT * FROM sz WHERE col_c = 3") results = cur.fetchall() - assert len(results) == 0, "ASSERT" + assert len(results) == 0, "ASSERT 16" cur.execute("SELECT * FROM sz WHERE col_c = 8") results = cur.fetchall() - assert len(results) == 0, "ASSERT" + assert len(results) == 0, "ASSERT 17" cur.execute("SELECT * FROM sz WHERE col_c >= 3") results = cur.fetchall() - assert len(results) == 0, "ASSERT" + assert len(results) == 0, "ASSERT 18" cur.execute("SELECT * FROM sz WHERE col_c <= 9") results = cur.fetchall() - assert len(results) == 0, "ASSERT" + assert len(results) == 0, "ASSERT 19" cur.execute("COMMIT") except Exception as e: @@ -1723,7 +1880,8 @@ def case_29_pre(A_conn, B_conn): "col_a INT, " "col_b TIMESTAMP, " "col_c INT, " - "PRIMARY KEY(col_a)) " + "PRIMARY KEY(col_a), " + "KEY(col_c))" "ENGINE = NDB, " "COMMENT=\"NDB_TABLE=FULLY_REPLICATED=1,TTL=10@col_b\"") except Exception as e: @@ -1866,39 +2024,70 @@ def case_29_post(A_conn, B_conn): exit (-1) -def case_45_thdA(conn): +def case_49_pre(A_conn, B_conn): + try: + cur = A_conn.cursor() + cur.execute("DROP TABLE IF EXISTS sz1") + cur.execute("CREATE TABLE test.sz1 (" + "col_a INT, " + "col_b TIMESTAMP, " + "col_c INT, " + "PRIMARY KEY(col_a), " + "UNIQUE KEY(col_c))" + "ENGINE = NDB, " + "COMMENT=\"NDB_TABLE=FULLY_REPLICATED=1,TTL=10@col_b\"") + except Exception as e: + print(f"PRE Create DB/TABLE failed: {e}") + A_conn.close() + B_conn.close() + exit (-1) + +def case_49_thdA(conn): + # Notice: this case has unique index on col_c global A_succ try: cur = conn.cursor() cur.execute("BEGIN") - cur.execute("INSERT INTO sz VALUES(1, sysdate(), 1), (2, sysdate(), 2), (3, sysdate(), 3), (4, sysdate(), 4), (5, sysdate(), 5), (6, sysdate(), 6), (7, sysdate(), 7), (8, sysdate(), 8), (9, sysdate(), 9), (10, sysdate(), 10)") - time.sleep(11) - cur.execute("SELECT * FROM sz WHERE col_c >= 7 FOR UPDATE") + cur.execute("INSERT INTO sz1 VALUES(1, sysdate(), 1), (2, sysdate(), 2), (3, sysdate(), 3), (4, sysdate(), 4), (5, sysdate(), 5), (6, sysdate(), 6), (7, sysdate(), 7), (8, sysdate(), 8), (9, sysdate(), 9), (10, sysdate(), 10)") + cur.execute("COMMIT") + time.sleep(2) + cur.execute("BEGIN") + cur.execute("SELECT * FROM sz1") results = cur.fetchall() - assert len(results) == 4, "ASSERT1" - cur.execute("UPDATE sz SET col_c = 100 WHERE col_c <= 3") - changed_rows = conn.affected_rows() - matched_rows = cur.rowcount - assert changed_rows == 3 and matched_rows == 3, "ASSERT2" - cur.execute("SELECT * FROM sz WHERE col_a <= 3 FOR SHARE") + assert len(results) == 10, "ASSERT" + cur.execute("SELECT * FROM sz1 where col_a = 6") results = cur.fetchall() - assert len(results) == 3, "ASSERT3" - for row in results: - col_c = row[2] - assert col_c == 100, "ASSERT4" - cur.execute("DELETE FROM sz WHERE col_c >= 20") - changed_rows = conn.affected_rows() - matched_rows = cur.rowcount - assert changed_rows == 3 and matched_rows == 3, "ASSERT5" - cur.execute("SELECT * FROM sz") + assert len(results) == 1, "ASSERT" + cur.execute("SELECT * FROM sz1 where col_a >= 6") results = cur.fetchall() - assert len(results) == 7, "ASSERT6" + assert len(results) == 5, "ASSERT" + # = condition here will use the unique index on col_c + # which acquires lock on the row implicitly. + cur.execute("SELECT * FROM sz1 where col_c = 8") + results = cur.fetchall() + assert len(results) == 1, "ASSERT" + # <= condition here won't use the unique index on col_c... + # so no lock acquires + cur.execute("SELECT * FROM sz1 where col_c <= 8") + results = cur.fetchall() + assert len(results) == 8, "ASSERT" + time.sleep(9) + cur.execute("SELECT * FROM sz1") + results = cur.fetchall() + # Here is different with the case_48 + assert len(results) == 1, "ASSERT" cur.execute("COMMIT") - - cur.execute("SELECT * FROM sz") + cur.execute("SELECT * FROM sz1") results = cur.fetchall() - assert len(results) == 0, "ASSERT7" + assert len(results) == 0, "ASSERT" + cur.execute("BEGIN") + cur.execute("INSERT INTO sz1 VALUES(1, sysdate(), 1), (2, sysdate(), 2), (3, sysdate(), 3), (4, sysdate(), 4), (5, sysdate(), 5), (6, sysdate(), 6), (7, sysdate(), 7), (8, sysdate(), 8), (9, sysdate(), 9), (10, sysdate(), 10)") + cur.execute("COMMIT") + time.sleep(2) + cur.execute("SELECT * FROM sz1") + results = cur.fetchall() + assert len(results) == 10, "ASSERT" except Exception as e: print(f"Thd A failed: {e}") @@ -1907,28 +2096,161 @@ def case_45_thdA(conn): cur.close() A_succ = True -def case_45_thdB(conn): +def case_49_thdB(conn): global B_succ try: - time.sleep(5) + time.sleep(15) cur = conn.cursor() cur.execute("BEGIN") - cur.execute("SELECT * FROM sz FOR SHARE") - #cur.execute("SELECT * FROM sz") + cur.execute("SELECT * FROM sz1 WHERE col_a <= 5 FOR SHARE") results = cur.fetchall() - assert len(results) == 0, "ASSERT" - time.sleep(5) - cur.execute("SELECT * FROM sz FOR UPDATE") - #cur.execute("SELECT * FROM sz") + assert len(results) == 5, "ASSERT" + time.sleep(7) + cur.execute("SELECT * FROM sz1") + results = cur.fetchall() + assert len(results) == 5, "ASSERT" + cur.execute("SELECT * FROM sz1 WHERE col_a = 3") + results = cur.fetchall() + assert len(results) == 1, "ASSERT" + cur.execute("SELECT * FROM sz1 WHERE col_a = 8") results = cur.fetchall() assert len(results) == 0, "ASSERT" - time.sleep(5) - cur.execute("SELECT * FROM sz") + cur.execute("SELECT * FROM sz1 WHERE col_a >= 3") + results = cur.fetchall() + assert len(results) == 3, "ASSERT" + cur.execute("SELECT * FROM sz1 WHERE col_a <= 9") + results = cur.fetchall() + assert len(results) == 5, "ASSERT" + + cur.execute("SELECT * FROM sz1 WHERE col_c = 3") + results = cur.fetchall() + assert len(results) == 1, "ASSERT" + cur.execute("SELECT * FROM sz1 WHERE col_c = 8") results = cur.fetchall() assert len(results) == 0, "ASSERT" + cur.execute("SELECT * FROM sz1 WHERE col_c >= 3") + results = cur.fetchall() + assert len(results) == 3, "ASSERT" + cur.execute("SELECT * FROM sz1 WHERE col_c <= 9") + results = cur.fetchall() + assert len(results) == 5, "ASSERT" + cur.execute("COMMIT") - except Exception as e: - print(f"Thd B failed: {e}") + cur.execute("BEGIN") + cur.execute("SELECT * FROM sz1") + results = cur.fetchall() + assert len(results) == 0, "ASSERT" + cur.execute("SELECT * FROM sz1 WHERE col_a = 3") + results = cur.fetchall() + assert len(results) == 0, "ASSERT" + cur.execute("SELECT * FROM sz1 WHERE col_a = 8") + results = cur.fetchall() + assert len(results) == 0, "ASSERT" + cur.execute("SELECT * FROM sz1 WHERE col_a >= 3") + results = cur.fetchall() + assert len(results) == 0, "ASSERT" + cur.execute("SELECT * FROM sz1 WHERE col_a <= 9") + results = cur.fetchall() + assert len(results) == 0, "ASSERT" + + cur.execute("SELECT * FROM sz1 WHERE col_c = 3") + results = cur.fetchall() + assert len(results) == 0, "ASSERT" + cur.execute("SELECT * FROM sz1 WHERE col_c = 8") + results = cur.fetchall() + assert len(results) == 0, "ASSERT" + cur.execute("SELECT * FROM sz1 WHERE col_c >= 3") + results = cur.fetchall() + assert len(results) == 0, "ASSERT" + cur.execute("SELECT * FROM sz1 WHERE col_c <= 9") + results = cur.fetchall() + assert len(results) == 0, "ASSERT" + cur.execute("COMMIT") + + except Exception as e: + print(f"Thd B failed: {e}") + time.sleep(2) + cur.close() + return + + cur.close() + B_succ = True + +def case_49_post(A_conn, B_conn): + try: + cur = A_conn.cursor() + cur.execute("DROP TABLE IF EXISTS sz1") + + except Exception as e: + print(f"POST Drop DB/TABLE failed: {e}") + A_conn.close() + B_conn.close() + exit (-1) + + +def case_45_thdA(conn): + global A_succ + try: + cur = conn.cursor() + cur.execute("BEGIN") + cur.execute("INSERT INTO sz VALUES(1, sysdate(), 1), (2, sysdate(), 2), (3, sysdate(), 3), (4, sysdate(), 4), (5, sysdate(), 5), (6, sysdate(), 6), (7, sysdate(), 7), (8, sysdate(), 8), (9, sysdate(), 9), (10, sysdate(), 10)") + time.sleep(11) + cur.execute("SELECT * FROM sz WHERE col_c >= 7 FOR UPDATE") + results = cur.fetchall() + assert len(results) == 4, "ASSERT1" + cur.execute("UPDATE sz SET col_c = 100 WHERE col_c <= 3") + changed_rows = conn.affected_rows() + matched_rows = cur.rowcount + assert changed_rows == 3 and matched_rows == 3, "ASSERT2" + cur.execute("SELECT * FROM sz WHERE col_a <= 3 FOR SHARE") + results = cur.fetchall() + assert len(results) == 3, "ASSERT3" + for row in results: + col_c = row[2] + assert col_c == 100, "ASSERT4" + cur.execute("DELETE FROM sz WHERE col_c >= 20") + changed_rows = conn.affected_rows() + matched_rows = cur.rowcount + assert changed_rows == 3 and matched_rows == 3, "ASSERT5" + cur.execute("SELECT * FROM sz") + results = cur.fetchall() + assert len(results) == 7, "ASSERT6" + cur.execute("COMMIT") + + cur.execute("SELECT * FROM sz") + results = cur.fetchall() + assert len(results) == 0, "ASSERT7" + + + except Exception as e: + print(f"Thd A failed: {e}") + cur.close() + return + cur.close() + A_succ = True + +def case_45_thdB(conn): + global B_succ + try: + time.sleep(5) + cur = conn.cursor() + cur.execute("BEGIN") + cur.execute("SELECT * FROM sz FOR SHARE") + #cur.execute("SELECT * FROM sz") + results = cur.fetchall() + assert len(results) == 0, "ASSERT" + time.sleep(5) + cur.execute("SELECT * FROM sz FOR UPDATE") + #cur.execute("SELECT * FROM sz") + results = cur.fetchall() + assert len(results) == 0, "ASSERT" + time.sleep(5) + cur.execute("SELECT * FROM sz") + results = cur.fetchall() + assert len(results) == 0, "ASSERT" + + except Exception as e: + print(f"Thd B failed: {e}") time.sleep(2) cur.close() return @@ -2247,11 +2569,11 @@ def case_36_thdA(conn): cur.execute("COMMIT") cur.execute("SELECT * FROM sz") results = cur.fetchall() - assert len(results) == 1, "ASSERT" + assert len(results) == 1, "ASSERT 1" time.sleep(11) cur.execute("SELECT * FROM sz") results = cur.fetchall() - assert len(results) == 0, "ASSERT" + assert len(results) == 0, "ASSERT 2" except Exception as e: print(f"Thd A failed: {e}") cur.close() @@ -2266,15 +2588,15 @@ def case_36_thdB(conn): cur = conn.cursor() cur.execute("SELECT * FROM sz") results = cur.fetchall() - assert len(results) == 1, "ASSERT" + assert len(results) == 1, "ASSERT 3" for row in results: col_a = row[0] - assert col_a == 1, "ASSERT" + assert col_a == 1, "ASSERT 4" time.sleep(6) cur.execute("SELECT * FROM sz") results = cur.fetchall() - assert len(results) == 0, "ASSERT" - assert check_rep(conn) == True, "ASSERT" + assert len(results) == 0, "ASSERT 5" + assert check_rep(conn) == True, "ASSERT 6" except Exception as e: print(f"Thd B failed: {e}") cur.close() @@ -2802,59 +3124,1170 @@ def case_43_thdB(conn): time.sleep(3) cur.execute("SELECT * FROM sz WHERE col_a = 1") results = cur.fetchall() - assert len(results) == 1, "ASSERT" + assert len(results) == 1, "ASSERT" + for row in results: + col_c = row[2] + assert col_c == 200, "ASSERT" + assert check_rep(conn) == True, "ASSERT" + time.sleep(3) + cur.execute("SELECT * FROM sz") + results = cur.fetchall() + assert len(results) == 0, "ASSERT" + assert check_rep(conn) == True, "ASSERT" + except Exception as e: + print(f"Thd B failed: {e}") + cur.close() + return + cur.close() + B_succ = True + +def case_44_pre(A_conn, B_conn): + return + +def case_44_thdA(conn): + global A_succ + try: + cur = conn.cursor() + cur.execute("BEGIN") + cur.execute("INSERT INTO sz VALUES(1, SYSDATE(), 100)") + cur.execute("INSERT INTO sz VALUES(2, SYSDATE(), 200)") + cur.execute("INSERT INTO sz VALUES(3, DATE_ADD(SYSDATE(), INTERVAL 1 DAY), 300)") + cur.execute("INSERT INTO sz VALUES(4, SYSDATE(), 400)") + time.sleep(11) + cur.execute("COMMIT") + cur.execute("SELECT * FROM sz") + results = cur.fetchall() + assert len(results) == 1, "ASSERT" + + except Exception as e: + print(f"Thd A failed: {e}") + cur.close() + return + cur.close() + A_succ = True + +def case_44_thdB(conn): + global B_succ + try: + time.sleep(12) + cur = conn.cursor() + cur.execute("SELECT * FROM sz") + results = cur.fetchall() + assert len(results) == 1, "ASSERT" + for row in results: + col_c = row[2] + assert col_c == 300, "ASSERT" + assert check_rep(conn) == True, "ASSERT" + except Exception as e: + print(f"Thd B failed: {e}") + cur.close() + return + cur.close() + B_succ = True + +def case_44_post(A_conn, B_conn): + try: + cur = A_conn.cursor() + cur.execute("BEGIN") + cur.execute("DELETE FROM sz") + cur.execute("COMMIT") + except Exception as e: + print(f"POST Drop DB/TABLE failed: {e}") + A_conn.close() + B_conn.close() + exit (-1) + + +def case_46_pre(A_conn, B_conn): + try: + B_cur = B_conn.cursor() + B_cur.execute("STOP REPLICA") + B_cur.execute("DROP DATABASE IF EXISTS test") + + cur = A_conn.cursor() + cur.execute("DROP DATABASE IF EXISTS test") + cur.execute("CREATE DATABASE test") + cur.execute("USE test") + cur.execute("CREATE TABLE test.sz1 (" + "col_a INT, " + "col_b TIMESTAMP, " + "col_c INT, " + "PRIMARY KEY(col_a), " + "UNIQUE KEY(col_c))" + "ENGINE = NDB, " + "COMMENT=\"NDB_TABLE=TTL=10@col_b\"") + cur.execute("CREATE TABLE test.sz2 (" + "col_a INT, " + "col_b TIMESTAMP, " + "col_c INT, " + "KEY(col_c)) " + "ENGINE = NDB, " + "COMMENT=\"NDB_TABLE=TTL=10@col_b\"") + cur.execute("CREATE TABLE test.sz3 (" + "col_a INT, " + "col_b TIMESTAMP, " + "col_c INT, " + "PRIMARY KEY(col_a), " + "KEY(col_c)) " + "ENGINE = NDB") + except Exception as e: + print(f"PRE Create DB/TABLE failed: {e}") + A_conn.close() + B_conn.close() + exit (-1) + +def case_46_thdA(conn): + global A_succ + try: + cur = conn.cursor() + cur.execute("USE test") + cur.execute("BEGIN") + cur.execute("INSERT INTO sz1 VALUES(1, SYSDATE(), 100)") + cur.execute("INSERT INTO sz1 VALUES(2, SYSDATE(), 200)") + cur.execute("INSERT INTO sz1 VALUES(3, DATE_ADD(SYSDATE(), INTERVAL 1 DAY), 300)") + cur.execute("INSERT INTO sz1 VALUES(4, SYSDATE(), 400)") + cur.execute("INSERT INTO sz2 VALUES(1, SYSDATE(), 100)") + cur.execute("INSERT INTO sz2 VALUES(2, SYSDATE(), 200)") + cur.execute("INSERT INTO sz2 VALUES(3, DATE_ADD(SYSDATE(), INTERVAL 1 DAY), 300)") + cur.execute("INSERT INTO sz2 VALUES(4, SYSDATE(), 400)") + cur.execute("INSERT INTO sz3 VALUES(1, SYSDATE(), 100)") + cur.execute("INSERT INTO sz3 VALUES(2, SYSDATE(), 200)") + cur.execute("INSERT INTO sz3 VALUES(3, DATE_ADD(SYSDATE(), INTERVAL 1 DAY), 300)") + cur.execute("INSERT INTO sz3 VALUES(4, SYSDATE(), 400)") + cur.execute("COMMIT") + cur.execute("SELECT * FROM sz1") + results = cur.fetchall() + assert len(results) == 4, "ASSERT" + cur.execute("SELECT * FROM sz2") + results = cur.fetchall() + assert len(results) == 4, "ASSERT" + cur.execute("SELECT * FROM sz3") + results = cur.fetchall() + assert len(results) == 4, "ASSERT" + time.sleep(11) + + cur.execute("SELECT * FROM sz1") + results = cur.fetchall() + assert len(results) == 1, "ASSERT" + for row in results: + col_c = row[2] + assert col_c == 300, "ASSERT" + cur.execute("SELECT * FROM sz2") + results = cur.fetchall() + assert len(results) == 1, "ASSERT" + for row in results: + col_c = row[2] + assert col_c == 300, "ASSERT" + cur.execute("SELECT * FROM sz3") + results = cur.fetchall() + assert len(results) == 4, "ASSERT" + subprocess.run([BIN_DIR+"/ndb_mgm", "-e", "start backup"], + stdout=subprocess.PIPE, stderr=subprocess.PIPE) + except Exception as e: + print(f"Thd A failed: {e}") + cur.close() + return + cur.close() + A_succ = True + +def case_46_thdB(conn): + global B_succ + time.sleep(17) + subprocess.run([BIN_DIR+"/ndb_restore", + "--ndb-connectstring=127.0.0.1:"+str(MGMD_PORT_R), + "--nodeid=2", "--backupid=1", + "--backup-path="+DATA_DIR_P_1+"/ndb_data/BACKUP/BACKUP-1", + "--restore_meta", "--no-restore-disk-objects"], + stdout=subprocess.PIPE, stderr=subprocess.PIPE) + subprocess.run([BIN_DIR+"/ndb_restore", + "--ndb-connectstring=127.0.0.1:"+str(MGMD_PORT_R), + "--nodeid=2", "--backupid=1", + "--backup-path="+DATA_DIR_P_1+"/ndb_data/BACKUP/BACKUP-1", + "--disable-indexes"], + stdout=subprocess.PIPE, stderr=subprocess.PIPE) + + subprocess.run([BIN_DIR+"/ndb_restore", + "--ndb-connectstring=127.0.0.1:"+str(MGMD_PORT_R), + "--nodeid=2", "--backupid=1", + "--backup-path="+DATA_DIR_P_1+"/ndb_data/BACKUP/BACKUP-1", + "--restore-data"], + stdout=subprocess.PIPE, stderr=subprocess.PIPE) + subprocess.run([BIN_DIR+"/ndb_restore", + "--ndb-connectstring=127.0.0.1:"+str(MGMD_PORT_R), + "--nodeid=3", "--backupid=1", + "--backup-path="+DATA_DIR_P_2+"/ndb_data/BACKUP/BACKUP-1", + "--restore-data"], + stdout=subprocess.PIPE, stderr=subprocess.PIPE) + + subprocess.run([BIN_DIR+"/ndb_restore", + "--ndb-connectstring=127.0.0.1:"+str(MGMD_PORT_R), + "--nodeid=2", "--backupid=1", + "--backup-path="+DATA_DIR_P_1+"/ndb_data/BACKUP/BACKUP-1", + "--rebuild-indexes"], + stdout=subprocess.PIPE, stderr=subprocess.PIPE) + time.sleep(10) + while True: + try: + new_conn = pymysql.connect(host='127.0.0.1', + port=MYSQLD_PORT_R, + user='root') + cur = new_conn.cursor() + cur.execute("USE test") + cur.execute("SELECT * FROM sz1") + results = cur.fetchall() + assert len(results) == 1, "ASSERT 1" + for row in results: + col_c = row[2] + assert col_c == 300, "ASSERT 2" + cur.execute("SELECT * FROM sz2") + results = cur.fetchall() + assert len(results) == 1, "ASSERT 3" + for row in results: + col_c = row[2] + assert col_c == 300, "ASSERT 4" + cur.execute("SELECT * FROM sz3") + results = cur.fetchall() + assert len(results) == 4, "ASSERT 5" + break + except pymysql.MySQLError as e: + errno = e.args[0] + if errno in [1412, 1049]: + #1412 - Table definition has changed, please retry transaction + #1049 - Unknown database 'test' + print(f"Waiting for synchronizing restored schema...Retry {e}") + time.sleep(10) + cur.close() + new_conn.close() + continue + else: + print(f"Thd B failed: {e}") + cur.close() + new_conn.close() + return + except Exception as e: + print(f"Thd B failed: {e}") + cur.close() + new_conn.close() + return + cur.close() + new_conn.close() + B_succ = True + +def case_46_post(A_conn, B_conn): + try: + cur = A_conn.cursor() + #cur.execute("DROP TABLE IF EXISTS sz1") + #cur.execute("DROP TABLE IF EXISTS sz2") + #cur.execute("DROP TABLE IF EXISTS sz3") + except Exception as e: + print(f"POST Drop DB/TABLE failed: {e}") + A_conn.close() + B_conn.close() + exit (-1) + + +def case_47_thdA(conn): + global A_succ + try: + cur = conn.cursor() + cur.execute("BEGIN") + cur.execute("INSERT INTO sz VALUES(1, SYSDATE(), 100)") + cur.execute("COMMIT") + time.sleep(11) + cur.execute("SELECT * FROM sz") + results = cur.fetchall() + assert len(results) == 0, "ASSERT" + cur.execute("BEGIN") + cur.execute("INSERT INTO sz VALUES(2, SYSDATE(), 100)") + cur.execute("COMMIT") + time.sleep(11) + cur.execute("BEGIN") + cur.execute("INSERT INTO sz VALUES(2, SYSDATE(), 100)") + cur.execute("COMMIT") + cur.execute("SELECT * FROM sz") + results = cur.fetchall() + assert len(results) == 1, "ASSERT" + for row in results: + col_a = row[0] + assert col_a == 2, "ASSERT" + + except Exception as e: + print(f"Thd A failed: {e}") + cur.close() + return + cur.close() + A_succ = True + +def case_47_thdB(conn): + global B_succ + try: + time.sleep(5) + cur = conn.cursor() + cur.execute("SELECT * FROM sz") + results = cur.fetchall() + assert len(results) == 1, "ASSERT" + for row in results: + col_a = row[0] + assert col_a == 1, "ASSERT" + time.sleep(10) + cur.execute("SELECT * FROM sz") + results = cur.fetchall() + assert len(results) == 1, "ASSERT" + for row in results: + col_a = row[0] + assert col_a == 2, "ASSERT" + time.sleep(6) + results = cur.fetchall() + assert len(results) == 0, "ASSERT" + assert check_rep(conn) == True, "ASSERT" + except Exception as e: + print(f"Thd B failed: {e}") + cur.close() + return + cur.close() + B_succ = True + + +def case_50_pre(A_conn, B_conn): + try: + cur = A_conn.cursor() + cur.execute("DROP TABLE IF EXISTS sz1") + cur.execute("CREATE TABLE test.sz1 (" + "col_a INT, " + "col_b TIMESTAMP, " + "col_c INT, " + "PRIMARY KEY(col_a))" + "ENGINE = NDB, " + "COMMENT=\"NDB_TABLE=TTL=10@col_b\"") + except Exception as e: + print(f"PRE Create DB/TABLE failed: {e}") + A_conn.close() + B_conn.close() + exit (-1) + +def case_50_thdA(conn): + global A_succ + try: + cur = conn.cursor() + cur.execute("BEGIN") + cur.execute("INSERT INTO sz1 VALUES(1, SYSDATE(), 100)") + cur.execute("INSERT INTO sz1 VALUES(2, SYSDATE(), 200)") + cur.execute("INSERT INTO sz1 VALUES(3, DATE_ADD(SYSDATE(), INTERVAL 1 DAY), 300)") + cur.execute("INSERT INTO sz1 VALUES(4, SYSDATE(), 400)") + cur.execute("COMMIT") + cur.execute("SELECT * FROM sz1") + results = cur.fetchall() + assert len(results) == 4, "ASSERT" + time.sleep(11) + cur.execute("SELECT * FROM sz1") + results = cur.fetchall() + assert len(results) == 1, "ASSERT" + for row in results: + col_a = row[0] + assert col_a == 3, "ASSERT" + + cur.execute("ALTER TABLE sz1 ADD UNIQUE INDEX uk(col_c)"); + cur.execute("SELECT * FROM sz1") + results = cur.fetchall() + assert len(results) == 1, "ASSERT" + cur.execute("SELECT * FROM sz1 WHERE col_c = 100") + results = cur.fetchall() + assert len(results) == 0, "ASSERT" + cur.execute("SELECT * FROM sz1 WHERE col_c = 200") + results = cur.fetchall() + assert len(results) == 0, "ASSERT" + cur.execute("SELECT * FROM sz1 WHERE col_c = 300") + results = cur.fetchall() + assert len(results) == 1, "ASSERT" + cur.execute("SELECT * FROM sz1 WHERE col_c = 400") + results = cur.fetchall() + assert len(results) == 0, "ASSERT" + + cur.execute("ALTER TABLE sz1 comment=\"NDB_TABLE=TTL=OFF\""); + cur.execute("SELECT * FROM sz1") + results = cur.fetchall() + assert len(results) == 4, "ASSERT" + cur.execute("SELECT * FROM sz1 WHERE col_c = 100") + results = cur.fetchall() + assert len(results) == 1, "ASSERT" + cur.execute("SELECT * FROM sz1 WHERE col_c = 200") + results = cur.fetchall() + assert len(results) == 1, "ASSERT" + cur.execute("SELECT * FROM sz1 WHERE col_c = 300") + results = cur.fetchall() + assert len(results) == 1, "ASSERT" + cur.execute("SELECT * FROM sz1 WHERE col_c = 400") + results = cur.fetchall() + assert len(results) == 1, "ASSERT" + + except Exception as e: + print(f"Thd A failed: {e}") + cur.close() + return + cur.close() + A_succ = True + +def case_50_thdB(conn): + global B_succ + try: + time.sleep(15) + cur = conn.cursor() + cur.execute("SELECT * FROM sz1") + results = cur.fetchall() + assert len(results) == 4, "ASSERT" + cur.execute("SELECT * FROM sz1 WHERE col_c = 100") + results = cur.fetchall() + assert len(results) == 1, "ASSERT" + cur.execute("SELECT * FROM sz1 WHERE col_c = 200") + results = cur.fetchall() + assert len(results) == 1, "ASSERT" + cur.execute("SELECT * FROM sz1 WHERE col_c = 300") + results = cur.fetchall() + assert len(results) == 1, "ASSERT" + cur.execute("SELECT * FROM sz1 WHERE col_c = 400") + results = cur.fetchall() + assert len(results) == 1, "ASSERT" + + assert check_rep(conn) == True, "ASSERT" + except Exception as e: + print(f"Thd B failed: {e}") + cur.close() + return + cur.close() + B_succ = True + +def case_50_post(A_conn, B_conn): + try: + cur = A_conn.cursor() + cur.execute("DROP TABLE IF EXISTS sz1") + except Exception as e: + print(f"POST Drop DB/TABLE failed: {e}") + A_conn.close() + B_conn.close() + exit (-1) + + +def case_51_pre(A_conn, B_conn): + # Precondition: ts_1 is pre created + try: + cur = A_conn.cursor() + cur.execute("DROP TABLE IF EXISTS sz1") + cur.execute("CREATE TABLE test.sz1 (" + "col_a INT, " + "col_b TIMESTAMP, " + "col_c INT, " + "col_d INT STORAGE DISK, " + "PRIMARY KEY(col_a))" + "ENGINE = NDB, TABLESPACE ts_1, " + "COMMENT=\"NDB_TABLE=TTL=10@col_b\"") + except Exception as e: + print(f"PRE Create DB/TABLE failed: {e}") + A_conn.close() + B_conn.close() + exit (-1) + +def case_51_thdA(conn): + global A_succ + try: + cur = conn.cursor() + cur.execute("BEGIN") + cur.execute("INSERT INTO sz1 VALUES(1, SYSDATE(), 100, 10000)") + cur.execute("INSERT INTO sz1 VALUES(2, SYSDATE(), 200, 20000)") + cur.execute("INSERT INTO sz1 VALUES(3, DATE_ADD(SYSDATE(), INTERVAL 1 DAY), 300, 30000)") + cur.execute("INSERT INTO sz1 VALUES(4, SYSDATE(), 400, 40000)") + cur.execute("COMMIT") + cur.execute("SELECT * FROM sz1") + results = cur.fetchall() + assert len(results) == 4, "ASSERT" + time.sleep(11) + cur.execute("SELECT * FROM sz1") + results = cur.fetchall() + assert len(results) == 1, "ASSERT" + for row in results: + col_a = row[0] + assert col_a == 3, "ASSERT" + + cur.execute("ALTER TABLE sz1 ADD UNIQUE INDEX uk(col_c)"); + cur.execute("SELECT * FROM sz1") + results = cur.fetchall() + assert len(results) == 1, "ASSERT" + cur.execute("SELECT * FROM sz1 WHERE col_c = 100") + results = cur.fetchall() + assert len(results) == 0, "ASSERT" + cur.execute("SELECT * FROM sz1 WHERE col_c = 200") + results = cur.fetchall() + assert len(results) == 0, "ASSERT" + cur.execute("SELECT * FROM sz1 WHERE col_c = 300") + results = cur.fetchall() + assert len(results) == 1, "ASSERT" + cur.execute("SELECT * FROM sz1 WHERE col_c = 400") + results = cur.fetchall() + assert len(results) == 0, "ASSERT" + + cur.execute("ALTER TABLE sz1 comment=\"NDB_TABLE=TTL=OFF\""); + cur.execute("SELECT * FROM sz1") + results = cur.fetchall() + assert len(results) == 4, "ASSERT" + cur.execute("SELECT * FROM sz1 WHERE col_c = 100") + results = cur.fetchall() + assert len(results) == 1, "ASSERT" + cur.execute("SELECT * FROM sz1 WHERE col_c = 200") + results = cur.fetchall() + assert len(results) == 1, "ASSERT" + cur.execute("SELECT * FROM sz1 WHERE col_c = 300") + results = cur.fetchall() + assert len(results) == 1, "ASSERT" + cur.execute("SELECT * FROM sz1 WHERE col_c = 400") + results = cur.fetchall() + assert len(results) == 1, "ASSERT" + + except Exception as e: + print(f"Thd A failed: {e}") + cur.close() + return + cur.close() + A_succ = True + +def case_51_thdB(conn): + global B_succ + try: + time.sleep(15) + cur = conn.cursor() + cur.execute("SELECT * FROM sz1") + results = cur.fetchall() + assert len(results) == 4, "ASSERT" + cur.execute("SELECT * FROM sz1 WHERE col_c = 100") + results = cur.fetchall() + assert len(results) == 1, "ASSERT" + cur.execute("SELECT * FROM sz1 WHERE col_c = 200") + results = cur.fetchall() + assert len(results) == 1, "ASSERT" + cur.execute("SELECT * FROM sz1 WHERE col_c = 300") + results = cur.fetchall() + assert len(results) == 1, "ASSERT" + cur.execute("SELECT * FROM sz1 WHERE col_c = 400") + results = cur.fetchall() + assert len(results) == 1, "ASSERT" + + assert check_rep(conn) == True, "ASSERT" + except Exception as e: + print(f"Thd B failed: {e}") + cur.close() + return + cur.close() + B_succ = True + +def case_51_post(A_conn, B_conn): + try: + cur = A_conn.cursor() + cur.execute("DROP TABLE IF EXISTS sz1") + except Exception as e: + print(f"POST Drop DB/TABLE failed: {e}") + A_conn.close() + B_conn.close() + exit (-1) + + +def case_52_pre(A_conn, B_conn): + # Precondition: ts_1 is pre created + try: + cur = A_conn.cursor() + cur.execute("DROP TABLE IF EXISTS sz1") + cur.execute("CREATE TABLE test.sz1 (" + "col_a INT, " + "col_b TIMESTAMP, " + "col_c INT, " + "col_d INT STORAGE DISK, " + "PRIMARY KEY(col_a))" + "ENGINE = NDB, TABLESPACE ts_1, " + "COMMENT=\"NDB_TABLE=TTL=10@col_b\"") + except Exception as e: + print(f"PRE Create DB/TABLE failed: {e}") + A_conn.close() + B_conn.close() + exit (-1) + +def case_52_thdA(conn): + global A_succ + try: + cur = conn.cursor() + cur.execute("BEGIN") + cur.execute("INSERT INTO sz1 VALUES(1, SYSDATE(), 100, 10000)") + cur.execute("INSERT INTO sz1 VALUES(2, SYSDATE(), 200, 20000)") + cur.execute("INSERT INTO sz1 VALUES(3, DATE_ADD(SYSDATE(), INTERVAL 1 DAY), 300, 30000)") + cur.execute("INSERT INTO sz1 VALUES(4, SYSDATE(), 400, 40000)") + cur.execute("COMMIT") + cur.execute("SELECT * FROM sz1") + results = cur.fetchall() + assert len(results) == 4, "ASSERT" + + cur.execute("ALTER TABLE sz1 CHANGE COLUMN col_b col_b INT STORAGE DISK"); + except Exception as e: + if e.args[0] != 1478: + print(f"Thd A failed: {e}") + cur.close() + return + try: + cur.execute("ALTER TABLE sz1 STORAGE DISK"); + except Exception as e: + if e.args[0] != 1478: + print(f"Thd A failed: {e}") + cur.close() + return + + cur.close() + A_succ = True + +def case_52_thdB(conn): + global B_succ + try: + time.sleep(11) + cur = conn.cursor() + cur.execute("SELECT * FROM sz1") + results = cur.fetchall() + assert len(results) == 1, "ASSERT" + + assert check_rep(conn) == True, "ASSERT" + except Exception as e: + print(f"Thd B failed: {e}") + cur.close() + return + cur.close() + B_succ = True + +def case_52_post(A_conn, B_conn): + try: + cur = A_conn.cursor() + cur.execute("DROP TABLE IF EXISTS sz1") + except Exception as e: + print(f"POST Drop DB/TABLE failed: {e}") + A_conn.close() + B_conn.close() + exit (-1) + + +def case_53_pre(A_conn, B_conn): + try: + cur = A_conn.cursor() + cur.execute("DROP TABLE IF EXISTS sz1") + cur.execute("CREATE TABLE test.sz1 (" + "col_a INT, " + "col_b TIMESTAMP, " + "col_c INT, " + "PRIMARY KEY(col_a))" + "ENGINE = NDB, " + "COMMENT=\"NDB_TABLE=TTL=10@col_b\"") + except Exception as e: + print(f"PRE Create DB/TABLE failed: {e}") + A_conn.close() + B_conn.close() + exit (-1) + +def case_53_thdA(conn): + global A_succ + try: + cur = conn.cursor() + cur.execute("BEGIN") + cur.execute("INSERT INTO sz1 VALUES(1, SYSDATE(), 100)") + cur.execute("INSERT INTO sz1 VALUES(2, SYSDATE(), 200)") + cur.execute("INSERT INTO sz1 VALUES(3, DATE_ADD(SYSDATE(), INTERVAL 1 DAY), 300)") + cur.execute("INSERT INTO sz1 VALUES(4, SYSDATE(), 400)") + cur.execute("COMMIT") + cur.execute("SELECT * FROM sz1") + results = cur.fetchall() + assert len(results) == 4, "ASSERT" + time.sleep(11) + cur.execute("SELECT * FROM sz1") + results = cur.fetchall() + assert len(results) == 1, "ASSERT" + for row in results: + col_a = row[0] + assert col_a == 3, "ASSERT" + + cur.execute("ALTER TABLE sz1 ADD INDEX uk(col_c)"); + cur.execute("SELECT * FROM sz1") + results = cur.fetchall() + assert len(results) == 1, "ASSERT" + cur.execute("SELECT * FROM sz1 WHERE col_c = 100") + results = cur.fetchall() + assert len(results) == 0, "ASSERT" + cur.execute("SELECT * FROM sz1 WHERE col_c = 200") + results = cur.fetchall() + assert len(results) == 0, "ASSERT" + cur.execute("SELECT * FROM sz1 WHERE col_c = 300") + results = cur.fetchall() + assert len(results) == 1, "ASSERT" + cur.execute("SELECT * FROM sz1 WHERE col_c = 400") + results = cur.fetchall() + assert len(results) == 0, "ASSERT" + + cur.execute("ALTER TABLE sz1 comment=\"NDB_TABLE=TTL=OFF\""); + cur.execute("SELECT * FROM sz1") + results = cur.fetchall() + assert len(results) == 4, "ASSERT" + cur.execute("SELECT * FROM sz1 WHERE col_c = 100") + results = cur.fetchall() + assert len(results) == 1, "ASSERT" + cur.execute("SELECT * FROM sz1 WHERE col_c = 200") + results = cur.fetchall() + assert len(results) == 1, "ASSERT" + cur.execute("SELECT * FROM sz1 WHERE col_c = 300") + results = cur.fetchall() + assert len(results) == 1, "ASSERT" + cur.execute("SELECT * FROM sz1 WHERE col_c = 400") + results = cur.fetchall() + assert len(results) == 1, "ASSERT" + + except Exception as e: + print(f"Thd A failed: {e}") + cur.close() + return + cur.close() + A_succ = True + +def case_53_thdB(conn): + global B_succ + try: + time.sleep(15) + cur = conn.cursor() + cur.execute("SELECT * FROM sz1") + results = cur.fetchall() + assert len(results) == 4, "ASSERT" + cur.execute("SELECT * FROM sz1 WHERE col_c = 100") + results = cur.fetchall() + assert len(results) == 1, "ASSERT" + cur.execute("SELECT * FROM sz1 WHERE col_c = 200") + results = cur.fetchall() + assert len(results) == 1, "ASSERT" + cur.execute("SELECT * FROM sz1 WHERE col_c = 300") + results = cur.fetchall() + assert len(results) == 1, "ASSERT" + cur.execute("SELECT * FROM sz1 WHERE col_c = 400") + results = cur.fetchall() + assert len(results) == 1, "ASSERT" + + assert check_rep(conn) == True, "ASSERT" + except Exception as e: + print(f"Thd B failed: {e}") + cur.close() + return + cur.close() + B_succ = True + +def case_53_post(A_conn, B_conn): + try: + cur = A_conn.cursor() + cur.execute("DROP TABLE IF EXISTS sz1") + except Exception as e: + print(f"POST Drop DB/TABLE failed: {e}") + A_conn.close() + B_conn.close() + exit (-1) + + +def case_54_pre(A_conn, B_conn): + try: + cur = A_conn.cursor() + cur.execute("DROP TABLE IF EXISTS parent") + cur.execute("DROP TABLE IF EXISTS sz1") + cur.execute("DROP TABLE IF EXISTS child") + cur.execute("CREATE TABLE parent (" + "col_a INT, " + "col_b_ui INT, " + "col_c_ui_upd INT, " + "col_d_ui_del INT, " + "PRIMARY KEY(col_a), " + "UNIQUE KEY(col_b_ui), " + "UNIQUE KEY(col_c_ui_upd), " + "UNIQUE KEY(col_d_ui_del)) " + "ENGINE = NDB") + cur.execute("CREATE TABLE test.sz1 (" + "col_a INT, " + "col_t TIMESTAMP, " + "col_b_ui INT, " + "col_c_ui_upd INT, " + "col_d_ui_del INT, " + "col_e_ui INT, " + "col_f_ui_upd INT, " + "col_g_ui_del INT, " + "PRIMARY KEY(col_a), " + "UNIQUE KEY(col_e_ui), " + "UNIQUE KEY(col_f_ui_upd), " + "UNIQUE KEY(col_g_ui_del), " + "FOREIGN KEY(col_b_ui) REFERENCES parent(col_b_ui) ON UPDATE CASCADE ON DELETE CASCADE, " + "FOREIGN KEY(col_c_ui_upd) REFERENCES parent(col_c_ui_upd) ON UPDATE CASCADE ON DELETE CASCADE, " + "FOREIGN KEY(col_d_ui_del) REFERENCES parent(col_d_ui_del) ON UPDATE CASCADE ON DELETE CASCADE) " + "ENGINE = NDB, " + "COMMENT=\"NDB_TABLE=TTL=10@col_t\"") + cur.execute("CREATE TABLE test.child (" + "col_a INT, " + "col_e_ui INT, " + "col_f_ui_upd INT, " + "col_g_ui_del INT, " + "PRIMARY KEY(col_a), " + "FOREIGN KEY(col_e_ui) REFERENCES sz1(col_e_ui) ON UPDATE CASCADE ON DELETE CASCADE, " + "FOREIGN KEY(col_f_ui_upd) REFERENCES sz1(col_f_ui_upd) ON UPDATE CASCADE ON DELETE CASCADE, " + "FOREIGN KEY(col_g_ui_del) REFERENCES sz1(col_g_ui_del) ON UPDATE CASCADE ON DELETE CASCADE) " + "ENGINE = NDB") + except Exception as e: + print(f"PRE Create DB/TABLE failed: {e}") + A_conn.close() + B_conn.close() + exit (-1) + +def case_54_thdA(conn): + global A_succ + try: + cur = conn.cursor() + exit + cur.execute("BEGIN") + cur.execute("INSERT INTO parent VALUES(1, 11, 12, 13)") + cur.execute("INSERT INTO parent VALUES(2, 21, 22, 23)") + cur.execute("INSERT INTO parent VALUES(3, 31, 32, 33)") + cur.execute("INSERT INTO parent VALUES(4, 41, 42, 43)") + cur.execute("INSERT INTO parent VALUES(5, 51, 52, 53)") + cur.execute("INSERT INTO parent VALUES(6, 61, 62, 63)") + cur.execute("INSERT INTO sz1 VALUES(1, SYSDATE(), 11, 12, 13, 14, 15, 16)") + cur.execute("INSERT INTO sz1 VALUES(2, SYSDATE(), 21, 22, 23, 24, 25, 26)") + cur.execute("INSERT INTO sz1 VALUES(3, SYSDATE(), 31, 32, 33, 34, 35, 36)") + cur.execute("INSERT INTO sz1 VALUES(4, SYSDATE(), 41, 42, 43, 44, 45, 46)") + cur.execute("INSERT INTO sz1 VALUES(5, SYSDATE(), 51, 52, 53, 54, 55, 56)") + cur.execute("INSERT INTO sz1 VALUES(6, SYSDATE(), 61, 62, 63, 64, 65, 66)") + cur.execute("INSERT INTO child VALUES(1, 14, 15, 16)") + cur.execute("INSERT INTO child VALUES(2, 24, 25, 26)") + cur.execute("INSERT INTO child VALUES(3, 34, 35, 36)") + cur.execute("INSERT INTO child VALUES(4, 44, 45, 46)") + cur.execute("INSERT INTO child VALUES(5, 54, 55, 56)") + cur.execute("INSERT INTO child VALUES(6, 64, 65, 66)") + cur.execute("COMMIT") + cur.execute("SELECT * FROM parent") + results = cur.fetchall() + assert len(results) == 6, "ASSERT" + cur.execute("SELECT * FROM sz1") + results = cur.fetchall() + assert len(results) == 6, "ASSERT" + cur.execute("SELECT * FROM child") + results = cur.fetchall() + assert len(results) == 6, "ASSERT" + + cur.execute("BEGIN") + cur.execute("UPDATE parent SET col_c_ui_upd = 222 WHERE col_c_ui_upd = 22") + cur.execute("DELETE FROM parent WHERE col_d_ui_del = 33") + cur.execute("COMMIT") + + cur.execute("SELECT * FROM parent WHERE col_c_ui_upd = 222"); + results = cur.fetchall() + assert len(results) == 1, "ASSERT" + cur.execute("SELECT * FROM sz1 WHERE col_c_ui_upd = 222"); + results = cur.fetchall() + assert len(results) == 1, "ASSERT" + for row in results: + col_a = row[0] + assert col_a == 2, "ASSERT" + + cur.execute("SELECT * FROM sz1 WHERE col_d_ui_del = 33"); + results = cur.fetchall() + assert len(results) == 0, "ASSERT" + cur.execute("SELECT * FROM child WHERE col_g_ui_del = 36"); + results = cur.fetchall() + assert len(results) == 0, "ASSERT" + + + cur.execute("BEGIN") + cur.execute("UPDATE sz1 SET col_f_ui_upd = 445 WHERE col_f_ui_upd = 45") + cur.execute("DELETE FROM sz1 WHERE col_g_ui_del = 56") + cur.execute("COMMIT") + + cur.execute("BEGIN") + cur.execute("SELECT * FROM sz1 WHERE col_f_ui_upd = 445"); + results = cur.fetchall() + assert len(results) == 1, "ASSERT" + cur.execute("SELECT * FROM child WHERE col_f_ui_upd = 445"); + results = cur.fetchall() + assert len(results) == 1, "ASSERT" + for row in results: + col_a = row[0] + assert col_a == 4, "ASSERT" + cur.execute("COMMIT") + + cur.execute("BEGIN") + cur.execute("SELECT * FROM sz1 WHERE col_g_ui_del = 56"); + results = cur.fetchall() + assert len(results) == 0, "ASSERT" + cur.execute("SELECT * FROM child WHERE col_g_ui_del = 56"); + results = cur.fetchall() + assert len(results) == 0, "ASSERT" + cur.execute("COMMIT") + + time.sleep(11) + + cur.execute("SELECT * FROM parent") + results = cur.fetchall() + assert len(results) == 5, "ASSERT1" + cur.execute("SELECT * FROM sz1") + results = cur.fetchall() + assert len(results) == 0, "ASSERT2" + cur.execute("SELECT * FROM child") + results = cur.fetchall() + assert len(results) == 4, "ASSERT3" + + cur.execute("BEGIN") + cur.execute("UPDATE parent SET col_c_ui_upd = 112 WHERE col_c_ui_upd = 12") + cur.execute("DELETE FROM parent WHERE col_d_ui_del = 63") + cur.execute("COMMIT") + + cur.execute("BEGIN") + cur.execute("SELECT * FROM sz1 WHERE col_c_ui_upd = 112"); + results = cur.fetchall() + assert len(results) == 0, "ASSERT" + cur.execute("SELECT * FROM sz1 WHERE col_d_ui_del = 63"); + results = cur.fetchall() + assert len(results) == 0, "ASSERT" + + cur.execute("SELECT * FROM child WHERE col_g_ui_del = 66"); + results = cur.fetchall() + assert len(results) == 1, "ASSERT" + cur.execute("COMMIT") + + cur.execute("BEGIN") + # crash + cur.execute("INSERT INTO sz1 VALUES(6, SYSDATE(), 61, 62, 63, 664, 65, 66)") + cur.execute("COMMIT") + + + except Exception as e: + print(f"Thd A failed: {e}") + cur.close() + return + cur.close() + A_succ = True + +def case_54_thdB(conn): + global B_succ + try: + time.sleep(15) + cur = conn.cursor() + + assert check_rep(conn) == True, "ASSERT" + except Exception as e: + print(f"Thd B failed: {e}") + cur.close() + return + cur.close() + B_succ = True + +def case_54_post(A_conn, B_conn): + try: + cur = A_conn.cursor() + #cur.execute("DROP TABLE IF EXISTS sz1") + except Exception as e: + print(f"POST Drop DB/TABLE failed: {e}") + A_conn.close() + B_conn.close() + exit (-1) + + +def case_55_pre(A_conn, B_conn): + try: + cur = A_conn.cursor() + cur.execute("DROP TABLE IF EXISTS parent") + cur.execute("DROP TABLE IF EXISTS sz1") + cur.execute("DROP TABLE IF EXISTS child") + cur.execute("CREATE TABLE parent (" + "col_a INT, " + "col_b_ui INT, " + "col_c_ui_upd INT, " + "col_d_ui_del INT, " + "PRIMARY KEY(col_a), " + "UNIQUE KEY(col_b_ui), " + "UNIQUE KEY(col_c_ui_upd), " + "UNIQUE KEY(col_d_ui_del)) " + "ENGINE = NDB") + cur.execute("CREATE TABLE test.sz1 (" + "col_a INT, " + "col_t TIMESTAMP, " + "col_b_ui INT, " + "col_c_ui_upd INT, " + "col_d_ui_del INT, " + "col_e_ui INT, " + "col_f_ui_upd INT, " + "col_g_ui_del INT, " + "PRIMARY KEY(col_a), " + "UNIQUE KEY(col_e_ui), " + "UNIQUE KEY(col_f_ui_upd), " + "UNIQUE KEY(col_g_ui_del), " + "FOREIGN KEY(col_b_ui) REFERENCES parent(col_b_ui) ON UPDATE CASCADE ON DELETE CASCADE, " + "FOREIGN KEY(col_c_ui_upd) REFERENCES parent(col_c_ui_upd) ON UPDATE CASCADE ON DELETE CASCADE, " + "FOREIGN KEY(col_d_ui_del) REFERENCES parent(col_d_ui_del) ON UPDATE CASCADE ON DELETE CASCADE) " + "ENGINE = NDB, " + "COMMENT=\"NDB_TABLE=TTL=10@col_t\"") + cur.execute("CREATE TABLE test.other (" + "col_a INT, " + "col_e_ui INT, " + "col_f_ui_upd INT, " + "col_g_ui_del INT, " + "PRIMARY KEY(col_a)) " + "ENGINE = NDB") + + # should return error + cur.execute("CREATE TABLE test.child (" + "col_a INT, " + "col_e_ui INT, " + "col_f_ui_upd INT, " + "col_g_ui_del INT, " + "PRIMARY KEY(col_a), " + "FOREIGN KEY(col_e_ui) REFERENCES sz1(col_e_ui) ON UPDATE CASCADE ON DELETE CASCADE, " + "FOREIGN KEY(col_f_ui_upd) REFERENCES sz1(col_f_ui_upd) ON UPDATE CASCADE ON DELETE CASCADE, " + "FOREIGN KEY(col_g_ui_del) REFERENCES sz1(col_g_ui_del) ON UPDATE CASCADE ON DELETE CASCADE) " + "ENGINE = NDB") + assert 0 + except Exception as e: + if e.args[0] != 1215: + print(f"PRE Create DB/TABLE failed: {e}") + A_conn.close() + B_conn.close() + exit (-1) + +def case_55_thdA(conn): + global A_succ + try: + cur = conn.cursor() + exit + cur.execute("BEGIN") + cur.execute("INSERT INTO parent VALUES(1, 11, 12, 13)") + cur.execute("INSERT INTO parent VALUES(2, 21, 22, 23)") + cur.execute("INSERT INTO parent VALUES(3, 31, 32, 33)") + cur.execute("INSERT INTO parent VALUES(4, 41, 42, 43)") + cur.execute("INSERT INTO parent VALUES(5, 51, 52, 53)") + cur.execute("INSERT INTO parent VALUES(6, 61, 62, 63)") + cur.execute("INSERT INTO sz1 VALUES(1, SYSDATE(), 11, 12, 13, 14, 15, 16)") + cur.execute("INSERT INTO sz1 VALUES(2, SYSDATE(), 21, 22, 23, 24, 25, 26)") + cur.execute("INSERT INTO sz1 VALUES(3, SYSDATE(), 31, 32, 33, 34, 35, 36)") + cur.execute("INSERT INTO sz1 VALUES(4, SYSDATE(), 41, 42, 43, 44, 45, 46)") + cur.execute("INSERT INTO sz1 VALUES(5, SYSDATE(), 51, 52, 53, 54, 55, 56)") + cur.execute("INSERT INTO sz1 VALUES(6, SYSDATE(), 61, 62, 63, 64, 65, 66)") + cur.execute("INSERT INTO other VALUES(1, 14, 15, 16)") + cur.execute("INSERT INTO other VALUES(2, 24, 25, 26)") + cur.execute("INSERT INTO other VALUES(3, 34, 35, 36)") + cur.execute("INSERT INTO other VALUES(4, 44, 45, 46)") + cur.execute("INSERT INTO other VALUES(5, 54, 55, 56)") + cur.execute("INSERT INTO other VALUES(6, 64, 65, 66)") + cur.execute("COMMIT") + cur.execute("SELECT * FROM parent") + results = cur.fetchall() + assert len(results) == 6, "ASSERT 1" + cur.execute("SELECT * FROM sz1") + results = cur.fetchall() + assert len(results) == 6, "ASSERT 2" + cur.execute("SELECT * FROM other") + results = cur.fetchall() + assert len(results) == 6, "ASSERT 3" + + cur.execute("BEGIN") + cur.execute("UPDATE parent SET col_c_ui_upd = 222 WHERE col_c_ui_upd = 22") + cur.execute("DELETE FROM parent WHERE col_d_ui_del = 33") + cur.execute("COMMIT") + + cur.execute("SELECT * FROM parent WHERE col_c_ui_upd = 222"); + results = cur.fetchall() + assert len(results) == 1, "ASSERT 4" + cur.execute("SELECT * FROM sz1 WHERE col_c_ui_upd = 222"); + results = cur.fetchall() + assert len(results) == 1, "ASSERT 5" + for row in results: + col_a = row[0] + assert col_a == 2, "ASSERT" + + cur.execute("SELECT * FROM sz1 WHERE col_d_ui_del = 33"); + results = cur.fetchall() + assert len(results) == 0, "ASSERT 6" + + + cur.execute("BEGIN") + cur.execute("UPDATE sz1 SET col_f_ui_upd = 445 WHERE col_f_ui_upd = 45") + cur.execute("DELETE FROM sz1 WHERE col_g_ui_del = 56") + cur.execute("COMMIT") + + cur.execute("BEGIN") + cur.execute("SELECT * FROM sz1 WHERE col_f_ui_upd = 445"); + results = cur.fetchall() + assert len(results) == 1, "ASSERT 7" for row in results: - col_c = row[2] - assert col_c == 200, "ASSERT" - assert check_rep(conn) == True, "ASSERT" - time.sleep(3) - cur.execute("SELECT * FROM sz") + col_a = row[0] + assert col_a == 4, "ASSERT 8" + cur.execute("COMMIT") + + cur.execute("BEGIN") + cur.execute("SELECT * FROM sz1 WHERE col_g_ui_del = 56"); results = cur.fetchall() - assert len(results) == 0, "ASSERT" - assert check_rep(conn) == True, "ASSERT" - except Exception as e: - print(f"Thd B failed: {e}") - cur.close() - return - cur.close() - B_succ = True + assert len(results) == 0, "ASSERT 9" + cur.execute("COMMIT") -def case_44_pre(A_conn, B_conn): - return + time.sleep(11) + + cur.execute("SELECT * FROM parent") + results = cur.fetchall() + assert len(results) == 5, "ASSERT 10" + cur.execute("SELECT * FROM sz1") + results = cur.fetchall() + assert len(results) == 0, "ASSERT 11" + cur.execute("SELECT * FROM other") + results = cur.fetchall() + assert len(results) == 6, "ASSERT 12" -def case_44_thdA(conn): - global A_succ - try: - cur = conn.cursor() cur.execute("BEGIN") - cur.execute("INSERT INTO sz VALUES(1, SYSDATE(), 100)") - cur.execute("INSERT INTO sz VALUES(2, SYSDATE(), 200)") - cur.execute("INSERT INTO sz VALUES(3, DATE_ADD(SYSDATE(), INTERVAL 1 DAY), 300)") - cur.execute("INSERT INTO sz VALUES(4, SYSDATE(), 400)") - time.sleep(11) + cur.execute("UPDATE parent SET col_c_ui_upd = 112 WHERE col_c_ui_upd = 12") cur.execute("COMMIT") - cur.execute("SELECT * FROM sz") + + cur.execute("BEGIN") + cur.execute("SELECT * FROM sz1 WHERE col_c_ui_upd = 112"); results = cur.fetchall() - assert len(results) == 1, "ASSERT" + assert len(results) == 0, "ASSERT 13" + + cur.execute("BEGIN") + cur.execute("DELETE FROM parent WHERE col_d_ui_del = 63") + cur.execute("COMMIT") + + cur.execute("BEGIN") + cur.execute("SET ttl_expired_rows_visible_in_delete = 1") + cur.execute("DELETE FROM sz1"); + changed_rows = conn.affected_rows() + matched_rows = cur.rowcount + print(f"changed: {changed_rows}, matched: {matched_rows}") + assert changed_rows == 4 and matched_rows == 4, "ASSERT" + cur.execute("COMMIT") + cur.execute("SET ttl_expired_rows_visible_in_delete = 0") + + # If a row in the TTL child table expires, the parent table cannot update or delete + # the related row until the purging thread truly deletes it from the child table. + # + # The reason is that the scan flag used by the foreign key always includes + # the "ignore TTL" flag in SUMA. + # add some cases here + + cur.execute("BEGIN") + cur.execute("DELETE FROM other"); + cur.execute("COMMIT") + cur.execute("ALTER TABLE test.other " + "ADD FOREIGN KEY(col_e_ui) REFERENCES sz1(col_e_ui) ON UPDATE CASCADE ON DELETE CASCADE, " + "ADD FOREIGN KEY(col_f_ui_upd) REFERENCES sz1(col_f_ui_upd) ON UPDATE CASCADE ON DELETE CASCADE, " + "ADD FOREIGN KEY(col_g_ui_del) REFERENCES sz1(col_g_ui_del) ON UPDATE CASCADE ON DELETE CASCADE") + assert 0 except Exception as e: - print(f"Thd A failed: {e}") - cur.close() - return + if e.args[0] != 1215: + print(f"Thd A failed: {e}") + cur.close() + return cur.close() A_succ = True -def case_44_thdB(conn): +def case_55_thdB(conn): global B_succ try: - time.sleep(12) + time.sleep(15) cur = conn.cursor() - cur.execute("SELECT * FROM sz") - results = cur.fetchall() - assert len(results) == 1, "ASSERT" - for row in results: - col_c = row[2] - assert col_c == 300, "ASSERT" + assert check_rep(conn) == True, "ASSERT" except Exception as e: print(f"Thd B failed: {e}") @@ -2863,12 +4296,10 @@ def case_44_thdB(conn): cur.close() B_succ = True -def case_44_post(A_conn, B_conn): +def case_55_post(A_conn, B_conn): try: cur = A_conn.cursor() - cur.execute("BEGIN") - cur.execute("DELETE FROM sz") - cur.execute("COMMIT") + #cur.execute("DROP TABLE IF EXISTS sz1") except Exception as e: print(f"POST Drop DB/TABLE failed: {e}") A_conn.close() @@ -2876,170 +4307,171 @@ def case_44_post(A_conn, B_conn): exit (-1) -def case_46_pre(A_conn, B_conn): +def case_56_pre(A_conn, B_conn): try: - B_cur = B_conn.cursor() - B_cur.execute("STOP REPLICA") - B_cur.execute("DROP DATABASE IF EXISTS test") - cur = A_conn.cursor() - cur.execute("DROP DATABASE IF EXISTS test") - cur.execute("CREATE DATABASE test") - cur.execute("USE test") - cur.execute("CREATE TABLE test.sz1 (" + cur.execute("DROP TABLE IF EXISTS parent") + cur.execute("DROP TABLE IF EXISTS parentttl") + cur.execute("DROP TABLE IF EXISTS child") + cur.execute("DROP TABLE IF EXISTS sz1") + cur.execute("CREATE TABLE parent (" "col_a INT, " - "col_b TIMESTAMP, " - "col_c INT, " - "PRIMARY KEY(col_a)) " - "ENGINE = NDB, " - "COMMENT=\"NDB_TABLE=TTL=10@col_b\"") - cur.execute("CREATE TABLE test.sz2 (" + "col_t TIMESTAMP, " + "col_b_ui INT, " + "col_c_ui_upd INT, " + "col_d_ui_del INT, " + "PRIMARY KEY(col_a), " + "UNIQUE KEY(col_b_ui), " + "UNIQUE KEY(col_c_ui_upd), " + "UNIQUE KEY(col_d_ui_del)) " + "ENGINE = NDB") + cur.execute("CREATE TABLE parentttl (" "col_a INT, " - "col_b TIMESTAMP, " - "col_c INT)" + "col_t TIMESTAMP, " + "col_b_ui INT, " + "col_c_ui_upd INT, " + "col_d_ui_del INT, " + "PRIMARY KEY(col_a), " + "UNIQUE KEY(col_b_ui), " + "UNIQUE KEY(col_c_ui_upd), " + "UNIQUE KEY(col_d_ui_del)) " "ENGINE = NDB, " - "COMMENT=\"NDB_TABLE=TTL=10@col_b\"") - cur.execute("CREATE TABLE test.sz3 (" + "comment=\"NDB_TABLE=TTL=10@col_t\"") + cur.execute("CREATE TABLE sz1 (" "col_a INT, " - "col_b TIMESTAMP, " - "col_c INT, " + "col_t TIMESTAMP, " + "col_b_ui INT, " + "col_c_ui_upd INT, " + "col_d_ui_del INT, " "PRIMARY KEY(col_a)) " "ENGINE = NDB") + + cur.execute("CREATE TABLE sz2 (" + "col_a INT, " + "col_t TIMESTAMP, " + "col_b_ui INT, " + "col_c_ui_upd INT, " + "col_d_ui_del INT, " + "PRIMARY KEY(col_a), " + "FOREIGN KEY(col_b_ui) REFERENCES parent(col_b_ui) ON UPDATE CASCADE ON DELETE CASCADE, " + "FOREIGN KEY(col_c_ui_upd) REFERENCES parent(col_c_ui_upd) ON UPDATE CASCADE ON DELETE CASCADE, " + "FOREIGN KEY(col_d_ui_del) REFERENCES parent(col_d_ui_del) ON UPDATE CASCADE ON DELETE CASCADE) " + "ENGINE = NDB") + + # should return error + cur.execute("CREATE TABLE child (" + "col_a INT, " + "col_t TIMESTAMP, " + "col_b_ui INT, " + "col_c_ui_upd INT, " + "col_d_ui_del INT, " + "PRIMARY KEY(col_a), " + "FOREIGN KEY(col_b_ui) REFERENCES parentttl(col_b_ui) ON UPDATE CASCADE ON DELETE CASCADE, " + "FOREIGN KEY(col_c_ui_upd) REFERENCES parentttl(col_c_ui_upd) ON UPDATE CASCADE ON DELETE CASCADE, " + "FOREIGN KEY(col_d_ui_del) REFERENCES parentttl(col_d_ui_del) ON UPDATE CASCADE ON DELETE CASCADE) " + "ENGINE = NDB") + assert 0 except Exception as e: - print(f"PRE Create DB/TABLE failed: {e}") - A_conn.close() - B_conn.close() - exit (-1) + if e.args[0] != 1215: + print(f"PRE Create DB/TABLE failed: {e}") + A_conn.close() + B_conn.close() + exit (-1) -def case_46_thdA(conn): +def case_56_thdA(conn): global A_succ try: cur = conn.cursor() - cur.execute("USE test") - cur.execute("BEGIN") - cur.execute("INSERT INTO sz1 VALUES(1, SYSDATE(), 100)") - cur.execute("INSERT INTO sz1 VALUES(2, SYSDATE(), 200)") - cur.execute("INSERT INTO sz1 VALUES(3, DATE_ADD(SYSDATE(), INTERVAL 1 DAY), 300)") - cur.execute("INSERT INTO sz1 VALUES(4, SYSDATE(), 400)") - cur.execute("INSERT INTO sz2 VALUES(1, SYSDATE(), 100)") - cur.execute("INSERT INTO sz2 VALUES(2, SYSDATE(), 200)") - cur.execute("INSERT INTO sz2 VALUES(3, DATE_ADD(SYSDATE(), INTERVAL 1 DAY), 300)") - cur.execute("INSERT INTO sz2 VALUES(4, SYSDATE(), 400)") - cur.execute("INSERT INTO sz3 VALUES(1, SYSDATE(), 100)") - cur.execute("INSERT INTO sz3 VALUES(2, SYSDATE(), 200)") - cur.execute("INSERT INTO sz3 VALUES(3, DATE_ADD(SYSDATE(), INTERVAL 1 DAY), 300)") - cur.execute("INSERT INTO sz3 VALUES(4, SYSDATE(), 400)") - cur.execute("COMMIT") - cur.execute("SELECT * FROM sz1") - results = cur.fetchall() - assert len(results) == 4, "ASSERT" - cur.execute("SELECT * FROM sz2") - results = cur.fetchall() - assert len(results) == 4, "ASSERT" - cur.execute("SELECT * FROM sz3") - results = cur.fetchall() - assert len(results) == 4, "ASSERT" - time.sleep(11) + cur.execute("ALTER TABLE sz1 " + "ADD FOREIGN KEY(col_b_ui) REFERENCES parentttl(col_b_ui) ON UPDATE CASCADE ON DELETE CASCADE, " + "ADD FOREIGN KEY(col_c_ui_upd) REFERENCES parentttl(col_c_ui_upd) ON UPDATE CASCADE ON DELETE CASCADE, " + "ADD FOREIGN KEY(col_d_ui_del) REFERENCES parentttl(col_d_ui_del) ON UPDATE CASCADE ON DELETE CASCADE") + assert 0 + except Exception as e: + if e.args[0] != 1215: + print(f"Thd A failed: {e}") + cur.close() + return - cur.execute("SELECT * FROM sz1") - results = cur.fetchall() - assert len(results) == 1, "ASSERT" - for row in results: - col_c = row[2] - assert col_c == 300, "ASSERT" - cur.execute("SELECT * FROM sz2") - results = cur.fetchall() - assert len(results) == 1, "ASSERT" - for row in results: - col_c = row[2] - assert col_c == 300, "ASSERT" - cur.execute("SELECT * FROM sz3") - results = cur.fetchall() - assert len(results) == 4, "ASSERT" - subprocess.run([BIN_DIR+"/ndb_mgm", "-e", "start backup"], - stdout=subprocess.PIPE, stderr=subprocess.PIPE) + try: + cur.execute("ALTER TABLE parent COMMENT=\"NDB_TABLE=TTL=10@col_t\"") + assert 0 except Exception as e: - print(f"Thd A failed: {e}") - cur.close() - return + if e.args[0] != 1846: + print(f"Thd A failed: {e}") + cur.close() + return + + try: + cur.execute("ALTER TABLE sz2 COMMENT=\"NDB_TABLE=TTL=10@col_t\"") + assert 0 + except Exception as e: + if e.args[0] != 1846: + print(f"Thd A failed: {e}") + cur.close() + return + + try: + cur.execute("CREATE TABLE child (" + "col_a INT, " + "col_t TIMESTAMP, " + "col_b_ui INT, " + "col_c_ui_upd INT, " + "col_d_ui_del INT, " + "PRIMARY KEY(col_a), " + "FOREIGN KEY(col_b_ui) REFERENCES parent(col_b_ui) ON UPDATE CASCADE ON DELETE CASCADE, " + "FOREIGN KEY(col_c_ui_upd) REFERENCES parent(col_c_ui_upd) ON UPDATE CASCADE ON DELETE CASCADE, " + "FOREIGN KEY(col_d_ui_del) REFERENCES parent(col_d_ui_del) ON UPDATE CASCADE ON DELETE CASCADE) " + "ENGINE = NDB, " + "comment=\"NDB_TABLE=TTL=10@col_t\"") + assert 0 + except Exception as e: + if e.args[0] != 1215: + print(f"Thd A failed: {e}") + cur.close() + return + + try: + cur.execute("CREATE TABLE child (" + "col_a INT, " + "col_t TIMESTAMP, " + "col_b_ui INT, " + "col_c_ui_upd INT, " + "col_d_ui_del INT, " + "PRIMARY KEY(col_a), " + "FOREIGN KEY(col_b_ui) REFERENCES parentttl(col_b_ui) ON UPDATE CASCADE ON DELETE CASCADE, " + "FOREIGN KEY(col_c_ui_upd) REFERENCES parentttl(col_c_ui_upd) ON UPDATE CASCADE ON DELETE CASCADE, " + "FOREIGN KEY(col_d_ui_del) REFERENCES parentttl(col_d_ui_del) ON UPDATE CASCADE ON DELETE CASCADE) " + "ENGINE = NDB, " + "comment=\"NDB_TABLE=TTL=10@col_t\"") + assert 0 + except Exception as e: + if e.args[0] != 1215: + print(f"Thd A failed: {e}") + cur.close() + cur.close() A_succ = True -def case_46_thdB(conn): +def case_56_thdB(conn): global B_succ - time.sleep(17) - subprocess.run([BIN_DIR+"/ndb_restore", - "--ndb-connectstring=127.0.0.1:"+str(MGMD_PORT_R), - "--nodeid=2", "--backupid=1", - "--backup-path="+DATA_DIR_P_1+"/ndb_data/BACKUP/BACKUP-1", - "--restore_meta", "--no-restore-disk-objects"], - stdout=subprocess.PIPE, stderr=subprocess.PIPE) - subprocess.run([BIN_DIR+"/ndb_restore", - "--ndb-connectstring=127.0.0.1:"+str(MGMD_PORT_R), - "--nodeid=2", "--backupid=1", - "--backup-path="+DATA_DIR_P_1+"/ndb_data/BACKUP/BACKUP-1", - "--restore-data"], - stdout=subprocess.PIPE, stderr=subprocess.PIPE) - subprocess.run([BIN_DIR+"/ndb_restore", - "--ndb-connectstring=127.0.0.1:"+str(MGMD_PORT_R), - "--nodeid=3", "--backupid=1", - "--backup-path="+DATA_DIR_P_2+"/ndb_data/BACKUP/BACKUP-1", - "--restore-data"], - stdout=subprocess.PIPE, stderr=subprocess.PIPE) - time.sleep(10) - while True: - try: - new_conn = pymysql.connect(host='127.0.0.1', - port=MYSQLD_PORT_R, - user='root') - cur = new_conn.cursor() - cur.execute("USE test") - cur.execute("SELECT * FROM sz1") - results = cur.fetchall() - assert len(results) == 1, "ASSERT" - for row in results: - col_c = row[2] - assert col_c == 300, "ASSERT" - cur.execute("SELECT * FROM sz2") - results = cur.fetchall() - assert len(results) == 1, "ASSERT" - for row in results: - col_c = row[2] - assert col_c == 300, "ASSERT" - cur.execute("SELECT * FROM sz3") - results = cur.fetchall() - assert len(results) == 4, "ASSERT" - break - except pymysql.MySQLError as e: - errno = e.args[0] - if errno in [1412, 1049]: - #1412 - Table definition has changed, please retry transaction - #1049 - Unknown database 'test' - print(f"Waiting for synchronizing restored schema...Retry {e}") - time.sleep(10) - cur.close() - new_conn.close() - continue - else: - print(f"Thd B failed: {e}") - cur.close() - new_conn.close() - return - except Exception as e: - print(f"Thd B failed: {e}") - cur.close() - new_conn.close() - return + try: + cur = conn.cursor() + except Exception as e: + print(f"Thd B failed: {e}") + cur.close() + return cur.close() - new_conn.close() B_succ = True -def case_46_post(A_conn, B_conn): +def case_56_post(A_conn, B_conn): try: cur = A_conn.cursor() - #cur.execute("DROP TABLE IF EXISTS sz1") - #cur.execute("DROP TABLE IF EXISTS sz2") - #cur.execute("DROP TABLE IF EXISTS sz3") + cur.execute("DROP TABLE IF EXISTS sz1") + cur.execute("DROP TABLE IF EXISTS sz2") + cur.execute("DROP TABLE IF EXISTS child") + cur.execute("DROP TABLE IF EXISTS parent") + cur.execute("DROP TABLE IF EXISTS parentttl") except Exception as e: print(f"POST Drop DB/TABLE failed: {e}") A_conn.close() @@ -3085,9 +4517,9 @@ def case(num): B_succ = False cases_require_debug_sync = [23, 24, 25] - cases_binlog = [36, 37, 38, 39, 40, 41, 42, 43, 44] + cases_binlog = [36, 37, 38, 39, 40, 41, 42, 43, 44, 47, 50, 51, 52, 53, 54, 55] cases_backup_restore = [46] - cases_need_extra_process = [29, 40, 42, 44, 46] + cases_need_extra_process = [28, 29, 40, 42, 44, 46, 49, 50, 51, 52, 53, 54, 55, 56] # 1. Connect @@ -3199,7 +4631,7 @@ def case(num): MGMD_PORT_R = getattr(my_config, 'MGMD_PORT_R', MGMD_PORT_R) MYSQLD_PORT_R = getattr(my_config, 'MYSQLD_PORT_R', MYSQLD_PORT_R) - case_num = 46 + case_num = 56 # 1. create database and table try: conn = pymysql.connect(host='127.0.0.1', @@ -3216,7 +4648,8 @@ def case(num): "col_a INT, " "col_b TIMESTAMP, " "col_c INT, " - "PRIMARY KEY(col_a)) " + "PRIMARY KEY(col_a), " + "UNIQUE KEY(col_c))" "ENGINE = NDB, " "COMMENT=\"NDB_TABLE=TTL=66@col_b\"") time.sleep(5) @@ -3269,13 +4702,17 @@ def case(num): case(23) case(25) - ##case(26) + #case(26) case(24) #READ LOCKED case(28) + case(48) # UNIQUE INDEX case(29) # FULLY_REPLICATED - case(45) + #case(49) # FULLY_REPLICATED, UNIQUE INDEX + # NOTICE seems unique index can not work with binlog replication, + # which will cause the replica mysql Stuck while applying the DROP TABLE operation + #case(45) #REPLACE INTO case(30) @@ -3297,5 +4734,19 @@ def case(num): case(44) case(45) - ##BACKUP RESTORE + #Unique index and trigger + case(47) + case(50) + case(53) + + #Disk column + case(51) + case(52) + + #Foreign key + #case(54) #Can only run this case after supporting use a TTL table as the parent table + #case(55) #Can only run this case after supporting use a TTL table as the child table + case(56) + + #BACKUP RESTORE case(46) diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 90c587fe46c..f5e1f881a8f 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -17611,6 +17611,11 @@ bool mysql_alter_table(THD *thd, const char *new_db, const char *new_name, goto end_inplace_noop; } + if (old_table_def && + (!old_table_def->foreign_key_parents().empty() || + !old_table_def->foreign_keys().empty())) { + table->file->ha_extra(HA_EXTRA_FK_TTL); + } // Ask storage engine whether to use copy or in-place enum_alter_inplace_result inplace_supported = table->file->check_if_supported_inplace_alter(altered_table, diff --git a/storage/ndb/plugin/ha_ndb_ddl_fk.cc b/storage/ndb/plugin/ha_ndb_ddl_fk.cc index f28992fb5ae..2ea01fcc423 100644 --- a/storage/ndb/plugin/ha_ndb_ddl_fk.cc +++ b/storage/ndb/plugin/ha_ndb_ddl_fk.cc @@ -1381,6 +1381,14 @@ int ha_ndbcluster::create_fks(THD *thd, Ndb *ndb, const char *dbname, } } + if (parent_tab.get_table()->isTTLEnabled() || + child_tab.get_table()->isTTLEnabled()) { + push_warning_printf(thd, Sql_condition::SL_WARNING, + ER_CANNOT_ADD_FOREIGN, + "Can not use foreign key on TTL table"); + return err_default; + } + const NDBCOL *parentcols[NDB_MAX_ATTRIBUTES_IN_INDEX + 1]; { unsigned pos = 0; diff --git a/storage/ndb/plugin/ha_ndbcluster.cc b/storage/ndb/plugin/ha_ndbcluster.cc index 509b27dbd4a..7cfe2b55e51 100644 --- a/storage/ndb/plugin/ha_ndbcluster.cc +++ b/storage/ndb/plugin/ha_ndbcluster.cc @@ -7163,6 +7163,11 @@ int ha_ndbcluster::extra(enum ha_extra_function operation) { DBUG_PRINT("info", ("Don't ignore TTL")); m_ttl_ignore = false; break; + case HA_EXTRA_FK_TTL: + DBUG_PRINT("info", ("HA_EXTRA_FK_TTL")); + DBUG_PRINT("info", ("Table has FK")); + m_ttl_fk = true; + break; default: break; } @@ -11677,7 +11682,7 @@ ha_ndbcluster::ha_ndbcluster(handlerton *hton, TABLE_SHARE *table_arg) m_pushed_operation(nullptr), m_cond(this), m_multi_cursor(nullptr), - m_ttl_ignore(false) { + m_ttl_ignore(false), m_ttl_fk(false) { DBUG_TRACE; stats.records = ~(ha_rows)0; // uninitialized @@ -16196,6 +16201,12 @@ enum_alter_inplace_result ha_ndbcluster::check_inplace_alter_supported( &unsupported_reason, max_rows_changed)) { return inplace_unsupported(ha_alter_info, unsupported_reason); } + if (new_tab.isTTLEnabled() && m_ttl_fk) { + ha_alter_info->unsupported_reason = "Table has fk restrictions, can not add TTL"; + ha_alter_info->report_unsupported_error("Adding TTL on table which has fk restrictions", + "drop the foreign keys from all the children tables"); + return HA_ALTER_ERROR; + } } if (max_rows_changed) { @@ -16404,6 +16415,7 @@ bool ha_ndbcluster::inplace_parse_comment(NdbDictionary::Table *new_tab, ndb_log_info("[API]parse TTL successfully: TTL = %u sec, " "TTL_COLUMN = %s", new_ttl_sec, ttl_column.c_str()); + // Zart ttl_col->getAttrId() here is always RNIL. new_ttl_column_no = ttl_col->getColumnNo(); int ttl_column_id = ttl_col->getAttrId(); diff --git a/storage/ndb/plugin/ha_ndbcluster.h b/storage/ndb/plugin/ha_ndbcluster.h index 5ce49416225..fc49ca467fc 100644 --- a/storage/ndb/plugin/ha_ndbcluster.h +++ b/storage/ndb/plugin/ha_ndbcluster.h @@ -743,6 +743,7 @@ class ha_ndbcluster : public handler, public Partition_handler { * TTL */ bool m_ttl_ignore; + bool m_ttl_fk; }; bool is_cluster_failure_code(int error); diff --git a/storage/ndb/src/kernel/blocks/dbacc/DbaccMain.cpp b/storage/ndb/src/kernel/blocks/dbacc/DbaccMain.cpp index ddd437a7772..1fc78283f77 100644 --- a/storage/ndb/src/kernel/blocks/dbacc/DbaccMain.cpp +++ b/storage/ndb/src/kernel/blocks/dbacc/DbaccMain.cpp @@ -1520,7 +1520,9 @@ void Dbacc::execACCKEYREQ(Signal *signal, Uint32 opPtrI, fragrecptr.p->lockCount[hash]++; #ifdef TTL_DEBUG if (NEED_PRINT(fragrecptr.p->myTableId)) { - g_eventLogger->info("Zart, Dbacc::execACCKEYREQ(), lock, table id: %u, frag id: %u", + g_eventLogger->info("Zart, Dbacc::execACCKEYREQ(), lock, " + "op: %u table id: %u, frag id: %u", + op, fragrecptr.p->myTableId, fragrecptr.p->fragmentid); } #endif // TTL_DEBUG diff --git a/storage/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp b/storage/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp index 3e805f44f24..cf12e636f9a 100644 --- a/storage/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp +++ b/storage/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp @@ -4579,8 +4579,16 @@ bool Dblqh::is_ttl_table(Uint32 table_id) { TablerecPtr t_tabptr; t_tabptr.i = table_id; ptrCheckGuard(t_tabptr, ctabrecFileSize, tablerec); - return (t_tabptr.p->m_ttl_sec != RNIL && - t_tabptr.p->m_ttl_col_no != RNIL); + if (t_tabptr.p->primaryTableId != table_id) { + TablerecPtr t_primary_tabptr; + t_primary_tabptr.i = t_tabptr.p->primaryTableId; + ptrCheckGuard(t_primary_tabptr, ctabrecFileSize, tablerec); + return (t_primary_tabptr.p->m_ttl_sec != RNIL && + t_primary_tabptr.p->m_ttl_col_no != RNIL); + } else { + return (t_tabptr.p->m_ttl_sec != RNIL && + t_tabptr.p->m_ttl_col_no != RNIL); + } } void Dblqh::release_frag_array(Tablerec *tabPtrP) diff --git a/storage/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp b/storage/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp index d459c84a536..4a7c18343dc 100644 --- a/storage/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp +++ b/storage/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp @@ -23418,6 +23418,7 @@ void Dbtc::fk_scanFromChildTable(Signal *signal, ScanTabReq::setViaSPJFlag(ri, 0); ScanTabReq::setPassAllConfsFlag(ri, 0); ScanTabReq::setExtendedConf(ri, 0); + // TODO(Zhao) Ignore TTL in some situations maybe? req->requestInfo = ri; req->transId1 = regApiPtr->transid[0]; req->transId2 = regApiPtr->transid[1]; diff --git a/storage/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp b/storage/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp index 1c4d2e69291..f50b4d49cac 100644 --- a/storage/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp +++ b/storage/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp @@ -1903,7 +1903,33 @@ bool Dbtup::execTUPKEYREQ(Signal* signal, * normal update operation. */ // TODO(Zhao): double check this solution - regOperPtr->op_type = ZUPDATE; + // regOperPtr->op_type = ZUPDATE; + /* + * Update this TODO note. Since I added special handling logic for TTL + * in the unique index (which is an extra internal table) of a TTL table: + * + * If its primary table is a TTL table, then in `exec_acckeyreq()`, + * it will be treated as a TTL table even if there is no TTL information + * on this extra table. Therefore, we don't need to convert `ZINSERT_TTL` + * to `ZUPDATE` here. + * + * Let's keep it as is for now and observe. + * + * Update: if we don't convert it to ZUPDATE here, the foreign key trigger + * will encounter an issue: + * 1. CREATE parent table which has TTL + * 2. CREATE child table which has foreign key references to the parent table + * 3. Insert a row into the parent table and insert the related row into the + * child table + * 4. Wait for the row in the parent table expires and then insert the row + * with the same primary key but different unique index key column + * THEN we can get an error from the inserting caused by using TTL table + * as the parent table. But we disable adding foreign key references to + * a TTL table currently, so it won't happen. + * TODO(Zhao) + * However this issue requests fixing when we support this foreign key feature + * in the future. + */ /** * The lock on the TUP fragment is required to update header info on * the base row, thus we use the variable m_base_header_bits in @@ -2436,7 +2462,13 @@ int Dbtup::handleReadReq( reinterpret_cast(req_struct->scan_rec); if (!scan_rec_ptr->scanLockMode /* X */ && !scan_rec_ptr->scanLockHold /* S */) { - ndbrequire(scan_rec_ptr->readCommitted); + /* + * NOTICE: + * Dbtc::fk_scanFromChildTable will break this assumption. + * Something seems wrong when constructing the scan request + * flag there. + */ + // ndbrequire(scan_rec_ptr->readCommitted); if (scan_rec_ptr->scanBlock == this) { PrepareAccLockReq4RAL(req_struct->scan_rec, signal); } else { @@ -2641,6 +2673,12 @@ int Dbtup::handleUpdateReq(Signal* signal, return -1; } } +#ifdef TTL_DEBUG + if (operPtrP->op_type == ZINSERT_TTL && !is_ttl_table(regTabPtr)) { + g_eventLogger->info("Zart, (UPDATE) ZINSERT_TTL on an duplicated " + "expired row on non-primary table"); + } +#endif // TTL_DEBUG Tuple_header *dst; Tuple_header *base= req_struct->m_tuple_ptr, *org; ChangeMask * change_mask_ptr; @@ -3858,6 +3896,12 @@ int Dbtup::handleDeleteReq(Signal* signal, } } +#ifdef TTL_DEBUG + if (!is_ttl_table(regTabPtr)) { + g_eventLogger->info("Zart, (DELETE) delete a row on non-primary table %u", + req_struct->fragPtrP->fragTableId); + } +#endif // TTL_DEBUG Uint32 copy_bits = 0; Tuple_header* dst = alloc_copy_tuple(regTabPtr, ®OperPtr->m_copy_tuple_location); diff --git a/storage/ndb/src/kernel/blocks/dbtux/DbtuxScan.cpp b/storage/ndb/src/kernel/blocks/dbtux/DbtuxScan.cpp index b7c411b4fad..8a8e8bc7c93 100644 --- a/storage/ndb/src/kernel/blocks/dbtux/DbtuxScan.cpp +++ b/storage/ndb/src/kernel/blocks/dbtux/DbtuxScan.cpp @@ -709,7 +709,13 @@ void Dbtux::PrepareAccLockReq4RAL(void* scan_rec_ptr, ndbrequire(c_scanOpPool.getValidPtr(scan_op_PTR)); ScanOp* scan_op = scan_op_PTR.p; ndbrequire(scan_op == c_ctx.scanPtr.p); - ndbrequire(scan_op->m_readCommitted); + /* + * NOTICE: + * Dbtc::fk_scanFromChildTable will break this assumption + * Something seems wrong in constructing scan request flag + * there in previous implementation. + */ + // ndbrequire(scan_op->m_readCommitted); #ifdef TTL_DEBUG g_eventLogger->info("Zart, Dbtux::PrepareAccLockReq4RAL, " "ScanOp::m_tableId: %u, scanAccPtr: %u", diff --git a/storage/ndb/src/kernel/blocks/suma/Suma.cpp b/storage/ndb/src/kernel/blocks/suma/Suma.cpp index 1a80d71507a..4041c42e4b6 100644 --- a/storage/ndb/src/kernel/blocks/suma/Suma.cpp +++ b/storage/ndb/src/kernel/blocks/suma/Suma.cpp @@ -3207,6 +3207,13 @@ void Suma::SyncRecord::nextScan(Signal *signal) { ScanFragReq::setStatScanFlag(req->requestInfo, 1); } + /* + * Zart + * TTL + * Ignore TTL in suma scan + */ + ScanFragReq::setTTLIgnoreFragFlag(req->requestInfo, 1); + req->fragmentNoKeyLen = fd.m_fragDesc.m_fragmentNo; req->schemaVersion = tabPtr.p->m_schemaVersion; req->transId1 = 0;