KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > quadcap > sql > ImportedKeyConstraint


1 package com.quadcap.sql;
2
3 /* Copyright 1999 - 2003 Quadcap Software. All rights reserved.
4  *
5  * This software is distributed under the Quadcap Free Software License.
6  * This software may be used or modified for any purpose, personal or
7  * commercial. Open Source redistributions are permitted. Commercial
8  * redistribution of larger works derived from, or works which bundle
9  * this software requires a "Commercial Redistribution License"; see
10  * http://www.quadcap.com/purchase.
11  *
12  * Redistributions qualify as "Open Source" under one of the following terms:
13  *
14  * Redistributions are made at no charge beyond the reasonable cost of
15  * materials and delivery.
16  *
17  * Redistributions are accompanied by a copy of the Source Code or by an
18  * irrevocable offer to provide a copy of the Source Code for up to three
19  * years at the cost of materials and delivery. Such redistributions
20  * must allow further use, modification, and redistribution of the Source
21  * Code under substantially the same terms as this license.
22  *
23  * Redistributions of source code must retain the copyright notices as they
24  * appear in each source code file, these license terms, and the
25  * disclaimer/limitation of liability set forth as paragraph 6 below.
26  *
27  * Redistributions in binary form must reproduce this Copyright Notice,
28  * these license terms, and the disclaimer/limitation of liability set
29  * forth as paragraph 6 below, in the documentation and/or other materials
30  * provided with the distribution.
31  *
32  * The Software is provided on an "AS IS" basis. No warranty is
33  * provided that the Software is free of defects, or fit for a
34  * particular purpose.
35  *
36  * Limitation of Liability. Quadcap Software shall not be liable
37  * for any damages suffered by the Licensee or any third party resulting
38  * from use of the Software.
39  */

40
41 import java.io.ByteArrayOutputStream JavaDoc;
42 import java.io.Externalizable JavaDoc;
43 import java.io.IOException JavaDoc;
44 import java.io.ObjectInput JavaDoc;
45 import java.io.ObjectOutput JavaDoc;
46
47 import java.util.Vector JavaDoc;
48
49 import java.sql.ResultSet JavaDoc;
50 import java.sql.SQLException JavaDoc;
51
52 import com.quadcap.sql.io.ObjectInputStream;
53 import com.quadcap.sql.io.ObjectOutputStream;
54
55 import com.quadcap.sql.file.BlockFile;
56
57 import com.quadcap.sql.index.Btree;
58
59 import com.quadcap.sql.types.Op;
60 import com.quadcap.sql.types.Value;
61
62 import com.quadcap.util.Debug;
63 import com.quadcap.util.Util;
64
65 /**
66  * Constraint for imported keys (i.e., this table references another
67  * table)
68  *
69  * @author Stan Bailes
70  */

