From 4ebe29819acc583465ce60f2e9bf36f5f5c9630f Mon Sep 17 00:00:00 2001 From: Axel Fontaine Date: Tue, 29 Dec 2015 11:10:11 +0100 Subject: [PATCH] Fixed #1109 ORA-65040 error when trying to clean different schema with system user --- .../dbsupport/oracle/OracleSchema.java | 96 +++++++++++-------- 1 file changed, 54 insertions(+), 42 deletions(-) diff --git a/flyway-core/src/main/java/org/flywaydb/core/internal/dbsupport/oracle/OracleSchema.java b/flyway-core/src/main/java/org/flywaydb/core/internal/dbsupport/oracle/OracleSchema.java index 9e58872179..069eb17a78 100644 --- a/flyway-core/src/main/java/org/flywaydb/core/internal/dbsupport/oracle/OracleSchema.java +++ b/flyway-core/src/main/java/org/flywaydb/core/internal/dbsupport/oracle/OracleSchema.java @@ -1,12 +1,12 @@ /** * Copyright 2010-2015 Axel Fontaine - * + *

* 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 - * + *

+ * 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. @@ -71,29 +71,39 @@ protected void doClean() throws SQLException { throw new FlywayException("Clean not supported on Oracle for user 'SYSTEM'! You should NEVER add your own objects to the SYSTEM schema!"); } - for (String statement : generateDropStatementsForSpatialExtensions()) { + String user = dbSupport.doGetCurrentSchemaName(); + boolean defaultSchemaForUser = user.equalsIgnoreCase(name); + + if (!defaultSchemaForUser) { + LOG.warn("Cleaning schema " + name + " by a different user (" + user + "): " + + "spatial extensions, queue tables, flashback tables and scheduled jobs will not be cleaned due to Oracle limitations"); + } + + for (String statement : generateDropStatementsForSpatialExtensions(defaultSchemaForUser)) { jdbcTemplate.execute(statement); } - for (String statement : generateDropStatementsForQueueTables()) { - try { - jdbcTemplate.execute(statement); - } catch (SQLException e) { - if (e.getErrorCode() == 65040) { - //for dropping queue tables, a special grant is required: - //GRANT EXECUTE ON DBMS_AQADM TO flyway; - LOG.error("Missing required grant to clean queue tables: GRANT EXECUTE ON DBMS_AQADM"); + if (defaultSchemaForUser) { + for (String statement : generateDropStatementsForQueueTables()) { + try { + jdbcTemplate.execute(statement); + } catch (SQLException e) { + if (e.getErrorCode() == 65040) { + //for dropping queue tables, a special grant is required: + //GRANT EXECUTE ON DBMS_AQADM TO flyway; + LOG.error("Missing required grant to clean queue tables: GRANT EXECUTE ON DBMS_AQADM"); + } + throw e; } - throw e; } - } - if (flashbackAvailable()) { - executeAlterStatementsForFlashbackTables(); - } + if (flashbackAvailable()) { + executeAlterStatementsForFlashbackTables(); + } - for (String statement : generateDropStatementsForScheduledJobs()) { - jdbcTemplate.execute(statement); + for (String statement : generateDropStatementsForScheduledJobs()) { + jdbcTemplate.execute(statement); + } } for (String statement : generateDropStatementsForObjectType("TRIGGER", "")) { @@ -251,10 +261,11 @@ private List generateDropStatementsForObjectType(String objectType, Stri /** * Generates the drop statements for Oracle Spatial Extensions-related database objects. * + * @param defaultSchemaForUser Whether we are currently cleaning the default schema for the logged in user. * @return The complete drop statements, ready to execute. * @throws SQLException when the drop statements could not be generated. */ - private List generateDropStatementsForSpatialExtensions() throws SQLException { + private List generateDropStatementsForSpatialExtensions(boolean defaultSchemaForUser) throws SQLException { List statements = new ArrayList(); if (!spatialExtensionsAvailable()) { @@ -270,12 +281,13 @@ private List generateDropStatementsForSpatialExtensions() throws SQLExce return statements; } + if (defaultSchemaForUser) { + statements.add("DELETE FROM mdsys.user_sdo_geom_metadata"); - statements.add("DELETE FROM mdsys.user_sdo_geom_metadata"); - - List indexNames = jdbcTemplate.queryForStringList("select INDEX_NAME from USER_SDO_INDEX_INFO"); - for (String indexName : indexNames) { - statements.add("DROP INDEX \"" + indexName + "\""); + List indexNames = jdbcTemplate.queryForStringList("select INDEX_NAME from USER_SDO_INDEX_INFO"); + for (String indexName : indexNames) { + statements.add("DROP INDEX \"" + indexName + "\""); + } } return statements; @@ -331,29 +343,29 @@ protected Table[] doAllTables() throws SQLException { // For every table this query will count the number of references (including the transitive ones) // and order the result list using that value. " SELECT r FROM" + - " (SELECT CONNECT_BY_ROOT t r FROM" + - " (SELECT DISTINCT c1.table_name f, NVL(c2.table_name, at.table_name) t" + - " FROM all_constraints c1" + - " RIGHT JOIN all_constraints c2 ON c2.constraint_name = c1.r_constraint_name" + - " RIGHT JOIN all_tables at ON at.table_name = c2.table_name" + - " WHERE at.owner = ?" + + " (SELECT CONNECT_BY_ROOT t r FROM" + + " (SELECT DISTINCT c1.table_name f, NVL(c2.table_name, at.table_name) t" + + " FROM all_constraints c1" + + " RIGHT JOIN all_constraints c2 ON c2.constraint_name = c1.r_constraint_name" + + " RIGHT JOIN all_tables at ON at.table_name = c2.table_name" + + " WHERE at.owner = ?" + // Ignore Recycle bin objects - " AND at.table_name NOT LIKE 'BIN$%'" + + " AND at.table_name NOT LIKE 'BIN$%'" + // Ignore Spatial Index Tables as they get dropped automatically when the index gets dropped. - " AND at.table_name NOT LIKE 'MDRT_%$'" + + " AND at.table_name NOT LIKE 'MDRT_%$'" + // Ignore Materialized View Logs - " AND at.table_name NOT LIKE 'MLOG$%' AND at.table_name NOT LIKE 'RUPD$%'" + + " AND at.table_name NOT LIKE 'MLOG$%' AND at.table_name NOT LIKE 'RUPD$%'" + // Ignore Oracle Text Index Tables - " AND at.table_name NOT LIKE 'DR$%'" + + " AND at.table_name NOT LIKE 'DR$%'" + // Ignore Index Organized Tables - " AND at.table_name NOT LIKE 'SYS_IOT_OVER_%'" + + " AND at.table_name NOT LIKE 'SYS_IOT_OVER_%'" + // Ignore Nested Tables - " AND at.nested != 'YES'" + + " AND at.nested != 'YES'" + // Ignore Nested Tables - " AND at.secondary != 'Y')" + - " CONNECT BY NOCYCLE PRIOR f = t)" + - " GROUP BY r" + - " ORDER BY COUNT(*)", name); + " AND at.secondary != 'Y')" + + " CONNECT BY NOCYCLE PRIOR f = t)" + + " GROUP BY r" + + " ORDER BY COUNT(*)", name); Table[] tables = new Table[tableNames.size()]; for (int i = 0; i < tableNames.size(); i++) {