0001: /* Copyright (c) 2001-2005, The HSQL Development Group
0002: * All rights reserved.
0003: *
0004: * Redistribution and use in source and binary forms, with or without
0005: * modification, are permitted provided that the following conditions are met:
0006: *
0007: * Redistributions of source code must retain the above copyright notice, this
0008: * list of conditions and the following disclaimer.
0009: *
0010: * Redistributions in binary form must reproduce the above copyright notice,
0011: * this list of conditions and the following disclaimer in the documentation
0012: * and/or other materials provided with the distribution.
0013: *
0014: * Neither the name of the HSQL Development Group nor the names of its
0015: * contributors may be used to endorse or promote products derived from this
0016: * software without specific prior written permission.
0017: *
0018: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0019: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0020: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0021: * ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG,
0022: * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
0023: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
0024: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
0025: * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
0026: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
0027: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
0028: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0029: */
0030:
0031: package org.hsqldb;
0032:
0033: import org.hsqldb.HsqlNameManager.HsqlName;
0034: import org.hsqldb.lib.ArrayUtil;
0035: import org.hsqldb.lib.HsqlArrayList;
0036: import org.hsqldb.lib.HashMappedList;
0037: import org.hsqldb.lib.Iterator;
0038: import org.hsqldb.lib.WrapperIterator;
0039: import org.hsqldb.persist.Logger;
0040:
0041: /**
0042: * Manages all SCHEMA related database objects
0043: *
0044: * @author fredt@users
0045: * @version 1.8.0
0046: * @since 1.8.0
0047: */
0048: public class SchemaManager {
0049:
0050: static final String SYSTEM_SCHEMA = "SYSTEM_SCHEMA";
0051: static final String DEFINITION_SCHEMA = "DEFINITION_SCHEMA";
0052: static final String INFORMATION_SCHEMA = "INFORMATION_SCHEMA";
0053: static final String PUBLIC_SCHEMA = "PUBLIC";
0054: static HsqlName INFORMATION_SCHEMA_HSQLNAME = HsqlNameManager
0055: .newHsqlSystemObjectName(INFORMATION_SCHEMA);
0056: static HsqlName SYSTEM_SCHEMA_HSQLNAME = HsqlNameManager
0057: .newHsqlSystemObjectName(SYSTEM_SCHEMA);
0058: Database database;
0059: HsqlName defaultSchemaHsqlName;
0060: HashMappedList schemaMap = new HashMappedList();
0061:
0062: SchemaManager(Database database) {
0063:
0064: this .database = database;
0065:
0066: Schema schema = new Schema(PUBLIC_SCHEMA, false);
0067:
0068: defaultSchemaHsqlName = schema.name;
0069:
0070: schemaMap.put(PUBLIC_SCHEMA, schema);
0071: }
0072:
0073: void createSchema(String name, boolean isQuoted)
0074: throws HsqlException {
0075:
0076: if (DEFINITION_SCHEMA.equals(name)
0077: || INFORMATION_SCHEMA.equals(name)
0078: || SYSTEM_SCHEMA.equals(name)) {
0079: throw Trace.error(Trace.INVALID_SCHEMA_NAME_NO_SUBCLASS);
0080: }
0081:
0082: Schema schema = new Schema(name, isQuoted);
0083:
0084: schemaMap.add(name, schema);
0085: }
0086:
0087: void dropSchema(String name, boolean cascade) throws HsqlException {
0088:
0089: Schema schema = (Schema) schemaMap.get(name);
0090:
0091: if (schema == null) {
0092: throw Trace.error(Trace.INVALID_SCHEMA_NAME_NO_SUBCLASS);
0093: }
0094:
0095: if (!cascade && !schema.isEmpty()) {
0096: throw Trace.error(Trace.DEPENDENT_DATABASE_OBJECT_EXISTS);
0097: }
0098:
0099: Iterator tableIterator = schema.tablesIterator();
0100:
0101: while (tableIterator.hasNext()) {
0102: Table table = ((Table) tableIterator.next());
0103:
0104: database.getUserManager().removeDbObject(table.getName());
0105: table.drop();
0106: }
0107:
0108: Iterator sequenceIterator = schema.sequencesIterator();
0109:
0110: while (tableIterator.hasNext()) {
0111: NumberSequence sequence = ((NumberSequence) sequenceIterator
0112: .next());
0113:
0114: database.getUserManager()
0115: .removeDbObject(sequence.getName());
0116: }
0117:
0118: schema.clearStructures();
0119: schemaMap.remove(name);
0120:
0121: if (defaultSchemaHsqlName.name.equals(name)) {
0122: if (schemaMap.isEmpty()) {
0123: schema = new Schema(PUBLIC_SCHEMA, false);
0124: } else {
0125: schema = (Schema) schemaMap.get(0);
0126: }
0127:
0128: defaultSchemaHsqlName = schema.name;
0129:
0130: schemaMap.put(defaultSchemaHsqlName.name, schema);
0131: }
0132:
0133: // these are called last and in this particular order
0134: database.getUserManager().removeSchemaReference(schema);
0135: database.getSessionManager().removeSchemaReference(schema);
0136: }
0137:
0138: void renameSchema(String name, String newName, boolean isQuoted)
0139: throws HsqlException {
0140:
0141: Schema schema = (Schema) schemaMap.get(name);
0142: Schema exists = (Schema) schemaMap.get(newName);
0143:
0144: if (schema == null || exists != null
0145: || INFORMATION_SCHEMA.equals(newName)) {
0146: throw Trace.error(Trace.INVALID_SCHEMA_NAME_NO_SUBCLASS,
0147: schema == null ? name : newName);
0148: }
0149:
0150: schema.name.rename(newName, isQuoted);
0151:
0152: int index = schemaMap.getIndex(name);
0153:
0154: schemaMap.set(index, newName, schema);
0155: }
0156:
0157: void clearStructures() {
0158:
0159: Iterator it = schemaMap.values().iterator();
0160:
0161: while (it.hasNext()) {
0162: Schema schema = (Schema) it.next();
0163:
0164: schema.clearStructures();
0165: }
0166: }
0167:
0168: public Iterator userSchemaNameIterator() {
0169: return schemaMap.keySet().iterator();
0170: }
0171:
0172: HsqlName toSchemaHsqlName(String name) {
0173:
0174: Schema schema = (Schema) schemaMap.get(name);
0175:
0176: return schema == null ? null : schema.name;
0177: }
0178:
0179: HsqlName getDefaultSchemaHsqlName() {
0180: return defaultSchemaHsqlName;
0181: }
0182:
0183: public String getDefaultSchemaName() {
0184: return defaultSchemaHsqlName.name;
0185: }
0186:
0187: boolean schemaExists(String name) {
0188:
0189: if (INFORMATION_SCHEMA.equals(name)) {
0190: return true;
0191: }
0192:
0193: return schemaMap.containsKey(name);
0194: }
0195:
0196: /**
0197: * If schemaName is null, return the current schema name, else return
0198: * the HsqlName object for the schema. If schemaName does not exist,
0199: * throw.
0200: */
0201: HsqlName getSchemaHsqlName(String name) throws HsqlException {
0202:
0203: if (name == null) {
0204: return defaultSchemaHsqlName;
0205: }
0206:
0207: if (INFORMATION_SCHEMA.equals(name)) {
0208: return INFORMATION_SCHEMA_HSQLNAME;
0209: }
0210:
0211: Schema schema = ((Schema) schemaMap.get(name));
0212:
0213: if (schema == null) {
0214: throw Trace.error(Trace.INVALID_SCHEMA_NAME_NO_SUBCLASS,
0215: name);
0216: }
0217:
0218: return schema.name;
0219: }
0220:
0221: /**
0222: * Same as above, but return string
0223: */
0224: String getSchemaName(String name) throws HsqlException {
0225: return getSchemaHsqlName(name).name;
0226: }
0227:
0228: /**
0229: * Iterator includes INFORMATION_SCHEMA
0230: */
0231: Iterator fullSchemaNamesIterator() {
0232: return new WrapperIterator(new WrapperIterator(
0233: INFORMATION_SCHEMA), schemaMap.keySet().iterator());
0234: }
0235:
0236: /**
0237: * is a schema read-only
0238: */
0239: public boolean isSystemSchema(HsqlName schema) {
0240:
0241: return (INFORMATION_SCHEMA_HSQLNAME.equals(schema) || SYSTEM_SCHEMA_HSQLNAME
0242: .equals(schema)) ? true : false;
0243: }
0244:
0245: public Iterator tablesIterator(String schema) {
0246:
0247: Schema temp = (Schema) schemaMap.get(schema);
0248:
0249: return temp.tablesIterator();
0250: }
0251:
0252: public Iterator allTablesIterator() {
0253:
0254: Iterator schemas = userSchemaNameIterator();
0255: Iterator tables = new WrapperIterator();
0256:
0257: while (schemas.hasNext()) {
0258: String name = (String) schemas.next();
0259: Iterator t = tablesIterator(name);
0260:
0261: tables = new WrapperIterator(tables, t);
0262: }
0263:
0264: return tables;
0265: }
0266:
0267: Iterator sequenceIterator(String schema) {
0268:
0269: Schema temp = (Schema) schemaMap.get(schema);
0270:
0271: return temp.sequencesIterator();
0272: }
0273:
0274: public Iterator allSequencesIterator() {
0275:
0276: Iterator it = schemaMap.values().iterator();
0277: Iterator sequences = new WrapperIterator();
0278:
0279: while (it.hasNext()) {
0280: Schema temp = (Schema) it.next();
0281:
0282: sequences = new WrapperIterator(sequences, temp
0283: .sequencesIterator());
0284: }
0285:
0286: return sequences;
0287: }
0288:
0289: /**
0290: * Returns an HsqlArrayList containing references to all non-system
0291: * tables and views. This includes all tables and views registered with
0292: * this Database.
0293: */
0294: public HsqlArrayList getAllTables() {
0295:
0296: Iterator schemas = userSchemaNameIterator();
0297: HsqlArrayList alltables = new HsqlArrayList();
0298:
0299: while (schemas.hasNext()) {
0300: String name = (String) schemas.next();
0301: HashMappedList current = getTables(name);
0302:
0303: alltables.addAll(current.values());
0304: }
0305:
0306: return alltables;
0307: }
0308:
0309: public HashMappedList getTables(String schema) {
0310:
0311: Schema temp = (Schema) schemaMap.get(schema);
0312:
0313: return temp.tableList;
0314: }
0315:
0316: /**
0317: * @throws HsqlException if exists.
0318: */
0319: void checkUserViewNotExists(Session session, String viewName,
0320: String schema) throws HsqlException {
0321:
0322: boolean exists = database.schemaManager.findUserTable(session,
0323: viewName, schema) != null;
0324:
0325: if (exists) {
0326: throw Trace.error(Trace.VIEW_ALREADY_EXISTS, viewName);
0327: }
0328: }
0329:
0330: /**
0331: * @throws HsqlException if exists
0332: */
0333: void checkUserTableNotExists(Session session, String tableName,
0334: String schema) throws HsqlException {
0335:
0336: boolean exists = findUserTable(session, tableName, schema) != null;
0337:
0338: if (exists) {
0339: throw Trace.error(Trace.TABLE_ALREADY_EXISTS, tableName);
0340: }
0341: }
0342:
0343: /**
0344: * Returns the specified user-defined table or view visible within the
0345: * context of the specified Session, or any system table of the given
0346: * name. It excludes any temp tables created in other Sessions.
0347: * Throws if the table does not exist in the context.
0348: */
0349: public Table getTable(Session session, String name, String schema)
0350: throws HsqlException {
0351:
0352: Table t = findUserTable(session, name, schema);
0353:
0354: if (t == null) {
0355: if (!INFORMATION_SCHEMA.equals(schema)) {
0356: throw Trace.error(Trace.TABLE_NOT_FOUND);
0357: }
0358:
0359: if (database.dbInfo != null) {
0360: t = database.dbInfo.getSystemTable(session, name);
0361: }
0362: }
0363:
0364: if (t == null) {
0365: throw Trace.error(Trace.TABLE_NOT_FOUND, name);
0366: }
0367:
0368: return t;
0369: }
0370:
0371: /**
0372: * Returns the specified user-defined table or view visible within the
0373: * context of the specified Session. It excludes system tables and
0374: * any temp tables created in different Sessions.
0375: * Throws if the table does not exist in the context.
0376: */
0377: public Table getUserTable(Session session, String name,
0378: String schema) throws HsqlException {
0379:
0380: Table t = findUserTable(session, name, schema);
0381:
0382: if (t == null) {
0383: throw Trace.error(Trace.TABLE_NOT_FOUND, name);
0384: }
0385:
0386: return t;
0387: }
0388:
0389: /**
0390: * Returns the specified user-defined table or view visible within the
0391: * context of the specified schema. It excludes system tables.
0392: * Returns null if the table does not exist in the context.
0393: */
0394: Table findUserTable(Session session, String name, String schemaName) {
0395:
0396: Schema schema = (Schema) schemaMap.get(schemaName);
0397:
0398: if (schema == null) {
0399: return null;
0400: }
0401:
0402: for (int i = 0, tsize = schema.tableList.size(); i < tsize; i++) {
0403: Table t = (Table) schema.tableList.get(i);
0404:
0405: if (t.equals(session, name)) {
0406: return t;
0407: }
0408: }
0409:
0410: return null;
0411: }
0412:
0413: /**
0414: * Registers the specified table or view with this Database.
0415: */
0416: void linkTable(Table t) {
0417:
0418: Schema schema = (Schema) schemaMap.get(t.getSchemaName());
0419:
0420: schema.tableList.add(t.getName().name, t);
0421: }
0422:
0423: NumberSequence getSequence(String name, String schemaName)
0424: throws HsqlException {
0425:
0426: NumberSequence sequence = findSequence(name, schemaName);
0427:
0428: if (sequence == null) {
0429: throw Trace.error(Trace.SEQUENCE_NOT_FOUND, name);
0430: }
0431:
0432: return sequence;
0433: }
0434:
0435: /**
0436: * Returns the specified Sequence visible within the
0437: * context of the specified Session.
0438: */
0439: public NumberSequence findSequence(String name, String schemaName)
0440: throws HsqlException {
0441:
0442: Schema schema = (Schema) schemaMap.get(schemaName);
0443: NumberSequence sequence = schema.sequenceManager
0444: .getSequence(name);
0445:
0446: return sequence;
0447: }
0448:
0449: /**
0450: * Returns the table that has an index with the given name and schema.
0451: */
0452: Table findUserTableForIndex(Session session, String name,
0453: String schemaName) {
0454:
0455: Schema schema = (Schema) schemaMap.get(schemaName);
0456: HsqlName tablename = schema.indexNameList.getOwner(name);
0457:
0458: if (tablename == null) {
0459: return null;
0460: }
0461:
0462: return findUserTable(session, tablename.name, schemaName);
0463: }
0464:
0465: /**
0466: * Returns index of a table or view in the HsqlArrayList that
0467: * contains the table objects for this Database.
0468: *
0469: * @param table the Table object
0470: * @return the index of the specified table or view, or -1 if not found
0471: */
0472: int getTableIndex(Table table) {
0473:
0474: Schema schema = (Schema) schemaMap.get(table.getSchemaName());
0475:
0476: for (int i = 0, tsize = schema.tableList.size(); i < tsize; i++) {
0477: Table t = (Table) schema.tableList.get(i);
0478:
0479: if (t == table) {
0480: return i;
0481: }
0482: }
0483:
0484: return -1;
0485: }
0486:
0487: /**
0488: * Drops the index with the specified name.
0489: */
0490: void dropIndex(Session session, String indexname, String schema,
0491: boolean ifExists) throws HsqlException {
0492:
0493: Table t = findUserTableForIndex(session, indexname, schema);
0494:
0495: if (t == null) {
0496: if (ifExists) {
0497: return;
0498: } else {
0499: throw Trace.error(Trace.INDEX_NOT_FOUND, indexname);
0500: }
0501: }
0502:
0503: t.checkDropIndex(indexname, null, false);
0504: session.commit();
0505: session.setScripting(true);
0506:
0507: TableWorks tw = new TableWorks(session, t);
0508:
0509: tw.dropIndex(indexname);
0510: }
0511:
0512: //------------ name management
0513:
0514: /**
0515: * Checks if a Trigger with given name either exists or does not, based on
0516: * the value of the argument, yes.
0517: */
0518: void checkTriggerExists(String name, String schemaName, boolean yes)
0519: throws HsqlException {
0520:
0521: Schema schema = (Schema) schemaMap.get(schemaName);
0522: boolean exists = schema.triggerNameList.containsName(name);
0523:
0524: if (exists != yes) {
0525: int code = yes ? Trace.TRIGGER_NOT_FOUND
0526: : Trace.TRIGGER_ALREADY_EXISTS;
0527:
0528: throw Trace.error(code, name);
0529: }
0530: }
0531:
0532: void registerTriggerName(String name, HsqlName tableName)
0533: throws HsqlException {
0534:
0535: Schema schema = (Schema) schemaMap.get(tableName.schema.name);
0536:
0537: schema.triggerNameList.addName(name, tableName,
0538: Trace.TRIGGER_ALREADY_EXISTS);
0539: }
0540:
0541: void checkIndexExists(String name, String schemaName, boolean yes)
0542: throws HsqlException {
0543:
0544: Schema schema = (Schema) schemaMap.get(schemaName);
0545: boolean exists = schema.indexNameList.containsName(name);
0546:
0547: if (exists != yes) {
0548: int code = yes ? Trace.INDEX_NOT_FOUND
0549: : Trace.INDEX_ALREADY_EXISTS;
0550:
0551: throw Trace.error(code, name);
0552: }
0553: }
0554:
0555: void registerIndexName(String name, HsqlName tableName)
0556: throws HsqlException {
0557:
0558: Schema schema = (Schema) schemaMap.get(tableName.schema.name);
0559:
0560: schema.indexNameList.addName(name, tableName,
0561: Trace.INDEX_ALREADY_EXISTS);
0562: }
0563:
0564: void removeIndexName(String name, HsqlName tableName)
0565: throws HsqlException {
0566:
0567: Schema schema = (Schema) schemaMap.get(tableName.schema.name);
0568:
0569: schema.indexNameList.removeName(name);
0570: }
0571:
0572: void removeIndexNames(HsqlName tableName) {
0573:
0574: Schema schema = (Schema) schemaMap.get(tableName.schema.name);
0575:
0576: schema.indexNameList.removeOwner(tableName);
0577: }
0578:
0579: void renameIndex(String oldName, String newName, HsqlName tableName)
0580: throws HsqlException {
0581:
0582: Schema schema = (Schema) schemaMap.get(tableName.schema.name);
0583:
0584: schema.indexNameList.rename(oldName, newName,
0585: Trace.INDEX_ALREADY_EXISTS);
0586: }
0587:
0588: void checkConstraintExists(String name, String schemaName,
0589: boolean yes) throws HsqlException {
0590:
0591: Schema schema = (Schema) schemaMap.get(schemaName);
0592: boolean exists = schema.constraintNameList.containsName(name);
0593:
0594: if (exists != yes) {
0595: int code = yes ? Trace.CONSTRAINT_NOT_FOUND
0596: : Trace.CONSTRAINT_ALREADY_EXISTS;
0597:
0598: throw Trace.error(code, name);
0599: }
0600: }
0601:
0602: void registerConstraintName(String name, HsqlName tableName)
0603: throws HsqlException {
0604:
0605: Schema schema = (Schema) schemaMap.get(tableName.schema.name);
0606:
0607: schema.constraintNameList.addName(name, tableName,
0608: Trace.CONSTRAINT_ALREADY_EXISTS);
0609: }
0610:
0611: void removeConstraintName(String name, HsqlName tableName)
0612: throws HsqlException {
0613:
0614: Schema schema = (Schema) schemaMap.get(tableName.schema.name);
0615:
0616: schema.constraintNameList.removeName(name);
0617: }
0618:
0619: void removeConstraintNames(HsqlName tableName) {
0620:
0621: Schema schema = (Schema) schemaMap.get(tableName.schema.name);
0622:
0623: schema.constraintNameList.removeOwner(tableName);
0624: }
0625:
0626: // sequence
0627: NumberSequence createSequence(HsqlName hsqlname, long start,
0628: long increment, int type) throws HsqlException {
0629:
0630: Schema schema = (Schema) schemaMap.get(hsqlname.schema.name);
0631:
0632: return schema.sequenceManager.createSequence(hsqlname, start,
0633: increment, type);
0634: }
0635:
0636: void dropSequence(NumberSequence sequence) throws HsqlException {
0637:
0638: Schema schema = (Schema) schemaMap
0639: .get(sequence.getSchemaName());
0640:
0641: schema.sequenceManager.dropSequence(sequence.getName().name);
0642: }
0643:
0644: void logSequences(Session session, Logger logger)
0645: throws HsqlException {
0646:
0647: for (int i = 0, size = schemaMap.size(); i < size; i++) {
0648: Schema schema = (Schema) schemaMap.get(i);
0649:
0650: schema.sequenceManager.logSequences(session, logger);
0651: }
0652: }
0653:
0654: /**
0655: * Clear copies of a temporary table from all sessions apart from one.
0656: */
0657: void clearTempTables(Session exclude, Table table) {
0658:
0659: Session[] sessions = database.sessionManager.getAllSessions();
0660: Index[] indexes = table.getIndexes();
0661:
0662: for (int i = 0; i < sessions.length; i++) {
0663: if (sessions[i] != exclude) {
0664: for (int j = 0; j < indexes.length; j++) {
0665: sessions[i].dropIndex(indexes[j].getName(), false);
0666: }
0667: }
0668: }
0669: }
0670:
0671: /**
0672: * Drops the specified user-defined view or table from this Database
0673: * object. <p>
0674: *
0675: * The process of dropping a table or view includes:
0676: * <OL>
0677: * <LI> checking that the specified Session's currently connected User
0678: * has the right to perform this operation and refusing to proceed if
0679: * not by throwing.
0680: * <LI> checking for referential constraints that conflict with this
0681: * operation and refusing to proceed if they exist by throwing.</LI>
0682: *
0683: * <LI> removing the specified Table from this Database object.
0684: * <LI> removing any exported foreign keys Constraint objects held by
0685: * any tables referenced by the table to be dropped. This is especially
0686: * important so that the dropped Table ceases to be referenced,
0687: * eventually allowing its full garbage collection.
0688: * <LI>
0689: * </OL>
0690: * <p>
0691: *
0692: * @param name of the table or view to drop
0693: * @param ifExists if true and if the Table to drop does not exist, fail
0694: * silently, else throw
0695: * @param isView true if the name argument refers to a View
0696: * @param session the connected context in which to perform this
0697: * operation
0698: * @throws HsqlException if any of the checks listed above fail
0699: */
0700: void dropTable(Session session, String name, String schemaName,
0701: boolean ifExists, boolean isView, boolean cascade)
0702: throws HsqlException {
0703:
0704: Table table = null;
0705: int dropIndex = -1;
0706: Schema schema = (Schema) schemaMap.get(schemaName);
0707:
0708: for (int i = 0; i < schema.tableList.size(); i++) {
0709: table = (Table) schema.tableList.get(i);
0710:
0711: if (table.equals(session, name) && isView == table.isView()) {
0712: dropIndex = i;
0713:
0714: break;
0715: } else {
0716: table = null;
0717: }
0718: }
0719:
0720: if (dropIndex == -1) {
0721: if (ifExists) {
0722: return;
0723: } else {
0724: throw Trace.error(isView ? Trace.VIEW_NOT_FOUND
0725: : Trace.TABLE_NOT_FOUND, name);
0726: }
0727: }
0728:
0729: session.checkAdmin();
0730: session.checkDDLWrite();
0731:
0732: // ft - concurrent
0733: session.commit();
0734: dropTable(table, cascade);
0735: session.setScripting(true);
0736: }
0737:
0738: void dropTable(Table table, boolean cascade) throws HsqlException {
0739:
0740: Schema schema = (Schema) schemaMap.get(table.getSchemaName());
0741: int dropIndex = schema.tableList.getIndex(table.getName().name);
0742:
0743: if (table.isView()) {
0744: checkCascadeDropViews((View) table, cascade);
0745: } else {
0746: checkCascadeDropReferenced(table, cascade);
0747: checkCascadeDropViews(table, cascade);
0748: }
0749:
0750: // get it again as table object might be a different one
0751: table = (Table) schema.tableList.remove(dropIndex);
0752:
0753: removeExportedKeys(table);
0754: database.getUserManager().removeDbObject(table.getName());
0755: schema.triggerNameList.removeOwner(table.tableName);
0756: schema.indexNameList.removeOwner(table.tableName);
0757: schema.constraintNameList.removeOwner(table.tableName);
0758: table.dropTriggers();
0759: table.drop();
0760: }
0761:
0762: void setTable(int index, Table table) {
0763:
0764: Schema schema = (Schema) schemaMap.get(table.getSchemaName());
0765:
0766: schema.tableList.set(index, table.getName().name, table);
0767: }
0768:
0769: void renameTable(Session session, Table table, String newName,
0770: boolean isQuoted) throws HsqlException {
0771:
0772: Schema schema = (Schema) schemaMap
0773: .get(table.tableName.schema.name);
0774: int i = schema.tableList.getIndex(table.tableName.name);
0775:
0776: checkCascadeDropViews(table, false);
0777: table.rename(session, newName, isQuoted);
0778: schema.tableList.setKey(i, newName);
0779: }
0780:
0781: /**
0782: * Throws if the table is referenced in a foreign key constraint.
0783: */
0784: private void checkCascadeDropReferenced(Table table, boolean cascade)
0785: throws HsqlException {
0786:
0787: Constraint[] constraints = table.getConstraints();
0788: Constraint currentConstraint = null;
0789: Table refTable = null;
0790: boolean isSelfRef = false;
0791:
0792: for (int i = constraints.length - 1; i >= 0; i--) {
0793: currentConstraint = constraints[i];
0794:
0795: if (currentConstraint.getType() != Constraint.MAIN) {
0796: continue;
0797: }
0798:
0799: refTable = currentConstraint.getRef();
0800: isSelfRef = (refTable != null && table.equals(refTable));
0801:
0802: if (isSelfRef) {
0803: continue;
0804: }
0805:
0806: if (cascade) {
0807: Constraint refConst = refTable
0808: .getConstraint(currentConstraint.getFkName());
0809: TableWorks tw = new TableWorks(null, refTable);
0810:
0811: tw.dropFKConstraint(refConst);
0812:
0813: constraints = table.constraintList;
0814: i = constraints.length;
0815: } else {
0816: throw Trace.error(Trace.TABLE_REFERENCED_CONSTRAINT,
0817: Trace.Database_dropTable, new Object[] {
0818: currentConstraint.getName().name,
0819: refTable.getName().name });
0820: }
0821: }
0822: }
0823:
0824: /**
0825: * Throws if the view is referenced in a view.
0826: */
0827: void checkCascadeDropViews(View view, boolean cascade)
0828: throws HsqlException {
0829:
0830: View[] views = getViewsWithView(view);
0831:
0832: if (views != null) {
0833: if (cascade) {
0834:
0835: // drop from end to avoid repeat drop
0836: for (int i = views.length - 1; i >= 0; i--) {
0837: dropTable(views[i], cascade);
0838: }
0839: } else {
0840: throw Trace.error(Trace.TABLE_REFERENCED_VIEW, views[0]
0841: .getName().name);
0842: }
0843: }
0844: }
0845:
0846: /**
0847: * Throws if the table is referenced in a view.
0848: */
0849: void checkCascadeDropViews(Table table, boolean cascade)
0850: throws HsqlException {
0851:
0852: View[] views = getViewsWithTable(table, null);
0853:
0854: if (views != null) {
0855: if (cascade) {
0856:
0857: // drop from end to avoid repeat drop
0858: for (int i = views.length - 1; i >= 0; i--) {
0859: dropTable(views[i], cascade);
0860: }
0861: } else {
0862: throw Trace.error(Trace.TABLE_REFERENCED_VIEW, views[0]
0863: .getName().name);
0864: }
0865: }
0866: }
0867:
0868: /**
0869: * Throws if the sequence is referenced in a view.
0870: */
0871: void checkCascadeDropViews(NumberSequence sequence, boolean cascade)
0872: throws HsqlException {
0873:
0874: View[] views = getViewsWithSequence(sequence);
0875:
0876: if (views != null) {
0877: if (cascade) {
0878:
0879: // drop from end to avoid repeat drop
0880: for (int i = views.length - 1; i >= 0; i--) {
0881: dropTable(views[i], cascade);
0882: }
0883: } else {
0884: throw Trace.error(Trace.SEQUENCE_REFERENCED_BY_VIEW,
0885: views[0].getName().name);
0886: }
0887: }
0888: }
0889:
0890: /**
0891: * Throws if the column is referenced in a view.
0892: */
0893: void checkColumnIsInView(Table table, String column)
0894: throws HsqlException {
0895:
0896: View[] views = getViewsWithTable(table, column);
0897:
0898: if (views != null) {
0899: throw Trace.error(Trace.COLUMN_IS_REFERENCED, views[0]
0900: .getName().name);
0901: }
0902: }
0903:
0904: /**
0905: * Returns an array of views that reference another view.
0906: */
0907: private View[] getViewsWithView(View view) {
0908:
0909: HsqlArrayList list = null;
0910: Schema schema = (Schema) schemaMap.get(view.getSchemaName());
0911:
0912: for (int i = 0; i < schema.tableList.size(); i++) {
0913: Table t = (Table) schema.tableList.get(i);
0914:
0915: if (t.isView()) {
0916: boolean found = ((View) t).hasView(view);
0917:
0918: if (found) {
0919: if (list == null) {
0920: list = new HsqlArrayList();
0921: }
0922:
0923: list.add(t);
0924: }
0925: }
0926: }
0927:
0928: return list == null ? null : (View[]) list
0929: .toArray(new View[list.size()]);
0930: }
0931:
0932: /**
0933: * Returns an array of views that reference the specified table or
0934: * the specified column if column parameter is not null.
0935: */
0936: private View[] getViewsWithTable(Table table, String column) {
0937:
0938: HsqlArrayList list = null;
0939: Iterator it = allTablesIterator();
0940:
0941: while (it.hasNext()) {
0942: Table t = (Table) it.next();
0943:
0944: if (t.isView()) {
0945: boolean found = column == null ? ((View) t)
0946: .hasTable(table) : ((View) t).hasColumn(table,
0947: column);
0948:
0949: if (found) {
0950: if (list == null) {
0951: list = new HsqlArrayList();
0952: }
0953:
0954: list.add(t);
0955: }
0956: }
0957: }
0958:
0959: return list == null ? null : (View[]) list
0960: .toArray(new View[list.size()]);
0961: }
0962:
0963: /**
0964: * Returns an array of views that reference a sequence.
0965: */
0966: View[] getViewsWithSequence(NumberSequence sequence) {
0967:
0968: HsqlArrayList list = null;
0969: Iterator it = allTablesIterator();
0970:
0971: while (it.hasNext()) {
0972: Table t = (Table) it.next();
0973:
0974: if (t.isView()) {
0975: boolean found = ((View) t).hasSequence(sequence);
0976:
0977: if (found) {
0978: if (list == null) {
0979: list = new HsqlArrayList();
0980: }
0981:
0982: list.add(t);
0983: }
0984: }
0985: }
0986:
0987: return list == null ? null : (View[]) list
0988: .toArray(new View[list.size()]);
0989: }
0990:
0991: /**
0992: * After addition or removal of columns and indexes all views that
0993: * reference the table should be recompiled.
0994: */
0995: void recompileViews(Table table) throws HsqlException {
0996:
0997: View[] viewlist = getViewsWithTable(table, null);
0998:
0999: if (viewlist != null) {
1000: for (int i = 0; i < viewlist.length; i++) {
1001: String schema = viewlist[i].compileTimeSchema.name;
1002:
1003: if (!schemaExists(schema)) {
1004: schema = null;
1005: }
1006:
1007: Session session = database.sessionManager
1008: .getSysSession(schema, false);
1009:
1010: viewlist[i].compile(session);
1011: }
1012: }
1013: }
1014:
1015: /**
1016: * Removes any foreign key Constraint objects (exported keys) held by any
1017: * tables referenced by the specified table. <p>
1018: *
1019: * This method is called as the last step of a successful call to
1020: * dropTable() in order to ensure that the dropped Table ceases to be
1021: * referenced when enforcing referential integrity.
1022: *
1023: * @param toDrop The table to which other tables may be holding keys.
1024: * This is a table that is in the process of being dropped.
1025: */
1026: void removeExportedKeys(Table toDrop) {
1027:
1028: Schema schema = (Schema) schemaMap.get(toDrop.getSchemaName());
1029:
1030: for (int i = 0; i < schema.tableList.size(); i++) {
1031: Table table = (Table) schema.tableList.get(i);
1032:
1033: for (int j = table.constraintList.length - 1; j >= 0; j--) {
1034: Table refTable = table.constraintList[j].getRef();
1035:
1036: if (toDrop == refTable) {
1037: table.constraintList = (Constraint[]) ArrayUtil
1038: .toAdjustedArray(table.constraintList,
1039: null, j, -1);
1040: }
1041: }
1042: }
1043: }
1044:
1045: /**
1046: * Drops a trigger with the specified name in the given context.
1047: */
1048: void dropTrigger(Session session, String name, String schemaName)
1049: throws HsqlException {
1050:
1051: Schema schema = (Schema) schemaMap.get(schemaName);
1052: boolean found = schema.triggerNameList.containsName(name);
1053:
1054: Trace.check(found, Trace.TRIGGER_NOT_FOUND, name);
1055:
1056: HsqlName tableName = (HsqlName) schema.triggerNameList
1057: .removeName(name);
1058: Table t = this .findUserTable(session, tableName.name,
1059: schemaName);
1060:
1061: t.dropTrigger(name);
1062: session.setScripting(true);
1063: }
1064:
1065: public class Schema {
1066:
1067: HsqlName name;
1068: DatabaseObjectNames triggerNameList;
1069: DatabaseObjectNames constraintNameList;
1070: DatabaseObjectNames indexNameList;
1071: SequenceManager sequenceManager;
1072: HashMappedList tableList;
1073:
1074: Schema(String name, boolean isquoted) {
1075:
1076: this .name = database.nameManager
1077: .newHsqlName(name, isquoted);
1078: triggerNameList = new DatabaseObjectNames();
1079: indexNameList = new DatabaseObjectNames();
1080: constraintNameList = new DatabaseObjectNames();
1081: sequenceManager = new SequenceManager();
1082: tableList = new HashMappedList();
1083: }
1084:
1085: boolean isEmpty() {
1086: return sequenceManager.sequenceMap.isEmpty()
1087: && tableList.isEmpty();
1088: }
1089:
1090: Iterator tablesIterator() {
1091: return tableList.values().iterator();
1092: }
1093:
1094: Iterator sequencesIterator() {
1095: return sequenceManager.sequenceMap.values().iterator();
1096: }
1097:
1098: void clearStructures() {
1099:
1100: if (tableList != null) {
1101: for (int i = 0; i < tableList.size(); i++) {
1102: Table table = (Table) tableList.get(i);
1103:
1104: table.dropTriggers();
1105: }
1106: }
1107:
1108: triggerNameList = null;
1109: indexNameList = null;
1110: constraintNameList = null;
1111: sequenceManager = null;
1112: tableList = null;
1113: }
1114: }
1115: }
|