Skip to content

Commit

Permalink
Feature request 2943959: add deletion rule details
Browse files Browse the repository at this point in the history
  • Loading branch information
johncurrier committed Feb 1, 2010
1 parent 437e454 commit e875ec2
Show file tree
Hide file tree
Showing 7 changed files with 108 additions and 40 deletions.
8 changes: 8 additions & 0 deletions dist/releaseNotes.html
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,14 @@ <h3><a href='http://schemaspy.sourceforge.net'>SchemaSpy</a> Release Notes</h3>
<code>-type db2zos</code>.<br>
Thanks to Christian Riedel for providing the z/OS-specific configuration file.
</li>
<li>Resolved <a href="https://sourceforge.net/tracker/?func=detail&aid=2942336&group_id=137197&atid=737987">
bug 2942336</a> - Related table names missing from table details
</li>
<li>Implemented <a href="https://sourceforge.net/tracker/?func=detail&aid=2943959&group_id=137197&atid=737990">
feature request 2943959</a> - Add deletion rule details.<br/>
Now shows details about foreign key constraint deletion rules:
cascade on delete, null on delete and restrict delete.
</li>
</ul>
</li>

Expand Down
75 changes: 74 additions & 1 deletion src/net/sourceforge/schemaspy/model/ForeignKeyConstraint.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import static java.sql.DatabaseMetaData.importedKeyCascade;
import static java.sql.DatabaseMetaData.importedKeyNoAction;
import static java.sql.DatabaseMetaData.importedKeyRestrict;
import static java.sql.DatabaseMetaData.importedKeySetNull;

