001: package com.quadcap.sql;
002:
003: /* Copyright 1999 - 2003 Quadcap Software. All rights reserved.
004: *
005: * This software is distributed under the Quadcap Free Software License.
006: * This software may be used or modified for any purpose, personal or
007: * commercial. Open Source redistributions are permitted. Commercial
008: * redistribution of larger works derived from, or works which bundle
009: * this software requires a "Commercial Redistribution License"; see
010: * http://www.quadcap.com/purchase.
011: *
012: * Redistributions qualify as "Open Source" under one of the following terms:
013: *
014: * Redistributions are made at no charge beyond the reasonable cost of
015: * materials and delivery.
016: *
017: * Redistributions are accompanied by a copy of the Source Code or by an
018: * irrevocable offer to provide a copy of the Source Code for up to three
019: * years at the cost of materials and delivery. Such redistributions
020: * must allow further use, modification, and redistribution of the Source
021: * Code under substantially the same terms as this license.
022: *
023: * Redistributions of source code must retain the copyright notices as they
024: * appear in each source code file, these license terms, and the
025: * disclaimer/limitation of liability set forth as paragraph 6 below.
026: *
027: * Redistributions in binary form must reproduce this Copyright Notice,
028: * these license terms, and the disclaimer/limitation of liability set
029: * forth as paragraph 6 below, in the documentation and/or other materials
030: * provided with the distribution.
031: *
032: * The Software is provided on an "AS IS" basis. No warranty is
033: * provided that the Software is free of defects, or fit for a
034: * particular purpose.
035: *
036: * Limitation of Liability. Quadcap Software shall not be liable
037: * for any damages suffered by the Licensee or any third party resulting
038: * from use of the Software.
039: */
040:
041: import java.io.ByteArrayOutputStream;
042: import java.io.Externalizable;
043: import java.io.IOException;
044: import java.io.ObjectInput;
045: import java.io.ObjectOutput;
046:
047: import java.util.Vector;
048:
049: import java.sql.ResultSet;
050: import java.sql.SQLException;
051:
052: import com.quadcap.sql.io.ObjectInputStream;
053: import com.quadcap.sql.io.ObjectOutputStream;
054:
055: import com.quadcap.sql.index.Btree;
056: import com.quadcap.sql.index.Comparator;
057:
058: /**
059: * Abstract base class for imported and exported key constraints.
060: *
061: * @author Stan Bailes
062: */
063: public abstract class ForeignKeyConstraint extends Constraint implements
064: Externalizable {
065: String fTableName;
066: Vector fColNames;
067: Table fTable;
068: UniqueConstraint fConstraint;
069: int[] fCols;
070: transient Comparator compare;
071:
072: /**
073: * Default constructor
074: */
075: public ForeignKeyConstraint() {
076: }
077:
078: public ForeignKeyConstraint(String name, String fTableName) {
079: super (name);
080: this .fTableName = fTableName;
081: }
082:
083: public ForeignKeyConstraint(String name, Vector colNames,
084: String fTableName, Vector fColNames) {
085: super (name, colNames);
086: this .fTableName = fTableName;
087: this .fColNames = fColNames;
088: }
089:
090: /**
091: * Reset any mapped columns (e.g. in case a column is added or deleted)
092: */
093: public void resetColumns() throws SQLException {
094: super .resetColumns();
095: fCols = null;
096: }
097:
098: public void checkInsert(Session session, Row row)
099: throws SQLException, IOException {
100: }
101:
102: public void applyInsert(Session session, Row row, long rowId,
103: Constraint activeIndex) throws SQLException, IOException {
104: }
105:
106: public void checkUpdate(Session session, Row row, long rowId)
107: throws SQLException, IOException {
108: }
109:
110: public void applyUpdate(Session session, byte[] oldKey, Row row,
111: Row oldRow, long rowId, Constraint activeIndex)
112: throws SQLException, IOException {
113: }
114:
115: public void checkDelete(Session session, Row row, long rowId)
116: throws SQLException, IOException {
117: }
118:
119: public void applyDelete(Session session, Row row, long rowId,
120: Constraint activeIndex) throws SQLException, IOException {
121: }
122:
123: /**
124: * Is this constraint 'deferred'?
125: */
126: public final boolean isDeferred() {
127: return (spec & INIT_DEFERRED) != 0;
128: }
129:
130: final Comparator getComparator() throws SQLException {
131: if (compare == null)
132: compare = new Key(getColumns().length);
133: return compare;
134: }
135:
136: /**
137: * Create a candidate key for a row from this table
138: */
139: public byte[] makeKey(Session session, Row row) throws SQLException {
140: return makeKey(row, getColumns());
141: }
142:
143: /**
144: * Create a candidate key for a row from the foreign table
145: */
146: public byte[] makeFKey(Session session, Row row)
147: throws IOException, SQLException {
148: return makeKey(row, getFCols(session.getDatabase()));
149: }
150:
151: private final byte[] makeKey(Row row, int[] k) throws SQLException {
152: return Key.makeKey(null, row, k, 0, false);
153: }
154:
155: public void setForeignColumn(String name) {
156: fColNames = new Vector();
157: fColNames.addElement(name);
158: }
159:
160: public void readExternal(ObjectInput in) throws IOException,
161: ClassNotFoundException {
162: super .readExternal(in);
163: fTableName = (String) in.readObject();
164: fColNames = (Vector) in.readObject();
165: }
166:
167: public void writeExternal(ObjectOutput out) throws IOException {
168: super .writeExternal(out);
169: out.writeObject(fTableName);
170: out.writeObject(fColNames);
171: }
172:
173: public String getFTableName() {
174: return fTableName;
175: }
176:
177: public void setFTableName(String s) {
178: fTableName = s;
179: }
180:
181: public Table getFTable(Database db) throws SQLException,
182: IOException {
183: if (fTable == null) {
184: Relation t = db.getRelation(fTableName);
185: if (t == null) {
186: throw new SQLException("No such table: " + fTableName,
187: "42000");
188: }
189: try {
190: fTable = (Table) t;
191: } catch (ClassCastException e) {
192: throw new SQLException("Not a base table: "
193: + fTableName, "42000");
194: }
195: }
196: return fTable;
197: }
198:
199: /**
200: * If you care, remember to 'extend' and embrace.
201: */
202: public void add(Session session) throws SQLException, IOException {
203: }
204:
205: abstract public void delete(Session session) throws SQLException,
206: IOException;
207:
208: /**
209: *
210: */
211: public int[] getFCols(Database db) throws SQLException, IOException {
212: if (fCols == null) {
213: if (fColNames == null) {
214: UniqueConstraint pk = getFTable(db).getPrimaryKey();
215: if (pk == null) {
216: throw new SQLException("No primary key for table "
217: + fTable.getName());
218: }
219: fConstraint = pk;
220: fCols = pk.getColumns();
221: } else {
222: fCols = getFTable(db).mapColumns(fColNames);
223: fConstraint = fTable.getIndexForColumns(fCols);
224: }
225: }
226: return fCols;
227: }
228:
229: boolean isSelfReferencing(Database db) throws IOException,
230: SQLException {
231: boolean ret = table == getFTable(db);
232: return ret;
233: }
234:
235: public String toString() {
236: StringBuffer sb = new StringBuffer(super .toString());
237: sb.append(" references " + fTableName + "(");
238: if (fColNames != null) {
239: for (int i = 0; i < fColNames.size(); i++) {
240: if (i > 0)
241: sb.append(",");
242: sb.append(fColNames.elementAt(i).toString());
243: }
244: }
245: sb.append(')');
246: return sb.toString();
247: }
248: }
|