| /* |
| * Copyright (c) 1998, 2021 Oracle and/or its affiliates. All rights reserved. |
| * |
| * This program and the accompanying materials are made available under the |
| * terms of the Eclipse Public License v. 2.0 which is available at |
| * http://www.eclipse.org/legal/epl-2.0, |
| * or the Eclipse Distribution License v. 1.0 which is available at |
| * http://www.eclipse.org/org/documents/edl-v10.php. |
| * |
| * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause |
| */ |
| |
| // Contributors: |
| // Oracle - initial API and implementation from Oracle TopLink |
| // Dies Koper - add support for creating indices on tables |
| // 01/11/2013-2.5 Guy Pelletier |
| // - 389090: JPA 2.1 DDL Generation Support |
| // 02/04/2013-2.5 Guy Pelletier |
| // - 389090: JPA 2.1 DDL Generation Support |
| // 04/12/2013-2.5 Guy Pelletier |
| // - 405640: JPA 2.1 schema generation drop operation fails to include dropping defaulted fk constraints. |
| package org.eclipse.persistence.tools.schemaframework; |
| |
| import java.io.Writer; |
| import java.net.URL; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.Set; |
| import java.util.Vector; |
| |
| import org.eclipse.persistence.descriptors.ClassDescriptor; |
| import org.eclipse.persistence.exceptions.DatabaseException; |
| import org.eclipse.persistence.exceptions.EclipseLinkException; |
| import org.eclipse.persistence.exceptions.ValidationException; |
| import org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor; |
| import org.eclipse.persistence.internal.helper.Helper; |
| import org.eclipse.persistence.internal.sequencing.Sequencing; |
| import org.eclipse.persistence.internal.sessions.AbstractSession; |
| import org.eclipse.persistence.internal.sessions.DatabaseSessionImpl; |
| import org.eclipse.persistence.sequencing.DefaultSequence; |
| import org.eclipse.persistence.sequencing.NativeSequence; |
| import org.eclipse.persistence.sequencing.Sequence; |
| import org.eclipse.persistence.sequencing.TableSequence; |
| import org.eclipse.persistence.sequencing.UnaryTableSequence; |
| |
| /** |
| * <p> |
| * <b>Purpose</b>: Define all user level protocol for development time database manipulation. |
| * <p> |
| * <b>Responsibilities</b>: |
| * <ul> |
| * <li> Define protocol for schema creation. |
| * <li> Define any useful testing specific protocol. |
| * </ul> |
| */ |
| public class SchemaManager { |
| protected DatabaseSessionImpl session; |
| protected Writer createSchemaWriter; |
| protected Writer dropSchemaWriter; |
| protected boolean createSQLFiles = true; //if true, schema writer will add terminator string. |
| protected TableCreator defaultTableCreator; |
| |
| /** Allow table creator to occur "fast" by just deleting all the rows. */ |
| public static boolean FAST_TABLE_CREATOR = false; |
| |
| /** Allow replacing of table to force the drop, this may require several passes. */ |
| public static boolean FORCE_DROP = true; |
| |
| /** Flag to determine if database schemas should be created during DDL generation */ |
| protected boolean createDatabaseSchemas = false; |
| protected HashSet<String> createdDatabaseSchemas = new HashSet<>(); |
| protected HashSet<String> createdDatabaseSchemasOnDatabase = new HashSet<>(); |
| protected HashMap<String, DatabaseObjectDefinition> dropDatabaseSchemas = new HashMap<>(); |
| |
| public SchemaManager(DatabaseSessionImpl session) { |
| this.session = session; |
| } |
| |
| public SchemaManager(org.eclipse.persistence.sessions.DatabaseSession session) { |
| this.session = ((DatabaseSessionImpl)session); |
| } |
| |
| protected Writer getDropSchemaWriter() { |
| return (dropSchemaWriter == null) ? createSchemaWriter : dropSchemaWriter; |
| } |
| |
| /** |
| * PUBLIC: If the schema manager is writing to a writer, append this string |
| * to that writer. |
| */ |
| public void appendToDDLWriter(String stringToWrite) { |
| // If this method is called, we know that it is the old case and |
| // it would not matter which schemaWriter we use as both the |
| // create and drop schemaWriters are essentially the same. |
| // So just pick one. |
| appendToDDLWriter(createSchemaWriter, stringToWrite); |
| } |
| |
| public void appendToDDLWriter(Writer schemaWriter, String stringToWrite) { |
| if (schemaWriter == null) { |
| return; //do nothing. Ignore append request |
| } |
| |
| try { |
| schemaWriter.write(stringToWrite); |
| schemaWriter.flush(); |
| } catch (java.io.IOException ioException) { |
| throw ValidationException.fileError(ioException); |
| } |
| } |
| |
| /** |
| * INTERNAL: |
| * builds the field names based on the type read in from the builder |
| */ |
| public void buildFieldTypes(TableDefinition tableDef) { |
| tableDef.buildFieldTypes(getSession()); |
| } |
| |
| /** |
| * PUBLIC: |
| * Close the schema writer. |
| */ |
| public void closeDDLWriter() { |
| closeDDLWriter(createSchemaWriter); |
| closeDDLWriter(dropSchemaWriter); |
| createSchemaWriter = null; |
| dropSchemaWriter = null; |
| } |
| |
| public void closeDDLWriter(Writer schemaWriter) { |
| if (schemaWriter == null) { |
| return; |
| } |
| |
| try { |
| schemaWriter.flush(); |
| schemaWriter.close(); |
| } catch (java.io.IOException ioException) { |
| throw ValidationException.fileError(ioException); |
| } |
| } |
| |
| /** |
| * INTERNAL: |
| * Called when dropping tables. Will build a map of those schemas (and a |
| * table that references it) that should be dropped. |
| */ |
| protected void collectDatabaseSchemasForDrop(DatabaseObjectDefinition databaseObjectDefinition) { |
| if (createDatabaseSchemas && databaseObjectDefinition.hasDatabaseSchema()) { |
| if (! dropDatabaseSchemas.containsKey(databaseObjectDefinition.getDatabaseSchema())) { |
| dropDatabaseSchemas.put(databaseObjectDefinition.getDatabaseSchema(), databaseObjectDefinition); |
| } |
| } |
| } |
| |
| /** |
| * Use the table definition to add the constraints to the database, this is normally done |
| * in two steps to avoid dependencies. |
| */ |
| public void createConstraints(TableDefinition tableDefinition) throws EclipseLinkException { |
| boolean usesBatchWriting = false; |
| |
| if (getSession().getPlatform().usesBatchWriting()) { |
| usesBatchWriting = true; |
| getSession().getPlatform().setUsesBatchWriting(false); |
| } |
| |
| try { |
| if (shouldWriteToDatabase()) { |
| tableDefinition.createConstraintsOnDatabase(getSession()); |
| } else { |
| tableDefinition.setCreateSQLFiles(createSQLFiles); |
| tableDefinition.createConstraints(getSession(), createSchemaWriter); |
| } |
| } finally { |
| if (usesBatchWriting) { |
| getSession().getPlatform().setUsesBatchWriting(true); |
| } |
| } |
| } |
| |
| void createUniqueConstraints(TableDefinition tableDefinition) throws EclipseLinkException { |
| if (shouldWriteToDatabase()) { |
| tableDefinition.createUniqueConstraintsOnDatabase(getSession()); |
| } else { |
| tableDefinition.setCreateSQLFiles(createSQLFiles); |
| tableDefinition.createUniqueConstraints(getSession(), createSchemaWriter); |
| } |
| } |
| |
| void createForeignConstraints(TableDefinition tableDefinition) throws EclipseLinkException { |
| if (shouldWriteToDatabase()) { |
| tableDefinition.createForeignConstraintsOnDatabase(getSession()); |
| } else { |
| tableDefinition.setCreateSQLFiles(createSQLFiles); |
| tableDefinition.createForeignConstraints(getSession(), createSchemaWriter); |
| } |
| } |
| |
| /** |
| * Use the definition object to create the schema entity on the database. |
| * This is used for creating tables, views, procedures ... etc ... |
| */ |
| public void createObject(DatabaseObjectDefinition databaseObjectDefinition) throws EclipseLinkException { |
| boolean usesBatchWriting = false; |
| |
| if (getSession().getPlatform().usesBatchWriting()) { |
| usesBatchWriting = true; |
| getSession().getPlatform().setUsesBatchWriting(false); |
| } |
| |
| try { |
| if (shouldWriteToDatabase()) { |
| // Check if we should create a database schema for this |
| // database object definition on the database. It is only |
| // create once and for the first database object definition |
| // that references it. |
| if (shouldCreateDatabaseSchema(databaseObjectDefinition, createdDatabaseSchemasOnDatabase)) { |
| databaseObjectDefinition.createDatabaseSchemaOnDatabase(getSession(), createdDatabaseSchemasOnDatabase); |
| } |
| |
| databaseObjectDefinition.createOnDatabase(getSession()); |
| } else { |
| // Check if we should create a database schema for this |
| // database object definition on the database. It is only |
| // create once and for the first database object definition |
| // that references it. |
| if (shouldCreateDatabaseSchema(databaseObjectDefinition, createdDatabaseSchemas)) { |
| databaseObjectDefinition.createDatabaseSchema(getSession(), createSchemaWriter, createdDatabaseSchemas); |
| appendToDDLWriter(createSchemaWriter, "\n"); |
| } |
| |
| databaseObjectDefinition.createObject(getSession(), createSchemaWriter); |
| if (createSQLFiles){ |
| this.appendToDDLWriter(createSchemaWriter, getSession().getPlatform().getStoredProcedureTerminationToken()); |
| } |
| this.appendToDDLWriter(createSchemaWriter, "\n"); |
| } |
| databaseObjectDefinition.postCreateObject(getSession(), createSchemaWriter, createSQLFiles); |
| } finally { |
| if (usesBatchWriting) { |
| getSession().getPlatform().setUsesBatchWriting(true); |
| } |
| } |
| } |
| |
| /** |
| * Create all the receiver's sequences on the database for all of the loaded descriptors. |
| */ |
| public void createSequences() throws EclipseLinkException { |
| createOrReplaceSequences(true); |
| } |
| |
| /** |
| * INTERNAL: |
| * Set to true if database schemas should be built during the DDL generation. |
| */ |
| public void setCreateDatabaseSchemas(boolean createDatabaseSchemas) { |
| this.createDatabaseSchemas = createDatabaseSchemas; |
| } |
| |
| public void setCreateSQLFiles(boolean genFlag) { |
| this.createSQLFiles = genFlag; |
| } |
| |
| /** |
| * Drop and recreate all the receiver's sequences on the database for all of the loaded descriptors. |
| */ |
| public void replaceSequences() throws EclipseLinkException { |
| createOrReplaceSequences(false); |
| } |
| |
| /** |
| * Common implementor for createSequence and replaceSequence |
| * @param create - true to create the sequences, false to replace them (dropped then create) |
| */ |
| protected void createOrReplaceSequences(boolean create) throws EclipseLinkException { |
| createOrReplaceSequences(create, create); |
| } |
| |
| /** |
| * Common implementor for createSequence and replaceSequence, distinguishes between sequence tables and sequence objects |
| * @param createSequenceTables - true to create the sequences tables, false to replace them (dropped then create) |
| * @param createSequences - true to create the sequences objects, false to replace them (dropped then create) |
| */ |
| protected void createOrReplaceSequences(boolean createSequenceTables, boolean createSequences) throws EclipseLinkException { |
| // PERF: Allow a special "fast" flag to be set on the session causes a delete from the table instead of a replace. |
| boolean fast = FAST_TABLE_CREATOR; |
| if (fast) { |
| // Assume sequences already created. |
| return; |
| } |
| |
| processSequenceDefinitions(createSequenceTables, createSequences, true); |
| } |
| |
| /** |
| * This will drop the database schemas if managing the database schemas. |
| */ |
| protected void dropSequences() { |
| processSequenceDefinitions(false, false, false); |
| } |
| |
| /** |
| * Method creates database tables/objects. If create is true, it will |
| * attempt to create the object and silently ignore exceptions. If create |
| * is false, it will drop the object ignoring any exceptions, then create |
| * it if the replace flag is true (otherwise a drop only). |
| * |
| * @param definition - the sequence definition |
| * @param createTables - true if table sequence table definitions should be created. |
| * @param createSequences - true if the sequence definition should be created, |
| * false if it should be dropped. |
| * @param replace - true if table definitions and sequence definitions should be replaced. |
| */ |
| protected void processSequenceDefinition(SequenceDefinition definition, final boolean createTables, final boolean createSequences, final boolean replace, Set<String> createdTableNames, Set<String> droppedTableNames) throws EclipseLinkException { |
| try { |
| // Handle the table definitions first. |
| if (definition.isTableSequenceDefinition()) { |
| TableDefinition tableDefinition = definition.buildTableDefinition(); |
| // Check that we haven't already created the table. |
| if (! createdTableNames.contains(tableDefinition.getFullName())) { |
| createdTableNames.add(tableDefinition.getFullName()); |
| |
| // Check if it exists on the database. NOTE: when writing to scripts only with |
| // no connection, this of course will always return false hence the need for |
| // the createdSequenceTableNames collection above. |
| boolean exists = checkTableExists(tableDefinition); |
| |
| if (createTables) { |
| // Don't create it if it already exists on the database. |
| // In all all other cases, write it out. |
| if ((shouldWriteToDatabase() && ! exists) || ! shouldWriteToDatabase()) { |
| createObject(tableDefinition); |
| } |
| } else { |
| // Don't check exists since if writing to scripts only with no connection, |
| // we'll never write the sql out. When executing to the database, the drop |
| // will fail and we'll ignore it. Note: TableSequenceDefinition's will drop |
| // their table definitions as needed (i.e.) when the jpa create database |
| // schemas flag is set and the table definition has a schema. Otherwise, |
| // we should not drop sequence tables since they may be re-used across |
| // persistence units (default behavior right now). |
| // TODO: We should drop them really unless it is the default SEQUENCE table?? |
| if (replace) { |
| dropObject(tableDefinition); |
| createObject(tableDefinition); |
| } |
| } |
| } |
| } |
| } catch (DatabaseException exception) { |
| // ignore any database exceptions here and keep going. |
| } |
| |
| // Handle the sequence objects second. |
| try { |
| if (createSequences) { |
| createObject(definition); |
| } else { |
| try { |
| // If the sequence definition has and will drop a table definition, then check |
| // if we have already dropped it. Table definitions are dropped as a whole if |
| // they have a schema name and the jpa create database schemas flag is set to true. |
| if (definition.isTableSequenceDefinition()) { |
| if (((TableSequenceDefinition) definition).shouldDropTableDefinition()) { |
| String tableDefinitionTableName = ((TableSequenceDefinition) definition).getSequenceTableName(); |
| |
| // If we have already dropped it, move on, otherwise drop it! |
| if (droppedTableNames.contains(tableDefinitionTableName)) { |
| return; // cut out early, we've already seen this table. |
| } else { |
| droppedTableNames.add(tableDefinitionTableName); |
| } |
| } |
| } |
| |
| dropObject(definition); |
| } catch (DatabaseException exception) { |
| // Ignore table not found for first creation |
| } |
| |
| // Drop only scripts we don't want to replace. |
| if (replace) { |
| createObject(definition); |
| } |
| } |
| } catch (Exception exception) { |
| // ignore any database exceptions here and keep chugging |
| } |
| } |
| |
| /** |
| * Common implementor for createSequence and replaceSequence, distinguishes between sequence tables and sequence objects |
| * @param createSequenceTables - true to create the sequences tables, false to replace them (dropped then create) |
| * @param createSequences - true to create the sequences objects, false to replace them (dropped then create) |
| * @param replaceSequences - true to actually replace, false to drop only. |
| */ |
| protected void processSequenceDefinitions(boolean createSequenceTables, boolean createSequences, boolean replaceSequences) throws EclipseLinkException { |
| Sequencing sequencing = getSession().getSequencing(); |
| |
| // Not required on Sybase native etc. |
| if (sequencing != null && sequencing.whenShouldAcquireValueForAll() != Sequencing.AFTER_INSERT) { |
| // Build the sequence definitions. |
| Set<SequenceDefinition> sequenceDefinitions = buildSequenceDefinitions(); |
| |
| // Now process the sequence definitions. |
| // CR 3870467, do not log stack |
| boolean shouldLogExceptionStackTrace = session.getSessionLog().shouldLogExceptionStackTrace(); |
| session.getSessionLog().setShouldLogExceptionStackTrace(false); |
| Set<String> createdSequenceTableNames = new HashSet<>(); |
| Set<String> droppedSequenceTableNames = new HashSet<>(); |
| |
| for (SequenceDefinition sequenceDefinition : sequenceDefinitions) { |
| processSequenceDefinition(sequenceDefinition, createSequenceTables, createSequences, replaceSequences, createdSequenceTableNames, droppedSequenceTableNames); |
| } |
| |
| // Set the log stack trace flag back. |
| session.getSessionLog().setShouldLogExceptionStackTrace(shouldLogExceptionStackTrace); |
| } |
| } |
| |
| /** |
| * INTERNAL: |
| * Build the sequence definitions. |
| */ |
| protected Set<SequenceDefinition> buildSequenceDefinitions() { |
| // Remember the processed - to handle each sequence just once. |
| Set<String> processedSequenceNames = new HashSet<>(); |
| Set<SequenceDefinition> sequenceDefinitions = new HashSet<>(); |
| |
| for (ClassDescriptor descriptor : getSession().getDescriptors().values()) { |
| if (descriptor.usesSequenceNumbers()) { |
| String seqName = descriptor.getSequenceNumberName(); |
| |
| if (seqName == null) { |
| seqName = getSession().getDatasourcePlatform().getDefaultSequence().getName(); |
| } |
| |
| if (! processedSequenceNames.contains(seqName)) { |
| processedSequenceNames.add(seqName); |
| |
| Sequence sequence = getSession().getDatasourcePlatform().getSequence(seqName); |
| SequenceDefinition sequenceDefinition = buildSequenceDefinition(sequence); |
| |
| if (sequenceDefinition != null) { |
| sequenceDefinitions.add(sequenceDefinition); |
| } |
| } |
| } |
| } |
| |
| return sequenceDefinitions; |
| } |
| |
| /** |
| * Check if the table exists by issuing a query. |
| * @param table database table meta-data |
| * @param suppressLogging whether to suppress logging during query execution |
| * @return value of {@code true} if given table exists or {@code false} otherwise |
| */ |
| public boolean checkTableExists(TableDefinition table, final boolean suppressLogging) { |
| final boolean loggingOff = session.isLoggingOff(); |
| try { |
| return session.getPlatform().checkTableExists(session, table, suppressLogging); |
| } finally { |
| session.setLoggingOff(loggingOff); |
| } |
| } |
| |
| /** |
| * Check if the table exists by issuing a query. |
| * Logging is suppressed during query execution. |
| * @param table database table meta-data |
| * @return value of {@code true} if given table exists or {@code false} otherwise |
| */ |
| public boolean checkTableExists(TableDefinition table) { |
| return checkTableExists(table, true); |
| } |
| |
| protected SequenceDefinition buildSequenceDefinition(Sequence sequence) { |
| if (sequence.shouldAcquireValueAfterInsert()) { |
| return null; |
| } |
| if (sequence instanceof TableSequence || |
| (sequence instanceof DefaultSequence && ((DefaultSequence)sequence).getDefaultSequence() instanceof TableSequence)) { |
| return new TableSequenceDefinition(sequence, createDatabaseSchemas); |
| } else if (sequence instanceof UnaryTableSequence || |
| (sequence instanceof DefaultSequence && ((DefaultSequence)sequence).getDefaultSequence() instanceof UnaryTableSequence)) { |
| return new UnaryTableSequenceDefinition(sequence, createDatabaseSchemas); |
| } else if (sequence instanceof NativeSequence || |
| (sequence instanceof DefaultSequence && ((DefaultSequence)sequence).getDefaultSequence() instanceof NativeSequence)) { |
| NativeSequence nativeSequence = null; |
| if (sequence instanceof NativeSequence) { |
| nativeSequence = (NativeSequence)sequence; |
| } else { |
| nativeSequence = (NativeSequence)((DefaultSequence)sequence).getDefaultSequence(); |
| } |
| if (nativeSequence.hasDelegateSequence()) { |
| return buildSequenceDefinition(((NativeSequence)sequence).getDelegateSequence()); |
| } |
| return new SequenceObjectDefinition(sequence); |
| } else { |
| return null; |
| } |
| } |
| |
| /** |
| * Use the table definition to drop the constraints from the table, this is normally done |
| * in two steps to avoid dependencies. |
| */ |
| public void dropConstraints(TableDefinition tableDefinition) throws EclipseLinkException { |
| boolean usesBatchWriting = false; |
| |
| if (getSession().getPlatform().usesBatchWriting()) { |
| usesBatchWriting = true; |
| getSession().getPlatform().setUsesBatchWriting(false); |
| } |
| |
| try { |
| if (shouldWriteToDatabase()) { |
| tableDefinition.dropConstraintsOnDatabase(getSession()); |
| } else { |
| tableDefinition.setCreateSQLFiles(createSQLFiles); |
| tableDefinition.dropConstraints(getSession(), getDropSchemaWriter()); |
| } |
| } finally { |
| if (usesBatchWriting) { |
| getSession().getPlatform().setUsesBatchWriting(true); |
| } |
| } |
| } |
| |
| /** |
| * Use the definition object to drop the schema entity from the database. |
| * This is used for dropping tables, views, procedures ... etc ... |
| */ |
| public void dropObject(DatabaseObjectDefinition databaseObjectDefinition) throws EclipseLinkException { |
| boolean usesBatchWriting = false; |
| |
| if (getSession().getPlatform().usesBatchWriting()) { |
| usesBatchWriting = true; |
| getSession().getPlatform().setUsesBatchWriting(false); |
| } |
| |
| try { |
| // If the object definition has a database schema collect it. |
| collectDatabaseSchemasForDrop(databaseObjectDefinition); |
| |
| databaseObjectDefinition.preDropObject(getSession(), getDropSchemaWriter(), this.createSQLFiles); |
| if (shouldWriteToDatabase()) { |
| // drop actual object |
| databaseObjectDefinition.dropFromDatabase(getSession()); |
| } else { |
| Writer dropSchemaWriter = getDropSchemaWriter(); |
| |
| // drop actual object |
| databaseObjectDefinition.dropObject(getSession(), dropSchemaWriter, createSQLFiles); |
| if (this.createSQLFiles){ |
| this.appendToDDLWriter(dropSchemaWriter, getSession().getPlatform().getStoredProcedureTerminationToken()); |
| } |
| this.appendToDDLWriter(dropSchemaWriter, "\n"); |
| } |
| } finally { |
| if (usesBatchWriting) { |
| getSession().getPlatform().setUsesBatchWriting(true); |
| } |
| } |
| } |
| |
| /** |
| * Drop (delete) the table named tableName from the database. |
| */ |
| public void dropTable(String tableName) throws EclipseLinkException { |
| TableDefinition tableDefinition; |
| |
| tableDefinition = new TableDefinition(); |
| tableDefinition.setName(tableName); |
| dropObject(tableDefinition); |
| } |
| |
| /** |
| * INTERNAL: |
| * Close the schema writer when the schema manger is garbage collected |
| */ |
| @Override |
| public void finalize() { |
| try { |
| this.closeDDLWriter(); |
| } catch (ValidationException exception) { |
| // do nothing |
| } |
| } |
| |
| /** |
| * PUBLIC: |
| * Use this method to generate stored procedures based on the dynamic SQL generated |
| * for your mappings and descriptors. This should be used with caution as it maintenance |
| * will be high. Stored procedures may be generated either directly on the database |
| * or to a file. |
| */ |
| public void generateStoredProcedures() throws EclipseLinkException { |
| new StoredProcedureGenerator(this).generateStoredProcedures(); |
| } |
| |
| /** |
| * PUBLIC: |
| * Use this method to generate stored procedures based on the dynamic SQL generated |
| * for your mappings and descriptors. This should be used with caution as it maintenance |
| * will be high. Stored procedures may be generated either directly on the database |
| * or to a file. |
| */ |
| public void generateStoredProcedures(Writer writer) throws EclipseLinkException { |
| new StoredProcedureGenerator(this).generateStoredProcedures(writer); |
| } |
| |
| /** |
| * PUBLIC: |
| * Use this method to generate stored procedures based on the dynamic SQL generated |
| * for your mappings and descriptors. This should be used with caution as it maintenance |
| * will be high. Stored procedures may be generated either directly on the database |
| * or to a file. |
| */ |
| public void generateStoredProceduresAndAmendmentClass(Writer writer, String fullyQualifiedClassName) throws EclipseLinkException { |
| String className = fullyQualifiedClassName.substring(fullyQualifiedClassName.lastIndexOf('.') + 1); |
| String packageName = fullyQualifiedClassName.substring(0, fullyQualifiedClassName.lastIndexOf('.')); |
| StoredProcedureGenerator storedProcedureGenerator = new StoredProcedureGenerator(this); |
| storedProcedureGenerator.generateStoredProcedures(); |
| |
| storedProcedureGenerator.generateAmendmentClass(writer, packageName, className); |
| } |
| |
| /** |
| * PUBLIC: |
| * Use this method to generate stored procedures based on the dynamic SQL generated |
| * for your mappings and descriptors. This should be used with caution as it maintenance |
| * will be high. Stored procedures may be generated either directly on the database |
| * or to a file. |
| */ |
| public void generateStoredProceduresAndAmendmentClass(String path, String fullyQualifiedClassName) throws EclipseLinkException { |
| java.io.FileWriter fileWriter = null; |
| try { |
| StoredProcedureGenerator storedProcedureGenerator = new StoredProcedureGenerator(this); |
| |
| if (!(path.endsWith("\\") || path.endsWith("/"))) { |
| path = path + "\\"; |
| } |
| |
| String className = fullyQualifiedClassName.substring(fullyQualifiedClassName.lastIndexOf('.') + 1); |
| String packageName = fullyQualifiedClassName.substring(0, fullyQualifiedClassName.lastIndexOf('.')); |
| String fileName = path + className + ".java"; |
| fileWriter = new java.io.FileWriter(fileName); |
| storedProcedureGenerator.generateStoredProcedures(); |
| storedProcedureGenerator.generateAmendmentClass(fileWriter, packageName, className); |
| fileWriter.close(); |
| } catch (java.io.IOException ioException) { |
| throw ValidationException.fileError(ioException); |
| } finally { |
| Helper.close(fileWriter); |
| } |
| } |
| |
| /** |
| * Return the appropriate accessor. |
| * Assume we are dealing with a JDBC accessor. |
| */ |
| protected DatabaseAccessor getAccessor() { |
| return (DatabaseAccessor) getSession().getAccessor(); |
| } |
| |
| /** |
| * Get a description of table columns available in a catalog. |
| * |
| * <P>Each column description has the following columns: |
| * <OL> |
| * <LI><B>TABLE_CAT</B> String {@literal =>} table catalog (may be null) |
| * <LI><B>TABLE_SCHEM</B> String {@literal =>} table schema (may be null) |
| * <LI><B>TABLE_NAME</B> String {@literal =>} table name |
| * <LI><B>COLUMN_NAME</B> String {@literal =>} column name |
| * <LI><B>DATA_TYPE</B> short {@literal =>} SQL type from java.sql.Types |
| * <LI><B>TYPE_NAME</B> String {@literal =>} Data source dependent type name |
| * <LI><B>COLUMN_SIZE</B> int {@literal =>} column size. For char or date |
| * types this is the maximum number of characters, for numeric or |
| * decimal types this is precision. |
| * <LI><B>BUFFER_LENGTH</B> is not used. |
| * <LI><B>DECIMAL_DIGITS</B> int {@literal =>} the number of fractional digits |
| * <LI><B>NUM_PREC_RADIX</B> int {@literal =>} Radix (typically either 10 or 2) |
| * <LI><B>NULLABLE</B> int {@literal =>} is NULL allowed? |
| * <UL> |
| * <LI> columnNoNulls - might not allow NULL values |
| * <LI> columnNullable - definitely allows NULL values |
| * <LI> columnNullableUnknown - nullability unknown |
| * </UL> |
| * <LI><B>REMARKS</B> String {@literal =>} comment describing column (may be null) |
| * <LI><B>COLUMN_DEF</B> String {@literal =>} default value (may be null) |
| * <LI><B>SQL_DATA_TYPE</B> int {@literal =>} unused |
| * <LI><B>SQL_DATETIME_SUB</B> int {@literal =>} unused |
| * <LI><B>CHAR_OCTET_LENGTH</B> int {@literal =>} for char types the |
| * maximum number of bytes in the column |
| * <LI><B>ORDINAL_POSITION</B> int {@literal =>} index of column in table |
| * (starting at 1) |
| * <LI><B>IS_NULLABLE</B> String {@literal =>} "NO" means column definitely |
| * does not allow NULL values; "YES" means the column might |
| * allow NULL values. An empty string means nobody knows. |
| * </OL> |
| * |
| * @param tableName a table name pattern |
| * @return a Vector of Records. |
| */ |
| public Vector getAllColumnNames(String tableName) throws DatabaseException { |
| return getAccessor().getColumnInfo(null, null, tableName, null, getSession()); |
| } |
| |
| /** |
| * Get a description of table columns available in a catalog. |
| * |
| * <P>Each column description has the following columns: |
| * <OL> |
| * <LI><B>TABLE_CAT</B> String {@literal =>} table catalog (may be null) |
| * <LI><B>TABLE_SCHEM</B> String {@literal =>} table schema (may be null) |
| * <LI><B>TABLE_NAME</B> String {@literal =>} table name |
| * <LI><B>COLUMN_NAME</B> String {@literal =>} column name |
| * <LI><B>DATA_TYPE</B> short {@literal =>} SQL type from java.sql.Types |
| * <LI><B>TYPE_NAME</B> String {@literal =>} Data source dependent type name |
| * <LI><B>COLUMN_SIZE</B> int {@literal =>} column size. For char or date |
| * types this is the maximum number of characters, for numeric or |
| * decimal types this is precision. |
| * <LI><B>BUFFER_LENGTH</B> is not used. |
| * <LI><B>DECIMAL_DIGITS</B> int {@literal =>} the number of fractional digits |
| * <LI><B>NUM_PREC_RADIX</B> int {@literal =>} Radix (typically either 10 or 2) |
| * <LI><B>NULLABLE</B> int {@literal =>} is NULL allowed? |
| * <UL> |
| * <LI> columnNoNulls - might not allow NULL values |
| * <LI> columnNullable - definitely allows NULL values |
| * <LI> columnNullableUnknown - nullability unknown |
| * </UL> |
| * <LI><B>REMARKS</B> String {@literal =>} comment describing column (may be null) |
| * <LI><B>COLUMN_DEF</B> String {@literal =>} default value (may be null) |
| * <LI><B>SQL_DATA_TYPE</B> int {@literal =>} unused |
| * <LI><B>SQL_DATETIME_SUB</B> int {@literal =>} unused |
| * <LI><B>CHAR_OCTET_LENGTH</B> int {@literal =>} for char types the |
| * maximum number of bytes in the column |
| * <LI><B>ORDINAL_POSITION</B> int {@literal =>} index of column in table |
| * (starting at 1) |
| * <LI><B>IS_NULLABLE</B> String {@literal =>} "NO" means column definitely |
| * does not allow NULL values; "YES" means the column might |
| * allow NULL values. An empty string means nobody knows. |
| * </OL> |
| * |
| * @param creatorName a schema name pattern; "" retrieves those |
| * without a schema |
| * @param tableName a table name pattern |
| * @return a Vector of Records. |
| */ |
| public Vector getAllColumnNames(String creatorName, String tableName) throws DatabaseException { |
| return getAccessor().getColumnInfo(null, creatorName, tableName, null, getSession()); |
| } |
| |
| /** |
| * Get a description of tables available in a catalog. |
| * |
| * <P>Each table description has the following columns: |
| * <OL> |
| * <LI><B>TABLE_CAT</B> String {@literal =>} table catalog (may be null) |
| * <LI><B>TABLE_SCHEM</B> String {@literal =>} table schema (may be null) |
| * <LI><B>TABLE_NAME</B> String {@literal =>} table name |
| * <LI><B>TABLE_TYPE</B> String {@literal =>} table type. Typical types are "TABLE", |
| * "VIEW", "SYSTEM TABLE", "GLOBAL TEMPORARY", |
| * "LOCAL TEMPORARY", "ALIAS", "SYNONYM". |
| * <LI><B>REMARKS</B> String {@literal =>} explanatory comment on the table |
| * </OL> |
| * |
| * <P><B>Note:</B> Some databases may not return information for |
| * all tables. |
| * |
| * @return a Vector of Records. |
| */ |
| public Vector getAllTableNames() throws DatabaseException { |
| return getAccessor().getTableInfo(null, null, null, null, getSession()); |
| } |
| |
| /** |
| * Get a description of table columns available in a catalog. |
| * |
| * <P>Each column description has the following columns: |
| * <OL> |
| * <LI><B>TABLE_CAT</B> String {@literal =>} table catalog (may be null) |
| * <LI><B>TABLE_SCHEM</B> String {@literal =>} table schema (may be null) |
| * <LI><B>TABLE_NAME</B> String {@literal =>} table name |
| * <LI><B>COLUMN_NAME</B> String {@literal =>} column name |
| * <LI><B>DATA_TYPE</B> short {@literal =>} SQL type from java.sql.Types |
| * <LI><B>TYPE_NAME</B> String {@literal =>} Data source dependent type name |
| * <LI><B>COLUMN_SIZE</B> int {@literal =>} column size. For char or date |
| * types this is the maximum number of characters, for numeric or |
| * decimal types this is precision. |
| * <LI><B>BUFFER_LENGTH</B> is not used. |
| * <LI><B>DECIMAL_DIGITS</B> int {@literal =>} the number of fractional digits |
| * <LI><B>NUM_PREC_RADIX</B> int {@literal =>} Radix (typically either 10 or 2) |
| * <LI><B>NULLABLE</B> int {@literal =>} is NULL allowed? |
| * <UL> |
| * <LI> columnNoNulls - might not allow NULL values |
| * <LI> columnNullable - definitely allows NULL values |
| * <LI> columnNullableUnknown - nullability unknown |
| * </UL> |
| * <LI><B>REMARKS</B> String {@literal =>} comment describing column (may be null) |
| * <LI><B>COLUMN_DEF</B> String {@literal =>} default value (may be null) |
| * <LI><B>SQL_DATA_TYPE</B> int {@literal =>} unused |
| * <LI><B>SQL_DATETIME_SUB</B> int {@literal =>} unused |
| * <LI><B>CHAR_OCTET_LENGTH</B> int {@literal =>} for char types the |
| * maximum number of bytes in the column |
| * <LI><B>ORDINAL_POSITION</B> int {@literal =>} index of column in table |
| * (starting at 1) |
| * <LI><B>IS_NULLABLE</B> String {@literal =>} "NO" means column definitely |
| * does not allow NULL values; "YES" means the column might |
| * allow NULL values. An empty string means nobody knows. |
| * </OL> |
| * |
| * @param creatorName a schema name pattern; "" retrieves those |
| * without a schema |
| * @return a Vector of Records. |
| */ |
| public Vector getAllTableNames(String creatorName) throws DatabaseException { |
| return getAccessor().getTableInfo(null, creatorName, null, null, getSession()); |
| } |
| |
| /** |
| * Get a description of table columns available in a catalog. |
| * |
| * <P>Only column descriptions matching the catalog, schema, table |
| * and column name criteria are returned. They are ordered by |
| * TABLE_SCHEM, TABLE_NAME and ORDINAL_POSITION. |
| * |
| * <P>Each column description has the following columns: |
| * <OL> |
| * <LI><B>TABLE_CAT</B> String {@literal =>} table catalog (may be null) |
| * <LI><B>TABLE_SCHEM</B> String {@literal =>} table schema (may be null) |
| * <LI><B>TABLE_NAME</B> String {@literal =>} table name |
| * <LI><B>COLUMN_NAME</B> String {@literal =>} column name |
| * <LI><B>DATA_TYPE</B> short {@literal =>} SQL type from java.sql.Types |
| * <LI><B>TYPE_NAME</B> String {@literal =>} Data source dependent type name |
| * <LI><B>COLUMN_SIZE</B> int {@literal =>} column size. For char or date |
| * types this is the maximum number of characters, for numeric or |
| * decimal types this is precision. |
| * <LI><B>BUFFER_LENGTH</B> is not used. |
| * <LI><B>DECIMAL_DIGITS</B> int {@literal =>} the number of fractional digits |
| * <LI><B>NUM_PREC_RADIX</B> int {@literal =>} Radix (typically either 10 or 2) |
| * <LI><B>NULLABLE</B> int {@literal =>} is NULL allowed? |
| * <UL> |
| * <LI> columnNoNulls - might not allow NULL values |
| * <LI> columnNullable - definitely allows NULL values |
| * <LI> columnNullableUnknown - nullability unknown |
| * </UL> |
| * <LI><B>REMARKS</B> String {@literal =>} comment describing column (may be null) |
| * <LI><B>COLUMN_DEF</B> String {@literal =>} default value (may be null) |
| * <LI><B>SQL_DATA_TYPE</B> int {@literal =>} unused |
| * <LI><B>SQL_DATETIME_SUB</B> int {@literal =>} unused |
| * <LI><B>CHAR_OCTET_LENGTH</B> int {@literal =>} for char types the |
| * maximum number of bytes in the column |
| * <LI><B>ORDINAL_POSITION</B> int {@literal =>} index of column in table |
| * (starting at 1) |
| * <LI><B>IS_NULLABLE</B> String {@literal =>} "NO" means column definitely |
| * does not allow NULL values; "YES" means the column might |
| * allow NULL values. An empty string means nobody knows. |
| * </OL> |
| * |
| * @param catalog a catalog name; "" retrieves those without a |
| * catalog; null means drop catalog name from the selection criteria |
| * @param schema a schema name pattern; "" retrieves those |
| * without a schema |
| * @param tableName a table name pattern |
| * @param columnName a column name pattern |
| * @return a Vector of Records. |
| */ |
| public Vector getColumnInfo(String catalog, String schema, String tableName, String columnName) throws DatabaseException { |
| return getAccessor().getColumnInfo(catalog, schema, tableName, columnName, getSession()); |
| } |
| |
| public AbstractSession getSession() { |
| return session; |
| } |
| |
| /** |
| * Get a description of tables available in a catalog. |
| * |
| * <P>Only table descriptions matching the catalog, schema, table |
| * name and type criteria are returned. They are ordered by |
| * TABLE_TYPE, TABLE_SCHEM and TABLE_NAME. |
| * |
| * <P>Each table description has the following columns: |
| * <OL> |
| * <LI><B>TABLE_CAT</B> String {@literal =>} table catalog (may be null) |
| * <LI><B>TABLE_SCHEM</B> String {@literal =>} table schema (may be null) |
| * <LI><B>TABLE_NAME</B> String {@literal =>} table name |
| * <LI><B>TABLE_TYPE</B> String {@literal =>} table type. Typical types are "TABLE", |
| * "VIEW", "SYSTEM TABLE", "GLOBAL TEMPORARY", |
| * "LOCAL TEMPORARY", "ALIAS", "SYNONYM". |
| * <LI><B>REMARKS</B> String {@literal =>} explanatory comment on the table |
| * </OL> |
| * |
| * <P><B>Note:</B> Some databases may not return information for |
| * all tables. |
| * |
| * @param catalog a catalog name; "" retrieves those without a |
| * catalog; null means drop catalog name from the selection criteria |
| * @param schema a schema name pattern; "" retrieves those |
| * without a schema |
| * @param tableName a table name pattern |
| * @param types a list of table types to include; null returns all types |
| * @return a Vector of Records. |
| */ |
| public Vector getTableInfo(String catalog, String schema, String tableName, String[] types) throws DatabaseException { |
| return getAccessor().getTableInfo(catalog, schema, tableName, types, getSession()); |
| } |
| |
| /** |
| * PUBLIC: |
| * Output all DDL statements directly to the database. |
| */ |
| public void outputDDLToDatabase() { |
| this.createSchemaWriter = null; |
| this.dropSchemaWriter = null; |
| } |
| |
| /** |
| * PUBLIC: |
| * Output all DDL statements to a file writer specified by the name in the parameter. |
| */ |
| public void outputDDLToFile(String fileName) { |
| this.createSchemaWriter = getWriter(fileName); |
| } |
| |
| public void outputCreateDDLToFile(String fileName) { |
| this.createSchemaWriter = getWriter(fileName); |
| } |
| |
| public void outputDropDDLToFile(String fileName) { |
| this.dropSchemaWriter = getWriter(fileName); |
| } |
| |
| protected Writer getWriter(String fileName) { |
| try { |
| return new java.io.FileWriter(fileName); |
| } catch (java.io.IOException ioException) { |
| // Try a url next, otherwise throw the existing error. |
| try { |
| URL url = new URL(fileName); |
| return new java.io.FileWriter(url.getFile()); |
| } catch (Exception e) { |
| // MalformedURLException and IOException |
| throw ValidationException.fileError(ioException); |
| } |
| } |
| } |
| |
| /** |
| * PUBLIC: |
| * Output all DDL statements to a writer specified in the parameter. |
| */ |
| public void outputDDLToWriter(Writer schemaWriter) { |
| this.createSchemaWriter = schemaWriter; |
| } |
| |
| public void outputCreateDDLToWriter(Writer createWriter) { |
| this.createSchemaWriter = createWriter; |
| } |
| |
| public void outputDropDDLToWriter(Writer dropWriter) { |
| this.dropSchemaWriter = dropWriter; |
| } |
| |
| /** |
| * Use the definition object to drop and recreate the schema entity on the database. |
| * This is used for dropping tables, views, procedures ... etc ... |
| * This handles and ignore any database error while dropping in case the object did not previously exist. |
| */ |
| public void replaceObject(DatabaseObjectDefinition databaseDefinition) throws EclipseLinkException { |
| // PERF: Allow a special "fast" flag to be set on the session causes a delete from the table instead of a replace. |
| boolean fast = FAST_TABLE_CREATOR; |
| if (fast && (databaseDefinition instanceof TableDefinition)) { |
| session.executeNonSelectingSQL("DELETE FROM " + databaseDefinition.getName()); |
| } else if (fast && (databaseDefinition instanceof StoredProcedureDefinition)) { |
| // do nothing |
| } else { |
| // CR 3870467, do not log stack |
| boolean shouldLogExceptionStackTrace = getSession().getSessionLog().shouldLogExceptionStackTrace(); |
| |
| if (shouldLogExceptionStackTrace) { |
| getSession().getSessionLog().setShouldLogExceptionStackTrace(false); |
| } |
| try { |
| dropObject(databaseDefinition); |
| } catch (DatabaseException exception) { |
| // Ignore error |
| } finally { |
| if (shouldLogExceptionStackTrace) { |
| getSession().getSessionLog().setShouldLogExceptionStackTrace(true); |
| } |
| } |
| |
| createObject(databaseDefinition); |
| } |
| } |
| |
| /** |
| * Construct the default TableCreator. |
| * If the default TableCreator is already created, just returns it. |
| */ |
| protected TableCreator getDefaultTableCreator(boolean generateFKConstraints) { |
| if(defaultTableCreator == null) { |
| defaultTableCreator = new DefaultTableGenerator(session.getProject(),generateFKConstraints).generateDefaultTableCreator(); |
| defaultTableCreator.setIgnoreDatabaseException(true); |
| } |
| return defaultTableCreator; |
| } |
| |
| /** |
| * Create the default table schema for the project this session associated with. |
| */ |
| public void createDefaultTables(boolean generateFKConstraints) { |
| //Create each table w/o throwing exception and/or exit if some of them are already existed in the db. |
| //If a table is already existed, skip the creation. |
| |
| boolean shouldLogExceptionStackTrace = getSession().getSessionLog().shouldLogExceptionStackTrace(); |
| getSession().getSessionLog().setShouldLogExceptionStackTrace(false); |
| |
| try { |
| TableCreator tableCreator = getDefaultTableCreator(generateFKConstraints); |
| tableCreator.createTables(this.session, this); |
| } catch (DatabaseException ex) { |
| // Ignore error |
| } finally { |
| getSession().getSessionLog().setShouldLogExceptionStackTrace(shouldLogExceptionStackTrace); |
| } |
| // Reset database change events to new tables. |
| if (this.session.getDatabaseEventListener() != null) { |
| this.session.getDatabaseEventListener().remove(this.session); |
| this.session.getDatabaseEventListener().register(this.session); |
| } |
| } |
| |
| /** |
| * INTERNAL: |
| * Iterate over the schemas that need to be dropped. |
| */ |
| public void dropDatabaseSchemas() { |
| for (DatabaseObjectDefinition dod : dropDatabaseSchemas.values()) { |
| if (shouldWriteToDatabase()) { |
| dod.dropDatabaseSchemaOnDatabase(getSession()); |
| } else { |
| dod.dropDatabaseSchema(getSession(), getDropSchemaWriter()); |
| appendToDDLWriter(getDropSchemaWriter(), "\n"); |
| } |
| } |
| } |
| |
| /** |
| * Create the default table schema for the project this session associated with. |
| */ |
| public void dropDefaultTables() { |
| // Drop each table w/o throwing exception and/or exit if some don't exist. |
| boolean shouldLogExceptionStackTrace = getSession().getSessionLog().shouldLogExceptionStackTrace(); |
| getSession().getSessionLog().setShouldLogExceptionStackTrace(false); |
| |
| try { |
| // Drop the tables. |
| TableCreator tableCreator = getDefaultTableCreator(true); |
| tableCreator.dropTables(this.session, this); |
| |
| // Drop the sequences. |
| dropSequences(); |
| |
| // Drop all the database schemas now if set to do so. This must be |
| // called after all the constraints, tables etc. are dropped. |
| dropDatabaseSchemas(); |
| } catch (DatabaseException ex) { |
| // Ignore error |
| } finally { |
| getSession().getSessionLog().setShouldLogExceptionStackTrace(shouldLogExceptionStackTrace); |
| } |
| // Reset database change events to new tables. |
| if (this.session.getDatabaseEventListener() != null) { |
| this.session.getDatabaseEventListener().remove(this.session); |
| this.session.getDatabaseEventListener().register(this.session); |
| } |
| } |
| |
| /** |
| * Drop and recreate the default table schema for the project this session associated with. |
| */ |
| public void replaceDefaultTables() throws EclipseLinkException { |
| replaceDefaultTables(true, true, true); |
| } |
| |
| /** |
| * Drop and recreate the default table schema for the project this session associated with. |
| */ |
| public void replaceDefaultTables(boolean createSequenceTables, boolean generateFKConstraints) throws EclipseLinkException { |
| replaceDefaultTables(createSequenceTables, false, generateFKConstraints); |
| } |
| |
| /** |
| * Drop and recreate the default table schema for the project this session associated with. |
| */ |
| public void replaceDefaultTables(boolean createSequenceTables, boolean createSequences, boolean generateFKConstraints) throws EclipseLinkException { |
| boolean shouldLogExceptionStackTrace = getSession().getSessionLog().shouldLogExceptionStackTrace(); |
| this.session.getSessionLog().setShouldLogExceptionStackTrace(false); |
| |
| try { |
| TableCreator tableCreator = getDefaultTableCreator(generateFKConstraints); |
| tableCreator.replaceTables(this.session, this, createSequenceTables, createSequences); |
| |
| // Drop all the database schemas now if set to do so. This must be |
| // called after all the constraints, tables etc. are dropped. |
| dropDatabaseSchemas(); |
| } catch (DatabaseException exception) { |
| // Ignore error |
| } finally { |
| this.session.getSessionLog().setShouldLogExceptionStackTrace(shouldLogExceptionStackTrace); |
| } |
| // Reset database change events to new tables. |
| if (this.session.getDatabaseEventListener() != null) { |
| this.session.getDatabaseEventListener().remove(this.session); |
| this.session.getDatabaseEventListener().register(this.session); |
| } |
| } |
| |
| public void setSession(DatabaseSessionImpl session) { |
| this.session = session; |
| } |
| |
| /** |
| * INTERNAL: |
| * Returns true if a database schema should be created during ddl generation |
| * for the given databaseObjectDefinition. |
| */ |
| protected boolean shouldCreateDatabaseSchema(DatabaseObjectDefinition databaseObjectDefinition, Set<String> createdDatabaseSchemas) { |
| return (createDatabaseSchemas && databaseObjectDefinition.shouldCreateDatabaseSchema(createdDatabaseSchemas)); |
| } |
| |
| /** |
| * PUBLIC: |
| * Return true if this SchemaManager should write to the database directly |
| */ |
| public boolean shouldWriteToDatabase() { |
| return ((this.createSchemaWriter == null) && (this.dropSchemaWriter == null)); |
| } |
| |
| /** |
| * Use the definition to alter sequence. |
| */ |
| public void alterSequence(SequenceDefinition sequenceDefinition) throws EclipseLinkException { |
| if (!sequenceDefinition.isAlterSupported(getSession())) { |
| return; |
| } |
| |
| boolean usesBatchWriting = false; |
| |
| if (getSession().getPlatform().usesBatchWriting()) { |
| usesBatchWriting = true; |
| getSession().getPlatform().setUsesBatchWriting(false); |
| } |
| |
| try { |
| if (shouldWriteToDatabase()) { |
| sequenceDefinition.alterOnDatabase(getSession()); |
| } else { |
| sequenceDefinition.alter(getSession(), createSchemaWriter); |
| } |
| } finally { |
| if (usesBatchWriting) { |
| getSession().getPlatform().setUsesBatchWriting(true); |
| } |
| } |
| } |
| |
| /** |
| * Create or extend the default table schema for the project this session associated with. |
| */ |
| public void extendDefaultTables(boolean generateFKConstraints) throws EclipseLinkException { |
| boolean shouldLogExceptionStackTrace = getSession().getSessionLog().shouldLogExceptionStackTrace(); |
| this.session.getSessionLog().setShouldLogExceptionStackTrace(false); |
| |
| try { |
| TableCreator tableCreator = getDefaultTableCreator(generateFKConstraints); |
| tableCreator.extendTables(this.session, this); |
| } catch (DatabaseException exception) { |
| // Ignore error |
| } finally { |
| this.session.getSessionLog().setShouldLogExceptionStackTrace(shouldLogExceptionStackTrace); |
| } |
| // Reset database change events to new tables. |
| if (this.session.getDatabaseEventListener() != null) { |
| this.session.getDatabaseEventListener().remove(this.session); |
| this.session.getDatabaseEventListener().register(this.session); |
| } |
| } |
| |
| } |