71 public class ImportedKeyConstraint extends ForeignKeyConstraint
72 implements Externalizable JavaDoc
73 {
74     long indexRoot = -1;
75     transient Btree index = null;
76     transient Btree fIndex = null;
77     transient ExportedKeyConstraint ec = null;
78
79     /**
80      * Default constructor required for serialization
81      */

82     public ImportedKeyConstraint() {}
83
84     /**
85      * Explicit constructor parser.
86      */

87     public ImportedKeyConstraint(String JavaDoc name, String JavaDoc fTableName) {
88     super(name, fTableName);
89     }
90
91     /**
92      * Explicit constructor with named columns
93      */

94     public ImportedKeyConstraint(String JavaDoc name, Vector JavaDoc colNames,
95                  String JavaDoc fTableName, Vector JavaDoc fColNames) {
96     super(name, colNames, fTableName, fColNames);
97     }
98
99     /**
100      * For <b>ALTER TABLE ADD CONSTRAINT</b>, we need to build our
101      * foreign index.
102      */

103     public void add(Session session) throws SQLException JavaDoc, IOException JavaDoc {
104     Database db = session.getDatabase();
105         BlockFile file = db.getFile();
106         getFCols(db);
107         if (fConstraint == null) {
108             throw new SQLException JavaDoc("No suitable foreign key", "23000");
109         }
110         
111     indexRoot = file.newPage();
112         index = new Btree(file, indexRoot, true);
113
114         String JavaDoc ecName = getExportConstraintName();
115         ec = new ExportedKeyConstraint(ecName, fColNames, table.getName(),
116                                        colNames, this, fConstraint);
117         ec.setForeignKeyCols(getColumns());
118         session.doStep(new AddConstraint(session, fTable, ec, false));
119
120     if (!table.isUnderConstruction()) {
121             IndexCursor c = table.getCursor(session, null);
122             if (c != null) {
123                 try {
124                     while (c.next()) {
125                         Row row = c.getRow();
126                         long rowId = c.getRowId();
127                         checkInsert(session, row);
128                         applyInsert(session, row, rowId, null);
129                     }
130                 } finally {
131                     c.close();
132                 }
133             }
134         }
135         db.updateRelation(fTable);
136     }
137
138     /**
139      * On <b>ALTER TABLE DROP CONSTRAINT</b>, delete the index and free
140      * the file resources it holds.
141      */

142     public void delete(Session session) throws SQLException JavaDoc, IOException JavaDoc {
143         // Don't bother if there isn't an index....
144
if (indexRoot > 0) {
145             Database db = session.getDatabase();
146             getIndex(db);
147             if (index != null) {
148                 index.free();
149                 index = null;
150             }
151             indexRoot = -1;
152         }
153     }
154
155     /**
156      * Return a name for the auto-generated 'export' constraint.
157      */

158     final String JavaDoc getExportConstraintName() {
159     StringBuffer JavaDoc sb = new StringBuffer JavaDoc("__ec_");
160     sb.append(table.getName());
161     sb.append('_');
162     sb.append(name);
163     return sb.toString();
164     }
165
166     /**
167      * On insert, verify that the referenced keys exist in the foreign
168      * table.
169      */

170     public void checkInsert(Session session, Row row)
171     throws SQLException JavaDoc, IOException JavaDoc
172     {
173     Database db = session.getDatabase();
174     int[] k = getColumns();
175     int[] fk = getFCols(db);
176
177     Row r = new Row(fTable.getColumnCount());
178     boolean anyNull = false;
179     boolean allNull = true;
180     for (int i = 0; i < k.length; i++) {
181         int col = k[i];
182         int fcol = fk[i];
183         Value v = row.item(col);
184         boolean isNull = Value.isNull(v);
185         anyNull |= isNull;
186         allNull &= isNull;
187         r.set(fcol, v);
188     }
189     UniqueConstraint con = fTable.getIndexForColumns(fk);
190     byte[] key = con.makeKey(session, r, 0);
191     Btree fTree = con.getIndex(db);
192     if (fTree.get(key) == null && !allNull
193         && (!anyNull || ((spec & (Constraint.FULL |
194                       Constraint.PARTIAL)) != 0))) {
195         if (isSelfReferencing(db) && checkSelfReferencing(row)) {
196         // it's ok, after all.
197
} else {
198         throw new SQLException JavaDoc(
199             "Foreign Key Constraint Violation: no parent: " +
200             this.toString(), "23000");
201         }
202     }
203     }
204
205     /**
206      * On insert, add the new 'export' constraint value
207      */

208     public void applyInsert(Session session, Row row, long rowId,
209                 Constraint activeIndex)
210     throws SQLException JavaDoc, IOException JavaDoc
211     {
212     byte[] key = makeKey(session, row, rowId);
213     AddIndexEntry add = new AddIndexEntry(session, this, key, rowId);
214     if (activeIndex == this) {
215         session.addPendingAction(add);
216     } else {
217         session.doStep(add);
218     }
219     }
220
221     /**
222      * On delete, remove the constraints holding the corresponding
223      * row values.
224      */

225     public void applyDelete(Session session, Row row, long rowId,
226                 Constraint activeIndex)
227     throws SQLException JavaDoc, IOException JavaDoc
228     {
229     Database db = session.getDatabase();
230     byte[] key = makeKey(session, row, rowId);
231     if (index == null) getIndex(db);
232     DeleteIndexEntry del = new DeleteIndexEntry(session, this, key);
233     if (activeIndex == this) {
234         session.addPendingAction(del);
235     } else {
236         session.doStep(del);
237     }
238     }
239
240     /**
241      * On update, if the imported key changes, we need to modify the
242      * index. Once this happens, we create a session context in which
243      * to record the index changes so we can do them all together, at
244      * the end.
245      */

246     public void checkUpdate(Session session, byte[] oldKey, Row row,
247                             Row oldRow, long rowId, Constraint activeIndex)
248     throws SQLException JavaDoc, IOException JavaDoc
249     {
250     checkInsert(session, row);
251     getComparator();
252     byte[] key = makeKey(session, row, rowId);
253     if (activeIndex != this) oldKey = makeKey(session, oldRow, rowId);
254     if (compare.compare(key, oldKey) != 0) {
255         UpdateIndex ui =
256                 (UpdateIndex)session.getContext(this, isDeferred());
257         if (ui == null) {
258         ui = new UpdateIndex(session, this);
259         session.putContext(this, isDeferred(), ui);
260         }
261         ui.addEntry(key, oldKey, rowId);
262     }
263     }
264
265     /**
266      * Check for the possibility that a row satisfies its own constraints.
267      * It's a strange world we live in, get used to it.
268      */

269     boolean checkSelfReferencing(Row row) throws SQLException JavaDoc {
270     boolean anyNull = false;
271     boolean allNull = true;
272     boolean allMatch = true;
273     for (int i = 0; i < fCols.length; i++) {
274         Value v = row.item(fCols[i]);
275         Value r = row.item(columns[i]);
276         boolean isNull = Value.isNull(v);
277         anyNull |= isNull;
278         allNull &= isNull;
279         if (allMatch) allMatch = Value.boolOp(Op.EQ, v, r);
280     }
281     if (allMatch || allNull) return true;
282     if (anyNull && (spec & (Constraint.FULL | Constraint.PARTIAL)) != 0)
283         return true;
284     return false;
285     }
286
287     /**
288      * Get (create if necessary) the Btree for the foreign index.
289      */

290     final Btree getForeignIndex(Session session)
291     throws SQLException JavaDoc, IOException JavaDoc
292     {
293     if (fIndex == null) {
294         fIndex = fConstraint.getIndex(session.getDatabase());
295     }
296     return fIndex;
297     }
298
299     /**
300      * Get the export constraint if it exists already.
301      */

302     public ExportedKeyConstraint findExportedKeyConstraint(Database db)
303     throws IOException JavaDoc, SQLException JavaDoc
304     {
305     if (ec == null) {
306         Table t = getFTable(db);
307         String JavaDoc ecName = getExportConstraintName();
308         ec = (ExportedKeyConstraint)t.getConstraint(ecName);
309     }
310     return ec;
311     }
312
313     /**
314      * For the purposes of creating a unique key, the rowId is included,
315      * whereas for purposes of checking foreign key integrity, the rowId
316      * is ignored, only the key value matters.
317      */

318     byte[] makeKey(Session session, Row row, long rowId)
319     throws SQLException JavaDoc
320     {
321     return Key.makeKey(table, row, getColumns(), rowId, true); // !!
322
}
323
324     /**
325      * Get the index (create it if necessary). The key for this index includes
326      * the actual key fields plus the row id to ensure uniqueness for Btreee
327      * operations. Some operations require that we use a special comparator
328      * which ignores the rowId part.
329      */

330     public Btree getIndex(Database db) throws IOException JavaDoc {
331     if (index == null) {
332             index = new Btree(db.getFile(), indexRoot, false);
333     }
334     return index;
335     }
336
337     /**
338      * Externalizable: read me from a stream
339      */

340     public void readExternal(ObjectInput JavaDoc in)
341     throws IOException JavaDoc, ClassNotFoundException JavaDoc
342     {
343     super.readExternal(in);
344     indexRoot = in.readLong();
345     }
346
347     /**
348      * Externalizable: write me to a stream
349      */

350     public void writeExternal(ObjectOutput JavaDoc out) throws IOException JavaDoc {
351     super.writeExternal(out);
352     out.writeLong(indexRoot);
353     }
354
355 }
356
Popular Tags