001: /*
002: * Copyright 2004-2008 H2 Group. Licensed under the H2 License, Version 1.0
003: * (http://h2database.com/html/license.html).
004: * Initial Developer: H2 Group
005: */
006: package org.h2.schema;
007:
008: import java.sql.SQLException;
009: import java.util.HashMap;
010: import java.util.HashSet;
011:
012: import org.h2.constant.ErrorCode;
013: import org.h2.constant.SysProperties;
014: import org.h2.constraint.Constraint;
015: import org.h2.engine.Constants;
016: import org.h2.engine.Database;
017: import org.h2.engine.DbObject;
018: import org.h2.engine.DbObjectBase;
019: import org.h2.engine.Session;
020: import org.h2.engine.User;
021: import org.h2.index.Index;
022: import org.h2.message.Message;
023: import org.h2.message.Trace;
024: import org.h2.table.Table;
025: import org.h2.table.TableData;
026: import org.h2.table.TableLink;
027: import org.h2.util.ObjectArray;
028:
029: /**
030: * A schema as created by the SQL statement
031: * CREATE SCHEMA
032: */
033: public class Schema extends DbObjectBase {
034:
035: private User owner;
036: private boolean system;
037:
038: private HashMap tablesAndViews = new HashMap();
039: private HashMap indexes = new HashMap();
040: private HashMap sequences = new HashMap();
041: private HashMap triggers = new HashMap();
042: private HashMap constraints = new HashMap();
043: private HashMap constants = new HashMap();
044:
045: /*
046: * Set of returned unique names that are not yet stored
047: * (to avoid returning the same unique name twice when multiple threads
048: * concurrently create objects).
049: */
050: private HashSet temporaryUniqueNames = new HashSet();
051:
052: public Schema(Database database, int id, String schemaName,
053: User owner, boolean system) {
054: super (database, id, schemaName, Trace.SCHEMA);
055: this .owner = owner;
056: this .system = system;
057: }
058:
059: public boolean canDrop() {
060: return !getName().equals(Constants.SCHEMA_INFORMATION)
061: && !getName().equals(Constants.SCHEMA_MAIN);
062: }
063:
064: public String getCreateSQLForCopy(Table table, String quotedName) {
065: throw Message.getInternalError();
066: }
067:
068: public String getDropSQL() {
069: return null;
070: }
071:
072: public String getCreateSQL() {
073: if (system) {
074: return null;
075: }
076: StringBuffer buff = new StringBuffer();
077: buff.append("CREATE SCHEMA ");
078: buff.append(getSQL());
079: buff.append(" AUTHORIZATION ");
080: buff.append(owner.getSQL());
081: return buff.toString();
082: }
083:
084: public int getType() {
085: return DbObject.SCHEMA;
086: }
087:
088: public void removeChildrenAndResources(Session session)
089: throws SQLException {
090: while (triggers != null && triggers.size() > 0) {
091: TriggerObject obj = (TriggerObject) triggers.values()
092: .toArray()[0];
093: database.removeSchemaObject(session, obj);
094: }
095: while (constraints != null && constraints.size() > 0) {
096: Constraint obj = (Constraint) constraints.values()
097: .toArray()[0];
098: database.removeSchemaObject(session, obj);
099: }
100: while (tablesAndViews != null && tablesAndViews.size() > 0) {
101: Table obj = (Table) tablesAndViews.values().toArray()[0];
102: database.removeSchemaObject(session, obj);
103: }
104: while (indexes != null && indexes.size() > 0) {
105: Index obj = (Index) indexes.values().toArray()[0];
106: database.removeSchemaObject(session, obj);
107: }
108: while (sequences != null && sequences.size() > 0) {
109: Sequence obj = (Sequence) sequences.values().toArray()[0];
110: database.removeSchemaObject(session, obj);
111: }
112: while (constants != null && constants.size() > 0) {
113: Constant obj = (Constant) constants.values().toArray()[0];
114: database.removeSchemaObject(session, obj);
115: }
116: database.removeMeta(session, getId());
117: owner = null;
118: invalidate();
119: }
120:
121: public void checkRename() throws SQLException {
122: }
123:
124: public User getOwner() {
125: return owner;
126: }
127:
128: private HashMap getMap(int type) {
129: switch (type) {
130: case DbObject.TABLE_OR_VIEW:
131: return tablesAndViews;
132: case DbObject.SEQUENCE:
133: return sequences;
134: case DbObject.INDEX:
135: return indexes;
136: case DbObject.TRIGGER:
137: return triggers;
138: case DbObject.CONSTRAINT:
139: return constraints;
140: case DbObject.CONSTANT:
141: return constants;
142: default:
143: throw Message.getInternalError("type=" + type);
144: }
145: }
146:
147: public void add(SchemaObject obj) throws SQLException {
148: if (SysProperties.CHECK && obj.getSchema() != this ) {
149: throw Message.getInternalError("wrong schema");
150: }
151: String name = obj.getName();
152: HashMap map = getMap(obj.getType());
153: if (SysProperties.CHECK && map.get(name) != null) {
154: throw Message.getInternalError("object already exists");
155: }
156: map.put(name, obj);
157: freeUniqueName(name);
158: }
159:
160: public void rename(SchemaObject obj, String newName)
161: throws SQLException {
162: int type = obj.getType();
163: HashMap map = getMap(type);
164: if (SysProperties.CHECK) {
165: if (!map.containsKey(obj.getName())) {
166: throw Message.getInternalError("not found: "
167: + obj.getName());
168: }
169: if (obj.getName().equals(newName)
170: || map.containsKey(newName)) {
171: throw Message
172: .getInternalError("object already exists: "
173: + newName);
174: }
175: }
176: map.remove(obj.getName());
177: freeUniqueName(obj.getName());
178: obj.rename(newName);
179: map.put(newName, obj);
180: freeUniqueName(newName);
181: }
182:
183: public Table findTableOrView(Session session, String name) {
184: Table table = (Table) tablesAndViews.get(name);
185: if (table == null && session != null) {
186: table = session.findLocalTempTable(name);
187: }
188: return table;
189: }
190:
191: public Index findIndex(String name) {
192: return (Index) indexes.get(name);
193: }
194:
195: public TriggerObject findTrigger(String name) {
196: return (TriggerObject) triggers.get(name);
197: }
198:
199: public Sequence findSequence(String sequenceName) {
200: return (Sequence) sequences.get(sequenceName);
201: }
202:
203: public Constraint findConstraint(String constraintName) {
204: return (Constraint) constraints.get(constraintName);
205: }
206:
207: public Constant findConstant(String constantName) {
208: return (Constant) constants.get(constantName);
209: }
210:
211: public void freeUniqueName(String name) {
212: if (name != null) {
213: temporaryUniqueNames.remove(name);
214: }
215: }
216:
217: private String getUniqueName(DbObject obj, HashMap map,
218: String prefix) {
219: String hash = Integer.toHexString(obj.getName().hashCode())
220: .toUpperCase();
221: String name = null;
222: for (int i = 1; i < hash.length(); i++) {
223: name = prefix + hash.substring(0, i);
224: if (!map.containsKey(name)
225: && !temporaryUniqueNames.contains(name)) {
226: break;
227: }
228: name = null;
229: }
230: if (name == null) {
231: prefix = prefix + hash + "_";
232: for (int i = 0;; i++) {
233: name = prefix + i;
234: if (!map.containsKey(name)
235: && !temporaryUniqueNames.contains(name)) {
236: break;
237: }
238: }
239: }
240: temporaryUniqueNames.add(name);
241: return name;
242: }
243:
244: public String getUniqueConstraintName(DbObject obj) {
245: return getUniqueName(obj, constraints, "CONSTRAINT_");
246: }
247:
248: public String getUniqueIndexName(DbObject obj, String prefix) {
249: return getUniqueName(obj, indexes, prefix);
250: }
251:
252: public Table getTableOrView(Session session, String name)
253: throws SQLException {
254: Table table = (Table) tablesAndViews.get(name);
255: if (table == null && session != null) {
256: table = session.findLocalTempTable(name);
257: }
258: if (table == null) {
259: throw Message.getSQLException(
260: ErrorCode.TABLE_OR_VIEW_NOT_FOUND_1, name);
261: }
262: return table;
263: }
264:
265: public Index getIndex(String name) throws SQLException {
266: Index index = (Index) indexes.get(name);
267: if (index == null) {
268: throw Message.getSQLException(ErrorCode.INDEX_NOT_FOUND_1,
269: name);
270: }
271: return index;
272: }
273:
274: public Constraint getConstraint(String name) throws SQLException {
275: Constraint constraint = (Constraint) constraints.get(name);
276: if (constraint == null) {
277: throw Message.getSQLException(
278: ErrorCode.CONSTRAINT_NOT_FOUND_1, name);
279: }
280: return constraint;
281: }
282:
283: public Constant getConstant(Session session, String constantName)
284: throws SQLException {
285: Constant constant = (Constant) constants.get(constantName);
286: if (constant == null) {
287: throw Message.getSQLException(
288: ErrorCode.CONSTANT_NOT_FOUND_1, constantName);
289: }
290: return constant;
291: }
292:
293: public Sequence getSequence(String sequenceName)
294: throws SQLException {
295: Sequence sequence = (Sequence) sequences.get(sequenceName);
296: if (sequence == null) {
297: throw Message.getSQLException(
298: ErrorCode.SEQUENCE_NOT_FOUND_1, sequenceName);
299: }
300: return sequence;
301: }
302:
303: public ObjectArray getAll(int type) {
304: HashMap map = getMap(type);
305: return new ObjectArray(map.values());
306: }
307:
308: public void remove(Session session, SchemaObject obj)
309: throws SQLException {
310: String objName = obj.getName();
311: HashMap map = getMap(obj.getType());
312: if (SysProperties.CHECK && !map.containsKey(objName)) {
313: throw Message.getInternalError("not found: " + objName);
314: }
315: map.remove(objName);
316: freeUniqueName(objName);
317: }
318:
319: /**
320: * Add a {@link TableData} to the schema.
321: *
322: * @param tableName the table name
323: * @param id the object id
324: * @param columns the column list
325: * @param persistent if the table should be persistent
326: * @param clustered if a clustered table should be created
327: * @return the created {@link TableData} object
328: */
329: public TableData createTable(String tableName, int id,
330: ObjectArray columns, boolean persistent, boolean clustered)
331: throws SQLException {
332: return new TableData(this , tableName, id, columns, persistent,
333: clustered);
334: }
335:
336: /**
337: * Add a {@link TableLink} to the schema.
338: *
339: * @param id the object id
340: * @param tableName the table name of the alias
341: * @param driver the driver class name
342: * @param url the database URL
343: * @param user the user name
344: * @param password the password
345: * @param originalTable the table name of the target table
346: * @param emitUpdates if updates should be emitted instead of delete/insert
347: * @param force create the object even if the database can not be accessed
348: * @return the {@link TableLink} object
349: */
350: public TableLink createTableLink(int id, String tableName,
351: String driver, String url, String user, String password,
352: String originalTable, boolean emitUpdates, boolean force)
353: throws SQLException {
354: return new TableLink(this, id, tableName, driver, url, user,
355: password, originalTable, emitUpdates, force);
356: }
357:
358: }
|