| 1 package com.quadcap.sql; 2 3 40 41 import java.io.ByteArrayOutputStream ; 42 import java.io.Externalizable ; 43 import java.io.IOException ; 44 import java.io.ObjectInput ; 45 import java.io.ObjectOutput ; 46 47 import java.util.Vector ; 48 49 import java.sql.ResultSet ; 50 import java.sql.SQLException ; 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 71 public class ImportedKeyConstraint extends ForeignKeyConstraint 72 implements Externalizable  73 { 74 long indexRoot = -1; 75 transient Btree index = null; 76 transient Btree fIndex = null; 77 transient ExportedKeyConstraint ec = null; 78 79 82 public ImportedKeyConstraint() {} 83 84 87 public ImportedKeyConstraint(String name, String fTableName) { 88 super(name, fTableName); 89 } 90 91 94 public ImportedKeyConstraint(String name, Vector colNames, 95 String fTableName, Vector fColNames) { 96 super(name, colNames, fTableName, fColNames); 97 } 98 99 103 public void add(Session session) throws SQLException , IOException { 104 Database db = session.getDatabase(); 105 BlockFile file = db.getFile(); 106 getFCols(db); 107 if (fConstraint == null) { 108 throw new SQLException ("No suitable foreign key", "23000"); 109 } 110 111 indexRoot = file.newPage(); 112 index = new Btree(file, indexRoot, true); 113 114 String 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 142 public void delete(Session session) throws SQLException , IOException { 143 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 158 final String getExportConstraintName() { 159 StringBuffer sb = new StringBuffer ("__ec_"); 160 sb.append(table.getName()); 161 sb.append('_'); 162 sb.append(name); 163 return sb.toString(); 164 } 165 166 170 public void checkInsert(Session session, Row row) 171 throws SQLException , IOException  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 } else { 198 throw new SQLException ( 199 "Foreign Key Constraint Violation: no parent: " + 200 this.toString(), "23000"); 201 } 202 } 203 } 204 205 208 public void applyInsert(Session session, Row row, long rowId, 209 Constraint activeIndex) 210 throws SQLException , IOException  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 225 public void applyDelete(Session session, Row row, long rowId, 226 Constraint activeIndex) 227 throws SQLException , IOException  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 246 public void checkUpdate(Session session, byte[] oldKey, Row row, 247 Row oldRow, long rowId, Constraint activeIndex) 248 throws SQLException , IOException  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 269 boolean checkSelfReferencing(Row row) throws SQLException { 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 290 final Btree getForeignIndex(Session session) 291 throws SQLException , IOException 292 { 293 if (fIndex == null) { 294 fIndex = fConstraint.getIndex(session.getDatabase()); 295 } 296 return fIndex; 297 } 298 299 302 public ExportedKeyConstraint findExportedKeyConstraint(Database db) 303 throws IOException , SQLException  304 { 305 if (ec == null) { 306 Table t = getFTable(db); 307 String ecName = getExportConstraintName(); 308 ec = (ExportedKeyConstraint)t.getConstraint(ecName); 309 } 310 return ec; 311 } 312 313 318 byte[] makeKey(Session session, Row row, long rowId) 319 throws SQLException  320 { 321 return Key.makeKey(table, row, getColumns(), rowId, true); } 323 324 330 public Btree getIndex(Database db) throws IOException { 331 if (index == null) { 332 index = new Btree(db.getFile(), indexRoot, false); 333 } 334 return index; 335 } 336 337 340 public void readExternal(ObjectInput in) 341 throws IOException , ClassNotFoundException  342 { 343 super.readExternal(in); 344 indexRoot = in.readLong(); 345 } 346 347 350 public void writeExternal(ObjectOutput out) throws IOException { 351 super.writeExternal(out); 352 out.writeLong(indexRoot); 353 } 354 355 } 356 | Popular Tags |