package com.quadcap.sql;
/* Copyright 1999 - 2003 Quadcap Software. All rights reserved.
*
* This software is distributed under the Quadcap Free Software License.
* This software may be used or modified for any purpose, personal or
* commercial. Open Source redistributions are permitted. Commercial
* redistribution of larger works derived from, or works which bundle
* this software requires a "Commercial Redistribution License"; see
* http://www.quadcap.com/purchase.
*
* Redistributions qualify as "Open Source" under one of the following terms:
*
* Redistributions are made at no charge beyond the reasonable cost of
* materials and delivery.
*
* Redistributions are accompanied by a copy of the Source Code or by an
* irrevocable offer to provide a copy of the Source Code for up to three
* years at the cost of materials and delivery. Such redistributions
* must allow further use, modification, and redistribution of the Source
* Code under substantially the same terms as this license.
*
* Redistributions of source code must retain the copyright notices as they
* appear in each source code file, these license terms, and the
* disclaimer/limitation of liability set forth as paragraph 6 below.
*
* Redistributions in binary form must reproduce this Copyright Notice,
* these license terms, and the disclaimer/limitation of liability set
* forth as paragraph 6 below, in the documentation and/or other materials
* provided with the distribution.
*
* The Software is provided on an "AS IS" basis. No warranty is
* provided that the Software is free of defects, or fit for a
* particular purpose.
*
* Limitation of Liability. Quadcap Software shall not be liable
* for any damages suffered by the Licensee or any third party resulting
* from use of the Software.
*/
import java.io.ByteArrayOutputStream;
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.Vector;
import java.sql.ResultSet;
import java.sql.SQLException;
import com.quadcap.sql.index.Btree;
import com.quadcap.sql.index.BCursor;
import com.quadcap.util.Debug;
import com.quadcap.util.Util;
/**
* A hidden 'ExportedKeyConstraint' is created for tables that
* are referenced as foreign keys by other tables.
*
* @author Stan Bailes
*/
public class ExportedKeyConstraint extends ForeignKeyConstraint
implements Externalizable
{
transient ImportedKeyConstraint iConstraint;
transient String iConstraintName;
String uConstraintName;
/**
* Default constructor
*/
public ExportedKeyConstraint() {}
/**
* Explicit constructor for matching ImportedKeyConstraint.
*/
public ExportedKeyConstraint(String name, Vector colNames,
String fTableName, Vector fColNames,
ImportedKeyConstraint iConstraint,
UniqueConstraint uConstraint)
throws SQLException
{
super(name, colNames, fTableName, fColNames);
this.iConstraint = iConstraint;
this.iConstraintName = iConstraint.getName();
this.uConstraintName = uConstraint.getName();
uConstraint.addExportConstraint(this);
if (this.colNames == null) {
this.colNames = uConstraint.getColumnNames();
}
}
public void delete(Session session) throws SQLException, IOException {
UniqueConstraint uc =
(UniqueConstraint)table.getConstraint(uConstraintName);
if (uc != null) {
uc.removeExportConstraint(name);
}
}
void setForeignKeyCols(int[] fCols) {
this.fCols = fCols;
}
public void checkUpdate(Session session, byte[] oldKey, Row row,
Row oldRow, long rowId, Constraint activeIndex)
throws SQLException, IOException
{
getComparator();
Database db = session.getDatabase();
byte[] newKey = makeKey(session, row);
if (activeIndex != this) oldKey = makeKey(session, oldRow);
if (compare.compare(newKey, oldKey) != 0) {
ExportedKeys ek = getExportedKeys(session);
if (isSelfReferencing(db)) {
byte[] oldfKey = makeFKey(session, oldRow);
byte[] newfKey = makeFKey(session, row);
ek.addSelfRefEntry(oldKey, newKey, oldfKey, newfKey);
} else {
ek.addEntry(oldKey, newKey);
}
}
}
public void checkDelete(Session session, Row row, long rowId)
throws SQLException, IOException
{
byte[] fkey = getImportedKeyConstraint(session.getDatabase()).makeFKey(session, row);
if (isSelfReferencing(session.getDatabase())) {
ExportedKeys ek = getExportedKeys(session);
byte[] key = makeKey(session, row);
ek.addDeleteSelfRef(key, fkey);
} else {
checkKeyRemoval(session, fkey);
}
}
public void checkKeyRemoval(Session session, byte[] oldkey)
throws SQLException, IOException
{
getComparator();
Database db = session.getDatabase();
Btree fTree = getForeignIndex(db);
int count = 0;
boolean match = false;
BCursor cursor = fTree.getCursor(false);
try {
boolean kvalid = cursor.seek(oldkey);
while (!match && (kvalid || cursor.next())) {
byte[] key = cursor.getKey();
int cmp = compare.compare(key, oldkey);
match = cmp == 0;
kvalid = false;
}
} finally {
cursor.release();
}
if (match) {
int refSpec = iConstraint.getRefAction(DELETE);
switch (refSpec) {
case NOACTION:
throw new SQLException(
"Foreign key constraint violation: children exist",
"23000");
case CASCADE:
ExportedKeys ek = getExportedKeys(session);
ek.removeKey(refSpec, oldkey);
break;
case SETNULL:
case SETDEFAULT:
// XXX TODO: set null, set default
throw new SQLException(
"Foreign key constraint violation and SET " +
"{NULL|DEFAULT} not implemented", "23000");
}
}
}
/**
* Utility function to get / lazy-create the session context used
* to keep track of key additions and removals generated by the current
* statement.
*/
ExportedKeys getExportedKeys(Session session) throws IOException {
ExportedKeys ek =
(ExportedKeys)session.getContext(this, isDeferred());
if (ek == null) {
ek = new ExportedKeys(session, this);
session.putContext(this, isDeferred(), ek);
}
return ek;
}
ImportedKeyConstraint getImportedKeyConstraint(Database db)
throws SQLException, IOException
{
if (iConstraint == null) {
getFTable(db);
iConstraint =
(ImportedKeyConstraint)fTable.getConstraint(iConstraintName);
}
return iConstraint;
}
Btree getForeignIndex(Database db) throws SQLException, IOException {
return getImportedKeyConstraint(db).getIndex(db);
}
public void readExternal(ObjectInput in)
throws IOException, ClassNotFoundException
{
super.readExternal(in);
iConstraintName = (String)in.readObject();
uConstraintName = (String)in.readObject();
}
public void writeExternal(ObjectOutput out) throws IOException {
super.writeExternal(out);
out.writeObject(iConstraintName);
out.writeObject(uConstraintName);
}
}
|