import java.util.ArrayList;
import java.util.Collections;
Expand Down Expand Up @@ -151,10 +153,81 @@ public int getDeleteRule() {
*
* @return
*/
public boolean isOnDeleteCascade() {
public boolean isCascadeOnDelete() {
return getDeleteRule() == importedKeyCascade;
}

/**
* Returns <code>true</code> if the constraint prevents the parent table
* from being deleted if child tables exist.
*
* @return
*/
public boolean isRestrictDelete() {
return getDeleteRule() == importedKeyNoAction || getDeleteRule() == importedKeyRestrict;
}

/**
* Returns <code>true</code> if the constraint indicates that the foreign key
* will be set to <code>null</code> when the parent key is deleted.
*
* @return
*/
public boolean isNullOnDelete() {
return getDeleteRule() == importedKeySetNull;
}

public String getDeleteRuleName() {
switch (getDeleteRule()) {
case importedKeyCascade:
return "Cascade on delete";

case importedKeyRestrict:
case importedKeyNoAction:
return "Restrict delete";

case importedKeySetNull:
return "Null on delete";

default:
return "";
}
}

public String getDeleteRuleDescription() {
switch (getDeleteRule()) {
case importedKeyCascade:
return "Cascade on delete:\n Deletion of parent deletes child";

case importedKeyRestrict:
case importedKeyNoAction:
return "Restrict delete:\n Parent cannot be deleted if children exist";

case importedKeySetNull:
return "Null on delete:\n Foreign key to parent set to NULL when parent deleted";

default:
return "";
}
}

public String getDeleteRuleAlias() {
switch (getDeleteRule()) {
case importedKeyCascade:
return "C";

case importedKeyRestrict:
case importedKeyNoAction:
return "R";

case importedKeySetNull:
return "N";

default:
return "";
}
}

/**
* Returns the update rule for this constraint.
*
Expand Down
6 changes: 0 additions & 6 deletions src/net/sourceforge/schemaspy/model/TableColumn.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ public class TableColumn {
private boolean allowImpliedChildren = true;
private boolean isExcluded = false;
private boolean isAllExcluded = false;
private boolean isOnDeleteCascade = false;

/**
* Create a column associated with a table.
Expand Down Expand Up @@ -221,10 +220,6 @@ public boolean isUnique() {
return isUnique;
}

public boolean isOnDeleteCascade() {
return isOnDeleteCascade ;
}

/**
* Returns <code>true</code> if this column is a primary key
*
Expand Down Expand Up @@ -303,7 +298,6 @@ public boolean isAllExcluded() {
public void addParent(TableColumn parent, ForeignKeyConstraint constraint) {
parents.put(parent, constraint);
table.addedParent();
isOnDeleteCascade |= constraint.isOnDeleteCascade();
}

/**
Expand Down
4 changes: 2 additions & 2 deletions src/net/sourceforge/schemaspy/view/HtmlColumnsPage.java
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ public void write(Database database, Collection<Table> tables, ColumnInfo column
HtmlTablePage formatter = HtmlTablePage.getInstance();

for (TableColumn column : columns) {
formatter.writeColumn(column, column.getTable().getName(), primaryColumns, indexedColumns, false, false, html);
formatter.writeColumn(column, column.getTable().getName(), primaryColumns, indexedColumns, false, html);
}

writeFooter(html);
Expand All @@ -137,7 +137,7 @@ private void writeHeader(Database db, int numberOfColumns, boolean hasOrphans, C
html.writeln("<p>");
html.writeln("<form name='options' action=''>");
html.writeln(" <label for='showRelatedCols'><input type=checkbox id='showRelatedCols'>Related columns</label>");
html.writeln(" <label for='showConstNames'><input type=checkbox id='showConstNames'>Constraint names</label>");
html.writeln(" <label for='showConstNames'><input type=checkbox id='showConstNames'>Constraints</label>");
html.writeln(" <label for='showComments'><input type=checkbox " + (showCommentsInitially ? "checked " : "") + " id='showComments'>Comments</label>");
html.writeln(" <label for='showLegend'><input type=checkbox checked id='showLegend'>Legend</label>");
html.writeln("</form>");
Expand Down
8 changes: 7 additions & 1 deletion src/net/sourceforge/schemaspy/view/HtmlConstraintsPage.java
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ private void writeForeignKeyConstraints(List<ForeignKeyConstraint> constraints,
html.writeln(" <th>Constraint Name</th>");
html.writeln(" <th>Child Column</th>");
html.writeln(" <th>Parent Column</th>");
html.writeln(" <th>Delete Rule</th>");
html.writeln("</tr>");
html.writeln("</thead>");
html.writeln("<tbody>");
Expand All @@ -98,7 +99,7 @@ private void writeForeignKeyConstraints(List<ForeignKeyConstraint> constraints,
}
if (constraints.size() == 0) {
html.writeln(" <tr>");
html.writeln(" <td class='detail' valign='top' colspan='3'>None detected</td>");
html.writeln(" <td class='detail' valign='top' colspan='4'>None detected</td>");
html.writeln(" </tr>");
}
html.writeln("</tbody>");
Expand Down Expand Up @@ -145,6 +146,11 @@ private void writeForeignKeyConstraint(ForeignKeyConstraint constraint, LineWrit
html.write("<br>");
}
html.writeln("</td>");
html.write(" <td class='detail'>");
String ruleText = constraint.getDeleteRuleDescription();
String ruleName = constraint.getDeleteRuleName();
html.write("<span title='" + ruleText + "'>" + ruleName + "&nbsp;</span>");
html.writeln("</td>");
html.writeln(" </tr>");
}

Expand Down
43 changes: 15 additions & 28 deletions src/net/sourceforge/schemaspy/view/HtmlTablePage.java
Original file line number Diff line number Diff line change
Expand Up @@ -68,14 +68,14 @@ public WriteStats write(Database db, Table table, boolean hasOrphans, File outpu
out.writeln("</td><td class='container' rowspan='2' align='right' valign='top'>");
writeLegend(true, out);
out.writeln("</td><tr valign='top'><td class='container' align='left' valign='top'>");
boolean onCascadeDelete = writeMainTable(table, out);
writeMainTable(table, out);
writeNumRows(db, table, out);
out.writeln("</td></tr></table>");
writeCheckConstraints(table, out);
writeIndexes(table, out);
writeView(table, db, out);
writeDiagram(table, stats, diagramsDir, out);
writeFooter(onCascadeDelete, out);
writeFooter(out);

return stats;
}
Expand All @@ -99,15 +99,13 @@ private void writeHeader(Table table, boolean hasImplied, LineWriter html) throw
}

html.writeln(" <label for='showRelatedCols'><input type=checkbox id='showRelatedCols'>Related columns</label>");
html.writeln(" <label for='showConstNames'><input type=checkbox id='showConstNames'>Constraint names</label>");
html.writeln(" <label for='showConstNames'><input type=checkbox id='showConstNames'>Constraints</label>");
html.writeln(" <label for='showComments'><input type=checkbox " + (showCommentsInitially ? "checked " : "") + "id='showComments'>Comments</label>");
html.writeln(" <label for='showLegend'><input type=checkbox checked id='showLegend'>Legend</label>");
html.writeln("</form>");
}

public boolean writeMainTable(Table table, LineWriter out) throws IOException {
boolean onCascadeDelete = false;

public void writeMainTable(Table table, LineWriter out) throws IOException {
HtmlColumnsPage.getInstance().writeMainTableHeader(table.getId() != null, null, out);

out.writeln("<tbody valign='top'>");
Expand All @@ -119,14 +117,12 @@ public boolean writeMainTable(Table table, LineWriter out) throws IOException {

boolean showIds = table.getId() != null;
for (TableColumn column : table.getColumns()) {
onCascadeDelete = writeColumn(column, null, primaries, indexedColumns, onCascadeDelete, showIds, out);
writeColumn(column, null, primaries, indexedColumns, showIds, out);
}
out.writeln("</table>");

return onCascadeDelete;
}

public boolean writeColumn(TableColumn column, String tableName, Set<TableColumn> primaries, Set<TableColumn> indexedColumns, boolean onCascadeDelete, boolean showIds, LineWriter out) throws IOException {
public void writeColumn(TableColumn column, String tableName, Set<TableColumn> primaries, Set<TableColumn> indexedColumns, boolean showIds, LineWriter out) throws IOException {
if (tableName != null) {
if (++columnCounter % 2 == 0)
out.writeln("<tr class='odd'>");
Expand Down Expand Up @@ -194,10 +190,10 @@ else if (indexedColumns.contains(column))
}
out.write(" <td class='detail'>");
String path = tableName == null ? "" : "tables/";
onCascadeDelete |= writeRelatives(column, false, path, out);
writeRelatives(column, false, path, out);
out.writeln("</td>");
out.write(" <td class='detail'>");
onCascadeDelete |= writeRelatives(column, true, path, out);
writeRelatives(column, true, path, out);
out.writeln(" </td>");
out.write(" <td class='comment detail'>");
String comments = column.getComments();
Expand All @@ -210,7 +206,6 @@ else if (indexedColumns.contains(column))
}
out.writeln("</td>");
out.writeln("</tr>");
return onCascadeDelete;
}

/**
Expand All @@ -220,10 +215,8 @@ else if (indexedColumns.contains(column))
* @param dumpParents boolean
* @param out LineWriter
* @throws IOException
* @return boolean - true if relatives are involved in an on cascade delete relationships
*/
private boolean writeRelatives(TableColumn baseRelative, boolean dumpParents, String path, LineWriter out) throws IOException {
boolean onCascadeDelete = false;
private void writeRelatives(TableColumn baseRelative, boolean dumpParents, String path, LineWriter out) throws IOException {
Set<TableColumn> columns = dumpParents ? baseRelative.getParents() : baseRelative.getChildren();
final int numColumns = columns.size();

Expand Down Expand Up @@ -257,23 +250,23 @@ private boolean writeRelatives(TableColumn baseRelative, boolean dumpParents, St
out.write("<span class='relatedKey'>.");
out.write(column.getName());
out.writeln("</span>");
if (constraint.isOnDeleteCascade()) {
out.write("<span title='On Delete Cascade\n Automatically deletes child tables when their parent is deleted'>*</span>");
onCascadeDelete = true;
}
out.writeln(" </td>");

out.write(" <td class='constraint'>");
out.write(constraint.getName());
String ruleText = constraint.getDeleteRuleDescription();
if (ruleText.length() > 0)
{
String ruleAlias = constraint.getDeleteRuleAlias();
out.write("<span title='" + ruleText + "'> " + ruleAlias + "</span>");
}
out.writeln("</td>");

out.writeln(" </tr>");
}
if (numColumns > 0) {
out.writeln(" </table>");
}

return onCascadeDelete;
}

private void writeNumRows(Database db, Table table, LineWriter out) throws IOException {
Expand Down Expand Up @@ -594,12 +587,6 @@ private void writeDiagram(Table table, WriteStats stats, File diagramsDir, LineW
}
}

protected void writeFooter(boolean onCascadeDelete, LineWriter out) throws IOException {
if (onCascadeDelete)
out.writeln("<br><span style='font-size: 85%;'>Related tables marked with * are involved in an 'on delete cascade' relationship.</span>");
super.writeFooter(out);
}

@Override
protected String getPathToRoot() {
return "../";
Expand Down
4 changes: 2 additions & 2 deletions src/net/sourceforge/schemaspy/view/XmlTableFormatter.java
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ private Node appendColumn(Node tableNode, TableColumn column) {
DOMUtil.appendAttribute(childNode, "table", childColumn.getTable().getName());
DOMUtil.appendAttribute(childNode, "column", childColumn.getName());
DOMUtil.appendAttribute(childNode, "implied", String.valueOf(constraint.isImplied()));
DOMUtil.appendAttribute(childNode, "onDeleteCascade", String.valueOf(constraint.isOnDeleteCascade()));
DOMUtil.appendAttribute(childNode, "onDeleteCascade", String.valueOf(constraint.isCascadeOnDelete()));
}

for (TableColumn parentColumn : column.getParents()) {
Expand All @@ -152,7 +152,7 @@ private Node appendColumn(Node tableNode, TableColumn column) {
DOMUtil.appendAttribute(parentNode, "table", parentColumn.getTable().getName());
DOMUtil.appendAttribute(parentNode, "column", parentColumn.getName());
DOMUtil.appendAttribute(parentNode, "implied", String.valueOf(constraint.isImplied()));
DOMUtil.appendAttribute(parentNode, "onDeleteCascade", String.valueOf(constraint.isOnDeleteCascade()));
DOMUtil.appendAttribute(parentNode, "onDeleteCascade", String.valueOf(constraint.isCascadeOnDelete()));
}

return columnNode;
Expand Down

0 comments on commit e875ec2

Please sign in to comment.