/* * Copyright 2007 - 2017 the original author or authors. * * 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 * * 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. * See the License for the specific language governing permissions and * limitations under the License. */ package net.sf.jailer.database; import java.io.IOException; import java.io.InputStream; import java.io.OutputStreamWriter; import java.io.Reader; import java.sql.Blob; import java.sql.Clob; import java.sql.Date; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.SQLXML; import java.sql.Timestamp; import java.sql.Types; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import net.sf.jailer.ExecutionContext; import net.sf.jailer.configuration.DBMS; import net.sf.jailer.database.Session.AbstractResultSetReader; import net.sf.jailer.database.Session.ResultSetReader; import net.sf.jailer.datamodel.Column; import net.sf.jailer.datamodel.Filter; import net.sf.jailer.datamodel.Table; import net.sf.jailer.subsetting.TransformerFactory; import net.sf.jailer.util.Base64; import net.sf.jailer.util.CellContentConverter; import net.sf.jailer.util.Quoting; import net.sf.jailer.util.SqlScriptExecutor; import net.sf.jailer.util.SqlUtil; /** * A {@link ResultSetReader} that writes the read rows as DML-statements * into the export-script. * * @author Ralf Wisser */ public class DMLTransformer extends AbstractResultSetReader { /** * The table to read from. */ private final Table table; /** * The file to write to. */ private final OutputStreamWriter scriptFileWriter; /** * Number of columns. */ private int columnCount; /** * Labels of columns. */ private String[] columnLabel = null; /** * Lob columns. */ private List<String> lobColumns = null; private boolean[] isLobColumn; /** * Literals for empty lob values. */ private String[] emptyLobValue = null; /** * Whether or not the table has columns of type CLOB or BLOB. */ private boolean tableHasLobs = false; /** * Lob columns indexes. */ private List<Integer> lobColumnIndexes = null; /** * Labels of columns as comma separated list. */ private String labelCSL; /** * For building compact insert-statements. */ private final StatementBuilder insertStatementBuilder; /** * For building compact insert-parts of upsert-statements. */ private Map<String, StatementBuilder> upsertInsertStatementBuilder = new HashMap<String, StatementBuilder>(); /** * Whether to create INSERTs or UPSERTS for all entities. */ private final boolean upsertOnly; /** * Maximum length of SQL values list (for generated inserts). */ private final int maxBodySize; /** * Counts the exported LOBs. (GUI support) */ public static long numberOfExportedLOBs; /** * For quoting of column names. */ protected final Quoting quoting; /** * If table has identity column (MSSQL/Sybase) */ private boolean tableHasIdentityColumn; /** * Current session; */ private final Session session; /** * Configuration of the target DBMS. */ private final DBMS targetDBMSConfiguration; /** * SQL Dialect. */ private final SQLDialect currentDialect; /** * The execution context. */ private final ExecutionContext executionContext; /** * Transforms {@link Filter} into SQL-expressions. */ private final ImportFilterTransformer importFilterTransformer; /** * Factory. */ public static class Factory implements TransformerFactory { private final int maxBodySize; private final boolean upsertOnly; private final OutputStreamWriter scriptFileWriter; private final Session session; private final DBMS targetDBMSConfiguration; private ImportFilterTransformer importFilterTransformer; /** * The execution context. */ private final ExecutionContext executionContext; /** * Constructor. * * @param scriptFileWriter the file to write to * @param maxBodySize maximum length of SQL values list (for generated inserts) * @param upsertOnly use 'upsert' statements for all entities */ public Factory(OutputStreamWriter scriptFileWriter, boolean upsertOnly, int maxBodySize, Session session, DBMS targetDBMSConfiguration, ExecutionContext executionContext) { this.maxBodySize = maxBodySize; this.upsertOnly = upsertOnly; this.scriptFileWriter = scriptFileWriter; this.session = session; this.targetDBMSConfiguration = targetDBMSConfiguration; this.executionContext = executionContext; } /** * Creates transformer (as {@link ResultSetReader} which * transforms rows of a given table into an external representation. * * @param table the table * @return a transformer */ @Override public ResultSetReader create(Table table) throws SQLException { return new DMLTransformer(table, scriptFileWriter, upsertOnly, maxBodySize, session, targetDBMSConfiguration, importFilterTransformer, executionContext); } /** * Sets the {@link ImportFilterTransformer}. */ public void setImportFilterTransformer(ImportFilterTransformer importFilterManager) { this.importFilterTransformer = importFilterManager; } }; private final List<Column> selectionClause; /** * Constructor. * * @param table the table to read from * @param scriptFileWriter the file to write to * @param maxBodySize maximum length of SQL values list (for generated inserts) * @param upsertOnly use 'upsert' statements for all entities * @param session the session * @param targetDBMSConfiguration configuration of the target DBMS * @param executionContext * @param importFilterTransformer2 */ protected DMLTransformer(Table table, OutputStreamWriter scriptFileWriter, boolean upsertOnly, int maxBodySize, Session session, DBMS targetDBMSConfiguration, ImportFilterTransformer importFilterTransformer, ExecutionContext executionContext) throws SQLException { this.executionContext = executionContext; this.targetDBMSConfiguration = targetDBMSConfiguration; this.maxBodySize = maxBodySize; this.upsertOnly = upsertOnly; this.table = table; this.scriptFileWriter = scriptFileWriter; this.currentDialect = targetDBMSConfiguration.getSqlDialect(); this.insertStatementBuilder = new StatementBuilder(currentDialect.isSupportsMultiRowInserts() || DBMS.ORACLE.equals(targetDBMSConfiguration) || DBMS.SQLITE.equals(targetDBMSConfiguration)? maxBodySize : 1); this.quoting = createQuoting(session); this.importFilterTransformer = importFilterTransformer; if (targetDBMSConfiguration != null && targetDBMSConfiguration != session.dbms) { if (targetDBMSConfiguration.getIdentifierQuoteString() != null) { this.quoting.setIdentifierQuoteString(targetDBMSConfiguration.getIdentifierQuoteString()); } } this.session = session; this.selectionClause = table.getSelectionClause(session); tableHasIdentityColumn = false; if (targetDBMSConfiguration.isIdentityInserts()) { for (Column c: table.getColumns()) { if (c.isIdentityColumn) { tableHasIdentityColumn = true; break; } } } } protected Quoting createQuoting(Session session) throws SQLException { return new Quoting(session); } /** * Reads result-set and writes into export-script. */ public void readCurrentRow(ResultSet resultSet) throws SQLException { if (columnLabel == null) { columnCount = getMetaData(resultSet).getColumnCount(); columnLabel = new String[columnCount + 1]; lobColumns = new ArrayList<String>(); isLobColumn = new boolean[columnCount + 1]; emptyLobValue = new String[columnCount + 1]; lobColumnIndexes = new ArrayList<Integer>(); labelCSL = ""; tableHasLobs = false; for (int i = 1; i <= columnCount; ++i) { String mdColumnLabel = quoting.quote(getMetaData(resultSet).getColumnLabel(i)); int mdColumnType = getMetaData(resultSet).getColumnType(i); if ((mdColumnType == Types.BLOB || mdColumnType == Types.CLOB || mdColumnType == Types.NCLOB || mdColumnType == Types.SQLXML) && !DBMS.SQLITE.equals(targetDBMSConfiguration)) { tableHasLobs = true; isLobColumn[i] = true; lobColumnIndexes.add(i); lobColumns.add(mdColumnLabel); if (mdColumnType == Types.SQLXML) { emptyLobValue[i] = null; } else { DBMS c = targetDBMSConfiguration; emptyLobValue[i] = mdColumnType == Types.BLOB? c.getEmptyBLOBValue() : mdColumnType == Types.CLOB? c.getEmptyCLOBValue() : c.getEmptyNCLOBValue(); } if (emptyLobValue[i] == null) { continue; } } columnLabel[i] = mdColumnLabel; if (labelCSL.length() > 0) { labelCSL += ", "; } labelCSL += columnLabel[i]; } } try { StringBuffer valueList = new StringBuffer(""); StringBuffer namedValues = new StringBuffer(""); boolean f = true; Map<Integer, String> smallLobsPerIndex = new HashMap<Integer, String>(); CellContentConverter cellContentConverter = getCellContentConverter(resultSet, session, targetDBMSConfiguration); for (int i = 1; i <= columnCount; ++i) { Object content = null; if (columnLabel[i] == null) { continue; } boolean isSmallLob = false; if (isLobColumn[i]) { content = cellContentConverter.getSmallLob(resultSet, i); if (content != null) { isSmallLob = true; smallLobsPerIndex.put(i, (String) content); } } if (content == null) { content = cellContentConverter.getObject(resultSet, i); if (resultSet.wasNull()) { content = null; } } if (!f) { namedValues.append(", "); valueList.append(", "); } f = false; String cVal = isSmallLob? (String) content : convertToSql(cellContentConverter, resultSet, i, content); if (!isSmallLob && content != null && emptyLobValue[i] != null) { cVal = emptyLobValue[i]; } valueList.append(cVal); namedValues.append(cVal + " " + columnLabel[i]); } if (table.getUpsert() || upsertOnly) { if (table.primaryKey.getColumns().isEmpty()) { throw new RuntimeException("Unable to merge/upsert into table \"" + table.getName() + "\".\n" + "No primary key."); } Map<String, String> val = new HashMap<String, String>(); StringBuffer valuesWONull = new StringBuffer(""); StringBuffer columnsWONull = new StringBuffer(""); f = true; for (int i = 1; i <= columnCount; ++i) { if (columnLabel[i] == null) { continue; } Object content = cellContentConverter.getObject(resultSet, i); if (resultSet.wasNull()) { content = null; } String cVal = convertToSql(cellContentConverter, resultSet, i, content); if (DBMS.POSTGRESQL.equals(targetDBMSConfiguration) && (content instanceof Date || content instanceof Timestamp)) { // explicit cast needed cVal = "timestamp " + cVal; } if (DBMS.POSTGRESQL.equals(targetDBMSConfiguration)) { // explicit cast needed int mdColumnType = getMetaData(resultSet).getColumnType(i); if (mdColumnType == Types.TIME) { cVal = "time " + cVal; } } if (content != null && emptyLobValue[i] != null) { cVal = smallLobsPerIndex.get(i); if (cVal == null) { cVal = emptyLobValue[i]; } } val.put(columnLabel[i], cVal); if (content != null) { if (!f) { valuesWONull.append(", "); columnsWONull.append(", "); } f = false; valuesWONull.append(cVal); columnsWONull.append(columnLabel[i]); } } String insertHead = "Insert into " + qualifiedTableName(table) + "(" + columnsWONull + ") "; f = true; StringBuffer whereForTerminator = new StringBuffer(""); StringBuffer where = new StringBuffer(""); StringBuffer whereWOAlias = new StringBuffer(""); // assemble 'where' for sub-select and update for (Column pk: table.primaryKey.getColumns()) { if (!f) { whereForTerminator.append(" and "); where.append(" and "); whereWOAlias.append(" and "); } f = false; whereForTerminator.append("T." + quoting.requote(pk.name) + "=Q." + quoting.requote(pk.name)); String value; String name = quoting.quote(pk.name); if (val.containsKey(name)) { value = val.get(name); } else if (val.containsKey(name.toLowerCase())) { value = val.get(name.toLowerCase()); } else { value = val.get(name.toUpperCase()); } where.append("T." + quoting.requote(pk.name) + "=" + value); whereWOAlias.append(quoting.requote(pk.name) + "=" + value); } if (currentDialect.getUpsertMode() == UPSERT_MODE.MERGE && !tableHasLobs) { // MERGE INTO JL_TMP T USING (SELECT 1 c1, 2 c2 from dual) incoming // ON (T.c1 = incoming.c1) // WHEN MATCHED THEN UPDATE SET T.c2 = incoming.c2 // WHEN NOT MATCHED THEN INSERT (T.c1, T.c2) VALUES (incoming.c1, incoming.c2) insertHead = "MERGE INTO " + qualifiedTableName(table) + " T USING("; StringBuffer terminator = new StringBuffer(") Q ON(" + whereForTerminator + ") "); StringBuffer sets = new StringBuffer(); StringBuffer tSchema = new StringBuffer(); StringBuffer iSchema = new StringBuffer(); for (int i = 1; i <= columnCount; ++i) { if (columnLabel[i] == null) { continue; } if (!isPrimaryKeyColumn(columnLabel[i])) { if (sets.length() > 0) { sets.append(", "); } sets.append("T." + columnLabel[i] + "=Q." + columnLabel[i]); } if (tSchema.length() > 0) { tSchema.append(", "); } tSchema.append("T." + columnLabel[i]); if (iSchema.length() > 0) { iSchema.append(", "); } iSchema.append("Q." + columnLabel[i]); } if (sets.length() > 0) { terminator.append("WHEN MATCHED THEN UPDATE SET " + sets + " "); } terminator.append("WHEN NOT MATCHED THEN INSERT (" + tSchema + ") VALUES(" + iSchema + ");\n"); StatementBuilder sb = upsertInsertStatementBuilder.get(insertHead); if (sb == null) { sb = new StatementBuilder(maxBodySize); upsertInsertStatementBuilder.put(insertHead, sb); } String item = "Select " + valueList + " from dual"; if (!sb.isAppendable(insertHead, item)) { writeToScriptFile(sb.build(), true); } if (sb.isEmpty()) { item = "Select " + namedValues + " from dual"; } sb.append(insertHead, item, " UNION ALL ", terminator.toString()); } else if (currentDialect.getUpsertMode() == UPSERT_MODE.DB2) { insertHead += "Select * From (values "; StringBuffer terminator = new StringBuffer(") as Q(" + columnsWONull + ") Where not exists (Select * from " + qualifiedTableName(table) + " T " + "Where "); terminator.append(whereForTerminator + ");\n"); StatementBuilder sb = upsertInsertStatementBuilder.get(insertHead); if (sb == null) { sb = new StatementBuilder(maxBodySize); upsertInsertStatementBuilder.put(insertHead, sb); } String item = "(" + valuesWONull + ")"; if (!sb.isAppendable(insertHead, item)) { writeToScriptFile(sb.build(), true); } sb.append(insertHead, item, ", ", terminator.toString()); } else { String item = "Select " + valuesWONull + " From " + (currentDialect.getUpsertMode() == UPSERT_MODE.FROM_DUAL || currentDialect.getUpsertMode() == UPSERT_MODE.MERGE? // oracle table with lobs "dual" : currentDialect.getUpsertMode() == UPSERT_MODE.FROM_SYSDUMMY1? "sysibm.sysdummy1" : SQLDialect.DUAL_TABLE); StringBuffer terminator = new StringBuffer(" Where not exists (Select * from " + qualifiedTableName(table) + " T " + "Where "); terminator.append(where + ");\n"); StatementBuilder sb = upsertInsertStatementBuilder.get(insertHead); if (sb == null) { sb = new StatementBuilder(1 /* insertStatementBuilder.getMaxBodySize() */); upsertInsertStatementBuilder.put(insertHead, sb); } if (!sb.isAppendable(insertHead, item)) { writeToScriptFile(sb.build(), true); } sb.append(insertHead, item, ", ", terminator.toString()); } if (currentDialect.getUpsertMode() != UPSERT_MODE.MERGE || tableHasLobs) { StringBuffer insert = new StringBuffer(""); insert.append("Update " + qualifiedTableName(table) + " set "); f = true; for (int i = 1; i <= columnCount; ++i) { if (columnLabel[i] == null || (emptyLobValue[i] != null && !"null".equals(val.get(columnLabel[i])))) { continue; } if (isPrimaryKeyColumn(columnLabel[i])) { continue; } if (!f) { insert.append(", "); } f = false; insert.append(columnLabel[i] + "=" + val.get(columnLabel[i])); } if (!f) { insert.append(" Where " + whereWOAlias + ";\n"); writeToScriptFile(insert.toString(), true); } } } else { if (DBMS.DB2_ZOS.equals(targetDBMSConfiguration) && maxBodySize > 1) { String insertSchema = "Insert into " + qualifiedTableName(table) + "(" + labelCSL + ") "; String item = "\n Select " + valueList + " From sysibm.sysdummy1"; if (!insertStatementBuilder.isAppendable(insertSchema, item)) { writeToScriptFile(insertStatementBuilder.build(), true); } insertStatementBuilder.append(insertSchema, item, " Union all ", ";\n"); } else if (DBMS.ORACLE.equals(targetDBMSConfiguration) && maxBodySize > 1) { String insertSchema = "Insert into " + qualifiedTableName(table) + "(" + labelCSL + ") "; String item = "\n Select " + valueList + " From DUAL"; if (!insertStatementBuilder.isAppendable(insertSchema, item)) { writeToScriptFile(insertStatementBuilder.build(), true); } insertStatementBuilder.append(insertSchema, item, " Union all ", ";\n"); } else if (DBMS.SQLITE.equals(targetDBMSConfiguration) && maxBodySize > 1) { String insertSchema = "Insert into " + qualifiedTableName(table) + "(" + labelCSL + ") "; String item = "\n Select " + valueList + " "; if (!insertStatementBuilder.isAppendable(insertSchema, item)) { writeToScriptFile(insertStatementBuilder.build(), true); } insertStatementBuilder.append(insertSchema, item, " Union all ", ";\n"); } else { String insertSchema = "Insert into " + qualifiedTableName(table) + "(" + labelCSL + ") values "; String item = (maxBodySize > 1? "\n " : "") + "(" + valueList + ")"; if (!insertStatementBuilder.isAppendable(insertSchema, item)) { writeToScriptFile(insertStatementBuilder.build(), true); } insertStatementBuilder.append(insertSchema, item, ", ", ";\n"); } } exportLobs(table, resultSet, smallLobsPerIndex.keySet()); } catch (IOException e) { throw new RuntimeException(e); } } /** * Converts cell content to SQL literals. * * @param cellContentConverter converter * @param resultSet points to current row * @param i current result set index * @param content cell content * @return SQL literal */ protected String convertToSql(CellContentConverter cellContentConverter, ResultSet resultSet, int i, Object content) throws SQLException { String cVal = cellContentConverter.toSql(content); Column column = selectionClause.get(i - 1); Filter filter = column.getFilter(); if (filter != null && importFilterTransformer != null) { if (!filter.isApplyAtExport()) { return importFilterTransformer.transform(column, cVal); } } if (content != null && filter != null && filter.getExpression().trim().startsWith(Filter.LITERAL_PREFIX)) { return content.toString(); } return cVal; } /** * Gets qualified table name. * * @param t the table * @return qualified name of t */ protected String qualifiedTableName(Table t) { String schema = t.getOriginalSchema(""); String mappedSchema = executionContext.getSchemaMapping().get(schema); if (mappedSchema != null) { schema = mappedSchema; } if (schema.length() == 0) { return quoting.requote(t.getUnqualifiedName()); } return quoting.requote(schema) + "." + quoting.requote(t.getUnqualifiedName()); } /** * Checks if columns is part of primary key. * * @param column the column * @return <code>true</code> if column is part of primary key */ private boolean isPrimaryKeyColumn(String column) { for (Column c: table.primaryKey.getColumns()) { if (c.name.equalsIgnoreCase(column)) { return true; } } return false; } /** * Exports the (c|b)lob content. * * @param resultSet export current row */ private void exportLobs(Table table, ResultSet resultSet, Set<Integer> smallLobsIndexes) throws IOException, SQLException { synchronized (scriptFileWriter) { CellContentConverter cellContentConverter = getCellContentConverter(resultSet, session, targetDBMSConfiguration); for (int i = 0; i < lobColumnIndexes.size(); ++i) { if (smallLobsIndexes.contains(lobColumnIndexes.get(i))) { continue; } Object lob = resultSet.getObject(lobColumnIndexes.get(i)); Map<String, String> val = new HashMap<String, String>(); for (int j = 1; j <= columnCount; ++j) { if (columnLabel[j] == null) { continue; } Object content = cellContentConverter.getObject(resultSet, j); if (resultSet.wasNull()) { content = null; } String cVal = cellContentConverter.toSql(content); val.put(columnLabel[j], cVal); } boolean f = true; StringBuffer where = new StringBuffer(""); for (Column pk: table.primaryKey.getColumns()) { if (!f) { where.append(" and "); } f = false; where.append(quoting.requote(pk.name) + "=" + val.get(pk.name)); } if (lob instanceof SQLXML) { ++numberOfExportedLOBs; flush(); SQLXML xml = (SQLXML) lob; writeToScriptFile(SqlScriptExecutor.UNFINISHED_MULTILINE_COMMENT + "XML " + qualifiedTableName(table) + ", " + lobColumns.get(i) + ", " + where + "\n", false); Reader in = xml.getCharacterStream(); int c; StringBuffer line = new StringBuffer(SqlScriptExecutor.UNFINISHED_MULTILINE_COMMENT); while ((c = in.read()) != -1) { if ((char) c == '\n') { writeToScriptFile(line.toString() + "\\n\n", false); line = new StringBuffer(SqlScriptExecutor.UNFINISHED_MULTILINE_COMMENT); } else { if ((char) c == '\r') { line.append("\\r"); } else { line.append((char) c); if ((char) c == '\\') { line.append((char) c); } } } if (line.length() >= 200) { writeToScriptFile(line.toString() + "\n", false); line = new StringBuffer(SqlScriptExecutor.UNFINISHED_MULTILINE_COMMENT); } } in.close(); writeToScriptFile(line.toString() + "\n" + SqlScriptExecutor.FINISHED_MULTILINE_COMMENT + "\n", false); } if (lob instanceof Clob) { ++numberOfExportedLOBs; flush(); Clob clob = (Clob) lob; writeToScriptFile(SqlScriptExecutor.UNFINISHED_MULTILINE_COMMENT + "CLOB " + qualifiedTableName(table) + ", " + lobColumns.get(i) + ", " + where + "\n", false); Reader in = clob.getCharacterStream(); int c; StringBuffer line = new StringBuffer(SqlScriptExecutor.UNFINISHED_MULTILINE_COMMENT); while ((c = in.read()) != -1) { if ((char) c == '\n') { writeToScriptFile(line.toString() + "\\n\n", false); line = new StringBuffer(SqlScriptExecutor.UNFINISHED_MULTILINE_COMMENT); } else { if ((char) c == '\r') { line.append("\\r"); } else { line.append((char) c); if ((char) c == '\\') { line.append((char) c); } } } if (line.length() >= 200) { writeToScriptFile(line.toString() + "\n", false); line = new StringBuffer(SqlScriptExecutor.UNFINISHED_MULTILINE_COMMENT); } } in.close(); writeToScriptFile(line.toString() + "\n" + SqlScriptExecutor.FINISHED_MULTILINE_COMMENT + "\n", false); } if (lob instanceof Blob) { ++numberOfExportedLOBs; flush(); Blob blob = (Blob) lob; writeToScriptFile(SqlScriptExecutor.UNFINISHED_MULTILINE_COMMENT + "BLOB " + qualifiedTableName(table) + ", " + lobColumns.get(i) + ", " + where + "\n", false); InputStream in = blob.getBinaryStream(); int b; StringBuffer line = new StringBuffer(SqlScriptExecutor.UNFINISHED_MULTILINE_COMMENT); byte[] buffer = new byte[64]; int size = 0; while ((b = in.read()) != -1) { buffer[size++] = (byte) b; if (size == buffer.length) { writeToScriptFile(line.toString() + Base64.encodeBytes(buffer, Base64.DONT_BREAK_LINES) + "\n", false); line = new StringBuffer(SqlScriptExecutor.UNFINISHED_MULTILINE_COMMENT); size = 0; } } in.close(); writeToScriptFile(line.toString() + Base64.encodeBytes(buffer, 0, size, Base64.DONT_BREAK_LINES) + "\n" + SqlScriptExecutor.FINISHED_MULTILINE_COMMENT + "\n", false); } } } } /** * Flushes the export-reader. */ public void flush() { try { writeToScriptFile(insertStatementBuilder.build(), true); for (StatementBuilder sb: upsertInsertStatementBuilder.values()) { writeToScriptFile(sb.build(), true); } } catch (IOException e) { throw new RuntimeException(e); } } /** * Flushes the export-reader. */ public void close() { flush(); synchronized (scriptFileWriter) { if (identityInsertTable != null) { try { scriptFileWriter.write("SET IDENTITY_INSERT " + qualifiedTableName(identityInsertTable) + " OFF;\n"); } catch (IOException e) { throw new RuntimeException(e); } identityInsertTable = null; } } } /** * Table which is currently enabled for identity-inserts. */ private static Table identityInsertTable = null; /** * Writes into script. */ private void writeToScriptFile(String content, boolean wrap) throws IOException { synchronized (scriptFileWriter) { if (tableHasIdentityColumn) { if (identityInsertTable != table) { if (identityInsertTable != null) { scriptFileWriter.write("SET IDENTITY_INSERT " + qualifiedTableName(identityInsertTable) + " OFF;\n"); identityInsertTable = null; } scriptFileWriter.write("SET IDENTITY_INSERT " + qualifiedTableName(table) + " ON;\n"); identityInsertTable = table; } } if (wrap && DBMS.ORACLE.equals(targetDBMSConfiguration)) { scriptFileWriter.write(SqlUtil.splitDMLStatement(content, 2400)); } else { scriptFileWriter.write(content); } } } }