/* Copyright (c) 2001-2008, The HSQL Development Group
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of the HSQL Development Group nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG,
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.hsqldb;
import org.hsqldb.HsqlNameManager.HsqlName;
import org.hsqldb.lib.ArrayUtil;
import org.hsqldb.lib.HsqlArrayList;
import org.hsqldb.lib.HashMappedList;
import org.hsqldb.lib.Iterator;
import org.hsqldb.lib.WrapperIterator;
import org.hsqldb.persist.Logger;
/**
* Manages all SCHEMA related database objects
*
* @author fredt@users
* @version 1.8.0
* @since 1.8.0
*/
public class SchemaManager {
static final String SYSTEM_SCHEMA = "SYSTEM_SCHEMA";
static final String DEFINITION_SCHEMA = "DEFINITION_SCHEMA";
static final String INFORMATION_SCHEMA = "INFORMATION_SCHEMA";
static final String PUBLIC_SCHEMA = "PUBLIC";
static HsqlName INFORMATION_SCHEMA_HSQLNAME =
HsqlNameManager.newHsqlSystemObjectName(INFORMATION_SCHEMA);
static HsqlName SYSTEM_SCHEMA_HSQLNAME =
HsqlNameManager.newHsqlSystemObjectName(SYSTEM_SCHEMA);
Database database;
HsqlName defaultSchemaHsqlName;
HashMappedList schemaMap = new HashMappedList();
SchemaManager(Database database) {
this.database = database;
Schema schema = new Schema(PUBLIC_SCHEMA, false);
defaultSchemaHsqlName = schema.name;
schemaMap.put(PUBLIC_SCHEMA, schema);
}
void createSchema(String name, boolean isQuoted) throws HsqlException {
if (DEFINITION_SCHEMA.equals(name) || INFORMATION_SCHEMA.equals(name)
|| SYSTEM_SCHEMA.equals(name)) {
throw Trace.error(Trace.INVALID_SCHEMA_NAME_NO_SUBCLASS);
}
Schema schema = new Schema(name, isQuoted);
schemaMap.add(name, schema);
}
void dropSchema(String name, boolean cascade) throws HsqlException {
Schema schema = (Schema) schemaMap.get(name);
if (schema == null) {
throw Trace.error(Trace.INVALID_SCHEMA_NAME_NO_SUBCLASS);
}
if (!cascade &&!schema.isEmpty()) {
throw Trace.error(Trace.DEPENDENT_DATABASE_OBJECT_EXISTS);
}
Iterator tableIterator = schema.tablesIterator();
while (tableIterator.hasNext()) {
Table table = ((Table) tableIterator.next());
database.getUserManager().removeDbObject(table.getName());
table.drop();
}
Iterator sequenceIterator = schema.sequencesIterator();
while (tableIterator.hasNext()) {
NumberSequence sequence =
((NumberSequence) sequenceIterator.next());
database.getUserManager().removeDbObject(sequence.getName());
}
schema.clearStructures();
schemaMap.remove(name);
if (defaultSchemaHsqlName.name.equals(name)) {
if (schemaMap.isEmpty()) {
schema = new Schema(PUBLIC_SCHEMA, false);
} else {
schema = (Schema) schemaMap.get(0);
}
defaultSchemaHsqlName = schema.name;
schemaMap.put(defaultSchemaHsqlName.name, schema);
}
// these are called last and in this particular order
database.getUserManager().removeSchemaReference(schema);
database.getSessionManager().removeSchemaReference(schema);
}
void renameSchema(String name, String newName,
boolean isQuoted) throws HsqlException {
Schema schema = (Schema) schemaMap.get(name);
Schema exists = (Schema) schemaMap.get(newName);
if (schema == null || exists != null
|| INFORMATION_SCHEMA.equals(newName)) {
throw Trace.error(Trace.INVALID_SCHEMA_NAME_NO_SUBCLASS,
schema == null ? name
: newName);
}
schema.name.rename(newName, isQuoted);
int index = schemaMap.getIndex(name);
schemaMap.set(index, newName, schema);
}
void clearStructures() {
Iterator it = schemaMap.values().iterator();
while (it.hasNext()) {
Schema schema = (Schema) it.next();
schema.clearStructures();
}
}
public Iterator userSchemaNameIterator() {
return schemaMap.keySet().iterator();
}
HsqlName toSchemaHsqlName(String name) {
Schema schema = (Schema) schemaMap.get(name);
return schema == null ? null
: schema.name;
}
HsqlName getDefaultSchemaHsqlName() {
return defaultSchemaHsqlName;
}
public String getDefaultSchemaName() {
return defaultSchemaHsqlName.name;
}
boolean schemaExists(String name) {
if (INFORMATION_SCHEMA.equals(name)) {
return true;
}
return schemaMap.containsKey(name);
}
/**
* If schemaName is null, return the current schema name, else return
* the HsqlName object for the schema. If schemaName does not exist,
* throw.
*/
HsqlName getSchemaHsqlName(String name) throws HsqlException {
if (name == null) {
return defaultSchemaHsqlName;
}
if (INFORMATION_SCHEMA.equals(name)) {
return INFORMATION_SCHEMA_HSQLNAME;
}
Schema schema = ((Schema) schemaMap.get(name));
if (schema == null) {
throw Trace.error(Trace.INVALID_SCHEMA_NAME_NO_SUBCLASS, name);
}
return schema.name;
}
/**
* Same as above, but return string
*/
String getSchemaName(String name) throws HsqlException {
return getSchemaHsqlName(name).name;
}
/**
* Iterator includes INFORMATION_SCHEMA
*/
Iterator fullSchemaNamesIterator() {
return new WrapperIterator(new WrapperIterator(INFORMATION_SCHEMA),
schemaMap.keySet().iterator());
}
/**
* is a schema read-only
*/
public boolean isSystemSchema(HsqlName schema) {
return (INFORMATION_SCHEMA_HSQLNAME.equals(schema) || SYSTEM_SCHEMA_HSQLNAME.equals(schema))
? true
: false;
}
public Iterator tablesIterator(String schema) {
Schema temp = (Schema) schemaMap.get(schema);
return temp.tablesIterator();
}
public Iterator allTablesIterator() {
Iterator schemas = userSchemaNameIterator();
Iterator tables = new WrapperIterator();
while (schemas.hasNext()) {
String name = (String) schemas.next();
Iterator t = tablesIterator(name);
tables = new WrapperIterator(tables, t);
}
return tables;
}
Iterator sequenceIterator(String schema) {
Schema temp = (Schema) schemaMap.get(schema);
return temp.sequencesIterator();
}
public Iterator allSequencesIterator() {
Iterator it = schemaMap.values().iterator();
Iterator sequences = new WrapperIterator();
while (it.hasNext()) {
Schema temp = (Schema) it.next();
sequences = new WrapperIterator(sequences,
temp.sequencesIterator());
}
return sequences;
}
/**
* Returns an HsqlArrayList containing references to all non-system
* tables and views. This includes all tables and views registered with
* this Database.
*/
public HsqlArrayList getAllTables() {
Iterator schemas = userSchemaNameIterator();
HsqlArrayList alltables = new HsqlArrayList();
while (schemas.hasNext()) {
String name = (String) schemas.next();
HashMappedList current = getTables(name);
alltables.addAll(current.values());
}
return alltables;
}
public HashMappedList getTables(String schema) {
Schema temp = (Schema) schemaMap.get(schema);
return temp.tableList;
}
/**
* @throws HsqlException if exists.
*/
void checkUserViewNotExists(Session session, String viewName,
String schema) throws HsqlException {
boolean exists =
database.schemaManager.findUserTable(session, viewName, schema)
!= null;
if (exists) {
throw Trace.error(Trace.VIEW_ALREADY_EXISTS, viewName);
}
}
/**
* @throws HsqlException if exists
*/
void checkUserTableNotExists(Session session, String tableName,
String schema) throws HsqlException {
boolean exists = findUserTable(session, tableName, schema) != null;
if (exists) {
throw Trace.error(Trace.TABLE_ALREADY_EXISTS, tableName);
}
}
/**
* Returns the specified user-defined table or view visible within the
* context of the specified Session, or any system table of the given
* name. It excludes any temp tables created in other Sessions.
* Throws if the table does not exist in the context.
*/
public Table getTable(Session session, String name,
String schema) throws HsqlException {
Table t = findUserTable(session, name, schema);
if (t == null) {
if (!INFORMATION_SCHEMA.equals(schema)) {
throw Trace.error(Trace.TABLE_NOT_FOUND);
}
if (database.dbInfo != null) {
t = database.dbInfo.getSystemTable(session, name);
}
}
if (t == null) {
throw Trace.error(Trace.TABLE_NOT_FOUND, name);
}
return t;
}
/**
* Returns the specified user-defined table or view visible within the
* context of the specified Session. It excludes system tables and
* any temp tables created in different Sessions.
* Throws if the table does not exist in the context.
*/
public Table getUserTable(Session session, String name,
String schema) throws HsqlException {
Table t = findUserTable(session, name, schema);
if (t == null) {
throw Trace.error(Trace.TABLE_NOT_FOUND, name);
}
return t;
}
/**
* Returns the specified user-defined table or view visible within the
* context of the specified schema. It excludes system tables.
* Returns null if the table does not exist in the context.
*/
Table findUserTable(Session session, String name, String schemaName) {
Schema schema = (Schema) schemaMap.get(schemaName);
if (schema == null) {
return null;
}
for (int i = 0, tsize = schema.tableList.size(); i < tsize; i++) {
Table t = (Table) schema.tableList.get(i);
if (t.equals(session, name)) {
return t;
}
}
return null;
}
/**
* Registers the specified table or view with this Database.
*/
void linkTable(Table t) {
Schema schema = (Schema) schemaMap.get(t.getSchemaName());
schema.tableList.add(t.getName().name, t);
}
NumberSequence getSequence(String name,
String schemaName) throws HsqlException {
NumberSequence sequence = findSequence(name, schemaName);
if (sequence == null) {
throw Trace.error(Trace.SEQUENCE_NOT_FOUND, name);
}
return sequence;
}
/**
* Returns the specified Sequence visible within the
* context of the specified Session.
*/
public NumberSequence findSequence(String name,
String schemaName)
throws HsqlException {
Schema schema = (Schema) schemaMap.get(schemaName);
NumberSequence sequence = schema.sequenceManager.getSequence(name);
return sequence;
}
/**
* Returns the table that has an index with the given name and schema.
*/
Table findUserTableForIndex(Session session, String name,
String schemaName) {
Schema schema = (Schema) schemaMap.get(schemaName);
HsqlName tablename = schema.indexNameList.getOwner(name);
if (tablename == null) {
return null;
}
return findUserTable(session, tablename.name, schemaName);
}
/**
* Returns index of a table or view in the HsqlArrayList that
* contains the table objects for this Database.
*
* @param table the Table object
* @return the index of the specified table or view, or -1 if not found
*/
int getTableIndex(Table table) {
Schema schema = (Schema) schemaMap.get(table.getSchemaName());
for (int i = 0, tsize = schema.tableList.size(); i < tsize; i++) {
Table t = (Table) schema.tableList.get(i);
if (t == table) {
return i;
}
}
return -1;
}
/**
* Drops the index with the specified name.
*/
void dropIndex(Session session, String indexname, String schema,
boolean ifExists) throws HsqlException {
Table t = findUserTableForIndex(session, indexname, schema);
if (t == null) {
if (ifExists) {
return;
} else {
throw Trace.error(Trace.INDEX_NOT_FOUND, indexname);
}
}
t.checkDropIndex(indexname, null, false);
session.commit();
session.setScripting(true);
TableWorks tw = new TableWorks(session, t);
tw.dropIndex(indexname);
}
//------------ name management
/**
* Checks if a Trigger with given name either exists or does not, based on
* the value of the argument, yes.
*/
void checkTriggerExists(String name, String schemaName,
boolean yes) throws HsqlException {
Schema schema = (Schema) schemaMap.get(schemaName);
boolean exists = schema.triggerNameList.containsName(name);
if (exists != yes) {
int code = yes ? Trace.TRIGGER_NOT_FOUND
: Trace.TRIGGER_ALREADY_EXISTS;
throw Trace.error(code, name);
}
}
void registerTriggerName(String name,
HsqlName tableName) throws HsqlException {
Schema schema = (Schema) schemaMap.get(tableName.schema.name);
schema.triggerNameList.addName(name, tableName,
Trace.TRIGGER_ALREADY_EXISTS);
}
void checkIndexExists(String name, String schemaName,
boolean yes) throws HsqlException {
Schema schema = (Schema) schemaMap.get(schemaName);
boolean exists = schema.indexNameList.containsName(name);
if (exists != yes) {
int code = yes ? Trace.INDEX_NOT_FOUND
: Trace.INDEX_ALREADY_EXISTS;
throw Trace.error(code, name);
}
}
void registerIndexName(String name,
HsqlName tableName) throws HsqlException {
Schema schema = (Schema) schemaMap.get(tableName.schema.name);
schema.indexNameList.addName(name, tableName,
Trace.INDEX_ALREADY_EXISTS);
}
void removeIndexName(String name,
HsqlName tableName) throws HsqlException {
Schema schema = (Schema) schemaMap.get(tableName.schema.name);
schema.indexNameList.removeName(name);
}
void removeIndexNames(HsqlName tableName) {
Schema schema = (Schema) schemaMap.get(tableName.schema.name);
schema.indexNameList.removeOwner(tableName);
}
void renameIndex(String oldName, String newName,
HsqlName tableName) throws HsqlException {
Schema schema = (Schema) schemaMap.get(tableName.schema.name);
schema.indexNameList.rename(oldName, newName,
Trace.INDEX_ALREADY_EXISTS);
}
void checkConstraintExists(String name, String schemaName,
boolean yes) throws HsqlException {
Schema schema = (Schema) schemaMap.get(schemaName);
boolean exists = schema.constraintNameList.containsName(name);
if (exists != yes) {
int code = yes ? Trace.CONSTRAINT_NOT_FOUND
: Trace.CONSTRAINT_ALREADY_EXISTS;
throw Trace.error(code, name);
}
}
void registerConstraintName(String name,
HsqlName tableName) throws HsqlException {
Schema schema = (Schema) schemaMap.get(tableName.schema.name);
schema.constraintNameList.addName(name, tableName,
Trace.CONSTRAINT_ALREADY_EXISTS);
}
void removeConstraintName(String name,
HsqlName tableName) throws HsqlException {
Schema schema = (Schema) schemaMap.get(tableName.schema.name);
schema.constraintNameList.removeName(name);
}
void removeConstraintNames(HsqlName tableName) {
Schema schema = (Schema) schemaMap.get(tableName.schema.name);
schema.constraintNameList.removeOwner(tableName);
}
// sequence
NumberSequence createSequence(HsqlName hsqlname, long start,
long increment,
int type) throws HsqlException {
Schema schema = (Schema) schemaMap.get(hsqlname.schema.name);
return schema.sequenceManager.createSequence(hsqlname, start,
increment, type);
}
void dropSequence(NumberSequence sequence) throws HsqlException {
Schema schema = (Schema) schemaMap.get(sequence.getSchemaName());
schema.sequenceManager.dropSequence(sequence.getName().name);
}
void logSequences(Session session, Logger logger) throws HsqlException {
for (int i = 0, size = schemaMap.size(); i < size; i++) {
Schema schema = (Schema) schemaMap.get(i);
schema.sequenceManager.logSequences(session, logger);
}
}
/**
* Clear copies of a temporary table from all sessions apart from one.
*/
void clearTempTables(Session exclude, Table table) {
Session[] sessions = database.sessionManager.getAllSessions();
Index[] indexes = table.getIndexes();
for (int i = 0; i < sessions.length; i++) {
if (sessions[i] != exclude) {
for (int j = 0; j < indexes.length; j++) {
sessions[i].dropIndex(indexes[j].getName(), false);
}
}
}
}
/**
* Drops the specified user-defined view or table from this Database
* object. <p>
*
* The process of dropping a table or view includes:
* <OL>
* <LI> checking that the specified Session's currently connected User
* has the right to perform this operation and refusing to proceed if
* not by throwing.
* <LI> checking for referential constraints that conflict with this
* operation and refusing to proceed if they exist by throwing.</LI>
*
* <LI> removing the specified Table from this Database object.
* <LI> removing any exported foreign keys Constraint objects held by
* any tables referenced by the table to be dropped. This is especially
* important so that the dropped Table ceases to be referenced,
* eventually allowing its full garbage collection.
* <LI>
* </OL>
* <p>
*
* @param name of the table or view to drop
* @param ifExists if true and if the Table to drop does not exist, fail
* silently, else throw
* @param isView true if the name argument refers to a View
* @param session the connected context in which to perform this
* operation
* @throws HsqlException if any of the checks listed above fail
*/
void dropTable(Session session, String name, String schemaName,
boolean ifExists, boolean isView,
boolean cascade) throws HsqlException {
Table table = null;
int dropIndex = -1;
Schema schema = (Schema) schemaMap.get(schemaName);
for (int i = 0; i < schema.tableList.size(); i++) {
table = (Table) schema.tableList.get(i);
if (table.equals(session, name) && isView == table.isView()) {
dropIndex = i;
break;
} else {
table = null;
}
}
if (dropIndex == -1) {
if (ifExists) {
return;
} else {
throw Trace.error(isView ? Trace.VIEW_NOT_FOUND
: Trace.TABLE_NOT_FOUND, name);
}
}
session.checkAdmin();
session.checkDDLWrite();
// ft - concurrent
session.commit();
dropTable(table, cascade);
session.setScripting(true);
}
void dropTable(Table table, boolean cascade) throws HsqlException {
Schema schema = (Schema) schemaMap.get(table.getSchemaName());
int dropIndex = schema.tableList.getIndex(table.getName().name);
if (table.isView()) {
checkCascadeDropViews((View) table, cascade);
} else {
checkCascadeDropReferenced(table, cascade);
checkCascadeDropViews(table, cascade);
}
// get it again as table object might be a different one
table = (Table) schema.tableList.remove(dropIndex);
removeExportedKeys(table);
database.getUserManager().removeDbObject(table.getName());
schema.triggerNameList.removeOwner(table.tableName);
schema.indexNameList.removeOwner(table.tableName);
schema.constraintNameList.removeOwner(table.tableName);
table.dropTriggers();
table.drop();
}
void setTable(int index, Table table) {
Schema schema = (Schema) schemaMap.get(table.getSchemaName());
schema.tableList.set(index, table.getName().name, table);
}
void renameTable(Session session, Table table, String newName,
boolean isQuoted) throws HsqlException {
Schema schema = (Schema) schemaMap.get(table.tableName.schema.name);
int i = schema.tableList.getIndex(table.tableName.name);
checkCascadeDropViews(table, false);
table.rename(session, newName, isQuoted);
schema.tableList.setKey(i, newName);
}
/**
* Throws if the table is referenced in a foreign key constraint.
*/
private void checkCascadeDropReferenced(Table table,
boolean cascade) throws HsqlException {
Constraint[] constraints = table.getConstraints();
Constraint currentConstraint = null;
Table refTable = null;
boolean isSelfRef = false;
for (int i = constraints.length - 1; i >= 0; i--) {
currentConstraint = constraints[i];
if (currentConstraint.getType() != Constraint.MAIN) {
continue;
}
refTable = currentConstraint.getRef();
isSelfRef = (refTable != null && table.equals(refTable));
if (isSelfRef) {
continue;
}
if (cascade) {
Constraint refConst =
refTable.getConstraint(currentConstraint.getFkName());
TableWorks tw = new TableWorks(null, refTable);
tw.dropFKConstraint(refConst);
constraints = table.constraintList;
i = constraints.length;
} else {
throw Trace.error(Trace.TABLE_REFERENCED_CONSTRAINT,
Trace.Database_dropTable, new Object[] {
currentConstraint.getName().name, refTable.getName().name
});
}
}
}
/**
* Throws if the view is referenced in a view.
*/
void checkCascadeDropViews(View view,
boolean cascade) throws HsqlException {
View[] views = getViewsWithView(view);
if (views != null) {
if (cascade) {
// drop from end to avoid repeat drop
for (int i = views.length - 1; i >= 0; i--) {
dropTable(views[i], cascade);
}
} else {
throw Trace.error(Trace.TABLE_REFERENCED_VIEW,
views[0].getName().name);
}
}
}
/**
* Throws if the table is referenced in a view.
*/
void checkCascadeDropViews(Table table,
boolean cascade) throws HsqlException {
View[] views = getViewsWithTable(table, null);
if (views != null) {
if (cascade) {
// drop from end to avoid repeat drop
for (int i = views.length - 1; i >= 0; i--) {
dropTable(views[i], cascade);
}
} else {
throw Trace.error(Trace.TABLE_REFERENCED_VIEW,
views[0].getName().name);
}
}
}
/**
* Throws if the sequence is referenced in a view.
*/
void checkCascadeDropViews(NumberSequence sequence,
boolean cascade) throws HsqlException {
View[] views = getViewsWithSequence(sequence);
if (views != null) {
if (cascade) {
// drop from end to avoid repeat drop
for (int i = views.length - 1; i >= 0; i--) {
dropTable(views[i], cascade);
}
} else {
throw Trace.error(Trace.SEQUENCE_REFERENCED_BY_VIEW,
views[0].getName().name);
}
}
}
/**
* Throws if the column is referenced in a view.
*/
void checkColumnIsInView(Table table,
String column) throws HsqlException {
View[] views = getViewsWithTable(table, column);
if (views != null) {
throw Trace.error(Trace.COLUMN_IS_REFERENCED,
views[0].getName().name);
}
}
/**
* Returns an array of views that reference another view.
*/
private View[] getViewsWithView(View view) {
HsqlArrayList list = null;
Schema schema = (Schema) schemaMap.get(view.getSchemaName());
for (int i = 0; i < schema.tableList.size(); i++) {
Table t = (Table) schema.tableList.get(i);
if (t.isView()) {
boolean found = ((View) t).hasView(view);
if (found) {
if (list == null) {
list = new HsqlArrayList();
}
list.add(t);
}
}
}
return list == null ? null
: (View[]) list.toArray(new View[list.size()]);
}
/**
* Returns an array of views that reference the specified table or
* the specified column if column parameter is not null.
*/
private View[] getViewsWithTable(Table table, String column) {
HsqlArrayList list = null;
Iterator it = allTablesIterator();
while (it.hasNext()) {
Table t = (Table) it.next();
if (t.isView()) {
boolean found = column == null ? ((View) t).hasTable(table)
: ((View) t).hasColumn(table,
column);
if (found) {
if (list == null) {
list = new HsqlArrayList();
}
list.add(t);
}
}
}
return list == null ? null
: (View[]) list.toArray(new View[list.size()]);
}
/**
* Returns an array of views that reference a sequence.
*/
View[] getViewsWithSequence(NumberSequence sequence) {
HsqlArrayList list = null;
Iterator it = allTablesIterator();
while (it.hasNext()) {
Table t = (Table) it.next();
if (t.isView()) {
boolean found = ((View) t).hasSequence(sequence);
if (found) {
if (list == null) {
list = new HsqlArrayList();
}
list.add(t);
}
}
}
return list == null ? null
: (View[]) list.toArray(new View[list.size()]);
}
/**
* After addition or removal of columns and indexes all views that
* reference the table should be recompiled.
*/
void recompileViews(Table table) throws HsqlException {
View[] viewlist = getViewsWithTable(table, null);
if (viewlist != null) {
for (int i = 0; i < viewlist.length; i++) {
String schema = viewlist[i].compileTimeSchema.name;
if (!schemaExists(schema)) {
schema = null;
}
Session session =
database.sessionManager.getSysSession(schema, false);
viewlist[i].compile(session);
}
}
}
/**
* Removes any foreign key Constraint objects (exported keys) held by any
* tables referenced by the specified table. <p>
*
* This method is called as the last step of a successful call to
* dropTable() in order to ensure that the dropped Table ceases to be
* referenced when enforcing referential integrity.
*
* @param toDrop The table to which other tables may be holding keys.
* This is a table that is in the process of being dropped.
*/
void removeExportedKeys(Table toDrop) {
Schema schema = (Schema) schemaMap.get(toDrop.getSchemaName());
for (int i = 0; i < schema.tableList.size(); i++) {
Table table = (Table) schema.tableList.get(i);
for (int j = table.constraintList.length - 1; j >= 0; j--) {
Table refTable = table.constraintList[j].getRef();
if (toDrop == refTable) {
table.constraintList =
(Constraint[]) ArrayUtil.toAdjustedArray(
table.constraintList, null, j, -1);
}
}
}
}
/**
* Drops a trigger with the specified name in the given context.
*/
void dropTrigger(Session session, String name,
String schemaName) throws HsqlException {
Schema schema = (Schema) schemaMap.get(schemaName);
boolean found = schema.triggerNameList.containsName(name);
Trace.check(found, Trace.TRIGGER_NOT_FOUND, name);
HsqlName tableName =
(HsqlName) schema.triggerNameList.removeName(name);
Table t = this.findUserTable(session, tableName.name, schemaName);
t.dropTrigger(name);
session.setScripting(true);
}
public class Schema {
HsqlName name;
DatabaseObjectNames triggerNameList;
DatabaseObjectNames constraintNameList;
DatabaseObjectNames indexNameList;
SequenceManager sequenceManager;
HashMappedList tableList;
Schema(String name, boolean isquoted) {
this.name = database.nameManager.newHsqlName(name, isquoted);
triggerNameList = new DatabaseObjectNames();
indexNameList = new DatabaseObjectNames();
constraintNameList = new DatabaseObjectNames();
sequenceManager = new SequenceManager();
tableList = new HashMappedList();
}
boolean isEmpty() {
return sequenceManager.sequenceMap.isEmpty()
&& tableList.isEmpty();
}
Iterator tablesIterator() {
return tableList.values().iterator();
}
Iterator sequencesIterator() {
return sequenceManager.sequenceMap.values().iterator();
}
void clearStructures() {
if (tableList != null) {
for (int i = 0; i < tableList.size(); i++) {
Table table = (Table) tableList.get(i);
table.dropTriggers();
}
}
triggerNameList = null;
indexNameList = null;
constraintNameList = null;
sequenceManager = null;
tableList = null;
}
}
}