Source Code Cross Referenced for SchemaDiff.java in  » Database-Client » SQL-Workbench » workbench » db » diff » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Database Client » SQL Workbench » workbench.db.diff 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * SchemaDiff.java
0003:         *
0004:         * This file is part of SQL Workbench/J, http://www.sql-workbench.net
0005:         *
0006:         * Copyright 2002-2008, Thomas Kellerer
0007:         * No part of this code maybe reused without the permission of the author
0008:         *
0009:         * To contact the author please send an email to: support@sql-workbench.net
0010:         *
0011:         */
0012:        package workbench.db.diff;
0013:
0014:        import java.io.IOException;
0015:        import java.io.Writer;
0016:        import java.sql.SQLException;
0017:        import java.util.ArrayList;
0018:        import java.util.HashSet;
0019:        import java.util.Iterator;
0020:        import java.util.List;
0021:        import workbench.db.DbMetadata;
0022:        import workbench.db.DbSettings;
0023:        import workbench.db.ProcedureDefinition;
0024:        import workbench.db.SequenceDefinition;
0025:        import workbench.db.SequenceReader;
0026:        import workbench.db.TableIdentifier;
0027:        import workbench.db.WbConnection;
0028:        import workbench.db.report.ReportProcedure;
0029:        import workbench.db.report.ReportSequence;
0030:        import workbench.db.report.ReportTable;
0031:        import workbench.db.report.ReportView;
0032:        import workbench.db.report.TagWriter;
0033:        import workbench.log.LogMgr;
0034:        import workbench.resource.ResourceMgr;
0035:        import workbench.storage.RowActionMonitor;
0036:        import workbench.util.StrBuffer;
0037:        import workbench.util.StrWriter;
0038:        import workbench.util.StringUtil;
0039:
0040:        /**
0041:         * Compare two Schemas for differences in the definition of the tables
0042:         * 
0043:         * @author  support@sql-workbench.net
0044:         */
0045:        public class SchemaDiff {
0046:            public static final String TAG_ADD_TABLE = "add-table";
0047:            public static final String TAG_ADD_VIEW = "add-view";
0048:            public static final String TAG_DROP_TABLE = "drop-table";
0049:            public static final String TAG_DROP_VIEW = "drop-view";
0050:            public static final String TAG_DROP_PROC = "drop-procedure";
0051:            public static final String TAG_ADD_PROC = "add-procedure";
0052:            public static final String TAG_DROP_SEQUENCE = "drop-sequence";
0053:
0054:            public static final String TAG_REF_CONN = "reference-connection";
0055:            public static final String TAG_TARGET_CONN = "target-connection";
0056:            public static final String TAG_COMPARE_INFO = "compare-settings";
0057:            public static final String TAG_VIEW_PAIR = "view-info";
0058:            public static final String TAG_TABLE_PAIR = "table-info";
0059:            public static final String TAG_PROC_PAIR = "procedure-info";
0060:            public static final String TAG_INDEX_INFO = "include-index";
0061:            public static final String TAG_FK_INFO = "include-foreign-key";
0062:            public static final String TAG_PK_INFO = "include-primary-key";
0063:            public static final String TAG_GRANT_INFO = "include-tablegrants";
0064:            public static final String TAG_CONSTRAINT_INFO = "include-constraints";
0065:            public static final String TAG_VIEW_INFO = "include-views";
0066:            public static final String TAG_PROC_INFO = "include-procs";
0067:            public static final String TAG_SEQUENCE_INFO = "include-sequences";
0068:
0069:            private WbConnection sourceDb;
0070:            private WbConnection targetDb;
0071:            private List<Object> objectsToCompare;
0072:            private List<TableIdentifier> tablesToDelete;
0073:            private List<ProcedureDefinition> procsToDelete;
0074:            private List<TableIdentifier> viewsToDelete;
0075:            private List<SequenceDefinition> sequencesToDelete;
0076:
0077:            private String namespace;
0078:            private String encoding = "UTF-8";
0079:            private boolean compareJdbcTypes = false;
0080:            private boolean diffIndex = true;
0081:            private boolean diffForeignKeys = true;
0082:            private boolean diffPrimaryKeys = true;
0083:            private boolean diffConstraints = false;
0084:            private boolean diffGrants = false;
0085:            private boolean diffViews = true;
0086:            private boolean diffProcs = true;
0087:            private boolean diffSequences = true;
0088:
0089:            //	private boolean diffComments;
0090:            private RowActionMonitor monitor;
0091:            private boolean cancel = false;
0092:            private String referenceSchema;
0093:            private String targetSchema;
0094:            private List<String> tablesToIgnore;
0095:
0096:            public SchemaDiff() {
0097:            }
0098:
0099:            /**
0100:             *	Create a new SchemaDiff for the given connections
0101:             */
0102:            public SchemaDiff(WbConnection source, WbConnection target) {
0103:                this (source, target, null);
0104:            }
0105:
0106:            /**
0107:             * Create a new SchemaDiff for the given connections with the given 
0108:             * namespace to be used when writing the XML.
0109:             * 
0110:             * @param source The connection to the reference schema
0111:             * @param target the connection to the target schema
0112:             * @param xmlNameSpace the namespace to be used for the XML, may be null.
0113:             */
0114:            public SchemaDiff(WbConnection source, WbConnection target,
0115:                    String xmlNameSpace) {
0116:                sourceDb = source;
0117:                targetDb = target;
0118:                this .namespace = xmlNameSpace;
0119:            }
0120:
0121:            public void setIncludeSequences(boolean flag) {
0122:                this .diffSequences = flag;
0123:            }
0124:
0125:            public boolean getIncludeSequences() {
0126:                return this .diffSequences;
0127:            }
0128:
0129:            /**
0130:             * Control whether foreign keys should be compared as well.
0131:             * The default is to compare foreign keys.
0132:             */
0133:            public void setIncludeForeignKeys(boolean flag) {
0134:                this .diffForeignKeys = flag;
0135:            }
0136:
0137:            public boolean getIncludeForeignKeys() {
0138:                return this .diffForeignKeys;
0139:            }
0140:
0141:            /**
0142:             *	Control whether index definitions should be compared as well.
0143:             *  The default is to compare index definitions
0144:             */
0145:            public void setIncludeIndex(boolean flag) {
0146:                this .diffIndex = flag;
0147:            }
0148:
0149:            public boolean getIncludeIndex() {
0150:                return this .diffIndex;
0151:            }
0152:
0153:            /**
0154:             * Control whether primary keys should be compared as well.
0155:             * The default is to compare primary keys.
0156:             */
0157:            public void setIncludePrimaryKeys(boolean flag) {
0158:                this .diffPrimaryKeys = flag;
0159:            }
0160:
0161:            public boolean getIncludePrimaryKeys() {
0162:                return this .diffPrimaryKeys;
0163:            }
0164:
0165:            /**
0166:             * Control whether table constraints should be compared as well.
0167:             * The default is to not compare primary keys.
0168:             */
0169:            public void setIncludeTableConstraints(boolean flag) {
0170:                this .diffConstraints = flag;
0171:            }
0172:
0173:            public boolean getIncludeTableConstraints() {
0174:                return this .diffConstraints;
0175:            }
0176:
0177:            public void setCompareJdbcTypes(boolean flag) {
0178:                this .compareJdbcTypes = flag;
0179:            }
0180:
0181:            public boolean getCompareJdbcTypes() {
0182:                return this .compareJdbcTypes;
0183:            }
0184:
0185:            public void setIncludeViews(boolean flag) {
0186:                this .diffViews = flag;
0187:            }
0188:
0189:            public void setIncludeProcedures(boolean flag) {
0190:                this .diffProcs = flag;
0191:            }
0192:
0193:            public void setIncludeTableGrants(boolean flag) {
0194:                this .diffGrants = flag;
0195:            }
0196:
0197:            public boolean getIncludeTableGrants() {
0198:                return this .diffGrants;
0199:            }
0200:
0201:            //	public void setIncludeComments(boolean flag) { this.diffComments = flag; }
0202:
0203:            /**
0204:             *	Set the {@link workbench.storage.RowActionMonitor} for reporting progress
0205:             */
0206:            public void setMonitor(RowActionMonitor mon) {
0207:                this .monitor = mon;
0208:            }
0209:
0210:            /**
0211:             *	Cancel the creation of the XML file
0212:             *  @see #isCancelled()
0213:             */
0214:            public void cancel() {
0215:                this .cancel = true;
0216:            }
0217:
0218:            /**
0219:             *	Return if the XML generation has been cancelled
0220:             * @return true if #cancel() has been called
0221:             */
0222:            public boolean isCancelled() {
0223:                return this .cancel;
0224:            }
0225:
0226:            /** 
0227:             * Define table names to be compared. The table names in the passed
0228:             * lists will be converted to TableIdentifiers and then passed 
0229:             * on to setTables(List<TableIdentifier>, List<TableIdentifier>)
0230:             * 
0231:             * No name matching will take place. Thus it's possible to compare
0232:             * tables that might have different names but are supposed to be identical
0233:             * otherwise. 
0234:             * 
0235:             * @see #setTables(List, List)
0236:             * @see #compareAll()
0237:             */
0238:            public void setTableNames(List<String> referenceList,
0239:                    List<String> targetList) throws SQLException {
0240:                ArrayList<TableIdentifier> reference = new ArrayList<TableIdentifier>(
0241:                        referenceList.size());
0242:                ArrayList<TableIdentifier> target = new ArrayList<TableIdentifier>(
0243:                        targetList.size());
0244:
0245:                String ttype = this .sourceDb.getMetadata().getTableTypeName();
0246:                for (String tname : referenceList) {
0247:                    TableIdentifier tbl = new TableIdentifier(tname);
0248:                    tbl.setType(ttype);
0249:                    reference.add(tbl);
0250:                }
0251:
0252:                ttype = this .targetDb.getMetadata().getTableTypeName();
0253:                for (String tname : targetList) {
0254:                    TableIdentifier tbl = new TableIdentifier(tname);
0255:                    tbl.setType(ttype);
0256:                    target.add(tbl);
0257:                }
0258:                setTables(reference, target);
0259:            }
0260:
0261:            /** 
0262:             * Define the tables to be compared. They will be compared based 
0263:             * on the position in the arrays (i.e. reference at index 0 will be
0264:             * compared to target at index 0...)
0265:             * 
0266:             * No name matching will take place. Thus it's possible to compare
0267:             * tables that might have different names but are supposed to be identical
0268:             * otherwise. 
0269:             * 
0270:             * @see #setTables(List)
0271:             * @see #compareAll()
0272:             */
0273:            public void setTables(List<TableIdentifier> referenceList,
0274:                    List<TableIdentifier> targetList) throws SQLException {
0275:                if (referenceList == null)
0276:                    throw new NullPointerException(
0277:                            "Source tables may not be null");
0278:                if (targetList == null)
0279:                    throw new NullPointerException(
0280:                            "Target tables may not be null");
0281:                if (referenceList.size() != targetList.size())
0282:                    throw new IllegalArgumentException(
0283:                            "Number of source and target tables have to match");
0284:                int count = referenceList.size();
0285:                this .objectsToCompare = new ArrayList<Object>(count);
0286:
0287:                if (this .monitor != null) {
0288:                    this .monitor
0289:                            .setMonitorType(RowActionMonitor.MONITOR_PROCESS_TABLE);
0290:                    this .monitor.setCurrentObject(ResourceMgr
0291:                            .getString("MsgDiffRetrieveDbInfo"), -1, -1);
0292:                }
0293:
0294:                for (int i = 0; i < count; i++) {
0295:                    if (this .cancel) {
0296:                        this .objectsToCompare = null;
0297:                        break;
0298:                    }
0299:                    TableIdentifier reference = referenceList.get(i);
0300:
0301:                    if (reference == null)
0302:                        continue;
0303:
0304:                    TableIdentifier target = targetList.get(i);
0305:                    DiffEntry entry = new DiffEntry(reference, target);
0306:                    this .objectsToCompare.add(entry);
0307:                }
0308:            }
0309:
0310:            private ReportView createReportViewInstance(TableIdentifier tbl,
0311:                    WbConnection con) throws SQLException {
0312:                tbl.adjustCase(con);
0313:                ReportView view = new ReportView(tbl, con, diffIndex,
0314:                        this .namespace);
0315:                return view;
0316:            }
0317:
0318:            private ReportTable createReportTableInstance(TableIdentifier tbl,
0319:                    WbConnection con) throws SQLException {
0320:                tbl.adjustCase(con);
0321:                return new ReportTable(tbl, con, this .namespace, diffIndex,
0322:                        diffForeignKeys, diffPrimaryKeys, diffConstraints,
0323:                        diffGrants);
0324:            }
0325:
0326:            /**
0327:             * Define a list of table names that should not be compared.
0328:             * Tables in the reference/source database that match one of the 
0329:             * names in this list will be skipped.
0330:             */
0331:            public void setExcludeTables(List<String> tables) {
0332:                if (tables == null || tables.size() == 0) {
0333:                    this .tablesToIgnore = null;
0334:                    return;
0335:                }
0336:                int count = tables.size();
0337:                this .tablesToIgnore = new ArrayList<String>(count);
0338:                for (String tname : tables) {
0339:                    this .tablesToIgnore.add(this .sourceDb.getMetadata()
0340:                            .adjustObjectnameCase(tname));
0341:                }
0342:            }
0343:
0344:            /**
0345:             *	Setup this SchemaDiff object to compare all tables that the user
0346:             *  can access in the reference connection with all matching (=same name)
0347:             *  tables in the target connection.
0348:             *  This will retrieve all user tables from the reference (=source)
0349:             *  connection and will match them to the tables in the target connection.
0350:             *  
0351:             *  When using compareAll() drop statements will be created for tables 
0352:             *  present in the target connection but not existing in the reference
0353:             *  connection.
0354:             *
0355:             * @see #setTables(List, List)
0356:             * @see #setTables(List)
0357:             */
0358:            public void compareAll() throws SQLException {
0359:                setSchemas(null, null);
0360:            }
0361:
0362:            /**
0363:             *	Setup this SchemaDiff object to compare all tables that the user
0364:             *  can access in the reference connection with all matching (=same name)
0365:             *  tables in the target connection.
0366:             *  This will retrieve all user tables from the reference (=source)
0367:             *  connection and will match them to the tables in the target connection.
0368:             *  
0369:             *  When using compareAll() drop statements will be created for tables 
0370:             *  present in the target connection but not existing in the reference
0371:             *  connection.
0372:             *
0373:             * @see #setTables(List, List)
0374:             * @see #setTables(List)
0375:             */
0376:            public void setSchemas(String rSchema, String tSchema)
0377:                    throws SQLException {
0378:                if (this .monitor != null) {
0379:                    this .monitor.setMonitorType(RowActionMonitor.MONITOR_PLAIN);
0380:                    this .monitor.setCurrentObject(ResourceMgr
0381:                            .getString("MsgDiffRetrieveDbInfo"), -1, -1);
0382:                }
0383:                this .referenceSchema = (rSchema == null ? this .sourceDb
0384:                        .getMetadata().getSchemaToUse() : this .sourceDb
0385:                        .getMetadata().adjustSchemaNameCase(rSchema));
0386:                this .targetSchema = (tSchema == null ? this .targetDb
0387:                        .getMetadata().getSchemaToUse() : this .sourceDb
0388:                        .getMetadata().adjustSchemaNameCase(tSchema));
0389:
0390:                String[] types;
0391:                if (diffViews) {
0392:                    types = new String[] {
0393:                            this .sourceDb.getMetadata().getTableTypeName(),
0394:                            this .sourceDb.getMetadata().getViewTypeName() };
0395:                } else {
0396:                    types = new String[] { this .sourceDb.getMetadata()
0397:                            .getTableTypeName() };
0398:                }
0399:                List<TableIdentifier> refTables = sourceDb.getMetadata()
0400:                        .getTableList(this .referenceSchema, types);
0401:                List<TableIdentifier> target = targetDb.getMetadata()
0402:                        .getTableList(this .targetSchema, types);
0403:
0404:                processTableList(refTables, target);
0405:
0406:                if (diffProcs) {
0407:                    List<ProcedureDefinition> refProcs = sourceDb.getMetadata()
0408:                            .getProcedureList(null, this .referenceSchema);
0409:                    List<ProcedureDefinition> targetProcs = targetDb
0410:                            .getMetadata().getProcedureList(null,
0411:                                    this .targetSchema);
0412:                    processProcedureList(refProcs, targetProcs);
0413:                }
0414:
0415:                if (diffSequences) {
0416:                    SequenceReader refReader = sourceDb.getMetadata()
0417:                            .getSequenceReader();
0418:                    List<SequenceDefinition> refSeqs = refReader
0419:                            .getSequences(this .referenceSchema);
0420:                    SequenceReader tarReader = targetDb.getMetadata()
0421:                            .getSequenceReader();
0422:                    List<SequenceDefinition> tarSeqs = tarReader
0423:                            .getSequences(this .referenceSchema);
0424:                    processSequenceList(refSeqs, tarSeqs);
0425:                }
0426:            }
0427:
0428:            private void processTableList(List<TableIdentifier> refTables,
0429:                    List<TableIdentifier> targetTables) throws SQLException {
0430:                int count = refTables.size();
0431:                HashSet<String> refTableNames = new HashSet<String>();
0432:
0433:                this .objectsToCompare = new ArrayList<Object>(count);
0434:                DbMetadata targetMeta = this .targetDb.getMetadata();
0435:
0436:                if (this .monitor != null) {
0437:                    this .monitor.setMonitorType(RowActionMonitor.MONITOR_PLAIN);
0438:                }
0439:
0440:                for (int i = 0; i < count; i++) {
0441:                    if (this .cancel) {
0442:                        this .objectsToCompare = null;
0443:                        break;
0444:                    }
0445:
0446:                    TableIdentifier rid = refTables.get(i);
0447:
0448:                    // The table names to be excluded have been put into 
0449:                    // the list after calling adjustObjectnameCase() on the input values
0450:                    // so we have to apply the same logic here.
0451:                    String tname = StringUtil.trimQuotes(rid.getTableName());
0452:                    tname = this .sourceDb.getMetadata().adjustObjectnameCase(
0453:                            tname);
0454:                    if (this .tablesToIgnore != null
0455:                            && this .tablesToIgnore.contains(tname))
0456:                        continue;
0457:
0458:                    if (this .monitor != null) {
0459:                        this .monitor.setCurrentObject(ResourceMgr
0460:                                .getFormattedString("MsgLoadTableInfo", tname),
0461:                                -1, -1);
0462:                    }
0463:
0464:                    TableIdentifier tid = rid.createCopy();
0465:                    tid.setSchema(this .targetSchema);
0466:
0467:                    DiffEntry entry = null;
0468:                    if (targetMeta.objectExists(tid, rid.getType())) {
0469:                        tid.setType(rid.getType());
0470:                        entry = new DiffEntry(rid, tid);
0471:                    } else {
0472:                        entry = new DiffEntry(rid, null);
0473:                    }
0474:                    objectsToCompare.add(entry);
0475:                    refTableNames.add(tname);
0476:                }
0477:
0478:                if (cancel)
0479:                    return;
0480:
0481:                this .tablesToDelete = new ArrayList<TableIdentifier>();
0482:                this .viewsToDelete = new ArrayList<TableIdentifier>();
0483:
0484:                if (targetTables != null) {
0485:                    String tableType = targetDb.getMetadata()
0486:                            .getTableTypeName();
0487:                    count = targetTables.size();
0488:                    for (int i = 0; i < count; i++) {
0489:                        TableIdentifier t = targetTables.get(i);
0490:                        String tbl = StringUtil.trimQuotes(t.getTableName());
0491:                        if (this .tablesToIgnore != null
0492:                                && this .tablesToIgnore.contains(tbl))
0493:                            continue;
0494:
0495:                        if (targetDb.getMetadata().isDefaultCase(tbl)) {
0496:                            tbl = sourceDb.getMetadata().adjustObjectnameCase(
0497:                                    tbl);
0498:                        }
0499:                        if (!refTableNames.contains(tbl)) {
0500:                            if (tableType.equals(t.getType())) {
0501:                                this .tablesToDelete.add(t);
0502:                            } else {
0503:                                this .viewsToDelete.add(t);
0504:                            }
0505:                        }
0506:                    }
0507:                }
0508:            }
0509:
0510:            private void processSequenceList(List<SequenceDefinition> refSeqs,
0511:                    List<SequenceDefinition> targetSeqs) {
0512:                HashSet<String> refSeqNames = new HashSet<String>();
0513:                this .sequencesToDelete = new ArrayList<SequenceDefinition>();
0514:
0515:                if (this .monitor != null) {
0516:                    this .monitor.setMonitorType(RowActionMonitor.MONITOR_PLAIN);
0517:                }
0518:
0519:                SequenceReader refReader = this .sourceDb.getMetadata()
0520:                        .getSequenceReader();
0521:                SequenceReader targetReader = this .targetDb.getMetadata()
0522:                        .getSequenceReader();
0523:
0524:                for (SequenceDefinition refSeq : refSeqs) {
0525:                    if (this .cancel) {
0526:                        this .objectsToCompare = null;
0527:                        break;
0528:                    }
0529:
0530:                    if (this .monitor != null) {
0531:                        this .monitor.setCurrentObject(ResourceMgr
0532:                                .getFormattedString("MsgLoadSeqInfo", refSeq
0533:                                        .getSequenceName()), -1, -1);
0534:                    }
0535:
0536:                    SequenceDiffEntry entry = null;
0537:                    SequenceDefinition def = targetReader
0538:                            .getSequenceDefinition(this .targetSchema, refSeq
0539:                                    .getSequenceName());
0540:                    entry = new SequenceDiffEntry(refSeq, def);
0541:                    objectsToCompare.add(entry);
0542:                    refSeqNames.add(refSeq.getSequenceName());
0543:                }
0544:
0545:                if (cancel)
0546:                    return;
0547:
0548:                if (targetSeqs != null) {
0549:                    for (SequenceDefinition tSeq : targetSeqs) {
0550:                        String seqname = tSeq.getSequenceName();
0551:                        if (!refSeqNames.contains(seqname)) {
0552:                            this .sequencesToDelete.add(tSeq);
0553:                        }
0554:                    }
0555:                }
0556:
0557:            }
0558:
0559:            private void processProcedureList(
0560:                    List<ProcedureDefinition> refProcs,
0561:                    List<ProcedureDefinition> targetProcs) {
0562:                HashSet<String> refProcNames = new HashSet<String>();
0563:                this .procsToDelete = new ArrayList<ProcedureDefinition>();
0564:
0565:                DbMetadata targetMeta = this .targetDb.getMetadata();
0566:
0567:                this .monitor.setMonitorType(RowActionMonitor.MONITOR_PLAIN);
0568:
0569:                for (ProcedureDefinition refProc : refProcs) {
0570:                    if (this .cancel) {
0571:                        this .objectsToCompare = null;
0572:                        break;
0573:                    }
0574:
0575:                    if (this .monitor != null) {
0576:                        this .monitor.setCurrentObject(ResourceMgr
0577:                                .getFormattedString("MsgLoadProcInfo", refProc
0578:                                        .getProcedureName()), -1, -1);
0579:                    }
0580:
0581:                    ProcDiffEntry entry = null;
0582:                    ProcedureDefinition tp = new ProcedureDefinition(null,
0583:                            this .targetSchema, refProc.getProcedureName(),
0584:                            refProc.getResultType());
0585:                    if (targetMeta.procedureExists(tp)) {
0586:                        entry = new ProcDiffEntry(refProc, tp);
0587:                    } else {
0588:                        entry = new ProcDiffEntry(refProc, null);
0589:                    }
0590:                    objectsToCompare.add(entry);
0591:                    refProcNames.add(refProc.getProcedureName());
0592:                }
0593:
0594:                if (cancel)
0595:                    return;
0596:
0597:                if (targetProcs != null) {
0598:                    for (ProcedureDefinition tProc : targetProcs) {
0599:                        String procname = tProc.getProcedureName();
0600:                        if (!refProcNames.contains(procname)) {
0601:                            this .procsToDelete.add(tProc);
0602:                        }
0603:                    }
0604:                }
0605:            }
0606:
0607:            /**
0608:             * Define the reference tables to be compared with the matching 
0609:             * tables (based on the name) in the target connection. The list 
0610:             * has to contain objects of type {@link workbench.db.TableIdentifier}
0611:             *
0612:             * @see #setTables(List, List)
0613:             * @see #compareAll()
0614:             */
0615:            public void setTables(List<TableIdentifier> reference)
0616:                    throws SQLException {
0617:                this .processTableList(reference, null);
0618:            }
0619:
0620:            /**
0621:             *	Return the XML that describes how the target schema needs to be 
0622:             *  modified in order to get the same structure as the reference schema.
0623:             *
0624:             *	For this, each defined table in the reference schema will be compared
0625:             *  to the corresponding table in the target schema. 
0626:             *
0627:             *  @see TableDiff#getMigrateTargetXml()
0628:             */
0629:            public String getMigrateTargetXml() {
0630:                StrWriter writer = new StrWriter(5000);
0631:                try {
0632:                    this .writeXml(writer);
0633:                } catch (Exception e) {
0634:                    LogMgr.logError("SchemaDiff.getMigrateTargetXml()",
0635:                            "Error getting XML", e);
0636:                }
0637:                return writer.toString();
0638:            }
0639:
0640:            /**
0641:             *	Return the encoding that is used in the encoding attribute of the XML tag
0642:             */
0643:            public String getEncoding() {
0644:                return encoding;
0645:            }
0646:
0647:            /**
0648:             *	Set the encoding that is used for writing the XML. This will
0649:             *  be put into the <?xml tag at the beginning of the generated XML
0650:             */
0651:            public void setEncoding(String encoding) {
0652:                this .encoding = encoding;
0653:            }
0654:
0655:            /**
0656:             *	Write the XML of the schema differences to the supplied writer.
0657:             *  This writes some meta information about the compare, and then 
0658:             *  creates a {@link TableDiff} object for each pair of tables that
0659:             *  needs to be compared. The output of {@link TableDiff#getMigrateTargetXml()}
0660:             *  will then be written into the writer.
0661:             */
0662:            public void writeXml(Writer out) throws IOException {
0663:                if (objectsToCompare == null)
0664:                    throw new NullPointerException(
0665:                            "Source tables may not be null");
0666:
0667:                StrBuffer indent = new StrBuffer("  ");
0668:                StrBuffer tblIndent = new StrBuffer("    ");
0669:                TagWriter tw = new TagWriter(this .namespace);
0670:                out.write("<?xml version=\"1.0\" encoding=\"");
0671:                out.write(this .encoding);
0672:                out.write("\"?>\n");
0673:
0674:                if (this .monitor != null) {
0675:                    this .monitor
0676:                            .setMonitorType(RowActionMonitor.MONITOR_PROCESS_TABLE);
0677:                }
0678:
0679:                writeTag(out, null, "schema-diff", true);
0680:                writeDiffInfo(out);
0681:                int count = this .objectsToCompare.size();
0682:                List<ViewDiff> viewDiffs = new ArrayList<ViewDiff>();
0683:                String tableType = sourceDb.getMetadata().getTableTypeName();
0684:                // First we have to process the tables
0685:                for (int i = 0; i < count; i++) {
0686:                    Object o = objectsToCompare.get(i);
0687:                    if (o instanceof  ProcDiffEntry)
0688:                        continue;
0689:                    if (o instanceof  SequenceDiffEntry)
0690:                        continue;
0691:
0692:                    DiffEntry entry = (DiffEntry) o;
0693:                    if (this .cancel)
0694:                        break;
0695:
0696:                    if (this .monitor != null) {
0697:                        this .monitor.setCurrentObject(entry.reference
0698:                                .getTableExpression(), i + 1, count);
0699:                    }
0700:
0701:                    try {
0702:                        if (tableType.equalsIgnoreCase(entry.reference
0703:                                .getType())) {
0704:                            ReportTable source = createReportTableInstance(
0705:                                    entry.reference, this .sourceDb);
0706:                            if (entry.target == null) {
0707:                                out.write("\n");
0708:                                writeTag(out, indent, TAG_ADD_TABLE, true,
0709:                                        "name", entry.reference.getTableName());
0710:                                StrBuffer s = source.getXml(tblIndent);
0711:                                s.writeTo(out);
0712:                                writeTag(out, indent, TAG_ADD_TABLE, false);
0713:                            } else {
0714:                                ReportTable target = createReportTableInstance(
0715:                                        entry.target, this .targetDb);
0716:                                TableDiff d = new TableDiff(source, target,
0717:                                        this );
0718:                                //d.setCompareComments(this.diffComments);
0719:                                d.setIndent(indent);
0720:                                d.setTagWriter(tw);
0721:                                StrBuffer s = d.getMigrateTargetXml();
0722:                                if (s.length() > 0) {
0723:                                    out.write("\n");
0724:                                    s.writeTo(out);
0725:                                }
0726:                            }
0727:                        } else {
0728:                            // We cannot write out the diff for the views immediately
0729:                            // because they should be listed after the table diffs
0730:                            ReportView source = createReportViewInstance(
0731:                                    entry.reference, sourceDb);
0732:                            ReportView target = null;
0733:                            if (entry.target != null) {
0734:                                target = createReportViewInstance(entry.target,
0735:                                        targetDb);
0736:                            }
0737:                            ViewDiff d = new ViewDiff(source, target);
0738:                            d.setIndent(indent);
0739:                            d.setTagWriter(tw);
0740:                            viewDiffs.add(d);
0741:                        }
0742:                    } catch (SQLException sql) {
0743:                        LogMgr.logError("SchemaDiff.writeXml()",
0744:                                "Error comparing " + entry.toString(), sql);
0745:                    }
0746:                }
0747:
0748:                if (this .cancel)
0749:                    return;
0750:
0751:                this .appendDropTables(out, indent);
0752:                out.write("\n");
0753:
0754:                if (this .diffViews) {
0755:                    this .appendViewDiff(viewDiffs, out);
0756:                    //out.write("\n");
0757:                    this .appendDropViews(out, indent, tw);
0758:                }
0759:                if (this .diffSequences) {
0760:                    this .appendSequenceDiff(out, indent, tw);
0761:                    out.write("\n");
0762:                }
0763:
0764:                if (this .diffProcs) {
0765:                    this .appendProcDiff(out, indent, tw);
0766:                    out.write("\n");
0767:                }
0768:
0769:                if (this .cancel)
0770:                    return;
0771:
0772:                if (this .diffProcs) {
0773:                    this .appendProcDiff(out, indent, tw);
0774:                    out.write("\n");
0775:                }
0776:
0777:                writeTag(out, null, "schema-diff", false);
0778:            }
0779:
0780:            private void appendSequenceDiff(Writer out, StrBuffer indent,
0781:                    TagWriter tw) throws IOException {
0782:                int count = this .objectsToCompare.size();
0783:                for (int i = 0; i < count; i++) {
0784:                    Object o = objectsToCompare.get(i);
0785:                    if (o instanceof  DiffEntry)
0786:                        continue;
0787:                    if (o instanceof  ProcDiffEntry)
0788:                        continue;
0789:
0790:                    SequenceDiffEntry entry = (SequenceDiffEntry) o;
0791:                    ReportSequence rp = new ReportSequence(entry.reference,
0792:                            this .namespace);
0793:                    ReportSequence tp = (entry.target == null ? null
0794:                            : new ReportSequence(entry.target, this .namespace));
0795:                    SequenceDiff diff = new SequenceDiff(rp, tp);
0796:                    diff.setIndent(indent);
0797:                    diff.setTagWriter(tw);
0798:                    StrBuffer xml = diff.getMigrateTargetXml();
0799:                    if (xml.length() > 0) {
0800:                        out.write("\n");
0801:                        xml.writeTo(out);
0802:                    }
0803:                }
0804:
0805:                if (this .sequencesToDelete == null
0806:                        || sequencesToDelete.size() == 0)
0807:                    return;
0808:
0809:                out.write('\n');
0810:                writeTag(out, indent, TAG_DROP_SEQUENCE, true);
0811:                StrBuffer myindent = new StrBuffer(indent);
0812:                myindent.append("  ");
0813:                Iterator itr = this .sequencesToDelete.iterator();
0814:                for (SequenceDefinition def : sequencesToDelete) {
0815:                    writeTagValue(out, myindent, ReportSequence.TAG_SEQ_NAME,
0816:                            def.getSequenceName());
0817:                }
0818:                writeTag(out, indent, TAG_DROP_SEQUENCE, false);
0819:            }
0820:
0821:            private void appendProcDiff(Writer out, StrBuffer indent,
0822:                    TagWriter tw) throws IOException {
0823:                int count = this .objectsToCompare.size();
0824:                for (int i = 0; i < count; i++) {
0825:                    Object o = objectsToCompare.get(i);
0826:                    if (o instanceof  DiffEntry)
0827:                        continue;
0828:                    if (o instanceof  SequenceDiffEntry)
0829:                        continue;
0830:
0831:                    ProcDiffEntry entry = (ProcDiffEntry) o;
0832:                    ReportProcedure rp = new ReportProcedure(entry.reference,
0833:                            this .sourceDb);
0834:                    ReportProcedure tp = new ReportProcedure(entry.target,
0835:                            this .targetDb);
0836:                    ProcDiff diff = new ProcDiff(rp, tp);
0837:                    diff.setIndent(indent);
0838:                    diff.setTagWriter(tw);
0839:                    StrBuffer xml = diff.getMigrateTargetXml();
0840:                    if (xml.length() > 0) {
0841:                        out.write("\n");
0842:                        xml.writeTo(out);
0843:                    }
0844:                }
0845:
0846:                if (this .procsToDelete == null || procsToDelete.size() == 0)
0847:                    return;
0848:
0849:                out.write('\n');
0850:                writeTag(out, indent, TAG_DROP_PROC, true);
0851:                StrBuffer myindent = new StrBuffer(indent);
0852:                myindent.append("  ");
0853:                Iterator itr = this .procsToDelete.iterator();
0854:                while (itr.hasNext()) {
0855:                    ProcedureDefinition def = (ProcedureDefinition) itr.next();
0856:                    ReportProcedure rp = new ReportProcedure(def, targetDb);
0857:                    rp.setIndent(myindent);
0858:                    StrBuffer xml = rp.getXml(false);
0859:                    xml.writeTo(out);
0860:                }
0861:                writeTag(out, indent, TAG_DROP_PROC, false);
0862:            }
0863:
0864:            private void appendViewDiff(List<ViewDiff> diffs, Writer out)
0865:                    throws IOException {
0866:                for (ViewDiff d : diffs) {
0867:                    StrBuffer source = d.getMigrateTargetXml();
0868:                    if (source.length() > 0) {
0869:                        out.write("\n");
0870:                        source.writeTo(out);
0871:                    }
0872:                }
0873:            }
0874:
0875:            private void appendDropViews(Writer out, StrBuffer indent,
0876:                    TagWriter tw) throws IOException {
0877:                if (this .viewsToDelete == null
0878:                        || this .viewsToDelete.size() == 0)
0879:                    return;
0880:                out.write("\n");
0881:                writeTag(out, indent, TAG_DROP_VIEW, true);
0882:                Iterator itr = this .viewsToDelete.iterator();
0883:                StrBuffer myindent = new StrBuffer(indent);
0884:                myindent.append("  ");
0885:                while (itr.hasNext()) {
0886:                    TableIdentifier t = (TableIdentifier) itr.next();
0887:                    writeTagValue(out, myindent, ReportView.TAG_VIEW_NAME, t
0888:                            .getTableName());
0889:                }
0890:                writeTag(out, indent, TAG_DROP_VIEW, false);
0891:            }
0892:
0893:            private void appendDropTables(Writer out, StrBuffer indent)
0894:                    throws IOException {
0895:                if (this .tablesToDelete == null
0896:                        || this .tablesToDelete.size() == 0)
0897:                    return;
0898:                out.write("\n");
0899:                writeTag(out, indent, TAG_DROP_TABLE, true);
0900:                Iterator itr = this .tablesToDelete.iterator();
0901:                StrBuffer myindent = new StrBuffer(indent);
0902:                myindent.append("  ");
0903:                while (itr.hasNext()) {
0904:                    TableIdentifier t = (TableIdentifier) itr.next();
0905:                    writeTagValue(out, myindent, ReportTable.TAG_TABLE_NAME, t
0906:                            .getTableName());
0907:                }
0908:                writeTag(out, indent, TAG_DROP_TABLE, false);
0909:            }
0910:
0911:            private void writeDiffInfo(Writer out) throws IOException {
0912:                StrBuffer indent = new StrBuffer("  ");
0913:                StrBuffer indent2 = new StrBuffer("    ");
0914:                writeTag(out, indent, TAG_REF_CONN, true);
0915:                StrBuffer info = this .sourceDb.getDatabaseInfoAsXml(indent2,
0916:                        this .namespace);
0917:                info.writeTo(out);
0918:                writeTag(out, indent, TAG_REF_CONN, false);
0919:                out.write("\n");
0920:                out
0921:                        .write("  <!-- If the target connection is modified according to the  -->\n");
0922:                out
0923:                        .write("  <!-- defintions in this file, then its structure will be    -->\n");
0924:                out.write("  <!-- the same as the reference connection -->\n");
0925:                writeTag(out, indent, TAG_TARGET_CONN, true);
0926:                info = this .targetDb.getDatabaseInfoAsXml(indent2,
0927:                        this .namespace);
0928:                info.writeTo(out);
0929:                writeTag(out, indent, TAG_TARGET_CONN, false);
0930:                out.write("\n");
0931:
0932:                info = new StrBuffer();
0933:                TagWriter tw = new TagWriter(this .namespace);
0934:
0935:                tw.appendOpenTag(info, indent, TAG_COMPARE_INFO);
0936:                info.append('\n');
0937:                tw.appendTag(info, indent2, TAG_INDEX_INFO, this .diffIndex);
0938:                tw.appendTag(info, indent2, TAG_FK_INFO, this .diffForeignKeys);
0939:                tw.appendTag(info, indent2, TAG_PK_INFO, this .diffPrimaryKeys);
0940:                tw.appendTag(info, indent2, TAG_CONSTRAINT_INFO,
0941:                        this .diffConstraints);
0942:                tw.appendTag(info, indent2, TAG_GRANT_INFO, this .diffGrants);
0943:                tw.appendTag(info, indent2, TAG_VIEW_INFO, this .diffViews);
0944:
0945:                if (this .referenceSchema != null && this .targetSchema != null) {
0946:                    tw.appendTag(info, indent2, "reference-schema",
0947:                            this .referenceSchema);
0948:                    tw.appendTag(info, indent2, "target-schema",
0949:                            this .targetSchema);
0950:                }
0951:                int count = this .objectsToCompare.size();
0952:                String tattr[] = new String[] { "type", "reference",
0953:                        "compareTo" };
0954:                String pattr[] = new String[] { "referenceProcedure",
0955:                        "compareTo" };
0956:                String tbls[] = new String[3];
0957:                DbSettings dbs = this .sourceDb.getMetadata().getDbSettings();
0958:                for (int i = 0; i < count; i++) {
0959:                    // check for ignored tables
0960:                    //if (this.referenceTables[i] == null) continue;
0961:                    Object o = objectsToCompare.get(i);
0962:                    if (o instanceof  DiffEntry) {
0963:                        DiffEntry de = (DiffEntry) o;
0964:                        tbls[0] = de.reference.getType();
0965:                        tbls[1] = (de.target == null ? "" : StringUtil
0966:                                .trimQuotes(de.target.getTableName()));
0967:                        tbls[2] = StringUtil.trimQuotes(de.reference
0968:                                .getTableName());
0969:                        if (dbs.isViewType(tbls[0])) {
0970:                            tw.appendOpenTag(info, indent2, TAG_VIEW_PAIR,
0971:                                    tattr, tbls, false);
0972:                        } else {
0973:                            tw.appendOpenTag(info, indent2, TAG_TABLE_PAIR,
0974:                                    tattr, tbls, false);
0975:                        }
0976:                    } else if (o instanceof  ProcDiffEntry) {
0977:                        ProcDiffEntry pe = (ProcDiffEntry) o;
0978:                        tbls[0] = pe.reference.getProcedureName();
0979:                        tbls[1] = (pe.target == null ? "" : pe.target
0980:                                .getProcedureName());
0981:
0982:                        tw.appendOpenTag(info, indent2, TAG_PROC_PAIR, pattr,
0983:                                tbls, false);
0984:                    } else if (o instanceof  SequenceDiffEntry) {
0985:                        SequenceDiffEntry pe = (SequenceDiffEntry) o;
0986:                        tbls[0] = pe.reference.getSequenceName();
0987:                        tbls[1] = (pe.target == null ? "" : pe.target
0988:                                .getSequenceName());
0989:                        tw.appendOpenTag(info, indent2, TAG_PROC_PAIR, pattr,
0990:                                tbls, false);
0991:                    }
0992:                    info.append("/>\n");
0993:
0994:                }
0995:                tw.appendCloseTag(info, indent, TAG_COMPARE_INFO);
0996:
0997:                info.writeTo(out);
0998:            }
0999:
1000:            private void writeTag(Writer out, StrBuffer indent, String tag,
1001:                    boolean isOpeningTag) throws IOException {
1002:                writeTag(out, indent, tag, isOpeningTag, null, null);
1003:            }
1004:
1005:            private void writeTag(Writer out, StrBuffer indent, String tag,
1006:                    boolean isOpeningTag, String attr, String attrValue)
1007:                    throws IOException {
1008:                if (indent != null)
1009:                    indent.writeTo(out);
1010:                if (isOpeningTag) {
1011:                    out.write("<");
1012:                } else {
1013:                    out.write("</");
1014:                }
1015:                if (this .namespace != null) {
1016:                    out.write(namespace);
1017:                    out.write(":");
1018:                }
1019:                out.write(tag);
1020:                if (isOpeningTag && attr != null) {
1021:                    out.write(' ');
1022:                    out.write(attr);
1023:                    out.write("=\"");
1024:                    out.write(attrValue);
1025:                    out.write('"');
1026:                }
1027:                out.write(">\n");
1028:            }
1029:
1030:            private void writeTagValue(Writer out, StrBuffer indent,
1031:                    String tag, String value) throws IOException {
1032:                if (indent != null)
1033:                    indent.writeTo(out);
1034:                out.write("<");
1035:                if (this .namespace != null) {
1036:                    out.write(namespace);
1037:                    out.write(":");
1038:                }
1039:                out.write(tag);
1040:                out.write(">");
1041:                out.write(value);
1042:                out.write("</");
1043:                if (this .namespace != null) {
1044:                    out.write(namespace);
1045:                    out.write(":");
1046:                }
1047:                out.write(tag);
1048:                out.write(">\n");
1049:            }
1050:        }
1051:
1052:        class SequenceDiffEntry {
1053:            SequenceDefinition reference;
1054:            SequenceDefinition target;
1055:
1056:            public SequenceDiffEntry(SequenceDefinition ref,
1057:                    SequenceDefinition tar) {
1058:                reference = ref;
1059:                target = tar;
1060:            }
1061:        }
1062:
1063:        class ProcDiffEntry {
1064:            ProcedureDefinition reference;
1065:            ProcedureDefinition target;
1066:
1067:            public ProcDiffEntry(ProcedureDefinition ref,
1068:                    ProcedureDefinition tar) {
1069:                reference = ref;
1070:                target = tar;
1071:            }
1072:        }
1073:
1074:        class DiffEntry {
1075:            TableIdentifier reference;
1076:            TableIdentifier target;
1077:
1078:            public DiffEntry(TableIdentifier ref, TableIdentifier tar) {
1079:                reference = ref;
1080:                target = tar;
1081:            }
1082:
1083:            public String toString() {
1084:                if (target == null)
1085:                    return reference.getType() + ": "
1086:                            + reference.getTableExpression();
1087:                else
1088:                    return reference.getType() + ": "
1089:                            + reference.getTableExpression() + " to "
1090:                            + target.getType() + ": "
1091:                            + target.getTableExpression();
1092:            }
1093:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.