PKtQKMETA-INF/MANIFEST.MFMLK-. K-*ϳR03PKPK tQK+org/jumpmind/symmetric/io/DbCompare$1.class2$%org/jumpmind/symmetric/io/DbCompare$1java/lang/Object!org/jumpmind/db/sql/ISqlRowMapperthis$0%Lorg/jumpmind/symmetric/io/DbCompare;((Lorg/jumpmind/symmetric/io/DbCompare;)VCode    ()VLineNumberTableLocalVariableTablethis'Lorg/jumpmind/symmetric/io/DbCompare$1;mapRow4(Lorg/jumpmind/db/sql/Row;)Lorg/jumpmind/db/sql/Row;rowLorg/jumpmind/db/sql/Row;-(Lorg/jumpmind/db/sql/Row;)Ljava/lang/Object;   SourceFileDbCompare.java SignaturePLjava/lang/Object;Lorg/jumpmind/db/sql/ISqlRowMapper;EnclosingMethod"#org/jumpmind/symmetric/io/DbCompare InnerClasses   8 *+ * =   6+@A &*+ !# PK tQK ?org/jumpmind/symmetric/io/DbCompare$CountingSqlReadCursor.class299org/jumpmind/symmetric/io/DbCompare$CountingSqlReadCursorjava/lang/Object"org/jumpmind/db/sql/ISqlReadCursorjava/io/Closeablewrapped$Lorg/jumpmind/db/sql/ISqlReadCursor; Signature?Lorg/jumpmind/db/sql/ISqlReadCursor;countIthis$0%Lorg/jumpmind/symmetric/io/DbCompare;L(Lorg/jumpmind/symmetric/io/DbCompare;Lorg/jumpmind/db/sql/ISqlReadCursor;)VB(Lorg/jumpmind/db/sql/ISqlReadCursor;)VCode    ()V    LineNumberTableLocalVariableTablethis;Lorg/jumpmind/symmetric/io/DbCompare$CountingSqlReadCursor;LocalVariableTypeTablenext()Lorg/jumpmind/db/sql/Row; & #'()Ljava/lang/Object;)org/jumpmind/db/sql/RowrowLorg/jumpmind/db/sql/Row; StackMapTableclose / - 1 #$ SourceFileDbCompare.javadLjava/lang/Object;Lorg/jumpmind/db/sql/ISqlReadCursor;Ljava/io/Closeable; InnerClasses7#org/jumpmind/symmetric/io/DbCompareCountingSqlReadCursor     f*+***,, *-. ! "  #$k*%(L+ *Y`+2 346 ! *+,(-8 *. ; <  !A#'%*023 45 68PK tQKyH]])org/jumpmind/symmetric/io/DbCompare.class2[#org/jumpmind/symmetric/io/DbComparejava/lang/ObjectlogLorg/slf4j/Logger;defaultRowMapper#Lorg/jumpmind/db/sql/ISqlRowMapper; Signature>Lorg/jumpmind/db/sql/ISqlRowMapper; sourceEngine)Lorg/jumpmind/symmetric/ISymmetricEngine; targetEngineconfig+Lorg/jumpmind/symmetric/io/DbCompareConfig;dbValueComparator-Lorg/jumpmind/symmetric/io/DbValueComparator;(Lorg/jumpmind/symmetric/ISymmetricEngine;Lorg/jumpmind/symmetric/ISymmetricEngine;Lorg/jumpmind/symmetric/io/DbCompareConfig;)VCode  ()V  getClass()Ljava/lang/Class; org/slf4j/LoggerFactory ! getLogger%(Ljava/lang/Class;)Lorg/slf4j/Logger; # %%org/jumpmind/symmetric/io/DbCompare$1 $' (((Lorg/jumpmind/symmetric/io/DbCompare;)V *  ,  . 0 2+org/jumpmind/symmetric/io/DbValueComparator 14 5U(Lorg/jumpmind/symmetric/ISymmetricEngine;Lorg/jumpmind/symmetric/ISymmetricEngine;)V 7 LineNumberTableLocalVariableTablethis%Lorg/jumpmind/symmetric/io/DbCompare;compare-()Lorg/jumpmind/symmetric/io/DbCompareReport; ?A@)org/jumpmind/symmetric/io/DbCompareConfig BCgetNumericScale()I 1E FGsetNumericScale(I)V I JKgetSqlDiffOutputStream()Ljava/io/OutputStream;M)org/jumpmind/symmetric/io/DbCompareReport L PRQjava/lang/System STcurrentTimeMillis()J V WXgetTablesToCompare()Ljava/util/List; PZ [\outLjava/io/PrintStream; L^ _`printReportHeader(Ljava/io/PrintStream;)V bdcjava/util/List efiterator()Ljava/util/Iterator; hjijava/util/Iterator klnext()Ljava/lang/Object;n)org/jumpmind/symmetric/io/DbCompareTables p qr compareTablesz(Lorg/jumpmind/symmetric/io/DbCompareTables;Ljava/io/OutputStream;)Lorg/jumpmind/symmetric/io/DbCompareReport$TableReport; Lt uvaddTableReport:(Lorg/jumpmind/symmetric/io/DbCompareReport$TableReport;)Vx%Completed table {}. Elapsed time: {} z|{0org/apache/commons/lang/time/DurationFormatUtils }~formatDurationWords(JZZ)Ljava/lang/String; org/slf4j/Logger info9(Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)V L printTableReportO(Lorg/jumpmind/symmetric/io/DbCompareReport$TableReport;Ljava/io/PrintStream;)Vjava/lang/StringBuilderException while comparing (Ljava/lang/String;)V m getSourceTable()Lorg/jumpmind/db/model/Table; append-(Ljava/lang/Object;)Ljava/lang/StringBuilder; to -(Ljava/lang/String;)Ljava/lang/StringBuilder; m getTargetTable toString()Ljava/lang/String; error*(Ljava/lang/String;Ljava/lang/Throwable;)V h hasNext()Z L `printReportFooter#dbcompare complete. Total Time: {} '(Ljava/lang/String;Ljava/lang/Object;)Vjava/lang/Exception sqlDiffOutputLjava/io/OutputStream;report+Lorg/jumpmind/symmetric/io/DbCompareReport;startJtablesToCompareLjava/util/List;tables+Lorg/jumpmind/symmetric/io/DbCompareTables; tableReport7Lorg/jumpmind/symmetric/io/DbCompareReport$TableReport;elapsedeLjava/lang/Exception; totalTimeLocalVariableTypeTable=Ljava/util/List; StackMapTablejava/io/OutputStream ? getSqlDiffFileName #org/apache/commons/lang/StringUtils isEmpty(Ljava/lang/String;)Z%t java/lang/String contains(Ljava/lang/CharSequence;)Z2org/jumpmind/symmetric/io/FirstUseFileOutputStream java/lang/RuntimeExceptionFailed to open stream to file '' sqlDiffFileNameLjava/lang/String;C(Lorg/jumpmind/symmetric/io/DbCompareTables;)Ljava/io/OutputStream;%s replaceD(Ljava/lang/CharSequence;Ljava/lang/CharSequence;)Ljava/lang/String; org/jumpmind/db/model/Table getName format9(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/String;"  replaceAll8(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;\]\[fileNameFormatted  'org/jumpmind/symmetric/ISymmetricEngine   getDatabasePlatform.()Lorg/jumpmind/db/platform/IDatabasePlatform;  getSourceComparisonSQLk(Lorg/jumpmind/symmetric/io/DbCompareTables;Lorg/jumpmind/db/platform/IDatabasePlatform;)Ljava/lang/String;  getTargetComparisonSQL9org/jumpmind/symmetric/io/DbCompare$CountingSqlReadCursor *org/jumpmind/db/platform/IDatabasePlatform getSqlTemplateDirty$()Lorg/jumpmind/db/sql/ISqlTemplate;  org/jumpmind/db/sql/ISqlTemplate  queryForCursor[(Ljava/lang/String;Lorg/jumpmind/db/sql/ISqlRowMapper;)Lorg/jumpmind/db/sql/ISqlReadCursor; " #L(Lorg/jumpmind/symmetric/io/DbCompare;Lorg/jumpmind/db/sql/ISqlReadCursor;)V%5org/jumpmind/symmetric/io/DbCompareReport$TableReport $ $( )setSourceTable $+ ,setTargetTable . k/()Lorg/jumpmind/db/sql/Row;1-org/jumpmind/symmetric/io/DbCompareDiffWriter 03 4m(Lorg/jumpmind/symmetric/ISymmetricEngine;Lorg/jumpmind/symmetric/io/DbCompareTables;Ljava/io/OutputStream;)V 6 JP9R{} rows processed for table {}. Elapsed time {}. ({} ms.) Current report status {} ;=<java/lang/Integer >?valueOf(I)Ljava/lang/Integer; ACBjava/lang/Long >D(J)Ljava/lang/Long; F G((Ljava/lang/String;[Ljava/lang/Object;)VI&org/jumpmind/symmetric/io/DbCompareRow HK L(Lorg/jumpmind/symmetric/ISymmetricEngine;Lorg/jumpmind/symmetric/io/DbValueComparator;Lorg/jumpmind/db/model/Table;Lorg/jumpmind/db/sql/Row;)V N OP comparePk~(Lorg/jumpmind/symmetric/io/DbCompareTables;Lorg/jumpmind/symmetric/io/DbCompareRow;Lorg/jumpmind/symmetric/io/DbCompareRow;)I HR ST compareTod(Lorg/jumpmind/symmetric/io/DbCompareTables;Lorg/jumpmind/symmetric/io/DbCompareRow;)Ljava/util/Map; VXW java/util/Map $Z [countMatchedRow 0] ^_ writeUpdate:(Lorg/jumpmind/symmetric/io/DbCompareRow;Ljava/util/Map;)V $a bcountDifferentRow 0d ef writeInsert+(Lorg/jumpmind/symmetric/io/DbCompareRow;)V $h icountMissingRow 0k lf writeDelete $n o countExtraRow q rscountI $u vG setSourceRows $x yG setTargetRows {}|org/apache/commons/io/IOUtils ~ closeQuietly(Ljava/io/OutputStream;)V { ~(Ljava/io/Closeable;)V sourceSelect targetSelect sourceCursor;Lorg/jumpmind/symmetric/io/DbCompare$CountingSqlReadCursor; targetCursor sourceRowLorg/jumpmind/db/sql/Row; targetRowcounter startTime diffWriter/Lorg/jumpmind/symmetric/io/DbCompareDiffWriter;streamsourceCompareRow(Lorg/jumpmind/symmetric/io/DbCompareRow;targetCompareRowdeltasLjava/util/Map;ALjava/util/Map;org/jumpmind/db/sql/Rowjava/lang/Throwable H  comparePksV(Lorg/jumpmind/symmetric/io/DbCompareTables;Lorg/jumpmind/symmetric/io/DbCompareRow;)I ? getSourceWhereClause&(Ljava/lang/String;)Ljava/lang/String;  getPrimaryKeyColumns!()[Lorg/jumpmind/db/model/Column;  getComparisonSQL(Lorg/jumpmind/db/model/Table;[Lorg/jumpmind/db/model/Column;Lorg/jumpmind/db/platform/IDatabasePlatform;Ljava/lang/String;)Ljava/lang/String;platform,Lorg/jumpmind/db/platform/IDatabasePlatform; whereClausejava/util/ArrayList  m getColumnMapping()Ljava/util/Map; V get&(Ljava/lang/Object;)Ljava/lang/Object;org/jumpmind/db/model/Column\No target column mapped to source PK column {}. Dbcompare may be inaccurate for this table.  warn b add(Ljava/lang/Object;)Z ? getTargetWhereClausemappedPkColumnssourcePkColumnLorg/jumpmind/db/model/Column; targetColumn0Ljava/util/List;[Lorg/jumpmind/db/model/Column; (org/jumpmind/db/sql/DmlStatement$DmlType SELECT*Lorg/jumpmind/db/sql/DmlStatement$DmlType;   getCatalog   getSchema   getColumns  createDmlStatement(Lorg/jumpmind/db/sql/DmlStatement$DmlType;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;[Lorg/jumpmind/db/model/Column;[Lorg/jumpmind/db/model/Column;[ZLjava/lang/String;)Lorg/jumpmind/db/sql/DmlStatement;  org/jumpmind/db/sql/DmlStatement getSql   buildOrderBy|(Lorg/jumpmind/db/model/Table;[Lorg/jumpmind/db/model/Column;Lorg/jumpmind/db/platform/IDatabasePlatform;)Ljava/lang/String;Comparison SQL: {}tableLorg/jumpmind/db/model/Table; sortByColumns statement"Lorg/jumpmind/db/sql/DmlStatement;sqlLjava/lang/StringBuilder;  getDatabaseInfo)()Lorg/jumpmind/db/platform/DatabaseInfo; %org/jumpmind/db/platform/DatabaseInfo getDelimiterToken ORDER BY ,  Clength  G setLength databaseInfo'Lorg/jumpmind/db/platform/DatabaseInfo;quote orderByClause sortByColumn columnName?()Ljava/util/List; ? isUseSymmetricConfig  XloadTablesFromConfig  XloadTablesFromArguments  getTriggerRouterService8()Lorg/jumpmind/symmetric/service/ITriggerRouterService; 4org/jumpmind/symmetric/service/ITriggerRouterService  !getTriggersForCurrentNode(Z)Ljava/util/List; # $getTablePrefix &(',org/jumpmind/symmetric/common/TableConstants )*getConfigTables$(Ljava/lang/String;)Ljava/util/List;,$org/jumpmind/symmetric/model/Trigger +. / getFullyQualifiedSourceTableName b1  ?3 4XgetTargetTableNames 6 78 loadTables2(Ljava/util/List;Ljava/util/List;)Ljava/util/List;triggers configTables tableNamestrigger&Lorg/jumpmind/symmetric/model/Trigger;8Ljava/util/List;$Ljava/util/List;(Ljava/util/List;Ljava/util/List;)Ljava/util/List; B G D EF filterTables"(Ljava/util/List;)Ljava/util/List; HJI.org/apache/commons/collections/CollectionUtils K(Ljava/util/Collection;)Z bM NCsizeP)org/jumpmind/symmetric/SymmetricExceptionRlTable names must be the same length as the list of target table names. Check your arguments. table names = T target table names = OV G bX Y(I)Ljava/lang/Object; [ \]parseQualifiedTableName#(Ljava/lang/String;)Ljava/util/Map; VM ` abgetTableFromCache2(Ljava/lang/String;Z)Lorg/jumpmind/db/model/Table;dcatalogfschema i ajV(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Z)Lorg/jumpmind/db/model/Table;l!No source table found for name {} mn o=(Lorg/jumpmind/db/model/Table;Lorg/jumpmind/db/model/Table;)V q rsloadTargetTable\(Lorg/jumpmind/symmetric/io/DbCompareTables;Ljava/lang/String;)Lorg/jumpmind/db/model/Table;u!No target table found for name {} mw xapplyColumnMappings mz {|filterExcludedColumns.(Lorg/jumpmind/symmetric/io/DbCompareConfig;)V ~ CgetPrimaryKeyColumnCountbSource table {} doesn't have any primary key columns and will not be considered in the comparison.   mapPrimaryKey.(Lorg/jumpmind/symmetric/io/DbCompareTables;)ZtargetTableNamesfilteredTablesNamesi tableName sourceTabletableNamePartstargetTableName targetTablesuccessZ5Ljava/util/Map;WNo target column mapped to source PK column {}. Unable to perform dbcompare on table {}     setPrimaryKey(Z)V  removeAllColumns   addColumns(Ljava/util/Collection;)V targetColumnscolumnreorderedColumnsmappedPkColumn  getDefaultCatalog  getDefaultSchema  getTransformForq(Lorg/jumpmind/db/model/Table;)Lorg/jumpmind/symmetric/service/impl/TransformService$TransformTableNodeGroupLink;  loadTargetTableUsingTransformq(Lorg/jumpmind/symmetric/service/impl/TransformService$TransformTableNodeGroupLink;)Lorg/jumpmind/db/model/Table; m , (Lorg/jumpmind/db/model/Table;)V m  setTransformU(Lorg/jumpmind/symmetric/service/impl/TransformService$TransformTableNodeGroupLink;)V  getTriggerRouterForK(Lorg/jumpmind/db/model/Table;)Lorg/jumpmind/symmetric/model/TriggerRouter; *org/jumpmind/symmetric/model/TriggerRouter getTargetCatalog  getTargetSchema  lcloneException while cloning   setCatalog   setSchema  setName$java/lang/CloneNotSupportedExceptiontargetTableNameOverride transformRLorg/jumpmind/symmetric/service/impl/TransformService$TransformTableNodeGroupLink; triggerRouter,Lorg/jumpmind/symmetric/model/TriggerRouter;ex&Ljava/lang/CloneNotSupportedException;Porg/jumpmind/symmetric/service/impl/TransformService$TransformTableNodeGroupLink  &getTriggerRouterForTableForCurrentNodeH(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Z)Ljava/util/Set; d java/util/Set   getRouter'()Lorg/jumpmind/symmetric/model/Router; #org/jumpmind/symmetric/model/Router getNodeGroupLink.()Lorg/jumpmind/symmetric/model/NodeGroupLink; *org/jumpmind/symmetric/model/NodeGroupLink getTargetNodeGroupId  getNodeService/()Lorg/jumpmind/symmetric/service/INodeService; +org/jumpmind/symmetric/service/INodeService getCachedIdentity%()Lorg/jumpmind/symmetric/model/Node; !org/jumpmind/symmetric/model/Node getNodeGroupId  equals'(Ljava/lang/String;Ljava/lang/String;)ZtriggerRoutersLjava/util/Set;routerTargetNodeGroupIdcompareTargetNodeGroupId=Ljava/util/Set;   findIdentity  getTransformService4()Lorg/jumpmind/symmetric/service/ITransformService; 0org/jumpmind/symmetric/service/ITransformService findTransformsForH(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/util/List;   getFullyQualifiedTargetTableNamesourceNodeGroupIdtargetNodeGroupId transformsdLjava/util/List; ! "getTargetCatalogName $ %getTargetSchemaName ' (getTargetTableName cloneTable<(Lorg/jumpmind/db/model/Table;)Lorg/jumpmind/db/model/Table; , -(Ljava/lang/Throwable;)V ?/ 0XgetIncludedTableNames2rincludedTableNames not provided, includedTableNames must be provided when not comparing using SymmetricDS config. J(Ljava/util/List;)Ljava/util/List; 6 7compareTableNames b9 :KaddAll ?< =XgetExcludedTableNames ?  bA BremovefilteredTablesincludedTableNameexcludedTablesexcludedTableName H Itrim K LequalsIgnoreCasesourceTableNamesourceTableNamePartstargetTableNameParts getConfig-()Lorg/jumpmind/symmetric/io/DbCompareConfig; SourceFileDbCompare.java InnerClassesDmlTypeCountingSqlReadCursor TableReportY4org/jumpmind/symmetric/service/impl/TransformServiceTransformTableNodeGroupLink!    8***"*$Y*&)*-+*+-*,/*1Y+,368"I;=J K%L*M7N9*8:;8 8 8<=' *6*+>D*HLLYNMOB*U:,Y]a:sgm:*+o:,sO!e7 *"w y,Y1:*"Y,YO!e7*"y,Dwz8fQSUVW%X,YD[M\S]Z^b_i^n`wa|bcbYgijkjm9f :;%DdM*Z |, %O8LbhALbmh-LbhJKB*+L+Κ4+Զ֚+Y+ްMYY+, !8qrt!u"v@y9 B:;:"!J p*+M,Κb,N-Y+SN-NY-ް:YY-DLM8& ~+DMOn94p:;phVOMm qr (*+*- N*+*/:Y**--*)!:Y**/*)!:$Y&:+'+*-:-: 6 O7 : :,0Y*/+,2: *+5:0Y*/+2:   9  7pDO e7*"8Y :SY+SYySY@SYSEHY*-*6+J: HY*/*6+ J:*+M6>+Q:U Y \`-:-: 1 cg-: jm-: ptpw:zz8F-<AO_dmy #(-FHMfhsx  %9(:;(( Adm s   9HhsOs. .m$0 L@HH@H-HV m$0 m$0 m$0 OP}, -, -,+-8 9*:; u!*++N*++,-89*!:;!!s ~YN+Y:66<2:+:*" -W*++:*++,8* "27EHQ[k9H~:;~~v"/2k vSmb, mbmb [-++++ :Y:W*+,-W*"8*  , : G U9H[:;[[[[=,/W -::Y:,Y: 6 69 2:Y:  WW d8* (<W_hr~9\ :;| h (\ <, W /D 5WX *+ *L*L+8 !"#&9 :; bX !m*-L*-"%MYN+a:)g+:,-0--W*-*+258"+,.%0<1J2V0`694m:;]9P:%H;<<= ]9>P:?%H;?0bbbh%78 @2 {YAN*+C:,G;L,L+OYYQS,U6W::*-Z:^*-_:;*-cegh:*"kmYm: : ,G,W: *  p:  *"tC v *+y }*"* 6  - WL-8%; =?'@5BG@OEUGcHfIxJKLMNMQRSVXYZ ]^_'`*c/d8fCgQhTk\lamjEyq9 {:;{;{ rqkR'scfxw t V \ 4{;?{? rqk?xE ObbCV7"m)bbbb YM+Y:66<2N+-:*"-+,W+N-Y:662:Y:,a:g:W-Y:66#2:0 W++8juw!x0y5z<{AzF|H~Qw[cw}9f :;!00!cwww mb,mb mbmbmbbh mbbrsN*/:*/:*+G*+:*N+-+-*+:::,Ι!*/+hND+N%:OYYȷ+U---,+--8n",6;BGMOY^gpw9\ :;d"f6:Y (Om $M!i*-+++M,:9gN-:*/:-8*  2>Q[]g9>i:;iM2+> Q   M 'h5 _*- M*/ N*-,-+:GW:Κ8. $-38:BOZ]9>_:;_M$;:%O :%]bh*/+ +#+&hM,8 9 :;)*l+MY,+8 9 :; HX f+*+.GY13**+.*+258 9 +:;EF 4Y+LAM*+.G`*+.a:BgN+a:"g:*-5 ,W ,+8W*+;GjY,>N*+;a:Dg:,a:#g:*5 -@W-,8R7NXakux      9R:;C74DN^E5F ?C?^E? ,bbhbbhh bbh bb&bbbhbbbhh bbbh bb7R+GL,GM+,J*-+ZN*/,Z:-gg׸J8&   #$"3!5#94R:;RMR$.N5O$.N5OPQ/*+8@9 :;RST*U@$V$LW XZ PK tQKߔaa(org/jumpmind/symmetric/io/DbCompare.java/** * Licensed to JumpMind Inc under one or more contributor * license agreements. See the NOTICE file distributed * with this work for additional information regarding * copyright ownership. JumpMind Inc licenses this file * to you under the GNU General Public License, version 3.0 (GPLv3) * (the "License"); you may not use this file except in compliance * with the License. * * You should have received a copy of the GNU General Public License, * version 3.0 (GPLv3) along with this library; if not, see * . * * 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 org.jumpmind.symmetric.io; import java.io.Closeable; import java.io.OutputStream; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.io.IOUtils; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.time.DurationFormatUtils; import org.jumpmind.db.model.Column; import org.jumpmind.db.model.Table; import org.jumpmind.db.platform.DatabaseInfo; import org.jumpmind.db.platform.IDatabasePlatform; import org.jumpmind.db.sql.DmlStatement; import org.jumpmind.db.sql.DmlStatement.DmlType; import org.jumpmind.db.sql.ISqlReadCursor; import org.jumpmind.db.sql.ISqlRowMapper; import org.jumpmind.db.sql.Row; import org.jumpmind.symmetric.ISymmetricEngine; import org.jumpmind.symmetric.SymmetricException; import org.jumpmind.symmetric.common.TableConstants; import org.jumpmind.symmetric.io.DbCompareReport.TableReport; import org.jumpmind.symmetric.model.Trigger; import org.jumpmind.symmetric.model.TriggerRouter; import org.jumpmind.symmetric.service.impl.TransformService.TransformTableNodeGroupLink; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * DbCompare has the ability to compare two SQL-based datasources and output a report of * of differences, and optionally SQL to bring the target into sync with the source. */ public class DbCompare { final Logger log = LoggerFactory.getLogger(getClass()); ISqlRowMapper defaultRowMapper = new ISqlRowMapper() { @Override public Row mapRow(Row row) { return row; } }; private ISymmetricEngine sourceEngine; private ISymmetricEngine targetEngine; private DbCompareConfig config; private DbValueComparator dbValueComparator; public DbCompare(ISymmetricEngine sourceEngine, ISymmetricEngine targetEngine, DbCompareConfig config) { this.config = config; this.sourceEngine = sourceEngine; this.targetEngine = targetEngine; dbValueComparator = new DbValueComparator(sourceEngine, targetEngine); } public DbCompareReport compare() { dbValueComparator.setNumericScale(config.getNumericScale()); OutputStream sqlDiffOutput = getSqlDiffOutputStream(); DbCompareReport report = new DbCompareReport(); long start = System.currentTimeMillis(); List tablesToCompare = getTablesToCompare(); report.printReportHeader(System.out); for (DbCompareTables tables : tablesToCompare) { try { TableReport tableReport = compareTables(tables, sqlDiffOutput); report.addTableReport(tableReport); long elapsed = System.currentTimeMillis() - start; log.info("Completed table {}. Elapsed time: {}", tableReport, DurationFormatUtils.formatDurationWords((elapsed), true, true)); report.printTableReport(tableReport, System.out); } catch (Exception e) { log.error("Exception while comparing " + tables.getSourceTable() + " to " + tables.getTargetTable(), e); } } report.printReportFooter(System.out); long totalTime = System.currentTimeMillis() - start; log.info("dbcompare complete. Total Time: {}", DurationFormatUtils.formatDurationWords((totalTime), true, true)); return report; } protected OutputStream getSqlDiffOutputStream() { String sqlDiffFileName = config.getSqlDiffFileName(); if (!StringUtils.isEmpty(sqlDiffFileName) && !sqlDiffFileName.contains("%t")) { try { return new FirstUseFileOutputStream(sqlDiffFileName); } catch (Exception e) { throw new RuntimeException("Failed to open stream to file '" + sqlDiffFileName + "'", e); } } else { return null; } } protected OutputStream getSqlDiffOutputStream(DbCompareTables tables) { String sqlDiffFileName = config.getSqlDiffFileName(); if (!StringUtils.isEmpty(sqlDiffFileName)) { // allow file per table. String fileNameFormatted = sqlDiffFileName.replace("%t", "%s"); fileNameFormatted = String.format(fileNameFormatted, tables.getSourceTable().getName()); fileNameFormatted = fileNameFormatted.replaceAll("\"", "").replaceAll("\\]", "").replaceAll("\\[", ""); try { return new FirstUseFileOutputStream(fileNameFormatted); } catch (Exception e) { throw new RuntimeException("Failed to open stream to file '" + fileNameFormatted + "'", e); } } else { return null; } } protected TableReport compareTables(DbCompareTables tables, OutputStream sqlDiffOutput) { String sourceSelect = getSourceComparisonSQL(tables, sourceEngine.getDatabasePlatform()); String targetSelect = getTargetComparisonSQL(tables, targetEngine.getDatabasePlatform()); CountingSqlReadCursor sourceCursor = new CountingSqlReadCursor(sourceEngine.getDatabasePlatform(). getSqlTemplateDirty().queryForCursor(sourceSelect, defaultRowMapper)); CountingSqlReadCursor targetCursor = new CountingSqlReadCursor(targetEngine.getDatabasePlatform(). getSqlTemplateDirty().queryForCursor(targetSelect, defaultRowMapper)); TableReport tableReport = new TableReport(); tableReport.setSourceTable(tables.getSourceTable().getName()); tableReport.setTargetTable(tables.getTargetTable().getName()); Row sourceRow = sourceCursor.next(); Row targetRow = targetCursor.next(); int counter = 0; long startTime = System.currentTimeMillis(); DbCompareDiffWriter diffWriter = null; OutputStream stream = null; if (sqlDiffOutput != null) { diffWriter = new DbCompareDiffWriter(targetEngine, tables, sqlDiffOutput); } else { stream = getSqlDiffOutputStream(tables); diffWriter = new DbCompareDiffWriter(targetEngine, tables, stream); } try { while (true) { if (sourceRow == null && targetRow == null) { break; } counter++; if ((counter % 50000) == 0) { long elapsed = System.currentTimeMillis() - startTime; log.info("{} rows processed for table {}. Elapsed time {}. ({} ms.) Current report status {}", counter, tables.getSourceTable().getName(), DurationFormatUtils.formatDurationWords((elapsed), true, true), elapsed, tableReport); } DbCompareRow sourceCompareRow = sourceRow != null ? new DbCompareRow(sourceEngine, dbValueComparator, tables.getSourceTable(), sourceRow) : null; DbCompareRow targetCompareRow = targetRow != null ? new DbCompareRow(targetEngine, dbValueComparator, tables.getTargetTable(), targetRow) : null; int comparePk = comparePk(tables, sourceCompareRow, targetCompareRow); if (comparePk == 0) { Map deltas = sourceCompareRow.compareTo(tables, targetCompareRow); if (deltas.isEmpty()) { tableReport.countMatchedRow(); } else { diffWriter.writeUpdate(targetCompareRow, deltas); tableReport.countDifferentRow(); } sourceRow = sourceCursor.next(); targetRow = targetCursor.next(); } else if (comparePk < 0) { diffWriter.writeInsert(sourceCompareRow); tableReport.countMissingRow(); sourceRow = sourceCursor.next(); } else { diffWriter.writeDelete(targetCompareRow); tableReport.countExtraRow(); targetRow = targetCursor.next(); } tableReport.setSourceRows(sourceCursor.count); tableReport.setTargetRows(targetCursor.count); } } finally { if (stream != null) { IOUtils.closeQuietly(stream); } IOUtils.closeQuietly(sourceCursor); IOUtils.closeQuietly(targetCursor); } return tableReport; } protected int comparePk(DbCompareTables tables, DbCompareRow sourceCompareRow, DbCompareRow targetCompareRow) { if (sourceCompareRow != null && targetCompareRow == null) { return -1; } if (sourceCompareRow == null && targetCompareRow != null) { return 1; } return sourceCompareRow.comparePks(tables, targetCompareRow); } protected String getSourceComparisonSQL(DbCompareTables tables, IDatabasePlatform platform) { String whereClause = config.getSourceWhereClause(tables.getSourceTable().getName()); return getComparisonSQL(tables.getSourceTable(), tables.getSourceTable().getPrimaryKeyColumns(), platform, whereClause); } protected String getTargetComparisonSQL(DbCompareTables tables, IDatabasePlatform platform) { List mappedPkColumns = new ArrayList(); for (Column sourcePkColumn : tables.getSourceTable().getPrimaryKeyColumns()) { Column targetColumn = tables.getColumnMapping().get(sourcePkColumn); if (targetColumn == null) { log.warn("No target column mapped to source PK column {}. Dbcompare may be inaccurate for this table.", sourcePkColumn); } else { mappedPkColumns.add(targetColumn); } } String whereClause = config.getTargetWhereClause(tables.getTargetTable().getName()); return getComparisonSQL(tables.getTargetTable(), tables.getTargetTable().getPrimaryKeyColumns(), platform, whereClause); } protected String getComparisonSQL(Table table, Column[] sortByColumns, IDatabasePlatform platform, String whereClause) { DmlStatement statement = platform.createDmlStatement(DmlType.SELECT, table.getCatalog(), table.getSchema(), table.getName(), null, table.getColumns(), null, null); StringBuilder sql = new StringBuilder(statement.getSql()); sql.append(whereClause).append(" "); sql.append(buildOrderBy(table, sortByColumns, platform)); log.info("Comparison SQL: {}", sql); return sql.toString(); } protected String buildOrderBy(Table table, Column[] sortByColumns, IDatabasePlatform platform) { DatabaseInfo databaseInfo = platform.getDatabaseInfo(); String quote = databaseInfo.getDelimiterToken() == null ? "" : databaseInfo.getDelimiterToken(); StringBuilder orderByClause = new StringBuilder("ORDER BY "); for (Column sortByColumn : sortByColumns) { String columnName = new StringBuilder(quote).append(sortByColumn.getName()).append(quote).toString(); orderByClause.append(columnName); orderByClause.append(","); } orderByClause.setLength(orderByClause.length()-1); return orderByClause.toString(); } protected List getTablesToCompare() { List tablesToCompare; if (config.isUseSymmetricConfig()) { tablesToCompare = loadTablesFromConfig(); } else { tablesToCompare = loadTablesFromArguments(); } return tablesToCompare; } protected List loadTablesFromConfig() { List triggers = sourceEngine.getTriggerRouterService().getTriggersForCurrentNode(true); List configTables = TableConstants.getConfigTables(sourceEngine.getTablePrefix()); List tableNames = new ArrayList(); for (Trigger trigger : triggers) { if (!configTables.contains(trigger.getFullyQualifiedSourceTableName())) { tableNames.add(trigger.getFullyQualifiedSourceTableName()); } } return loadTables(tableNames, config.getTargetTableNames()); } protected List loadTables(List tableNames, List targetTableNames) { List compareTables = new ArrayList(1); List filteredTablesNames = filterTables(tableNames); if (!CollectionUtils.isEmpty(targetTableNames) && filteredTablesNames.size() != targetTableNames.size()) { throw new SymmetricException("Table names must be the same length as the list of target " + "table names. Check your arguments. table names = " + filteredTablesNames + " target table names = " + targetTableNames); } for (int i = 0; i < filteredTablesNames.size(); i++) { String tableName = filteredTablesNames.get(i); Table sourceTable = null; Map tableNameParts = sourceEngine.getDatabasePlatform().parseQualifiedTableName(tableName); if (tableNameParts.size() == 1) { sourceTable = sourceEngine.getDatabasePlatform().getTableFromCache(tableName, true); } else { sourceTable = sourceEngine.getDatabasePlatform(). getTableFromCache(tableNameParts.get("catalog"), tableNameParts.get("schema"), tableNameParts.get("table"), true); } if (sourceTable == null) { log.warn("No source table found for name {}", tableName); continue; } DbCompareTables tables = new DbCompareTables(sourceTable, null); String targetTableName = null; if (!CollectionUtils.isEmpty(targetTableNames)) { targetTableName = targetTableNames.get(i); } Table targetTable = loadTargetTable(tables, targetTableName); if (targetTable == null) { log.warn("No target table found for name {}", tableName); continue; } tables.applyColumnMappings(); tables.filterExcludedColumns(config); if (tables.getSourceTable().getPrimaryKeyColumnCount() == 0) { log.warn("Source table {} doesn't have any primary key columns and will not be considered in the comparison.", sourceTable); continue; } boolean success = mapPrimaryKey(tables); if (success) { compareTables.add(tables); } } return compareTables; } protected boolean mapPrimaryKey(DbCompareTables tables) { List mappedPkColumns = new ArrayList(); for (Column sourcePkColumn : tables.getSourceTable().getPrimaryKeyColumns()) { Column targetColumn = tables.getColumnMapping().get(sourcePkColumn); if (targetColumn == null) { log.warn("No target column mapped to source PK column {}. Unable to perform dbcompare on table {}", sourcePkColumn, tables.getSourceTable()); return false; } else { mappedPkColumns.add(targetColumn); } } Column[] targetColumns = tables.getTargetTable().getColumns(); for (Column column : targetColumns) { column.setPrimaryKey(false); } List reorderedColumns = new ArrayList(); for (Column mappedPkColumn : mappedPkColumns) { mappedPkColumn.setPrimaryKey(true); reorderedColumns.add(mappedPkColumn); } for (Column column : targetColumns) { if (!reorderedColumns.contains(column)) { reorderedColumns.add(column); } } tables.getTargetTable().removeAllColumns(); tables.getTargetTable().addColumns(reorderedColumns); return true; } protected Table loadTargetTable(DbCompareTables tables, String targetTableNameOverride) { Table targetTable = null; String catalog = targetEngine.getDatabasePlatform().getDefaultCatalog(); String schema = targetEngine.getDatabasePlatform().getDefaultSchema(); if (config.isUseSymmetricConfig()) { TransformTableNodeGroupLink transform = getTransformFor(tables.getSourceTable()); if (transform != null) { targetTable = loadTargetTableUsingTransform(transform); tables.setTargetTable(targetTable); tables.setTransform(transform); return targetTable; } TriggerRouter triggerRouter = getTriggerRouterFor(tables.getSourceTable()); if (triggerRouter != null) { catalog = triggerRouter.getTargetCatalog(catalog); schema = triggerRouter.getTargetSchema(schema); } } if (StringUtils.isEmpty(targetTableNameOverride)) { targetTable = targetEngine.getDatabasePlatform(). getTableFromCache(catalog, schema, tables.getSourceTable().getName(), true); } else { try { targetTable = (Table) tables.getSourceTable().clone(); } catch (CloneNotSupportedException ex) { throw new SymmetricException("Exception while cloning " + tables.getSourceTable()); } targetTable.setCatalog(""); targetTable.setSchema(""); targetTable.setName(targetTableNameOverride); } tables.setTargetTable(targetTable); return targetTable; } protected TriggerRouter getTriggerRouterFor(Table sourceTable) { // TODO get routers. Set triggerRouters = sourceEngine.getTriggerRouterService().getTriggerRouterForTableForCurrentNode( sourceTable.getCatalog(), sourceTable.getSchema(), sourceTable.getName(), false); for (TriggerRouter triggerRouter : triggerRouters) { String routerTargetNodeGroupId = triggerRouter.getRouter().getNodeGroupLink().getTargetNodeGroupId(); String compareTargetNodeGroupId = targetEngine.getNodeService().getCachedIdentity().getNodeGroupId(); if (StringUtils.equals(compareTargetNodeGroupId, routerTargetNodeGroupId)) { return triggerRouter; } } return null; } protected TransformTableNodeGroupLink getTransformFor(Table sourceTable) { String sourceNodeGroupId = sourceEngine.getNodeService().findIdentity().getNodeGroupId(); String targetNodeGroupId = targetEngine.getNodeService().findIdentity().getNodeGroupId(); List transforms = sourceEngine.getTransformService().findTransformsFor( sourceNodeGroupId, targetNodeGroupId, sourceTable.getName()); if (!CollectionUtils.isEmpty(transforms)) { TransformTableNodeGroupLink transform = transforms.get(0); // Only can operate on a single table transform for now. if (!StringUtils.isEmpty(transform.getFullyQualifiedTargetTableName())) { return transform; } } return null; } protected Table loadTargetTableUsingTransform(TransformTableNodeGroupLink transform) { Table targetTable = targetEngine.getDatabasePlatform(). getTableFromCache(transform.getTargetCatalogName(), transform.getTargetSchemaName(), transform.getTargetTableName(), true); return targetTable; } protected Table cloneTable(Table table) { try { return (Table) table.clone(); } catch (CloneNotSupportedException ex) { throw new RuntimeException(ex); } } protected List loadTablesFromArguments() { if (CollectionUtils.isEmpty(config.getIncludedTableNames())) { throw new RuntimeException("includedTableNames not provided, includedTableNames must be provided " + "when not comparing using SymmetricDS config."); } return loadTables(config.getIncludedTableNames(), config.getTargetTableNames()); } protected List filterTables(List tables) { List filteredTables = new ArrayList(tables.size()); if (!CollectionUtils.isEmpty(config.getIncludedTableNames())) { for (String includedTableName : config.getIncludedTableNames()) { for (String tableName : tables) { if (compareTableNames(tableName, includedTableName)) { filteredTables.add(tableName); } } } } else { filteredTables.addAll(tables); } if (!CollectionUtils.isEmpty(config.getExcludedTableNames())) { List excludedTables = new ArrayList(filteredTables); for (String excludedTableName : config.getExcludedTableNames()) { for (String tableName : filteredTables) { if (compareTableNames(tableName, excludedTableName)) { excludedTables.remove(tableName); } } } return excludedTables; } return filteredTables; } protected boolean compareTableNames(String sourceTableName, String targetTableName) { sourceTableName = sourceTableName.trim(); targetTableName = targetTableName.trim(); if (StringUtils.equalsIgnoreCase(sourceTableName, targetTableName)) { return true; } else { Map sourceTableNameParts = sourceEngine.getDatabasePlatform().parseQualifiedTableName(sourceTableName); Map targetTableNameParts = targetEngine.getDatabasePlatform().parseQualifiedTableName(targetTableName); return StringUtils.equalsIgnoreCase(sourceTableNameParts.get("table"), targetTableNameParts.get("table")); } } class CountingSqlReadCursor implements ISqlReadCursor, Closeable { ISqlReadCursor wrapped; int count = 0; CountingSqlReadCursor(ISqlReadCursor wrapped) { this.wrapped = wrapped; } @Override public Row next() { Row row = wrapped.next(); if (row != null) { count++; } return row; } @Override public void close() { wrapped.close(); } } public DbCompareConfig getConfig() { return config; } } PK ~QK`/org/jumpmind/symmetric/io/DbCompareConfig.class2)org/jumpmind/symmetric/io/DbCompareConfigjava/lang/Object WHERE_CLAUSELjava/lang/String; ConstantValue  where_clauseEXCLUDED_COLUMN exclude_columnssqlDiffFileNameincludedTableNamesLjava/util/List; Signature$Ljava/util/List;targetTableNamesexcludedTableNamesuseSymmetricConfigZ numericScaleI whereClausesLjava/util/Map;5Ljava/util/Map;tablesToExcludedColumnsGLjava/util/Map;>;()VCode !  #  % 'java/util/LinkedHashMap &! *  , LineNumberTableLocalVariableTablethis+Lorg/jumpmind/symmetric/io/DbCompareConfig;getSourceWhereClause&(Ljava/lang/String;)Ljava/lang/String;4source 6 78getWhereClause8(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; tableNamegetTargetWhereClause<target >@?#org/apache/commons/lang/StringUtils ABisEmpty(Ljava/lang/String;)Z D E2getUnqualifiedTableName whereClause StackMapTableIjava/lang/StringK"M HO PQreplaceD(Ljava/lang/CharSequence;Ljava/lang/CharSequence;)Ljava/lang/String;S` HU VW lastIndexOf(I)I HY Z[length()I H] ^_ substring(II)Ljava/lang/String;lastDot Hb cd toLowerCase()Ljava/lang/String;fjava/lang/StringBuilder Hh ijvalueOf&(Ljava/lang/Object;)Ljava/lang/String; el m(Ljava/lang/String;)Vo. eq rsappend-(Ljava/lang/String;)Ljava/lang/StringBuilder; eu vdtoString xzy java/util/Map {| containsKey(Ljava/lang/Object;)Z x~ get&(Ljava/lang/Object;)Ljava/lang/Object;1=1sourceOrTargettableNameLowerkeys[Ljava/lang/String;keyshouldIncludeColumn'(Ljava/lang/String;Ljava/lang/String;)Zjava/util/List |contains columnNamecolumnNameLowerexludedColumnNamesLocalVariableTypeTablegetSqlDiffFileName  setSqlDiffFileNamegetIncludedTableNames()Ljava/util/List;&()Ljava/util/List;  setIncludedTableNames(Ljava/util/List;)V'(Ljava/util/List;)VgetExcludedTableNames  setExcludedTableNamesisUseSymmetricConfig()ZsetUseSymmetricConfig(Z)VgetNumericScalesetNumericScale(I)VgetWhereClauses()Ljava/util/Map;7()Ljava/util/Map;setWhereClauses(Ljava/util/Map;)V8(Ljava/util/Map;)V5org/apache/commons/collections/map/CaseInsensitiveMap getTargetTableNames  setTargetTableNamesgetTablesToExcludedColumnsI()Ljava/util/Map;>;setTablesToExcludedColumnsJ(Ljava/util/Map;>;)V SourceFileDbCompareConfig.java!    c%* *"*$*&Y()*&Y(+-' ()*$. %/012<*+35--./09:2o*+;5M,= *+CN,-1235. /09FGHE2,+JLNL+RLNL+.T=+`+X\L+-9 :;<=*@. ,/0,9`G*788 +aNHYeY-gknp,pnpptSYeY-gknpptSYS:Y:66*2:*)w*)}H-. DE F/GJHMEOKdLrMKQ.>/09O?dG ] HHH# +aN,a:HYeY-gknp ptSY S:Y: 66= 2:*+w%*+}:  -2 UV WX,Y/W1\F]T^d_v\c.R/09} w1QF0d d Gg? HHHH4 HHHHH@ HHHHd/*-g. /0m>*+- jk./0 /*-m. /0P*+- pq./0 /*-s. /0P*+- vw./0 /*"-y. /0>*"- |}./0[/*$-. /0>*$- ./0/*)-. /0W *Y+)-  . /0   /*-. /0P*+- ./0 /*+-. /0P*++- ./0 PK ~QK\x6.org/jumpmind/symmetric/io/DbCompareConfig.java/** * Licensed to JumpMind Inc under one or more contributor * license agreements. See the NOTICE file distributed * with this work for additional information regarding * copyright ownership. JumpMind Inc licenses this file * to you under the GNU General Public License, version 3.0 (GPLv3) * (the "License"); you may not use this file except in compliance * with the License. * * You should have received a copy of the GNU General Public License, * version 3.0 (GPLv3) along with this library; if not, see * . * * 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 org.jumpmind.symmetric.io; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import org.apache.commons.collections.map.CaseInsensitiveMap; import org.apache.commons.lang.StringUtils; public class DbCompareConfig { public final static String WHERE_CLAUSE = "where_clause"; public final static String EXCLUDED_COLUMN = "exclude_columns"; private String sqlDiffFileName; private List includedTableNames; private List targetTableNames; private List excludedTableNames; private boolean useSymmetricConfig = true; private int numericScale = 3; private Map whereClauses = new LinkedHashMap(); private Map> tablesToExcludedColumns = new LinkedHashMap>(); public String getSourceWhereClause(String tableName) { return getWhereClause(tableName, "source"); } public String getTargetWhereClause(String tableName) { String whereClause = getWhereClause(tableName, "target"); if (StringUtils.isEmpty(whereClause)) { String simpleTableName = getUnqualifiedTableName(tableName); } return whereClause; } protected String getUnqualifiedTableName(String tableName) { tableName = tableName.replace("\"", ""); tableName = tableName.replace("`", ""); int lastDot = tableName.lastIndexOf('.'); if (lastDot > -1) { tableName = tableName.substring(lastDot+1, tableName.length()); } return tableName; } protected String getWhereClause(String tableName, String sourceOrTarget) { String tableNameLower = tableName.toLowerCase(); String[] keys = { tableNameLower + "." + sourceOrTarget + "." + WHERE_CLAUSE, tableNameLower + "." + WHERE_CLAUSE, WHERE_CLAUSE }; for (String key : keys) { if (whereClauses.containsKey(key)) { return whereClauses.get(key); } } return "1=1"; } protected boolean shouldIncludeColumn(String tableName, String columnName) { String tableNameLower = tableName.toLowerCase(); String columnNameLower = columnName.toLowerCase(); String[] keys = { tableNameLower + "." + EXCLUDED_COLUMN, EXCLUDED_COLUMN }; for (String key : keys) { if (tablesToExcludedColumns.containsKey(key)) { List exludedColumnNames = tablesToExcludedColumns.get(key); return !exludedColumnNames.contains(columnNameLower); } } return true; } public String getSqlDiffFileName() { return sqlDiffFileName; } public void setSqlDiffFileName(String sqlDiffFileName) { this.sqlDiffFileName = sqlDiffFileName; } public List getIncludedTableNames() { return includedTableNames; } public void setIncludedTableNames(List includedTableNames) { this.includedTableNames = includedTableNames; } public List getExcludedTableNames() { return excludedTableNames; } public void setExcludedTableNames(List excludedTableNames) { this.excludedTableNames = excludedTableNames; } public boolean isUseSymmetricConfig() { return useSymmetricConfig; } public void setUseSymmetricConfig(boolean useSymmetricConfig) { this.useSymmetricConfig = useSymmetricConfig; } public int getNumericScale() { return numericScale; } public void setNumericScale(int numericScale) { this.numericScale = numericScale; } public Map getWhereClauses() { return whereClauses; } @SuppressWarnings("unchecked") public void setWhereClauses(Map whereClauses) { this.whereClauses = new CaseInsensitiveMap(whereClauses); } public List getTargetTableNames() { return targetTableNames; } public void setTargetTableNames(List targetTableNames) { this.targetTableNames = targetTableNames; } public Map> getTablesToExcludedColumns() { return tablesToExcludedColumns; } public void setTablesToExcludedColumns(Map> tablesToExcludedColumns) { this.tablesToExcludedColumns = tablesToExcludedColumns; } } PKtQKMETA-INF/MANIFEST.MFPK tQK+aorg/jumpmind/symmetric/io/DbCompare$1.classPK tQK ?]org/jumpmind/symmetric/io/DbCompare$CountingSqlReadCursor.classPK tQKyH]]) org/jumpmind/symmetric/io/DbCompare.classPK tQKߔaa(horg/jumpmind/symmetric/io/DbCompare.javaPK ~QK`/org/jumpmind/symmetric/io/DbCompareConfig.classPK ~QK\x6.korg/jumpmind/symmetric/io/DbCompareConfig.javaPKr7