Quadcap Embeddable Database

com/quadcap/sql/Constraint.java

Go to the documentation of this file.
00001 package com.quadcap.sql; 00002 00003 /* Copyright 1999 - 2003 Quadcap Software. All rights reserved. 00004 * 00005 * This software is distributed under the Quadcap Free Software License. 00006 * This software may be used or modified for any purpose, personal or 00007 * commercial. Open Source redistributions are permitted. Commercial 00008 * redistribution of larger works derived from, or works which bundle 00009 * this software requires a "Commercial Redistribution License"; see 00010 * http://www.quadcap.com/purchase. 00011 * 00012 * Redistributions qualify as "Open Source" under one of the following terms: 00013 * 00014 * Redistributions are made at no charge beyond the reasonable cost of 00015 * materials and delivery. 00016 * 00017 * Redistributions are accompanied by a copy of the Source Code or by an 00018 * irrevocable offer to provide a copy of the Source Code for up to three 00019 * years at the cost of materials and delivery. Such redistributions 00020 * must allow further use, modification, and redistribution of the Source 00021 * Code under substantially the same terms as this license. 00022 * 00023 * Redistributions of source code must retain the copyright notices as they 00024 * appear in each source code file, these license terms, and the 00025 * disclaimer/limitation of liability set forth as paragraph 6 below. 00026 * 00027 * Redistributions in binary form must reproduce this Copyright Notice, 00028 * these license terms, and the disclaimer/limitation of liability set 00029 * forth as paragraph 6 below, in the documentation and/or other materials 00030 * provided with the distribution. 00031 * 00032 * The Software is provided on an "AS IS" basis. No warranty is 00033 * provided that the Software is free of defects, or fit for a 00034 * particular purpose. 00035 * 00036 * Limitation of Liability. Quadcap Software shall not be liable 00037 * for any damages suffered by the Licensee or any third party resulting 00038 * from use of the Software. 00039 */ 00040 00041 import java.io.Externalizable; 00042 import java.io.IOException; 00043 import java.io.ObjectInput; 00044 import java.io.ObjectOutput; 00045 00046 import java.util.Vector; 00047 00048 import java.sql.SQLException; 00049 00050 import com.quadcap.sql.index.Btree; 00051 00052 import com.quadcap.util.Debug; 00053 00054 /** 00055 * A constraint is a condition which must be satisfied relative to 00056 * the rows of a table. Constraint checking hooks are available for 00057 * both before and after table-modifying operations. 00058 * 00059 * @author Stan Bailes 00060 */ 00061 public abstract class Constraint implements Externalizable { 00062 transient Table table; 00063 transient int[] columns; 00064 Vector colNames = new Vector(); 00065 String name = null; 00066 int spec = 0; 00067 00068 // bits 0..1 of the constraint 00069 public static final int FULL = (1 << 0); 00070 public static final int PARTIAL = (1 << 1); 00071 00072 // two actions bits for update and delete 00073 public static final int NOACTION = 0; 00074 public static final int CASCADE = 1; 00075 public static final int SETNULL = 2; 00076 public static final int SETDEFAULT = 3; 00077 00078 // bits 2..3 (action) 00079 public static final int UPDATE = 2; 00080 // bits 4..5 (action) 00081 public static final int DELETE = 4; 00082 00083 // bit 6 00084 public static final int DEFERRABLE = (1 << 6); 00085 // bit 7 00086 public static final int INIT_DEFERRED = (1 << 7); 00087 // bit 8 00088 public static final int GLOBAL = (1 << 8); 00089 00090 /** 00091 * Default constructor 00092 */ 00093 public Constraint() {} 00094 00095 /** 00096 * Construct a named constraint 00097 */ 00098 public Constraint(String name) { 00099 this.name = name; 00100 } 00101 00102 /** 00103 * Construct a named constraint with a list of columns 00104 */ 00105 public Constraint(String name, Vector colNames) { 00106 this.name = name; 00107 this.colNames = colNames; 00108 } 00109 00110 /** 00111 * Return the constraint's name 00112 */ 00113 public String getName() { 00114 return name; 00115 } 00116 00117 /** 00118 * Set the constraint's name 00119 */ 00120 public void setName(String name) { 00121 this.name = name; 00122 } 00123 00124 /** 00125 * Get the referential action for the specified operation (UPD OR DEL) 00126 */ 00127 public int getRefAction(int opType) { 00128 return (spec >> opType) & 0x3; 00129 } 00130 00131 /** 00132 * String names for Various referential actions 00133 */ 00134 static String[] refActions = { "NO ACTION", "CASCADE", "SET NULL", 00135 "SET DEFAULT" }; 00136 00137 /** 00138 * Return the referential action for the specified operation 00139 */ 00140 public String getRefActionString(int opType) { 00141 return refActions[getRefAction(opType)]; 00142 } 00143 00144 /** 00145 * Set the 'global' flag 00146 */ 00147 public void setGlobal(boolean g) { 00148 if (g) { 00149 spec |= GLOBAL; 00150 } else { 00151 spec &= ~GLOBAL; 00152 } 00153 } 00154 00155 /** 00156 * Get the 'global' flag 00157 */ 00158 public boolean isGlobal() { return (spec & GLOBAL) != 0; } 00159 00160 /**---INSERT 00161 * Called before a row is INSERTED, with an opportunity to signal 00162 * a constraint violation if one can be detected. 00163 */ 00164 abstract public void checkInsert(Session session, Row row) 00165 throws SQLException, IOException 00166 ; 00167 00168 /** 00169 * Called after the specified row has been inserted, with the resulting 00170 * row ID, and with the active index. Constraints which maintain state 00171 * (such as an index) would extend this class and implement this 00172 * method to update the index 00173 */ 00174 abstract public void applyInsert(Session session, Row row, long rowId, 00175 Constraint activeIndex) 00176 throws SQLException, IOException 00177 ; 00178 00179 /**----DELETE 00180 * Called before a row is DELETED, with an opportunity to signal a 00181 * constraint violation if one can be detected. 00182 */ 00183 abstract public void checkDelete(Session session, Row row, long rowId) 00184 throws SQLException, IOException 00185 ; 00186 00187 /** 00188 * Called after a row has been deleted, with the old row and row ID. 00189 * Constraints which maintain state (such as an index) would extend 00190 * this class and implement this method to update the index. 00191 */ 00192 abstract public void applyDelete(Session session, Row row, long rowId, 00193 Constraint activeIndex) 00194 throws SQLException, IOException 00195 ; 00196 00197 /**----UPDATE 00198 * Called before a row is UPDATED, with an opportunity to signal a 00199 * constraint violation if one can be detected. 00200 * 00201 * Because the oldRow may be 'lazy', it's important to instantiate 00202 * whatever items are going to be needed later by applyUpdate *now*, 00203 * otherwise, apply may get the 'new' versions of those items, because 00204 * the underlying byte stream is modified by the time applyUpdate 00205 * gets called. 00206 */ 00207 abstract public void checkUpdate(Session session, byte[] oldKey, Row row, 00208 Row oldRow, long rowId, 00209 Constraint activeIndex) 00210 throws SQLException, IOException 00211 ; 00212 00213 /** 00214 * Called after a row has been updated, with the old row, old key, 00215 * new row and row ID. 00216 * Constraints which maintain state (such as an index) would extend 00217 * this class and implement this method to update the index. 00218 */ 00219 abstract public void applyUpdate(Session session, byte[] oldKey, Row row, 00220 Row oldRow, long rowId, 00221 Constraint activeIndex) 00222 throws SQLException, IOException 00223 ; 00224 00225 /** 00226 * Called when the constraint itself is being removed. Constraints which 00227 * allocate resources of any kind should release them here since they 00228 * are about to be discarded and gc'ed. 00229 */ 00230 abstract public void delete(Session session) 00231 throws SQLException, IOException 00232 ; 00233 00234 /** 00235 * Called when the constraint is added. Constraints which maintain 00236 * state (e.g., indexes) can build their initial data structures (or 00237 * whatever it is that they do at this time) 00238 */ 00239 abstract public void add(Session session) 00240 throws SQLException, IOException; 00241 00242 /** 00243 * Called to undo a constraint-add operation. 00244 */ 00245 public void undoAdd(Session session) 00246 throws SQLException, IOException { 00247 delete(session); 00248 } 00249 00250 00251 /** 00252 * Called to undo a constraint-add operation. 00253 */ 00254 public void undoDelete(Session session) 00255 throws SQLException, IOException 00256 { 00257 add(session); 00258 } 00259 00260 00261 /** 00262 * Set the deferrable flags 00263 */ 00264 public void setDeferrable(int def) { 00265 this.spec |= def; 00266 } 00267 00268 /** 00269 * Set the referential integrity flags 00270 */ 00271 public void setRefSpec(int ref) { 00272 this.spec |= ref; 00273 } 00274 00275 /** 00276 * Set the contstraint's table 00277 */ 00278 public void setTable(Table table) throws SQLException { 00279 this.table = table; 00280 this.columns = null; 00281 getColumns(); 00282 } 00283 00284 /** 00285 * Get the constraint's table 00286 */ 00287 public Table getTable() { return this.table; } 00288 00289 /** 00290 * Return the referential integrity and deferrability flags 00291 */ 00292 public int getSpec() { 00293 return spec; 00294 } 00295 00296 /** 00297 * Convenience method for setting single column constraints. 00298 */ 00299 public void setColumn(Column column) { 00300 if (colNames.size() != 0) { 00301 colNames = new Vector(); 00302 } 00303 colNames.add(column.getName()); 00304 this.columns = null; 00305 } 00306 00307 /** 00308 * For the simple, single column constraint, the constraint's column 00309 * 00310 * @exception SQLException if called for a multi-column constraint. 00311 */ 00312 public Column getColumn() throws SQLException { 00313 getColumns(); 00314 if (columns.length < 1) throw new SQLException("No column", "Q0000"); 00315 if (columns.length > 1) 00316 throw new SQLException("Not a single column constraint: " + this, 00317 "Q0000"); 00318 return table.getColumn(columns[0]); 00319 } 00320 00321 /** 00322 * Return the number of columns described by the constraint. 00323 */ 00324 public int getColumnCount() { 00325 return colNames.size(); 00326 } 00327 00328 /** 00329 * Zero based!!!! 00330 */ 00331 public Column getColumn(int c) throws SQLException { 00332 return table.getColumn(columns[c]); 00333 } 00334 00335 /** 00336 * Read me from a stream 00337 */ 00338 public void readExternal(ObjectInput in) 00339 throws IOException, ClassNotFoundException 00340 { 00341 spec = in.readInt(); 00342 name = (String)in.readObject(); 00343 colNames = (Vector)in.readObject(); 00344 columns = null; 00345 } 00346 00347 /** 00348 * Write me to a stream 00349 */ 00350 public void writeExternal(ObjectOutput out) throws IOException { 00351 out.writeInt(spec); 00352 out.writeObject(name); 00353 out.writeObject(colNames); 00354 } 00355 00356 /** 00357 * Return the integer indexes in the table's column list of the 00358 * columns in this constraint. We return a copy of our internal 00359 * array, for speed, and trust the caller to not mess with the 00360 * array... 00361 */ 00362 public int[] getColumns() throws SQLException { 00363 if (columns == null) { 00364 columns = table.mapColumns(colNames); 00365 } 00366 return columns; 00367 } 00368 00369 /** 00370 * Reset any mapped columns (e.g. in case a column is added or deleted) 00371 */ 00372 public void resetColumns() throws SQLException { 00373 columns = null; 00374 } 00375 00376 /** 00377 * Return a vector containing all of the column names 00378 */ 00379 public Vector getColumnNames() throws SQLException { 00380 return colNames; 00381 } 00382 00383 /** 00384 * Funny, but a lot of constraints have indexes. For the ones that 00385 * do, this can be a nifty little function. 00386 */ 00387 public Btree getIndex(Database db) throws IOException { 00388 return null; 00389 } 00390 00391 /** 00392 * Higher priority (larger numbers) execute first. 00393 */ 00394 public int getPriority() { return 3; } 00395 00396 /** 00397 * Is this constraint 'deferred'? 00398 */ 00399 public boolean isDeferred() { 00400 return false; // only foreign key constraints are deferrable... 00401 } 00402 00403 /** 00404 * Return a displayable representation for debugging 00405 */ 00406 public String toString() { 00407 StringBuffer sb = new StringBuffer("Constraint "); 00408 sb.append(name); 00409 sb.append(": "); 00410 if (table == null) { 00411 sb.append("<null table>"); 00412 } else { 00413 sb.append(table.getName()); 00414 } 00415 sb.append("("); 00416 if (colNames != null) { 00417 for (int i = 0; i < colNames.size(); i++) { 00418 if (i > 0) sb.append(','); 00419 sb.append(colNames.elementAt(i).toString()); 00420 } 00421 } 00422 sb.append(")"); 00423 if ((spec & FULL) != 0) sb.append(" FULL"); 00424 if ((spec & PARTIAL) != 0) sb.append(" PARTIAL"); 00425 00426 if (getRefAction(UPDATE) != NOACTION) { 00427 sb.append(" ON UPDATE "); 00428 sb.append(getRefActionString(UPDATE)); 00429 } 00430 if (getRefAction(DELETE) != NOACTION) { 00431 sb.append(" ON DELETE "); 00432 sb.append(getRefActionString(DELETE)); 00433 } 00434 if ((spec & DEFERRABLE) != 0) sb.append(" DEFERRABLE"); 00435 if ((spec & INIT_DEFERRED) != 0) sb.append(" INITIALLY DEFERRED"); 00436 00437 return sb.toString(); 00438 } 00439 }