001: /*
002: * $Id: ChildTableUpdater.java,v 1.1 2005/12/20 18:32:28 ahimanikya Exp $
003: * =======================================================================
004: * Copyright (c) 2005-2006 Axion Development Team. All rights reserved.
005: *
006: * Redistribution and use in source and binary forms, with or without
007: * modification, are permitted provided that the following conditions
008: * are met:
009: *
010: * 1. Redistributions of source code must retain the above
011: * copyright notice, this list of conditions and the following
012: * disclaimer.
013: *
014: * 2. Redistributions in binary form must reproduce the above copyright
015: * notice, this list of conditions and the following disclaimer in
016: * the documentation and/or other materials provided with the
017: * distribution.
018: *
019: * 3. The names "Tigris", "Axion", nor the names of its contributors may
020: * not be used to endorse or promote products derived from this
021: * software without specific prior written permission.
022: *
023: * 4. Products derived from this software may not be called "Axion", nor
024: * may "Tigris" or "Axion" appear in their names without specific prior
025: * written permission.
026: *
027: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
028: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
029: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
030: * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
031: * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
032: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
033: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
034: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
035: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
036: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
037: * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
038: * =======================================================================
039: */
040: package org.axiondb.engine.commands;
041:
042: import java.util.Iterator;
043: import java.util.List;
044:
045: import org.axiondb.AxionException;
046: import org.axiondb.ColumnIdentifier;
047: import org.axiondb.Database;
048: import org.axiondb.Literal;
049: import org.axiondb.Row;
050: import org.axiondb.RowDecorator;
051: import org.axiondb.RowIterator;
052: import org.axiondb.Selectable;
053: import org.axiondb.Table;
054: import org.axiondb.TableIdentifier;
055: import org.axiondb.constraints.ForeignKeyConstraint;
056: import org.axiondb.engine.rows.SimpleRow;
057: import org.axiondb.functions.AndFunction;
058: import org.axiondb.functions.EqualFunction;
059:
060: /**
061: * Update/Delete Child rows for a given relation.
062: *
063: * @author Ahimanikya Satapathy
064: */
065: public abstract class ChildTableUpdater extends BaseAxionCommand {
066:
067: protected void deleteOrSetNullChildRows(Database db,
068: Table parentTable, RowDecorator dec) throws AxionException {
069: for (Iterator iter = parentTable.getConstraints(); iter
070: .hasNext();) {
071: Object constraint = iter.next();
072: if (constraint instanceof ForeignKeyConstraint) {
073: ForeignKeyConstraint fk = (ForeignKeyConstraint) constraint;
074: deleteOrSetNullChildRows(db, parentTable, dec, fk);
075: }
076: }
077: }
078:
079: protected void deleteOrSetNullChildRows(Database db,
080: Table parentTable, RowDecorator dec, ForeignKeyConstraint fk)
081: throws AxionException {
082: // Check whether Child table has a row that is refering row to be deleted
083: // If ON DELETE option is used we can either delete or set null the child row
084: Selectable filter = null;
085: if (parentTable.getName().equals(fk.getParentTableName())) {
086: List parentCols = fk.getParentTableColumns();
087: List childCols = fk.getChildTableColumns();
088: Table childTable = db.getTable(fk.getChildTableName());
089:
090: filter = buildFilter(dec, parentCols);
091: RowIterator matching = getRowIterator(db,
092: new TableIdentifier(fk.getChildTableName()),
093: childTable, filter, false, dec);
094: if (matching.hasNext()) {
095: if (fk.getOnDeleteActionType() == ForeignKeyConstraint.CASCADE) {
096: deleteMatchingChildRows(matching);
097: } else if (fk.getOnDeleteActionType() == ForeignKeyConstraint.SETNULL) {
098: setNullForMatchingChildRows(childCols, childTable,
099: matching);
100: } else if (fk.getOnDeleteActionType() == ForeignKeyConstraint.SETDEFAULT) {
101: setDefaultForMatchingChildRows(childCols,
102: childTable, matching);
103: }
104: }
105: }
106: }
107:
108: protected void updateOrSetNullChildRows(Database db,
109: Table parentTable, Row parentOldRow, Row parentNewRow)
110: throws AxionException {
111: for (Iterator iter = parentTable.getConstraints(); iter
112: .hasNext();) {
113: Object constraint = iter.next();
114: if (constraint instanceof ForeignKeyConstraint) {
115: ForeignKeyConstraint fk = (ForeignKeyConstraint) constraint;
116: updateOrSetNullChildRows(db, parentTable, parentOldRow,
117: parentNewRow, fk);
118: }
119: }
120: }
121:
122: protected void updateOrSetNullChildRows(Database db,
123: Table parentTable, Row parentOldRow, Row parentNewRow,
124: ForeignKeyConstraint fk) throws AxionException {
125: // Check whether Child table has a row that is refering row to be deleted
126: // If ON DELETE option is used we can either delete or set null the child row
127: Selectable filter = null;
128: if (parentTable.getName().equals(fk.getParentTableName())) {
129: RowDecorator dec = makeRowDecorator(parentTable);
130: dec.setRow(parentOldRow);
131:
132: List parentCols = fk.getParentTableColumns();
133: List childCols = fk.getChildTableColumns();
134: Table childTable = db.getTable(fk.getChildTableName());
135:
136: filter = buildFilter(dec, parentCols);
137: RowIterator matching = getRowIterator(db,
138: new TableIdentifier(fk.getChildTableName()),
139: childTable, filter, false, dec);
140: if (matching.hasNext()) {
141: if (fk.getOnDeleteActionType() == ForeignKeyConstraint.CASCADE) {
142: updateMatchingChildRows(parentTable, parentNewRow,
143: parentCols, childCols, childTable, matching);
144: } else if (fk.getOnDeleteActionType() == ForeignKeyConstraint.SETNULL) {
145: setNullForMatchingChildRows(childCols, childTable,
146: matching);
147: } else if (fk.getOnDeleteActionType() == ForeignKeyConstraint.SETDEFAULT) {
148: setDefaultForMatchingChildRows(childCols,
149: childTable, matching);
150: }
151: }
152: }
153: }
154:
155: private Selectable buildFilter(RowDecorator dec, List columns)
156: throws AxionException {
157: Selectable filter = null;
158: for (int i = 0, I = columns.size(); i < I; i++) {
159: Selectable sel = (Selectable) columns.get(i);
160: Object val = sel.evaluate(dec);
161:
162: EqualFunction function = new EqualFunction();
163: function.addArgument(sel);
164: function.addArgument(new Literal(val));
165:
166: if (null == filter) {
167: filter = function;
168: } else {
169: AndFunction fn = new AndFunction();
170: fn.addArgument(filter);
171: fn.addArgument(function);
172: filter = fn;
173: }
174: }
175: return filter;
176: }
177:
178: private void deleteMatchingChildRows(RowIterator matching)
179: throws AxionException {
180: do {
181: matching.next();
182: matching.remove();
183: } while (matching.hasNext());
184: }
185:
186: private void setDefaultForMatchingChildRows(List childCols,
187: Table childTable, RowIterator matching)
188: throws AxionException {
189: do {
190: Row childOldrow = matching.next();
191: Row newrow = new SimpleRow(childOldrow);
192: for (int i = 0, I = childCols.size(); i < I; i++) {
193: ColumnIdentifier colid = ((ColumnIdentifier) childCols
194: .get(i));
195: int colndx = childTable.getColumnIndex(colid.getName());
196: newrow.set(colndx, childTable
197: .getColumn(colid.getName()).getDefault());
198: }
199: childTable.updateRow(childOldrow, newrow);
200: } while (matching.hasNext());
201: }
202:
203: private void setNullForMatchingChildRows(List childCols,
204: Table childTable, RowIterator matching)
205: throws AxionException {
206: do {
207: Row childOldrow = matching.next();
208: Row newrow = new SimpleRow(childOldrow);
209: for (int i = 0, I = childCols.size(); i < I; i++) {
210: ColumnIdentifier colid = ((ColumnIdentifier) childCols
211: .get(i));
212: int colndx = childTable.getColumnIndex(colid.getName());
213: newrow.set(colndx, null);
214: }
215: childTable.updateRow(childOldrow, newrow);
216: } while (matching.hasNext());
217: }
218:
219: private void updateMatchingChildRows(Table parentTable,
220: Row parentNewRow, List parentCols, List childCols,
221: Table childTable, RowIterator matching)
222: throws AxionException {
223: do {
224: Row childOldrow = matching.next();
225: Row newrow = new SimpleRow(childOldrow);
226: for (int i = 0, I = childCols.size(); i < I; i++) {
227: ColumnIdentifier colid = ((ColumnIdentifier) childCols
228: .get(i));
229: ColumnIdentifier pcolid = ((ColumnIdentifier) parentCols
230: .get(i));
231: int colndx = childTable.getColumnIndex(colid.getName());
232: int parentColndx = parentTable.getColumnIndex(pcolid
233: .getName());
234: newrow.set(colndx, parentNewRow.get(parentColndx));
235: }
236: childTable.updateRow(childOldrow, newrow);
237: } while (matching.hasNext());
238: }
239:
240: }
|