-
Notifications
You must be signed in to change notification settings - Fork 11
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Reporting Foreign Key references Partitioned table in analyze and assessment #2145
Changes from 7 commits
b066843
3c03d6c
ef67431
4c8267d
7050196
17c6c0a
c69c102
c178884
c6b0f80
1c28fe1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -27,6 +27,7 @@ import ( | |
"github.com/jackc/pgx/v5" | ||
"github.com/stretchr/testify/assert" | ||
"github.com/testcontainers/testcontainers-go/modules/yugabytedb" | ||
|
||
"github.com/yugabyte/yb-voyager/yb-voyager/src/issue" | ||
"github.com/yugabyte/yb-voyager/yb-voyager/src/ybversion" | ||
testutils "github.com/yugabyte/yb-voyager/yb-voyager/test/utils" | ||
|
@@ -273,6 +274,19 @@ func testSecurityInvokerView(t *testing.T) { | |
assertErrorCorrectlyThrownForIssueForYBVersion(t, err, "unrecognized parameter", securityInvokerViewIssue) | ||
} | ||
|
||
func testForeignKeyReferencesPartitionedTableIssue(t *testing.T) { | ||
ctx := context.Background() | ||
conn, err := getConn() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Consider using the new testcontainers package in this test file. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we do it separately for these issues integration tests as it will require changes to all these tests to not use the connection string to run the SQL commands directly and assert the error instead use the ExecuteSqls of the testContainer |
||
assert.NoError(t, err) | ||
|
||
defer conn.Close(context.Background()) | ||
_, err = conn.Exec(ctx, ` | ||
CREATE TABLE abc1(id int PRIMARY KEY, val text) PARTITION BY RANGE (id); | ||
CREATE TABLE abc_fk(id int PRIMARY KEY, abc_id INT REFERENCES abc1(id), val text) ;`) | ||
|
||
assertErrorCorrectlyThrownForIssueForYBVersion(t, err, `cannot reference partitioned table "abc1"`, foreignKeyReferencesPartitionedTableIssue) | ||
} | ||
|
||
func TestDDLIssuesInYBVersion(t *testing.T) { | ||
var err error | ||
ybVersion := os.Getenv("YB_VERSION") | ||
|
@@ -328,6 +342,10 @@ func TestDDLIssuesInYBVersion(t *testing.T) { | |
|
||
success = t.Run(fmt.Sprintf("%s-%s", "multi range datatype", ybVersion), testMultiRangeDatatypeIssue) | ||
assert.True(t, success) | ||
|
||
success = t.Run(fmt.Sprintf("%s-%s", "security invoker view", ybVersion), testSecurityInvokerView) | ||
assert.True(t, success) | ||
|
||
success = t.Run(fmt.Sprintf("%s-%s", "foreign key referenced partitioned table", ybVersion), testForeignKeyReferencesPartitionedTableIssue) | ||
assert.True(t, success) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -25,9 +25,9 @@ import ( | |
"github.com/google/go-cmp/cmp" | ||
"github.com/samber/lo" | ||
"github.com/stretchr/testify/assert" | ||
testutils "github.com/yugabyte/yb-voyager/yb-voyager/test/utils" | ||
|
||
"github.com/yugabyte/yb-voyager/yb-voyager/src/ybversion" | ||
testutils "github.com/yugabyte/yb-voyager/yb-voyager/test/utils" | ||
) | ||
|
||
const ( | ||
|
@@ -754,3 +754,56 @@ func TestCopyUnsupportedConstructIssuesDetected(t *testing.T) { | |
} | ||
} | ||
} | ||
|
||
func TestForeignKeyReferencesPartitionedTableIssues(t *testing.T) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can we remove any redundant test here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There are no redundant cases here all of them have different ways of defining the constraint and qualified or unqualified table names etc.. |
||
requiredDDLs := []string{ | ||
`CREATE TABLE abc1(id int PRIMARY KEY, val text) PARTITION BY RANGE (id);`, | ||
`CREATE TABLE schema1.abc(id int PRIMARY KEY, val text) PARTITION BY RANGE (id);`, | ||
} | ||
stmt1 := `CREATE TABLE abc_fk(id int PRIMARY KEY, abc_id INT REFERENCES abc1(id), val text) ;` | ||
stmt2 := `ALTER TABLE schema1.abc_fk1 | ||
ADD CONSTRAINT fk FOREIGN KEY (abc1_id) | ||
REFERENCES schema1.abc (id); | ||
` | ||
stmt3 := `CREATE TABLE abc_fk ( | ||
id INT PRIMARY KEY, | ||
abc_id INT, | ||
val TEXT, | ||
CONSTRAINT fk_abc FOREIGN KEY (abc_id) REFERENCES abc1(id) | ||
); | ||
` | ||
|
||
stmt4 := `CREATE TABLE schema1.abc_fk(id int PRIMARY KEY, abc_id INT, val text, FOREIGN KEY (abc_id) REFERENCES schema1.abc(id));` | ||
|
||
ddlStmtsWithIssues := map[string][]QueryIssue{ | ||
stmt1: []QueryIssue{ | ||
NewForeignKeyReferencesPartitionedTableIssue(TABLE_OBJECT_TYPE, "abc_fk", stmt1, "abc_fk_abc_id_fkey"), | ||
}, | ||
stmt2: []QueryIssue{ | ||
NewForeignKeyReferencesPartitionedTableIssue(TABLE_OBJECT_TYPE, "schema1.abc_fk1", stmt2, "fk"), | ||
}, | ||
stmt3: []QueryIssue{ | ||
NewForeignKeyReferencesPartitionedTableIssue(TABLE_OBJECT_TYPE, "abc_fk", stmt3, "fk_abc"), | ||
}, | ||
stmt4: []QueryIssue{ | ||
NewForeignKeyReferencesPartitionedTableIssue(TABLE_OBJECT_TYPE, "schema1.abc_fk", stmt4, "abc_fk_abc_id_fkey"), | ||
}, | ||
} | ||
parserIssueDetector := NewParserIssueDetector() | ||
for _, stmt := range requiredDDLs { | ||
err := parserIssueDetector.ParseRequiredDDLs(stmt) | ||
assert.NoError(t, err, "Error parsing required ddl: %s", stmt) | ||
} | ||
for stmt, expectedIssues := range ddlStmtsWithIssues { | ||
issues, err := parserIssueDetector.GetDDLIssues(stmt, ybversion.LatestStable) | ||
assert.NoError(t, err, "Error detecting issues for statement: %s", stmt) | ||
|
||
assert.Equal(t, len(expectedIssues), len(issues), "Mismatch in issue count for statement: %s", stmt) | ||
for _, expectedIssue := range expectedIssues { | ||
found := slices.ContainsFunc(issues, func(queryIssue QueryIssue) bool { | ||
return cmp.Equal(expectedIssue, queryIssue) | ||
}) | ||
assert.True(t, found, "Expected issue not found: %v in statement: %s", expectedIssue, stmt) | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lets add sqlstatement also here?
Moving forward(flattening of issues in assessment report), we will have this field for each issue and its good to have sql statement available in each case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SQL statement is already added for these later in the GetDDLIssues
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hmm.. not sure what is the reason of adding it there.
But adding at the time of issue creation makes more sense to me.
is the sql statement getting modified somewhere in between.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No not changing sql statement anywhere, it's just that skipping the overhead of passing the query to these
ddl_detectors
, so adding it in one go there itself.