fix(oracle): list materialized views without table duplicates

Closes #6611
This commit is contained in:
t8y2
2026-08-18 14:33:54 +00:00
parent 27fd668758
commit 95760e320a
2 changed files with 103 additions and 13 deletions
+48 -13
View File
@@ -103,13 +103,20 @@ SELECT t.TABLE_NAME AS OBJECT_NAME,
FROM ALL_TABLES t
WHERE t.OWNER = :1
AND t.NESTED = 'NO'
AND NOT EXISTS (
SELECT 1
FROM ALL_OBJECTS mv
WHERE mv.OWNER = t.OWNER
AND mv.OBJECT_NAME = t.TABLE_NAME
AND mv.OBJECT_TYPE = 'MATERIALIZED VIEW'
)
UNION ALL
SELECT o.OBJECT_NAME,
'VIEW' AS TABLE_TYPE,
CASE o.OBJECT_TYPE WHEN 'MATERIALIZED VIEW' THEN 'MATERIALIZED_VIEW' ELSE o.OBJECT_TYPE END AS TABLE_TYPE,
CAST(NULL AS VARCHAR2(4000)) AS COMMENTS
FROM ALL_OBJECTS o
WHERE o.OWNER = :2
AND o.OBJECT_TYPE = 'VIEW'
AND o.OBJECT_TYPE IN ('VIEW', 'MATERIALIZED VIEW')
)`
const oracleListTablesSessionUserBaseSQL = `
SELECT OBJECT_NAME, TABLE_TYPE, COMMENTS
@@ -119,12 +126,18 @@ SELECT t.TABLE_NAME AS OBJECT_NAME,
CAST(NULL AS VARCHAR2(4000)) AS COMMENTS
FROM USER_TABLES t
WHERE t.NESTED = 'NO'
AND NOT EXISTS (
SELECT 1
FROM USER_OBJECTS mv
WHERE mv.OBJECT_NAME = t.TABLE_NAME
AND mv.OBJECT_TYPE = 'MATERIALIZED VIEW'
)
UNION ALL
SELECT o.OBJECT_NAME,
'VIEW' AS TABLE_TYPE,
CASE o.OBJECT_TYPE WHEN 'MATERIALIZED VIEW' THEN 'MATERIALIZED_VIEW' ELSE o.OBJECT_TYPE END AS TABLE_TYPE,
CAST(NULL AS VARCHAR2(4000)) AS COMMENTS
FROM USER_OBJECTS o
WHERE o.OBJECT_TYPE = 'VIEW'
WHERE o.OBJECT_TYPE IN ('VIEW', 'MATERIALIZED VIEW')
)`
const oracleListTablesOrderSQL = `ORDER BY OBJECT_NAME`
const oracleListTablesSQL = oracleListTablesBaseSQL + "\n" + oracleListTablesOrderSQL
@@ -137,13 +150,24 @@ SELECT t.TABLE_NAME AS OBJECT_NAME,
FROM ALL_TABLES t
WHERE t.OWNER = :1
AND t.NESTED = 'NO'
AND NOT EXISTS (
SELECT 1
FROM ALL_OBJECTS mv
WHERE mv.OWNER = t.OWNER
AND mv.OBJECT_NAME = t.TABLE_NAME
AND mv.OBJECT_TYPE = 'MATERIALIZED VIEW'
)
UNION ALL
SELECT o.OBJECT_NAME,
CASE o.OBJECT_TYPE WHEN 'PACKAGE BODY' THEN 'PACKAGE_BODY' ELSE o.OBJECT_TYPE END AS OBJECT_TYPE,
CASE o.OBJECT_TYPE
WHEN 'PACKAGE BODY' THEN 'PACKAGE_BODY'
WHEN 'MATERIALIZED VIEW' THEN 'MATERIALIZED_VIEW'
ELSE o.OBJECT_TYPE
END AS OBJECT_TYPE,
CAST(NULL AS VARCHAR2(4000)) AS COMMENTS
FROM ALL_OBJECTS o
WHERE o.OWNER = :2
AND o.OBJECT_TYPE IN ('VIEW', 'PROCEDURE', 'FUNCTION', 'PACKAGE', 'PACKAGE BODY')
AND o.OBJECT_TYPE IN ('VIEW', 'MATERIALIZED VIEW', 'PROCEDURE', 'FUNCTION', 'PACKAGE', 'PACKAGE BODY')
UNION ALL
SELECT s.SYNONYM_NAME AS OBJECT_NAME,
'SYNONYM' AS OBJECT_TYPE,
@@ -159,12 +183,22 @@ SELECT t.TABLE_NAME AS OBJECT_NAME,
CAST(NULL AS VARCHAR2(4000)) AS COMMENTS
FROM USER_TABLES t
WHERE t.NESTED = 'NO'
AND NOT EXISTS (
SELECT 1
FROM USER_OBJECTS mv
WHERE mv.OBJECT_NAME = t.TABLE_NAME
AND mv.OBJECT_TYPE = 'MATERIALIZED VIEW'
)
UNION ALL
SELECT o.OBJECT_NAME,
CASE o.OBJECT_TYPE WHEN 'PACKAGE BODY' THEN 'PACKAGE_BODY' ELSE o.OBJECT_TYPE END AS OBJECT_TYPE,
CASE o.OBJECT_TYPE
WHEN 'PACKAGE BODY' THEN 'PACKAGE_BODY'
WHEN 'MATERIALIZED VIEW' THEN 'MATERIALIZED_VIEW'
ELSE o.OBJECT_TYPE
END AS OBJECT_TYPE,
CAST(NULL AS VARCHAR2(4000)) AS COMMENTS
FROM USER_OBJECTS o
WHERE o.OBJECT_TYPE IN ('VIEW', 'PROCEDURE', 'FUNCTION', 'PACKAGE', 'PACKAGE BODY')
WHERE o.OBJECT_TYPE IN ('VIEW', 'MATERIALIZED VIEW', 'PROCEDURE', 'FUNCTION', 'PACKAGE', 'PACKAGE BODY')
UNION ALL
SELECT s.SYNONYM_NAME AS OBJECT_NAME,
'SYNONYM' AS OBJECT_TYPE,
@@ -174,11 +208,12 @@ FROM USER_SYNONYMS s
const oracleListObjectsOrderSQL = `ORDER BY CASE OBJECT_TYPE
WHEN 'TABLE' THEN 0
WHEN 'VIEW' THEN 1
WHEN 'PROCEDURE' THEN 2
WHEN 'FUNCTION' THEN 3
WHEN 'SYNONYM' THEN 4
WHEN 'PACKAGE' THEN 5
ELSE 6
WHEN 'MATERIALIZED_VIEW' THEN 2
WHEN 'PROCEDURE' THEN 3
WHEN 'FUNCTION' THEN 4
WHEN 'SYNONYM' THEN 5
WHEN 'PACKAGE' THEN 6
ELSE 7
END, OBJECT_NAME`
const oracleListObjectsSQL = oracleListObjectsBaseSQL + "\n" + oracleListObjectsOrderSQL
const oracleListTriggersSQL = `
+55
View File
@@ -1744,6 +1744,61 @@ func TestListTablesSQLUsesSplitDictionaryQuery(t *testing.T) {
}
}
func TestOracleMetadataQueriesClassifyMaterializedViews(t *testing.T) {
tests := []struct {
name string
sqlText string
tableView string
objectView string
ownerMatch string
}{
{
name: "all list tables",
sqlText: oracleListTablesBaseSQL,
tableView: "ALL_TABLES",
objectView: "ALL_OBJECTS",
ownerMatch: "MV.OWNER = T.OWNER",
},
{
name: "user list tables",
sqlText: oracleListTablesSessionUserBaseSQL,
tableView: "USER_TABLES",
objectView: "USER_OBJECTS",
},
{
name: "all list objects",
sqlText: oracleListObjectsBaseSQL,
tableView: "ALL_TABLES",
objectView: "ALL_OBJECTS",
ownerMatch: "MV.OWNER = T.OWNER",
},
{
name: "user list objects",
sqlText: oracleListObjectsSessionUserBaseSQL,
tableView: "USER_TABLES",
objectView: "USER_OBJECTS",
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
sqlText := strings.ToUpper(test.sqlText)
if !strings.Contains(sqlText, "FROM "+test.tableView+" T") || !strings.Contains(sqlText, "FROM "+test.objectView+" MV") {
t.Fatalf("metadata query should classify tables against materialized-view objects: %s", test.sqlText)
}
if !strings.Contains(sqlText, "NOT EXISTS") || !strings.Contains(sqlText, "MV.OBJECT_NAME = T.TABLE_NAME") || !strings.Contains(sqlText, "MV.OBJECT_TYPE = 'MATERIALIZED VIEW'") {
t.Fatalf("metadata query should exclude materialized-view storage tables: %s", test.sqlText)
}
if test.ownerMatch != "" && !strings.Contains(sqlText, test.ownerMatch) {
t.Fatalf("cross-schema metadata query should keep materialized-view classification owner-scoped: %s", test.sqlText)
}
if !strings.Contains(sqlText, "'MATERIALIZED_VIEW'") || !strings.Contains(sqlText, "'MATERIALIZED VIEW'") {
t.Fatalf("metadata query should return the normalized materialized-view type: %s", test.sqlText)
}
})
}
}
func TestListTablesQueryAppliesMetadataConstraints(t *testing.T) {
query := oracleListTablesQuery("APP", metadataListConstraints{
Filter: "u_r",