Add engine tests for nonlocal tables

This commit is contained in:
Nick Tobey
2025-10-28 13:56:55 -07:00
parent 3ca970a4c5
commit ba3fbd0fc5
4 changed files with 255 additions and 86 deletions

View File

@@ -1635,6 +1635,16 @@ func TestDiffSystemTablePrepared(t *testing.T) {
RunDoltDiffSystemTableTestsPrepared(t, h)
}
func TestNonlocalTable(t *testing.T) {
h := newDoltEnginetestHarness(t)
RunNonlocalTableTests(t, h)
}
func TestNonlocalTablePrepared(t *testing.T) {
h := newDoltEnginetestHarness(t)
RunNonlocalTableTestsPrepared(t, h)
}
func TestSchemaDiffTableFunction(t *testing.T) {
harness := newDoltEnginetestHarness(t)
RunSchemaDiffTableFunctionTests(t, harness)

View File

@@ -1421,6 +1421,36 @@ func RunDoltDiffSystemTableTestsPrepared(t *testing.T, h DoltEnginetestHarness)
}
}
func RunNonlocalTableTests(t *testing.T, h DoltEnginetestHarness) {
if !types.IsFormat_DOLT(types.Format_Default) {
t.Skip("only new format support system table indexing")
}
for _, test := range NonlocalScripts {
t.Run(test.Name, func(t *testing.T) {
h = h.NewHarness(t)
defer h.Close()
h.Setup(setup.MydbData)
enginetest.TestScript(t, h, test)
})
}
}
func RunNonlocalTableTestsPrepared(t *testing.T, h DoltEnginetestHarness) {
if !types.IsFormat_DOLT(types.Format_Default) {
t.Skip("only new format support system table indexing")
}
for _, test := range NonlocalScripts {
t.Run(test.Name, func(t *testing.T) {
h = h.NewHarness(t)
defer h.Close()
h.Setup(setup.MydbData)
enginetest.TestScriptPrepared(t, h, test)
})
}
}
func RunSchemaDiffTableFunctionTests(t *testing.T, harness DoltEnginetestHarness) {
for _, test := range SchemaDiffTableFunctionScriptTests {
t.Run(test.Name, func(t *testing.T) {

View File

@@ -0,0 +1,186 @@
// Copyright 2022 Dolthub, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package enginetest
import (
"github.com/dolthub/go-mysql-server/enginetest"
"github.com/dolthub/go-mysql-server/enginetest/queries"
"github.com/dolthub/go-mysql-server/sql"
)
var _ enginetest.CustomValueValidator = &doltCommitValidator{}
var NonlocalScripts = []queries.ScriptTest{
{
Name: "basic nonlocal tables use case",
SetUpScript: []string{
"CALL DOLT_BRANCH('other')",
"CREATE TABLE aliased_table (pk char(8) PRIMARY KEY);",
"INSERT INTO aliased_table VALUES ('amzmapqt');",
"CALL dolt_checkout('other');",
`INSERT INTO dolt_nonlocal_tables(table_name, target_ref, ref_table, options) VALUES
('nonlocal_table', 'main', 'aliased_table', 'immediate')`,
`INSERT INTO nonlocal_table VALUES ('eesekkgo');`,
`CREATE TABLE local_table (pk char(8) PRIMARY KEY, FOREIGN KEY (pk) REFERENCES nonlocal_table(pk));`,
},
Assertions: []queries.ScriptTestAssertion{
{
Query: "select * from nonlocal_table;",
Expected: []sql.Row{{"amzmapqt"}, {"eesekkgo"}},
},
{
Query: "select * from `mydb/main`.aliased_table;",
Expected: []sql.Row{{"amzmapqt"}, {"eesekkgo"}},
},
{
Query: "show create table nonlocal_table;",
Expected: []sql.Row{{"aliased_table", "CREATE TABLE `aliased_table` (\n `pk` char(8) NOT NULL,\n PRIMARY KEY (`pk`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin"}},
},
{
Query: "show create table local_table;",
Expected: []sql.Row{{"local_table", "CREATE TABLE `local_table` (\n `pk` char(8) NOT NULL,\n PRIMARY KEY (`pk`),\n CONSTRAINT `local_table_ibfk_1` FOREIGN KEY (`pk`) REFERENCES `nonlocal_table` (`pk`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin"}},
},
{
Query: `INSERT INTO local_table VALUES ("amzmapqt");`,
ExpectedErr: nil,
},
{
Query: `INSERT INTO local_table VALUES ("fdnfjfjf");`,
ExpectedErrStr: "cannot add or update a child row - Foreign key violation on fk: `local_table_ibfk_1`, table: `local_table`, referenced table: `nonlocal_table`, key: `[fdnfjfjf]`",
},
{
Query: `CALL DOLT_VERIFY_CONSTRAINTS('--all');`,
Expected: []sql.Row{{0}},
},
},
},
{
Name: "detect foreign key invalidation is detected when rows are removed",
SetUpScript: []string{
"CALL DOLT_BRANCH('other')",
"CREATE TABLE aliased_table (pk char(8) PRIMARY KEY);",
"INSERT INTO aliased_table VALUES ('amzmapqt');",
"CALL dolt_checkout('other');",
`INSERT INTO dolt_nonlocal_tables(table_name, target_ref, ref_table, options) VALUES
('nonlocal_table', 'main', 'aliased_table', 'immediate')`,
`CREATE TABLE local_table (pk char(8) PRIMARY KEY, FOREIGN KEY (pk) REFERENCES nonlocal_table(pk));`,
"INSERT INTO local_table VALUES ('amzmapqt');",
"DELETE FROM `mydb/main`.aliased_table;",
"set @@dolt_force_transaction_commit=1",
},
Assertions: []queries.ScriptTestAssertion{
{
Query: "CALL DOLT_VERIFY_CONSTRAINTS('--all');",
Expected: []sql.Row{{1}},
},
{
Query: "SELECT violation_type FROM dolt_constraint_violations_local_table",
Expected: []sql.Row{{"foreign key"}},
},
{
// Check that neither command removed the FK relation (this can happen if it thinks the child table was dropped)
Query: "SHOW CREATE TABLE local_table;",
Expected: []sql.Row{{"local_table", "CREATE TABLE `local_table` (\n `pk` char(8) NOT NULL,\n PRIMARY KEY (`pk`),\n CONSTRAINT `local_table_ibfk_1` FOREIGN KEY (`pk`) REFERENCES `nonlocal_table` (`pk`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin"}},
},
},
},
{
Name: "detect foreign key invalidation is detected when the nonlocal table is dropped",
// DOLT_VERIFY_CONSTRAINTS detects constraint violations by attempting a merge against HEAD.
// The current behavior for merges is to delete FK constraints if a table doesn't exist after the merge.
// This is a bug with DOLT_VERIFY_CONSTRAINTS, not with nonlocal_tables. As a workaround,
// the `dolt constraints verify` CLI command can detect these violations, which we confirm via nonlocal.bats
Skip: true,
SetUpScript: []string{
"CREATE DATABASE IF NOT EXISTS mydb",
"USE mydb",
"CALL DOLT_BRANCH('other')",
"CREATE TABLE aliased_table (pk char(8) PRIMARY KEY);",
"INSERT INTO aliased_table VALUES ('amzmapqt');",
"CALL dolt_checkout('other');",
`INSERT INTO dolt_nonlocal_tables(table_name, target_ref, ref_table, options) VALUES
('nonlocal_table', 'main', 'aliased_table', 'immediate')`,
`CREATE TABLE local_table (pk char(8) PRIMARY KEY, FOREIGN KEY (pk) REFERENCES nonlocal_table(pk));`,
"INSERT INTO local_table VALUES ('amzmapqt');",
"DROP TABLE `mydb/main`.aliased_table;",
"set @@dolt_force_transaction_commit=1",
},
Assertions: []queries.ScriptTestAssertion{
{
Query: "CALL DOLT_VERIFY_CONSTRAINTS('--all');",
Expected: []sql.Row{{1}},
},
{
Query: "SELECT violation_type FROM dolt_constraint_violations_local_table",
Expected: []sql.Row{{"foreign key"}},
},
{
// Check that neither command removed the FK relation (this can happen if it thinks the child table was dropped)
Query: "SHOW CREATE TABLE local_table;",
Expected: []sql.Row{{"local_table", "CREATE TABLE `local_table` (\n `pk` char(8) NOT NULL,\n PRIMARY KEY (`pk`),\n CONSTRAINT `local_table_ibfk_1` FOREIGN KEY (`pk`) REFERENCES `nonlocal_table` (`pk`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin"}},
},
},
},
{
Name: "creating a table matching a nonlocal table rule results in an error",
SetUpScript: []string{
"CALL DOLT_BRANCH('other')",
`INSERT INTO dolt_nonlocal_tables(table_name, target_ref, options) VALUES
("nonlocal_table", "main", "immediate")`,
},
Assertions: []queries.ScriptTestAssertion{
{
Query: "CREATE TABLE nonlocal_table (pk char(8) PRIMARY KEY);",
ExpectedErrStr: "Cannot create table name nonlocal_table because it matches a name present in dolt_nonlocal_tables.",
},
},
},
{
Name: "nonlocal tables appear in 'show tables'",
SetUpScript: []string{
"CALL DOLT_BRANCH('other')",
"CREATE TABLE aliased_table (pk char(8) PRIMARY KEY);",
"CREATE TABLE table_alias_1 (pk char(8) PRIMARY KEY);",
"CREATE TABLE table_alias_wild_3 (pk char(8) PRIMARY KEY);",
"INSERT INTO aliased_table VALUES ('amzmapqt');",
"CALL dolt_checkout('other');",
`INSERT INTO dolt_nonlocal_tables(table_name, target_ref, ref_table, options) VALUES
("table_alias_1", "main", "", "immediate"),
("table_alias_2", "main", "aliased_table", "immediate"),
("table_alias_wild_*", "main", "", "immediate"),
("table_alias_missing", "main", "", "immediate");`,
},
Assertions: []queries.ScriptTestAssertion{
{
Query: "show tables",
Expected: []sql.Row{{"table_alias_1"}, {"table_alias_2"}, {"table_alias_wild_3"}},
},
},
},
{
Name: "detect invalid options",
SetUpScript: []string{
"CALL dolt_checkout('-b', 'other');",
`INSERT INTO dolt_nonlocal_tables(table_name, target_ref, options) VALUES
("nonlocal_table", "main", "invalid");`,
},
Assertions: []queries.ScriptTestAssertion{
{
Query: "select * from nonlocal_table;",
ExpectedErrStr: "Invalid nonlocal table options invalid: only valid value is 'immediate'.",
},
},
},
}

View File

@@ -10,28 +10,6 @@ teardown() {
teardown_common
}
@test "nonlocal: basic case" {
dolt checkout -b other
dolt sql <<SQL
CALL dolt_checkout('main');
CREATE TABLE aliased_table (pk char(8) PRIMARY KEY);
INSERT INTO aliased_table VALUES ("amzmapqt");
CALL dolt_checkout('other');
INSERT INTO dolt_nonlocal_tables(table_name, target_ref, ref_table, options) VALUES
("table_alias_branch", "main", "aliased_table", "immediate");
SQL
run dolt sql -q "select * from table_alias_branch;"
[ "$status" -eq 0 ]
[[ "$output" =~ "amzmapqt" ]] || false
# Nonlocal tables appear in "show create", but the output matches the aliased table.
run dolt sql -q "show create table table_alias_branch"
[ "$status" -eq 0 ]
[[ "$output" =~ "aliased_table" ]] || false
}
@test "nonlocal: branch name reflects the working set of the referenced branch" {
dolt checkout -b other
dolt sql <<SQL
@@ -261,16 +239,38 @@ SQL
[[ "$output" =~ 'dolt_constraint_violations_local_table' ]] || false
[[ "$output" =~ '| foreign key | eesekkgo | {"Index": "", "Table": "local_table", "Columns": ["pk"], "OnDelete": "RESTRICT", "OnUpdate": "RESTRICT", "ForeignKey": "local_table_ibfk_1", "ReferencedIndex": "", "ReferencedTable": "nonlocal_table", "ReferencedColumns": ["pk"]} |' ]] || false
run dolt sql -q "CALL DOLT_VERIFY_CONSTRAINTS('--all');"
[ "$status" -eq 1 ]
[[ "$output" =~ 'ForeignKey: local_table_ibfk_1' ]] || false
# Check that neither command removed the FK relation (this can happen if it thinks the child table was dropped)
# Check that verifying didn't remove the FK relation (this can happen if it thinks the child table was dropped)
run dolt sql -q 'SHOW CREATE TABLE local_table;'
[ "$status" -eq 0 ]
[[ "$output" =~ 'local_table_ibfk_1' ]] || false
}
@test "nonlocal: detect foreign key violations when rows are deleted from the nonlocal table" {
dolt checkout -b other
dolt sql <<SQL
CALL DOLT_CHECKOUT('main');
CREATE TABLE aliased_table (pk char(8) PRIMARY KEY);
SQL
dolt sql <<SQL
INSERT INTO dolt_nonlocal_tables(table_name, target_ref, ref_table, options) VALUES
("nonlocal_table", "main", "aliased_table", "immediate");
INSERT INTO nonlocal_table VALUES ("eesekkgo");
CREATE TABLE local_table (pk char(8) PRIMARY KEY, FOREIGN KEY (pk) REFERENCES nonlocal_table(pk));
SQL
dolt sql -q 'INSERT INTO local_table VALUES ("eesekkgo");'
run dolt sql -q 'INSERT INTO local_table VALUES ("fdnfjfjf");'
[ "$status" -eq 1 ]
[[ "$output" =~ 'Foreign key violation on fk: `local_table_ibfk_1`, table: `local_table`, referenced table: `nonlocal_table`, key: `[fdnfjfjf]`' ]] || false
# The current foreign keys hold, so they should validate
dolt constraints verify
# It's possible for foreign keys on nonlocal tables to become invalidated due to changes on the nonlocal
# branch, but this can be detected with dolt constraints verify
# Now try deleting the parent table and confirm that verifies correctly too.
dolt sql -q 'CALL DOLT_CHECKOUT("main"); DROP TABLE aliased_table;'
# dolt sql -q "CALL DOLT_VERIFY_CONSTRAINTS('--all')"
@@ -279,11 +279,6 @@ SQL
echo "$output"
[[ "$output" =~ 'table not found' ]] || false
run dolt sql -q "CALL DOLT_VERIFY_CONSTRAINTS('--all');"
[ "$status" -eq 1 ]
echo "$output"
[[ "$output" =~ 'ForeignKey: local_table_ibfk_1' ]] || false
# Check that neither command removed the FK relation (this can happen if it thinks the child table was dropped)
run dolt sql -q 'SHOW CREATE TABLE local_table;'
[ "$status" -eq 0 ]
@@ -357,58 +352,6 @@ SQL
[[ "$output" =~ "nonlocal_table | true" ]] || false
}
@test "nonlocal: invalid options detected" {
dolt sql <<SQL
INSERT INTO dolt_nonlocal_tables(table_name, target_ref, options) VALUES
("nonlocal_table", "main", "invalid");
SQL
run dolt sql -q "select * from nonlocal_table;"
[ "$status" -eq 1 ]
echo "$output"
[[ "$output" =~ "Invalid nonlocal table options" ]] || false
}
# The below tests are convenience features but not necessary for the MVP
@test "nonlocal: nonlocal tables appear in show_tables" {
dolt checkout -b other
dolt sql <<SQL
CALL dolt_checkout('main');
CREATE TABLE aliased_table (pk char(8) PRIMARY KEY);
CREATE TABLE table_alias_1 (pk char(8) PRIMARY KEY);
CREATE TABLE table_alias_wild_3 (pk char(8) PRIMARY KEY);
INSERT INTO aliased_table VALUES ("amzmapqt");
CALL dolt_checkout('other');
INSERT INTO dolt_nonlocal_tables(table_name, target_ref, ref_table, options) VALUES
("table_alias_1", "main", "", "immediate"),
("table_alias_2", "main", "aliased_table", "immediate"),
("table_alias_wild_*", "main", "", "immediate"),
("table_alias_missing", "main", "", "immediate");
SQL
# Nonlocal tables should appear in "show tables"
run dolt sql -q "show tables"
[ "$status" -eq 0 ]
[[ "$output" =~ "table_alias_1" ]] || false
[[ "$output" =~ "table_alias_2" ]] || false
[[ "$output" =~ "table_alias_wild_3" ]] || false
! [[ "$output" =~ "table_alias_missing" ]] || false
}
@test "nonlocal: creating a table matching a nonlocal table rule results in an error" {
dolt checkout -b other
dolt sql <<SQL
INSERT INTO dolt_nonlocal_tables(table_name, target_ref, options) VALUES
("nonlocal_table", "main", "immediate");
SQL
run dolt sql -q "CREATE TABLE nonlocal_table (pk char(8) PRIMARY KEY);"
[ "$status" -eq 1 ]
[[ "$output" =~ "Cannot create table name nonlocal_table because it matches a name present in dolt_nonlocal_tables." ]] || false
}
@test "nonlocal: adding an existing table to nonlocal tables errors" {
skip
dolt checkout -b other
@@ -417,6 +360,6 @@ SQL
INSERT INTO dolt_nonlocal_tables(table_name, target_ref, options) VALUES
("nonlocal_table", "main", "immediate");
SQL
[ "$status" -eq 0 ]
[ "$status" -eq 1 ]
[[ "$output" =~ "cannot make nonlocal table nonlocal_table, table already exists on branch other" ]] || false
}