Quadcap Embeddable Database

com/quadcap/sql/IndexConstraint.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.ByteArrayOutputStream; 00042 import java.io.Externalizable; 00043 import java.io.IOException; 00044 import java.io.ObjectInput; 00045 import java.io.ObjectOutput; 00046 00047 import java.util.Vector; 00048 00049 import java.sql.ResultSet; 00050 import java.sql.SQLException; 00051 00052 import com.quadcap.sql.file.ByteUtil; 00053 00054 import com.quadcap.sql.index.Btree; 00055 import com.quadcap.sql.index.Comparator; 00056 00057 import com.quadcap.sql.file.BlockFile; 00058 00059 import com.quadcap.util.Debug; 00060 import com.quadcap.util.Util; 00061 00062 /** 00063 * Base class for all index constraints. 00064 * 00065 * @author Stan Bailes 00066 */ 00067 abstract public class IndexConstraint extends Constraint 00068 implements Externalizable { 00069 Btree index = null; 00070 long indexRoot = -1; 00071 protected boolean useComparator = true; 00072 00073 /** 00074 * Default constructor (required for Externalizable) 00075 */ 00076 public IndexConstraint() {} 00077 00078 /** 00079 * Explicit constructor for named index 00080 */ 00081 public IndexConstraint(String name) { 00082 super(name); 00083 } 00084 00085 public IndexConstraint(String name, Vector names) { 00086 super(name, names); 00087 } 00088 00089 //------------------------------------------------------------------ 00090 // Abstract interface: implementation required 00091 /** 00092 * Make a serialized key appropriate to the constraint type, based on 00093 * the row and row id information 00094 */ 00095 abstract public byte[] makeKey(Session session, Row row, long rowId) 00096 throws SQLException 00097 ; 00098 00099 /** 00100 * Derived classes must implement this function, which returns the 00101 * constraint type as a human readable string. 00102 */ 00103 abstract public String constraintType(); 00104 00105 /** 00106 * Constraint.add(): We need to build an index! 00107 */ 00108 public void add(Session session) throws SQLException, IOException { 00109 index = null; 00110 indexRoot = -1; 00111 resetColumns(); 00112 getIndex(session.getDatabase()); 00113 00114 getColumns(); 00115 IndexCursor c = table.getCursor(session, this); 00116 if (c != null) { 00117 try { 00118 while (c.next()) { 00119 Row row = c.getRow(); 00120 long rowId = c.getRowId(); 00121 byte[] key = makeKey(session, row, rowId); 00122 if (index.get(key) != null) { 00123 throw new SQLException(constraintType() + 00124 " constraint violated"); 00125 } 00126 if (session.getConnection().inRecovery()) { 00127 rowId = session.getLog().getRowMap(rowId); 00128 } 00129 index.set(key, key.length, session.getBuf8(rowId), 0, 8); 00130 } 00131 } finally { 00132 c.close(); 00133 } 00134 } 00135 00136 } 00137 00138 /** 00139 * Constraint.delete(): We destroy our index 00140 */ 00141 public void delete(Session session) throws IOException { 00142 if (indexRoot > 0) { 00143 Database db = session.getDatabase(); 00144 getIndex(db); 00145 if (index != null) { 00146 index.free(); 00147 } 00148 } 00149 } 00150 00151 /** 00152 * Externalizable.readExternal(): Read me from a stream 00153 */ 00154 public void readExternal(ObjectInput in) 00155 throws IOException, ClassNotFoundException 00156 { 00157 super.readExternal(in); 00158 indexRoot = in.readLong(); 00159 useComparator = in.read() == 1; 00160 } 00161 00162 /** 00163 * Externalizable.writeExternal(): Write me to a stream 00164 */ 00165 public void writeExternal(ObjectOutput out) throws IOException { 00166 super.writeExternal(out); 00167 out.writeLong(indexRoot); 00168 out.write(useComparator ? 1 : 0); 00169 } 00170 00171 //--------------------------------- 00172 // Constraint.checkNNN() functions 00173 00174 /** 00175 * Constraint.checkInsert(): We could check for dups 00176 */ 00177 public void checkInsert(Session session, Row row) 00178 throws SQLException, IOException 00179 { 00180 } 00181 00182 public void checkUpdate(Session session, byte[] oldKey, Row row, 00183 Row oldRow, long rowId, Constraint activeIndex) 00184 throws SQLException, IOException 00185 { 00186 } 00187 00188 public void checkDelete(Session session, Row row, long rowId) 00189 throws SQLException, IOException 00190 { 00191 } 00192 00193 //--------------------------------- 00194 // Constraint.applyXXX() functions 00195 00196 /** 00197 * Constraint.applyInsert(): Add an index entry 00198 */ 00199 public void applyInsert(Session session, Row row, long rowId, 00200 Constraint activeIndex) 00201 throws SQLException, IOException 00202 { 00203 00204 Database db = session.getDatabase(); 00205 byte[] key = makeKey(session, row, rowId); 00206 AddIndexEntry add = new AddIndexEntry(session, this, key, rowId); 00207 if (activeIndex == this) { 00208 session.addPendingAction(add); 00209 } else { 00210 session.doStep(add); 00211 } 00212 } 00213 00214 // careful, 'oldKey' only applies to the 'activeIndex', which may not 00215 // be this constraint. 00216 public void applyUpdate(Session session, byte[] oldKey, Row row, 00217 Row oldRow, long rowId, Constraint activeIndex) 00218 throws SQLException, IOException 00219 { 00220 byte[] key = makeKey(session, row, rowId); 00221 if (activeIndex != this) { 00222 oldKey = makeKey(session, oldRow, rowId); 00223 } 00224 if (Util.compareBytes(key, oldKey) != 0) { 00225 UpdateIndex ui = 00226 (UpdateIndex)session.getContext(this, isDeferred()); 00227 if (ui == null) { 00228 ui = new UpdateIndex(session, this); 00229 session.putContext(this, isDeferred(), ui); 00230 } 00231 ui.addEntry(key, oldKey, rowId); 00232 } else { 00233 } 00234 } 00235 00236 public void applyDelete(Session session, Row row, long rowId, 00237 Constraint activeIndex) 00238 throws SQLException, IOException 00239 { 00240 Database db = session.getDatabase(); 00241 byte[] key = makeKey(session, row, rowId); 00242 00243 if (index == null) getIndex(db); 00244 DeleteIndexEntry del = new DeleteIndexEntry(session, this, key); 00245 if (activeIndex == this) { 00246 session.addPendingAction(del); 00247 } else { 00248 session.doStep(del); 00249 } 00250 } 00251 00252 /** 00253 * Does this constraint have enough information to uniquely identify 00254 * each row? 00255 */ 00256 public boolean isUnique() { return true; } 00257 00258 /** 00259 * Return the number of columns in the index implementing this constraint 00260 */ 00261 public int getIndexColumnCount() { 00262 return getColumnCount(); 00263 } 00264 00265 /** 00266 * Lazy getter for underlying Index object (a Btree, in this case) 00267 */ 00268 public Btree getIndex(Database db) throws IOException { 00269 if (index == null) { 00270 BlockFile file = db.getFile(); 00271 boolean create = false; 00272 if (indexRoot == -1) { 00273 indexRoot = file.newPage(); 00274 db.updateRelation(table); 00275 create = true; 00276 } 00277 if (useComparator) { 00278 Comparator compare = new Key(getIndexColumnCount()); 00279 index = new Btree(file, compare, indexRoot, create); 00280 } else { 00281 index = new Btree(file, indexRoot, create); 00282 } 00283 } 00284 return index; 00285 } 00286 00287 /** 00288 * Return a string representation of the constraint 00289 */ 00290 public String toString() { 00291 StringBuffer sb = new StringBuffer(); 00292 sb.append(getName()); 00293 if (table != null) { 00294 sb.append("("); 00295 try { 00296 Vector v = getColumnNames(); 00297 for (int i = 0; i < v.size(); i++) { 00298 if (i > 0) sb.append(','); 00299 sb.append(v.elementAt(i).toString()); 00300 } 00301 sb.append(")"); 00302 } catch (SQLException e) { 00303 sb.append("Exception: " + e.toString()); 00304 } 00305 } 00306 return sb.toString(); 00307 } 00308 }