001: /*
002: * Copyright (c) 1998 - 2005 Versant Corporation
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * Versant Corporation - initial API and implementation
010: */
011: package com.versant.core.jdbc.sql.diff;
012:
013: import com.versant.core.jdbc.metadata.JdbcTable;
014: import com.versant.core.jdbc.metadata.JdbcColumn;
015: import com.versant.core.jdbc.metadata.JdbcIndex;
016: import com.versant.core.jdbc.metadata.JdbcConstraint;
017: import com.versant.core.jdbc.sql.SqlDriver;
018:
019: import java.util.HashMap;
020: import java.util.ArrayList;
021: import java.util.Iterator;
022: import java.util.Set;
023: import java.io.PrintWriter;
024:
025: /**
026: * The DiffUtil class gets the diffs of a JdbcTable
027: * @keep-all
028: */
029: public class DiffUtil {
030:
031: private static SqlDriver driver = null;
032:
033: public static TableDiff checkTable(SqlDriver sqlDriver,
034: JdbcTable ourTable, JdbcTable dbTable, ControlParams checks) {
035: driver = sqlDriver;
036: TableDiff tableDiff = new TableDiff(ourTable, dbTable);
037: //check table
038: if (dbTable == null) {
039: tableDiff.setMissingTable(true);
040: if (!checks.checkColumnsOnly()) { // if the table is missing we also have to index and constraints
041: // check index's
042: doIndex(tableDiff, ourTable, dbTable, checks);
043: // check constraints's
044: doConstraint(tableDiff, ourTable, dbTable, checks);
045: }
046: return tableDiff;
047: }
048:
049: //check cols
050: doCols(tableDiff, ourTable, dbTable, checks);
051:
052: if (!checks.checkColumnsOnly()) {
053: // check pks
054: doPK(tableDiff, ourTable, dbTable, checks);
055:
056: // check index's
057: doIndex(tableDiff, ourTable, dbTable, checks);
058:
059: // check constraints's
060: doConstraint(tableDiff, ourTable, dbTable, checks);
061: }
062: driver = null;
063: if (tableDiff.hasErrors()) {
064: return tableDiff;
065: } else {
066: return null;
067: }
068: }
069:
070: private static void doCols(TableDiff tableDiff, JdbcTable ourTable,
071: JdbcTable dbTable, ControlParams checks) {
072: HashMap marks = new HashMap();
073: if (ourTable.cols != null) {
074:
075: for (int i = 0; i < ourTable.cols.length; i++) {
076: JdbcColumn ourCol = ourTable.cols[i];
077: // check if our column is in there
078: JdbcColumn dbCol = null;
079: if (dbTable.cols != null) {
080: for (int j = 0; j < dbTable.cols.length; j++) {
081: JdbcColumn col = dbTable.cols[j];
082: if (ourCol.name.equalsIgnoreCase(col.name)) {
083: marks.put(new Integer(j), null);
084: dbCol = col;
085: break;
086: }
087: }
088: }
089: if (!ourCol.shared) {
090: ColumnDiff diff = checkColumn(ourCol, dbCol, checks);
091: if (diff != null) {
092: tableDiff.getColDiffs().add(diff);
093: }
094: }
095: }
096: }
097: if (checks.checkExtraColumns) {
098: if (dbTable.cols != null) { // check for extra column
099: for (int i = 0; i < dbTable.cols.length; i++) {
100: if (!marks.containsKey(new Integer(i))) {
101: // we have a extra column
102: ColumnDiff diff = new ColumnDiff(null,
103: dbTable.cols[i]);
104: diff.setExtraCol(true);
105: tableDiff.getColDiffs().add(diff);
106: }
107: }
108: }
109: }
110: }
111:
112: private static void doPK(TableDiff tableDiff, JdbcTable ourTable,
113: JdbcTable dbTable, ControlParams checks) {
114:
115: if (checks.isCheckPK()) {
116: if (ourTable.pk != null && dbTable.pk == null) {
117: PKDiff diff = new PKDiff(null, null);
118: diff.setMissingPK(true);
119: tableDiff.getPkDiffs().add(diff);
120: } else {
121: HashMap marks = new HashMap();
122: if (ourTable.pk != null) {
123: for (int i = 0; i < ourTable.pk.length; i++) {
124: JdbcColumn ourCol = ourTable.pk[i];
125: // check if our column is in there
126: JdbcColumn dbCol = null;
127: if (dbTable.pk != null) {
128: for (int j = 0; j < dbTable.pk.length; j++) {
129: JdbcColumn col = dbTable.pk[j];
130: if (col != null) {
131: if (ourCol.name
132: .equalsIgnoreCase(col.name)) {
133: marks.put(new Integer(j), null);
134: dbCol = col;
135: break;
136: }
137: }
138: }
139: }
140: PKDiff diff = checkPK(ourCol, dbCol, checks);
141: if (diff != null) {
142: tableDiff.getPkDiffs().add(diff);
143: }
144: }
145: }
146: if (dbTable.pk != null) {
147: for (int i = 0; i < dbTable.pk.length; i++) {
148: if (!marks.containsKey(new Integer(i))) {
149: // we have a extra column
150: if (dbTable.pk[i] != null) {
151: PKDiff diff = new PKDiff(null,
152: dbTable.pk[i]);
153: diff.setExtraPKCol(true);
154: tableDiff.getPkDiffs().add(diff);
155: }
156: }
157: }
158: }
159: }
160: }
161: }
162:
163: private static void doIndex(TableDiff tableDiff,
164: JdbcTable ourTable, JdbcTable dbTable, ControlParams checks) {
165:
166: if (checks.isCheckIndex()) {
167: HashMap marks = new HashMap();
168: if (ourTable.indexes != null) {
169: for (int i = 0; i < ourTable.indexes.length; i++) {
170: JdbcIndex ourIndex = ourTable.indexes[i];
171: // check if our column is in there
172: HashMap possibleIndex = new HashMap();
173: if (dbTable != null) {
174: if (dbTable.indexes != null) {
175: for (int j = 0; j < dbTable.indexes.length; j++) {
176: JdbcIndex index = dbTable.indexes[j];
177: possibleIndex
178: .put(new Integer(j), index);
179: }
180: }
181: }
182: IndexDiff diff = null;
183: JdbcIndex closeDbIndex = null;
184: Integer closeKey = null;
185: boolean found = false;
186: Set keys = possibleIndex.keySet();
187: for (Iterator iterator = keys.iterator(); iterator
188: .hasNext();) {
189: Integer key = (Integer) iterator.next();
190: JdbcIndex dbIndex = (JdbcIndex) possibleIndex
191: .get(key);
192: diff = checkIndex(ourIndex, dbIndex, checks);
193: if (ourIndex.name
194: .equalsIgnoreCase(dbIndex.name)) {
195: closeDbIndex = dbIndex;
196: closeKey = key;
197: }
198: if (diff == null) {
199: found = true;
200: marks.put(key, null);
201: }
202: }
203:
204: if (!found) {
205: diff = checkIndex(ourIndex, closeDbIndex,
206: checks);
207: tableDiff.getIndexDiffs().add(diff);
208: if (closeKey != null) {
209: marks.put(closeKey, null);
210: }
211: }
212:
213: }
214: }
215: if (dbTable != null) { // extra index's
216: if (dbTable.indexes != null) {
217: for (int i = 0; i < dbTable.indexes.length; i++) {
218: if (!marks.containsKey(new Integer(i))) {
219: // we have a extra column
220: IndexDiff diff = new IndexDiff(null,
221: dbTable.indexes[i]);
222: diff.setExtraIndex(true);
223: tableDiff.getIndexDiffs().add(diff);
224: }
225: }
226: }
227: }
228: }
229: }
230:
231: private static void doConstraint(TableDiff tableDiff,
232: JdbcTable ourTable, JdbcTable dbTable, ControlParams checks) {
233: if (checks.isCheckConstraint()) {
234: HashMap marks = new HashMap();
235: if (ourTable.constraints != null) {
236: for (int i = 0; i < ourTable.constraints.length; i++) {
237: JdbcConstraint ourConstraint = ourTable.constraints[i];
238: // check if our column is in there
239: HashMap possibleConstraint = new HashMap();
240: if (dbTable != null) {
241: if (dbTable.constraints != null) {
242: for (int j = 0; j < dbTable.constraints.length; j++) {
243: JdbcConstraint constraint = dbTable.constraints[j];
244: try {
245: if (ourConstraint.src.name
246: .equalsIgnoreCase(constraint.src.name)
247: && (ourConstraint.dest.name
248: .equalsIgnoreCase(constraint.dest.name))) {
249: possibleConstraint.put(
250: new Integer(j),
251: constraint);
252: }
253: } catch (Exception e) {
254: }
255: }
256: }
257: }
258: ConstraintDiff diff = null;
259: JdbcConstraint closeDbConstraint = null;
260: Integer closeKey = null;
261: boolean found = false;
262: Set keys = possibleConstraint.keySet();
263: for (Iterator iterator = keys.iterator(); iterator
264: .hasNext();) {
265: Integer key = (Integer) iterator.next();
266: JdbcConstraint dbConstraint = (JdbcConstraint) possibleConstraint
267: .get(key);
268: diff = checkConstraint(ourConstraint,
269: dbConstraint, checks);
270: if (ourConstraint.name
271: .equalsIgnoreCase(dbConstraint.name)) {
272: closeDbConstraint = dbConstraint;
273: closeKey = key;
274: }
275: if (diff == null) {
276: found = true;
277: marks.put(key, null);
278:
279: }
280: }
281:
282: if (!found) {
283: diff = checkConstraint(ourConstraint,
284: closeDbConstraint, checks);
285: tableDiff.getConstraintDiffs().add(diff);
286: if (closeKey != null) {
287: marks.put(closeKey, null);
288: }
289: }
290: }
291: }
292: if (dbTable != null) { // extra constraints
293: if (dbTable.constraints != null) {
294: for (int i = 0; i < dbTable.constraints.length; i++) {
295: if (!marks.containsKey(new Integer(i))) {
296: // we have a extra column
297: if (dbTable.constraints[i] != null) {
298: ConstraintDiff diff = new ConstraintDiff(
299: null, dbTable.constraints[i]);
300: diff.setExtraConstraint(true);
301: diff.setDrop(true);
302: tableDiff.getConstraintDiffs()
303: .add(diff);
304: }
305: }
306: }
307: }
308: }
309: }
310: }
311:
312: private static ColumnDiff checkColumn(JdbcColumn ourCol,
313: JdbcColumn dbCol, ControlParams checks) {
314: ColumnDiff diff = new ColumnDiff(ourCol, dbCol);
315: if (dbCol == null) {
316: diff.setMissingCol(true);
317:
318: } else {// the db col names are the same
319: if (checks.isCheckType()) {
320: if (!driver.checkType(ourCol, dbCol)) {
321: diff.setTypeDiff(true);
322: }
323: }
324: if (checks.isCheckLength()) {
325: if (!driver.checkLenght(ourCol, dbCol)) {
326: diff.setLenghtDiff(true);
327: }
328: }
329: if (checks.isCheckScale()) {
330: if (!driver.checkScale(ourCol, dbCol)) {
331: diff.setScaleDiff(true);
332: }
333: }
334: if (checks.isCheckNulls()) {
335: if (!driver.checkNulls(ourCol, dbCol)) {
336: diff.setNullDiff(true);
337: }
338: }
339: }
340:
341: if (diff.hasErrors()) {
342: return diff;
343: } else {
344: return null;
345: }
346:
347: }
348:
349: private static PKDiff checkPK(JdbcColumn ourCol, JdbcColumn dbCol,
350: ControlParams checks) {
351: PKDiff diff = new PKDiff(ourCol, dbCol);
352: if (dbCol == null) {
353: diff.setMissingPKCol(true);
354: }
355: if (diff.hasErrors()) {
356: return diff;
357: } else {
358: return null;
359: }
360: }
361:
362: private static IndexDiff checkIndex(JdbcIndex ourIndex,
363: JdbcIndex dbIndex, ControlParams checks) {
364: IndexDiff diff = new IndexDiff(ourIndex, dbIndex);
365: if (dbIndex == null) {
366: diff.setMissingIndex(true);
367: } else {
368: //check cols
369: HashMap marks = new HashMap();
370: if (ourIndex.cols != null) {
371: for (int i = 0; i < ourIndex.cols.length; i++) {
372: JdbcColumn ourCol = ourIndex.cols[i];
373: // check if our column is in there
374: JdbcColumn dbCol = null;
375: if (dbIndex.cols != null) {
376: for (int j = 0; j < dbIndex.cols.length; j++) {
377: JdbcColumn col = dbIndex.cols[j];
378: if (ourCol.name.equalsIgnoreCase(col.name)) {
379: marks.put(new Integer(j), null);
380: dbCol = col;
381: break;
382: }
383: }
384: }
385: if (dbCol == null) {
386: diff.setMissingCol(true);
387: }
388: }
389: }
390: if (dbIndex != null && ourIndex != null) {
391: if (dbIndex.unique != ourIndex.unique) {
392: diff.setUniqueness(true);
393: }
394: }
395:
396: if (dbIndex.cols != null) {
397: for (int i = 0; i < dbIndex.cols.length; i++) {
398: if (!marks.containsKey(new Integer(i))) {
399: // we have a extra column in our Constraint
400: diff.setExtraCol(true);
401: }
402: }
403: }
404: }
405: if (diff.hasErrors()) {
406: return diff;
407: } else {
408: return null;
409: }
410: }
411:
412: public static ConstraintDiff checkConstraint(
413: JdbcConstraint ourConstraint, JdbcConstraint dbConstraint,
414: ControlParams checks) {
415: ConstraintDiff diff = new ConstraintDiff(ourConstraint,
416: dbConstraint);
417: if (dbConstraint == null) {
418: diff.setMissingConstraint(true);
419: } else {
420: //check cols
421: HashMap marks = new HashMap();
422: if (ourConstraint.srcCols != null) {
423: for (int i = 0; i < ourConstraint.srcCols.length; i++) {
424: JdbcColumn ourCol = ourConstraint.srcCols[i];
425: // check if our column is in there
426: JdbcColumn dbCol = null;
427: if (dbConstraint.srcCols != null) {
428: for (int j = 0; j < dbConstraint.srcCols.length; j++) {
429: JdbcColumn col = dbConstraint.srcCols[j];
430: if (col != null) {
431: if (ourCol.name
432: .equalsIgnoreCase(col.name)) {
433: marks.put(new Integer(j), null);
434: dbCol = col;
435: break;
436: }
437: }
438: }
439: }
440: if (dbCol == null) {
441: diff.setMissingCol(true);
442: diff.setDrop(true);
443: }
444: }
445: }
446: if (dbConstraint.srcCols != null) {
447: for (int i = 0; i < dbConstraint.srcCols.length; i++) {
448: if (!marks.containsKey(new Integer(i))) {
449: // we have a extra column in our Constraint
450: diff.setExtraCol(true);
451: diff.setDrop(true);
452: }
453: }
454: }
455: }
456:
457: if (diff.hasErrors()) {
458: return diff;
459: } else {
460: return null;
461: }
462: }
463:
464: /**
465: * reports the errors
466: * @param diffList
467: * @param out
468: */
469: public static void reportErrors(ArrayList diffList, PrintWriter out) {
470: for (Iterator iter = diffList.iterator(); iter.hasNext();) {
471: TableDiff tableDiff = (TableDiff) iter.next();
472: if (tableDiff.hasRealErrors()) {
473: printError(out, tableDiff.getOurTable().name);
474: }
475: if (tableDiff.isMissingTable()) {
476: printErrorMsg(out, "Table '"
477: + tableDiff.getOurTable().name
478: + "' does not exist.");
479: }
480: ArrayList colList = tableDiff.getColDiffs();
481: for (Iterator iterator = colList.iterator(); iterator
482: .hasNext();) {
483: ColumnDiff diff = (ColumnDiff) iterator.next();
484: if (diff.isExtraCol()) {
485: printErrorMsg(out, "Column '"
486: + diff.getDbCol().name
487: + "' is not known to JDOGenie");
488: }
489:
490: if (diff.isLenghtDiff()) {
491: printErrorMsg(out, "Column '"
492: + diff.getOurCol().name + "' length is "
493: + diff.getDbCol().length
494: + ", it should be "
495: + diff.getOurCol().length);
496: }
497:
498: if (diff.isMissingCol()) {
499: printErrorMsg(out, "Column '"
500: + diff.getOurCol().name
501: + "' does not exist.");
502: }
503:
504: if (diff.isNullDiff()) {
505: printErrorMsg(out, "Column '"
506: + diff.getOurCol().name
507: + "' null value is "
508: + (diff.getDbCol().nulls ? "'NULL'"
509: : "'NOT NULL'")
510: + ", it should be "
511: + (diff.getOurCol().nulls ? "'NULL'"
512: : "'NOT NULL'"));
513: }
514:
515: if (diff.isScaleDiff()) {
516: printErrorMsg(out, "Column '"
517: + diff.getOurCol().name + "' scale is "
518: + diff.getDbCol().scale + ", it should be "
519: + diff.getOurCol().scale);
520:
521: }
522:
523: if (diff.isTypeDiff()) {
524: printErrorMsg(out, "Column '"
525: + diff.getOurCol().name + "' type is "
526: + diff.getDbCol().sqlType
527: + ", it should be "
528: + diff.getOurCol().sqlType);
529: }
530: }
531: ArrayList pkList = tableDiff.getPkDiffs();
532: for (Iterator iterator = pkList.iterator(); iterator
533: .hasNext();) {
534: PKDiff diff = (PKDiff) iterator.next();
535: //
536: if (diff.isMissingPK()) {
537: printErrorMsg(out, "Primary key '"
538: + tableDiff.getOurTable().pkConstraintName
539: + "' on table '"
540: + tableDiff.getOurTable().name
541: + "' does not exist.");
542: } else {
543: if (diff.isMissingPKCol()) {
544: printErrorMsg(
545: out,
546: "Primary key '"
547: + tableDiff.getOurTable().pkConstraintName
548: + "' has a missing column '"
549: + diff.getOurCol().name + "'.");
550: }
551: if (diff.isExtraPKCol()) {
552: printErrorMsg(
553: out,
554: "Primary key '"
555: + tableDiff.getOurTable().pkConstraintName
556: + "' has a extra column '"
557: + diff.getDbCol().name
558: + "' that is not known to JDOGenie");
559: }
560: }
561: }
562: ArrayList indexList = tableDiff.getIndexDiffs();
563: for (Iterator iterator = indexList.iterator(); iterator
564: .hasNext();) {
565: IndexDiff diff = (IndexDiff) iterator.next();
566: //
567: if (diff.isMissingIndex()) {
568: printErrorMsg(out, "Index '"
569: + diff.getOurIndex().name
570: + "' does not exist.");
571: }
572: if (diff.isExtraIndex()) {
573: printErrorMsg(out, "Index '"
574: + diff.getDbIndex().name
575: + "' is not known to JDOGenie");
576: }
577: if (diff.isExtraCol()) {
578: printErrorMsg(
579: out,
580: "Index '"
581: + diff.getOurIndex().name
582: + "' has extra columns not known to JDOGenie");
583: }
584: if (diff.isMissingCol()) {
585: printErrorMsg(out, "Index '"
586: + diff.getOurIndex().name
587: + "' has missing columns");
588: }
589: if (diff.isUniqueness()) {
590: JdbcIndex ourIndex = diff.getOurIndex();
591: if (ourIndex.unique) {
592: printErrorMsg(out, "Index '"
593: + diff.getOurIndex().name
594: + "' is unique, but database is not");
595: } else {
596: printErrorMsg(out, "Index '"
597: + diff.getOurIndex().name
598: + "' is not unique, but database is");
599: }
600:
601: }
602: }
603: ArrayList constraintList = tableDiff.getConstraintDiffs();
604: for (Iterator iterator = constraintList.iterator(); iterator
605: .hasNext();) {
606: ConstraintDiff diff = (ConstraintDiff) iterator.next();
607: //
608: if (diff.isMissingConstraint()) {
609: printErrorMsg(out, "Constraint '"
610: + diff.getOurConstraint().name
611: + "' does not exist.");
612: }
613: if (diff.isExtraConstraint()) {
614: printErrorMsg(out, "Constraint '"
615: + diff.getDbConstraint().name
616: + "' is not known to JDOGenie");
617: }
618: if (diff.isExtraCol()) {
619: printErrorMsg(
620: out,
621: "Constraint '"
622: + diff.getOurConstraint().name
623: + "' has extra columns not known to JDOGenie");
624: }
625: if (diff.isMissingCol()) {
626: printErrorMsg(out, "Constraint '"
627: + diff.getOurConstraint().name
628: + "' has missing columns.");
629: }
630: }
631: }
632: }
633:
634: private static void printError(PrintWriter out, String tableName) {
635: out.print("\nTable ");
636: out.print(tableName);
637: out.println(" : FAIL");
638: }
639:
640: private static void printErrorMsg(PrintWriter out, String error) {
641: out.print(" ");
642: out.println(error);
643: }
644:
645: }
|