mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-09-17 14:21:39 +00:00
REPO-4180: Service Pack: MNT-20305 Oracle schema validation check failure with ojdbc7.jar version 12.1.0.2
- fixed regression in SchemaBootstrap that cause the schema validation to not be done - added support for custom sequences retrieval (active if only schema reference sequences file exists) - added dialect and script utility classes - refactored ExportDb, ScriptExecutorImpl and SchemaBootstrap to use the utility classes to reduce code duplication
This commit is contained in:
@@ -52,7 +52,6 @@ import java.sql.SQLXML;
|
||||
import java.sql.Savepoint;
|
||||
import java.sql.Statement;
|
||||
import java.sql.Struct;
|
||||
import java.sql.Types;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
@@ -82,6 +81,7 @@ import org.alfresco.repo.domain.patch.AppliedPatchDAO;
|
||||
import org.alfresco.service.cmr.repository.ContentWriter;
|
||||
import org.alfresco.service.descriptor.DescriptorService;
|
||||
import org.alfresco.util.DatabaseMetaDataHelper;
|
||||
import org.alfresco.util.DialectUtil;
|
||||
import org.alfresco.util.LogUtil;
|
||||
import org.alfresco.util.PropertyCheck;
|
||||
import org.alfresco.util.TempFileProvider;
|
||||
@@ -111,9 +111,6 @@ import org.springframework.extensions.surf.util.I18NUtil;
|
||||
*/
|
||||
public class SchemaBootstrap extends AbstractLifecycleBean
|
||||
{
|
||||
/** The placeholder for the configured <code>Dialect</code> class name: <b>${db.script.dialect}</b> */
|
||||
private static final String PLACEHOLDER_DIALECT = "\\$\\{db\\.script\\.dialect\\}";
|
||||
|
||||
/** The global property containing the default batch size used by --FOREACH */
|
||||
private static final String PROPERTY_DEFAULT_BATCH_SIZE = "system.upgrade.default.batchsize";
|
||||
|
||||
@@ -323,7 +320,6 @@ public class SchemaBootstrap extends AbstractLifecycleBean
|
||||
* type (e.g. PostgreSQL)
|
||||
*
|
||||
* @param schemaReferenceUrls the schemaReferenceUrls to set
|
||||
* @see #PLACEHOLDER_DIALECT
|
||||
*/
|
||||
public void setSchemaReferenceUrls(List<String> schemaReferenceUrls)
|
||||
{
|
||||
@@ -1155,64 +1151,11 @@ public class SchemaBootstrap extends AbstractLifecycleBean
|
||||
try { scriptInputStream.close(); } catch (Throwable e) {} // usually a duplicate close
|
||||
}
|
||||
// now execute it
|
||||
String dialectScriptUrl = scriptUrl.replaceAll(PLACEHOLDER_DIALECT, dialect.getClass().getName());
|
||||
String dialectScriptUrl = scriptUrl.replaceAll(DialectUtil.PLACEHOLDER_DIALECT, dialect.getClass().getName());
|
||||
// Replace the script placeholders
|
||||
executeScriptFile(connection, tempFile, dialectScriptUrl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces the dialect placeholder in the resource URL and attempts to find a file for
|
||||
* it. If not found, the dialect hierarchy will be walked until a compatible resource is
|
||||
* found. This makes it possible to have resources that are generic to all dialects.
|
||||
*
|
||||
* @return The Resource, otherwise null
|
||||
*/
|
||||
private Resource getDialectResource(Class<?> dialectClass, String resourceUrl)
|
||||
{
|
||||
// replace the dialect placeholder
|
||||
String dialectResourceUrl = resolveDialectUrl(dialectClass, resourceUrl);
|
||||
// get a handle on the resource
|
||||
Resource resource = rpr.getResource(dialectResourceUrl);
|
||||
if (!resource.exists())
|
||||
{
|
||||
// it wasn't found. Get the superclass of the dialect and try again
|
||||
Class<?> superClass = dialectClass.getSuperclass();
|
||||
if (Dialect.class.isAssignableFrom(superClass))
|
||||
{
|
||||
// we still have a Dialect - try again
|
||||
return getDialectResource(superClass, resourceUrl);
|
||||
}
|
||||
else
|
||||
{
|
||||
// we have exhausted all options
|
||||
return null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// we have a handle to it
|
||||
return resource;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes resource URL containing the {@link SchemaBootstrap#PLACEHOLDER_DIALECT dialect placeholder text}
|
||||
* and substitutes the placeholder with the name of the given dialect's class.
|
||||
* <p/>
|
||||
* For example:
|
||||
* <pre>
|
||||
* resolveDialectUrl(MySQLInnoDBDialect.class, "classpath:alfresco/db/${db.script.dialect}/myfile.xml")
|
||||
* </pre>
|
||||
* would give the following String:
|
||||
* <pre>
|
||||
* classpath:alfresco/db/org.hibernate.dialect.MySQLInnoDBDialect/myfile.xml
|
||||
* </pre>
|
||||
*/
|
||||
private String resolveDialectUrl(Class<?> dialectClass, String resourceUrl)
|
||||
{
|
||||
return resourceUrl.replaceAll(PLACEHOLDER_DIALECT, dialectClass.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces the dialect placeholder in the script URL and attempts to find a file for
|
||||
* it. If not found, the dialect hierarchy will be walked until a compatible script is
|
||||
@@ -1222,7 +1165,7 @@ public class SchemaBootstrap extends AbstractLifecycleBean
|
||||
*/
|
||||
private InputStream getScriptInputStream(Class<?> dialectClazz, String scriptUrl) throws Exception
|
||||
{
|
||||
Resource resource = getDialectResource(dialectClazz, scriptUrl);
|
||||
Resource resource = DialectUtil.getDialectResource(rpr, dialectClazz, scriptUrl);
|
||||
if (resource == null)
|
||||
{
|
||||
throw new AlfrescoRuntimeException("Script [ " + scriptUrl + " ] can't be found for " + dialectClazz);
|
||||
@@ -1749,8 +1692,12 @@ public class SchemaBootstrap extends AbstractLifecycleBean
|
||||
{
|
||||
// Remove the flag indicating a running bootstrap
|
||||
setBootstrapCompleted(connection);
|
||||
|
||||
// Validate the schema, post-upgrade
|
||||
validateSchema("Alfresco-{0}-Validation-Post-Upgrade-{1}-", null);
|
||||
// 4.0+ schema dump
|
||||
dumpSchema("post-upgrade");
|
||||
}
|
||||
reportNormalizedDumps();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1804,17 +1751,6 @@ public class SchemaBootstrap extends AbstractLifecycleBean
|
||||
}
|
||||
}
|
||||
|
||||
private void reportNormalizedDumps()
|
||||
{
|
||||
if (executedStatementsThreadLocal.get() != null)
|
||||
{
|
||||
// Validate the schema, post-upgrade
|
||||
validateSchema("Alfresco-{0}-Validation-Post-Upgrade-{1}-", null);
|
||||
// 4.0+ schema dump
|
||||
dumpSchema("post-upgrade");
|
||||
}
|
||||
}
|
||||
|
||||
private void writeLogsWithDBStatementExecuted()
|
||||
{
|
||||
// Copy the executed statements to the output file
|
||||
@@ -1861,11 +1797,11 @@ public class SchemaBootstrap extends AbstractLifecycleBean
|
||||
// and process each in turn.
|
||||
for (String schemaReferenceUrl : schemaReferenceUrls)
|
||||
{
|
||||
Resource referenceResource = getDialectResource(dialect.getClass(), schemaReferenceUrl);
|
||||
Resource referenceResource = DialectUtil.getDialectResource(rpr, dialect.getClass(), schemaReferenceUrl);
|
||||
|
||||
if (referenceResource == null || !referenceResource.exists())
|
||||
{
|
||||
String resourceUrl = resolveDialectUrl(dialect.getClass(), schemaReferenceUrl);
|
||||
String resourceUrl = DialectUtil.resolveDialectUrl(dialect.getClass(), schemaReferenceUrl);
|
||||
LogUtil.debug(logger, DEBUG_SCHEMA_COMP_NO_REF_FILE, resourceUrl);
|
||||
}
|
||||
else
|
||||
|
@@ -47,6 +47,7 @@ import org.alfresco.repo.domain.dialect.Dialect;
|
||||
import org.alfresco.repo.domain.dialect.MySQLInnoDBDialect;
|
||||
import org.alfresco.repo.domain.dialect.PostgreSQLDialect;
|
||||
import org.alfresco.service.cmr.repository.ContentWriter;
|
||||
import org.alfresco.util.DialectUtil;
|
||||
import org.alfresco.util.LogUtil;
|
||||
import org.alfresco.util.TempFileProvider;
|
||||
import org.apache.commons.logging.Log;
|
||||
@@ -58,8 +59,6 @@ import org.springframework.core.io.support.ResourcePatternResolver;
|
||||
|
||||
public class ScriptExecutorImpl implements ScriptExecutor
|
||||
{
|
||||
/** The placeholder for the configured <code>Dialect</code> class name: <b>${db.script.dialect}</b> */
|
||||
private static final String PLACEHOLDER_DIALECT = "\\$\\{db\\.script\\.dialect\\}";
|
||||
/** The global property containing the default batch size used by --FOREACH */
|
||||
private static final String PROPERTY_DEFAULT_BATCH_SIZE = "system.upgrade.default.batchsize";
|
||||
private static final String MSG_EXECUTING_GENERATED_SCRIPT = "schema.update.msg.executing_generated_script";
|
||||
@@ -186,68 +185,11 @@ public class ScriptExecutorImpl implements ScriptExecutor
|
||||
try { scriptInputStream.close(); } catch (Throwable e) {} // usually a duplicate close
|
||||
}
|
||||
// now execute it
|
||||
String dialectScriptUrl = scriptUrl.replaceAll(PLACEHOLDER_DIALECT, dialect.getClass().getName());
|
||||
String dialectScriptUrl = scriptUrl.replaceAll(DialectUtil.PLACEHOLDER_DIALECT, dialect.getClass().getName());
|
||||
// Replace the script placeholders
|
||||
executeScriptFile(connection, tempFile, dialectScriptUrl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces the dialect placeholder in the resource URL and attempts to find a file for
|
||||
* it. If not found, the dialect hierarchy will be walked until a compatible resource is
|
||||
* found. This makes it possible to have resources that are generic to all dialects.
|
||||
*
|
||||
* @return The Resource, otherwise null
|
||||
*/
|
||||
private Resource getDialectResource(Class dialectClass, String resourceUrl)
|
||||
{
|
||||
// replace the dialect placeholder
|
||||
String dialectResourceUrl = resolveDialectUrl(dialectClass, resourceUrl);
|
||||
// get a handle on the resource
|
||||
Resource resource = rpr.getResource(dialectResourceUrl);
|
||||
if (!resource.exists())
|
||||
{
|
||||
// it wasn't found. Get the superclass of the dialect and try again
|
||||
Class superClass = dialectClass.getSuperclass();
|
||||
if (Dialect.class.isAssignableFrom(superClass))
|
||||
{
|
||||
// we still have a Dialect - try again
|
||||
return getDialectResource(superClass, resourceUrl);
|
||||
}
|
||||
else
|
||||
{
|
||||
// we have exhausted all options
|
||||
return null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// we have a handle to it
|
||||
return resource;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes resource URL containing the {@link ScriptExecutorImpl#PLACEHOLDER_DIALECT dialect placeholder text}
|
||||
* and substitutes the placeholder with the name of the given dialect's class.
|
||||
* <p/>
|
||||
* For example:
|
||||
* <pre>
|
||||
* resolveDialectUrl(MySQLInnoDBDialect.class, "classpath:alfresco/db/${db.script.dialect}/myfile.xml")
|
||||
* </pre>
|
||||
* would give the following String:
|
||||
* <pre>
|
||||
* classpath:alfresco/db/org.hibernate.dialect.MySQLInnoDBDialect/myfile.xml
|
||||
* </pre>
|
||||
*
|
||||
* @param dialectClass Class
|
||||
* @param resourceUrl String
|
||||
* @return String
|
||||
*/
|
||||
private String resolveDialectUrl(Class dialectClass, String resourceUrl)
|
||||
{
|
||||
return resourceUrl.replaceAll(PLACEHOLDER_DIALECT, dialectClass.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces the dialect placeholder in the script URL and attempts to find a file for
|
||||
* it. If not found, the dialect hierarchy will be walked until a compatible script is
|
||||
@@ -257,7 +199,7 @@ public class ScriptExecutorImpl implements ScriptExecutor
|
||||
*/
|
||||
private InputStream getScriptInputStream(Class dialectClazz, String scriptUrl) throws Exception
|
||||
{
|
||||
Resource resource = getDialectResource(dialectClazz, scriptUrl);
|
||||
Resource resource = DialectUtil.getDialectResource(rpr, dialectClazz, scriptUrl);
|
||||
if (resource == null)
|
||||
{
|
||||
return null;
|
||||
|
107
src/main/java/org/alfresco/util/DBScriptUtil.java
Normal file
107
src/main/java/org/alfresco/util/DBScriptUtil.java
Normal file
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Repository
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2019 Alfresco Software Limited
|
||||
* %%
|
||||
* This file is part of the Alfresco software.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* Alfresco is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Alfresco is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
* #L%
|
||||
*/
|
||||
package org.alfresco.util;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.LineNumberReader;
|
||||
|
||||
import org.springframework.core.io.support.EncodedResource;
|
||||
|
||||
public abstract class DBScriptUtil
|
||||
{
|
||||
private static final String DEFAULT_SCRIPT_COMMENT_PREFIX = "--";
|
||||
|
||||
/**
|
||||
* Read a script from the provided EncodedResource and build a String containing
|
||||
* the lines.
|
||||
*
|
||||
* @param resource
|
||||
* the resource (potentially associated with a specific encoding) to
|
||||
* load the SQL script from
|
||||
* @return a String containing the script lines
|
||||
*/
|
||||
public static String readScript(EncodedResource resource) throws IOException
|
||||
{
|
||||
return readScript(resource, DEFAULT_SCRIPT_COMMENT_PREFIX);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a script from the provided EncodedResource, using the supplied line
|
||||
* comment prefix, and build a String containing the lines.
|
||||
*
|
||||
* @param resource
|
||||
* the resource (potentially associated with a specific encoding) to
|
||||
* load the SQL script from
|
||||
* @param lineCommentPrefix
|
||||
* the prefix that identifies comments in the SQL script (typically
|
||||
* "--")
|
||||
* @return a String containing the script lines
|
||||
*/
|
||||
private static String readScript(EncodedResource resource, String lineCommentPrefix) throws IOException
|
||||
{
|
||||
LineNumberReader lineNumberReader = new LineNumberReader(resource.getReader());
|
||||
try
|
||||
{
|
||||
return readScript(lineNumberReader, lineCommentPrefix);
|
||||
}
|
||||
finally
|
||||
{
|
||||
lineNumberReader.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a script from the provided LineNumberReader, using the supplied line
|
||||
* comment prefix, and build a String containing the lines.
|
||||
*
|
||||
* @param lineNumberReader
|
||||
* the LineNumberReader containing the script to be processed
|
||||
* @param lineCommentPrefix
|
||||
* the prefix that identifies comments in the SQL script (typically
|
||||
* "--")
|
||||
* @return a String containing the script lines
|
||||
*/
|
||||
private static String readScript(LineNumberReader lineNumberReader, String lineCommentPrefix) throws IOException
|
||||
{
|
||||
String statement = lineNumberReader.readLine();
|
||||
StringBuilder scriptBuilder = new StringBuilder();
|
||||
while (statement != null)
|
||||
{
|
||||
if (lineCommentPrefix != null && !statement.startsWith(lineCommentPrefix))
|
||||
{
|
||||
if (scriptBuilder.length() > 0)
|
||||
{
|
||||
scriptBuilder.append('\n');
|
||||
}
|
||||
scriptBuilder.append(statement);
|
||||
}
|
||||
statement = lineNumberReader.readLine();
|
||||
}
|
||||
|
||||
return scriptBuilder.toString();
|
||||
}
|
||||
|
||||
}
|
94
src/main/java/org/alfresco/util/DialectUtil.java
Normal file
94
src/main/java/org/alfresco/util/DialectUtil.java
Normal file
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Repository
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2019 Alfresco Software Limited
|
||||
* %%
|
||||
* This file is part of the Alfresco software.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* Alfresco is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Alfresco is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
* #L%
|
||||
*/
|
||||
package org.alfresco.util;
|
||||
|
||||
import org.alfresco.repo.domain.dialect.Dialect;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.support.ResourcePatternResolver;
|
||||
|
||||
public abstract class DialectUtil
|
||||
{
|
||||
/** The placeholder for the configured <code>Dialect</code> class name: <b>${db.script.dialect}</b> */
|
||||
public static final String PLACEHOLDER_DIALECT = "\\$\\{db\\.script\\.dialect\\}";
|
||||
|
||||
/**
|
||||
* Replaces the dialect placeholder in the resource URL and attempts to find a
|
||||
* file for it. If not found, the dialect hierarchy will be walked until a
|
||||
* compatible resource is found. This makes it possible to have resources that
|
||||
* are generic to all dialects.
|
||||
*
|
||||
* @return The Resource, otherwise null
|
||||
*/
|
||||
public static Resource getDialectResource(ResourcePatternResolver resourcePatternResolver, Class<?> dialectClass, String resourceUrl)
|
||||
{
|
||||
// replace the dialect placeholder
|
||||
String dialectResourceUrl = resolveDialectUrl(dialectClass, resourceUrl);
|
||||
// get a handle on the resource
|
||||
Resource resource = resourcePatternResolver.getResource(dialectResourceUrl);
|
||||
if (!resource.exists())
|
||||
{
|
||||
// it wasn't found. Get the superclass of the dialect and try again
|
||||
Class<?> superClass = dialectClass.getSuperclass();
|
||||
if (Dialect.class.isAssignableFrom(superClass))
|
||||
{
|
||||
// we still have a Dialect - try again
|
||||
return getDialectResource(resourcePatternResolver, superClass, resourceUrl);
|
||||
}
|
||||
else
|
||||
{
|
||||
// we have exhausted all options
|
||||
return null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// we have a handle to it
|
||||
return resource;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes resource URL containing the {@link DialectUtil#PLACEHOLDER_DIALECT
|
||||
* dialect placeholder text} and substitutes the placeholder with the name of
|
||||
* the given dialect's class.
|
||||
* <p/>
|
||||
* For example:
|
||||
*
|
||||
* <pre>
|
||||
* resolveDialectUrl(MySQLInnoDBDialect.class, "classpath:alfresco/db/${db.script.dialect}/myfile.xml")
|
||||
* </pre>
|
||||
*
|
||||
* would give the following String:
|
||||
*
|
||||
* <pre>
|
||||
* classpath:alfresco/db/org.hibernate.dialect.MySQLInnoDBDialect/myfile.xml
|
||||
* </pre>
|
||||
*/
|
||||
public static String resolveDialectUrl(Class<?> dialectClass, String resourceUrl)
|
||||
{
|
||||
return resourceUrl.replaceAll(PLACEHOLDER_DIALECT, dialectClass.getName());
|
||||
}
|
||||
}
|
@@ -25,9 +25,11 @@
|
||||
*/
|
||||
package org.alfresco.util.schemacomp;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.sql.Connection;
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Map;
|
||||
@@ -40,7 +42,9 @@ import org.alfresco.repo.domain.dialect.TypeNames;
|
||||
import org.alfresco.service.descriptor.Descriptor;
|
||||
import org.alfresco.service.descriptor.DescriptorService;
|
||||
import org.alfresco.util.DatabaseMetaDataHelper;
|
||||
import org.alfresco.util.DialectUtil;
|
||||
import org.alfresco.util.PropertyCheck;
|
||||
import org.alfresco.util.DBScriptUtil;
|
||||
import org.alfresco.util.schemacomp.model.Column;
|
||||
import org.alfresco.util.schemacomp.model.ForeignKey;
|
||||
import org.alfresco.util.schemacomp.model.Index;
|
||||
@@ -51,7 +55,10 @@ import org.alfresco.util.schemacomp.model.Table;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.support.EncodedResource;
|
||||
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
|
||||
import org.springframework.core.io.support.ResourcePatternResolver;
|
||||
|
||||
/**
|
||||
* Exports a database schema to an in-memory {@link Schema} object.
|
||||
@@ -60,6 +67,8 @@ import org.springframework.context.ApplicationContext;
|
||||
*/
|
||||
public class ExportDb
|
||||
{
|
||||
private static final String SCHEMA_REFERENCE_SEQUENCES_SQL_FILE = "classpath:alfresco/dbscripts/create/${db.script.dialect}/Schema-Reference-Sequences.sql";
|
||||
|
||||
/** Reverse map from database types to JDBC types (loaded from a Hibernate dialect). */
|
||||
private final Map<String, Integer> reverseTypeMap = new TreeMap<String, Integer>();
|
||||
|
||||
@@ -86,6 +95,7 @@ public class ExportDb
|
||||
|
||||
private final static Log log = LogFactory.getLog(ExportDb.class);
|
||||
|
||||
private ResourcePatternResolver rpr = new PathMatchingResourcePatternResolver(this.getClass().getClassLoader());
|
||||
|
||||
public ExportDb(ApplicationContext context)
|
||||
{
|
||||
@@ -227,19 +237,38 @@ public class ExportDb
|
||||
|
||||
|
||||
private void extractSchema(DatabaseMetaData dbmd, String schemaName, String prefixFilter)
|
||||
throws SQLException, IllegalArgumentException, IllegalAccessException
|
||||
throws SQLException, IllegalArgumentException, IllegalAccessException, IOException
|
||||
{
|
||||
if (log.isDebugEnabled())
|
||||
{
|
||||
log.debug("Retrieving tables: schemaName=[" + schemaName + "], prefixFilter=[" + prefixFilter + "]");
|
||||
}
|
||||
|
||||
|
||||
final ResultSet tables = dbmd.getTables(null, schemaName, prefixFilter, new String[]
|
||||
final String[] tableTypes;
|
||||
Resource sequencesRefResource = getSequencesReferenceResource();
|
||||
if (sequencesRefResource != null && sequencesRefResource.exists())
|
||||
{
|
||||
"TABLE", "VIEW", "SEQUENCE"
|
||||
});
|
||||
tableTypes = new String[] {"TABLE", "VIEW"};
|
||||
|
||||
retrieveAndProcessSequences(dbmd, sequencesRefResource, schemaName, prefixFilter);
|
||||
}
|
||||
else
|
||||
{
|
||||
tableTypes = new String[] { "TABLE", "VIEW", "SEQUENCE" };
|
||||
}
|
||||
|
||||
final ResultSet tables = dbmd.getTables(null, schemaName, prefixFilter, tableTypes);
|
||||
|
||||
processTables(dbmd, tables);
|
||||
}
|
||||
|
||||
private void processTables(DatabaseMetaData dbmd, ResultSet tables)
|
||||
throws SQLException, IllegalArgumentException, IllegalAccessException
|
||||
{
|
||||
if (tables == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
while (tables.next())
|
||||
{
|
||||
@@ -512,4 +541,101 @@ public class ExportDb
|
||||
{
|
||||
this.dbSchemaName = dbSchemaName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to find the schema reference sequences sql file. If not found, the
|
||||
* dialect hierarchy will be walked until a compatible resource is found. This
|
||||
* makes it possible to have resources that are generic to all dialects.
|
||||
*
|
||||
* @return The Resource, otherwise null
|
||||
*/
|
||||
private Resource getSequencesReferenceResource()
|
||||
{
|
||||
return DialectUtil.getDialectResource(rpr, dialect.getClass(), SCHEMA_REFERENCE_SEQUENCES_SQL_FILE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves and process DB sequences for the schema validation check.
|
||||
*
|
||||
* @param dbmd
|
||||
* the database meta data
|
||||
* @param resource
|
||||
* the resource to load the SQL script from
|
||||
* @param schemaName
|
||||
* the DB schema name
|
||||
* @param prefixFilter
|
||||
* the DB tables prefix filter
|
||||
*/
|
||||
private void retrieveAndProcessSequences(DatabaseMetaData dbmd, Resource resource, String schemaName, String prefixFilter)
|
||||
throws SQLException, IllegalArgumentException, IllegalAccessException, IOException
|
||||
{
|
||||
final String script = DBScriptUtil.readScript(new EncodedResource(resource, "UTF-8"));
|
||||
|
||||
if (!script.isEmpty())
|
||||
{
|
||||
retrieveAndProcessSequences(dbmd, script, schemaName, prefixFilter);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves and process DB sequences for the schema validation check.
|
||||
*
|
||||
* @param dbmd
|
||||
* the database meta data
|
||||
* @param script
|
||||
* the SQL script
|
||||
* @param schemaName
|
||||
* the DB schema name
|
||||
* @param prefixFilter
|
||||
* the DB tables prefix filter
|
||||
*/
|
||||
private void retrieveAndProcessSequences(DatabaseMetaData dbmd, String script, String schemaName, String prefixFilter)
|
||||
throws SQLException, IllegalArgumentException, IllegalAccessException
|
||||
{
|
||||
if (log.isDebugEnabled())
|
||||
{
|
||||
log.debug("Retrieving DB sequences...");
|
||||
}
|
||||
|
||||
PreparedStatement stmt = null;
|
||||
try
|
||||
{
|
||||
stmt = dbmd.getConnection().prepareStatement(script);
|
||||
stmt.setString(1, schemaName);
|
||||
stmt.setString(2, prefixFilter);
|
||||
|
||||
boolean haveResults = stmt.execute();
|
||||
|
||||
if (haveResults)
|
||||
{
|
||||
ResultSet sequences = stmt.getResultSet();
|
||||
|
||||
if (log.isDebugEnabled())
|
||||
{
|
||||
log.debug("Sequences processing started...");
|
||||
}
|
||||
|
||||
processTables(dbmd, sequences);
|
||||
|
||||
if (log.isDebugEnabled())
|
||||
{
|
||||
log.debug("Sequences processing completed.");
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (stmt != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
stmt.close();
|
||||
}
|
||||
catch (Throwable e)
|
||||
{
|
||||
// Little can be done at this stage.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user