001: /*
002:
003: Derby - Class org.apache.derby.impl.sql.compile.DDLStatementNode
004:
005: Licensed to the Apache Software Foundation (ASF) under one or more
006: contributor license agreements. See the NOTICE file distributed with
007: this work for additional information regarding copyright ownership.
008: The ASF licenses this file to you under the Apache License, Version 2.0
009: (the "License"); you may not use this file except in compliance with
010: the License. You may obtain a copy of the License at
011:
012: http://www.apache.org/licenses/LICENSE-2.0
013:
014: Unless required by applicable law or agreed to in writing, software
015: distributed under the License is distributed on an "AS IS" BASIS,
016: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017: See the License for the specific language governing permissions and
018: limitations under the License.
019:
020: */
021:
022: package org.apache.derby.impl.sql.compile;
023:
024: import org.apache.derby.iapi.services.compiler.MethodBuilder;
025:
026: import org.apache.derby.iapi.sql.ResultSet;
027:
028: import org.apache.derby.iapi.sql.dictionary.DataDictionary;
029: import org.apache.derby.iapi.sql.dictionary.SchemaDescriptor;
030: import org.apache.derby.iapi.sql.dictionary.TableDescriptor;
031: import org.apache.derby.iapi.sql.compile.CompilerContext;
032: import org.apache.derby.iapi.sql.conn.Authorizer;
033: import org.apache.derby.iapi.reference.SQLState;
034: import org.apache.derby.iapi.error.StandardException;
035:
036: import org.apache.derby.impl.sql.compile.ActivationClassBuilder;
037:
038: import org.apache.derby.iapi.services.sanity.SanityManager;
039: import org.apache.derby.iapi.reference.ClassName;
040:
041: import org.apache.derby.iapi.services.classfile.VMOpcode;
042: import org.apache.derby.catalog.UUID;
043:
044: /**
045: * A DDLStatementNode represents any type of DDL statement: CREATE TABLE,
046: * CREATE INDEX, ALTER TABLE, etc.
047: *
048: * @author Jeff Lichtman
049: */
050:
051: abstract class DDLStatementNode extends StatementNode {
052: /////////////////////////////////////////////////////////////////////////
053: //
054: // CONSTANTS
055: //
056: /////////////////////////////////////////////////////////////////////////
057:
058: public static final int UNKNOWN_TYPE = 0;
059: public static final int ADD_TYPE = 1;
060: public static final int DROP_TYPE = 2;
061: public static final int MODIFY_TYPE = 3;
062: public static final int LOCKING_TYPE = 4;
063:
064: /////////////////////////////////////////////////////////////////////////
065: //
066: // STATE
067: //
068: /////////////////////////////////////////////////////////////////////////
069:
070: private TableName objectName;
071: private boolean initOk;
072:
073: /**
074: sub-classes can set this to be true to allow implicit
075: creation of the main object's schema at execution time.
076: */
077: boolean implicitCreateSchema;
078:
079: /////////////////////////////////////////////////////////////////////////
080: //
081: // BEHAVIOR
082: //
083: /////////////////////////////////////////////////////////////////////////
084:
085: public void init(Object objectName) throws StandardException {
086: initAndCheck(objectName);
087: }
088:
089: /**
090: Initialize the object name we will be performing the DDL
091: on and check that we are not in the system schema
092: and that DDL is allowed.
093: */
094: protected void initAndCheck(Object objectName)
095: throws StandardException {
096:
097: this .objectName = (TableName) objectName;
098:
099: initOk = true;
100: }
101:
102: /**
103: * A DDL statement is always atomic
104: *
105: * @return true
106: */
107: public boolean isAtomic() {
108: return true;
109: }
110:
111: /**
112: * Return the name of the table being dropped.
113: * This is the unqualified table name.
114: *
115: * @return the relative name
116: */
117: public String getRelativeName() {
118: return objectName.getTableName();
119: }
120:
121: /**
122: * Return the full dot expression name of the
123: * object being dropped.
124: *
125: * @return the full name
126: */
127: public String getFullName() {
128: return objectName.getFullTableName();
129: }
130:
131: public final TableName getObjectName() {
132: return objectName;
133: }
134:
135: /**
136: * Convert this object to a String. See comments in QueryTreeNode.java
137: * for how this should be done for tree printing.
138: *
139: * @return This object as a String
140: */
141:
142: public String toString() {
143: if (SanityManager.DEBUG) {
144: return ((objectName == null) ? "" : objectName.toString())
145: + super .toString();
146: } else {
147: return "";
148: }
149: }
150:
151: int activationKind() {
152: return StatementNode.NEED_DDL_ACTIVATION;
153: }
154:
155: /**
156: * Generic generate code for all DDL statements.
157: *
158: * @param acb The ActivationClassBuilder for the class being built
159: * @param mb The execute() method to be built
160: *
161: * @exception StandardException Thrown on error
162: */
163:
164: public final void generate(ActivationClassBuilder acb,
165: MethodBuilder mb) throws StandardException {
166: if (SanityManager.DEBUG) {
167: if (!initOk)
168: SanityManager.THROWASSERT(getClass()
169: + " never called initAndCheck()");
170: }
171:
172: // The generated java is the expression:
173: // return ResultSetFactory.getDDLResultSet(this)
174: //
175:
176: acb.pushGetResultSetFactoryExpression(mb); // instance for getDDLResultSet
177: acb.pushThisAsActivation(mb); // first arg
178:
179: mb.callMethod(VMOpcode.INVOKEINTERFACE, (String) null,
180: "getDDLResultSet", ClassName.ResultSet, 1);
181: }
182:
183: /**
184: * Get a schema descriptor for this DDL object.
185: * Uses this.objectName. Always returns a schema,
186: * we lock in the schema name prior to execution.
187: * Checks if current authorizationID is owner of the schema.
188: *
189: * @return Schema Descriptor
190: *
191: * @exception StandardException throws on schema name
192: * that doesn't exist
193: */
194: protected final SchemaDescriptor getSchemaDescriptor()
195: throws StandardException {
196: return getSchemaDescriptor(true);
197: }
198:
199: /**
200: * Get a schema descriptor for this DDL object.
201: * Uses this.objectName. Always returns a schema,
202: * we lock in the schema name prior to execution.
203: *
204: * @param ownerCheck If check for schema owner is needed
205: *
206: * @return Schema Descriptor
207: *
208: * @exception StandardException throws on schema name
209: * that doesn't exist
210: */
211: protected final SchemaDescriptor getSchemaDescriptor(
212: boolean ownerCheck) throws StandardException {
213: String schemaName = objectName.getSchemaName();
214: //boolean needError = !(implicitCreateSchema || (schemaName == null));
215: boolean needError = !implicitCreateSchema;
216: SchemaDescriptor sd = getSchemaDescriptor(schemaName, needError);
217: CompilerContext cc = getCompilerContext();
218:
219: if (sd == null) {
220: /* Disable creating schemas starting with SYS */
221: if (schemaName.startsWith("SYS"))
222: throw StandardException.newException(
223: SQLState.LANG_NO_USER_DDL_IN_SYSTEM_SCHEMA,
224: statementToString(), schemaName);
225:
226: sd = new SchemaDescriptor(getDataDictionary(), schemaName,
227: (String) null, (UUID) null, false);
228:
229: if (isPrivilegeCollectionRequired())
230: cc.addRequiredSchemaPriv(schemaName, null,
231: Authorizer.CREATE_SCHEMA_PRIV);
232: }
233:
234: if (ownerCheck && isPrivilegeCollectionRequired())
235: cc.addRequiredSchemaPriv(sd.getSchemaName(), null,
236: Authorizer.MODIFY_SCHEMA_PRIV);
237:
238: /*
239: ** Catch the system schema here.
240: */
241: if (sd.isSystemSchema()) {
242: throw StandardException.newException(
243: SQLState.LANG_NO_USER_DDL_IN_SYSTEM_SCHEMA,
244: statementToString(), sd);
245: }
246: return sd;
247: }
248:
249: protected final TableDescriptor getTableDescriptor()
250: throws StandardException {
251: return getTableDescriptor(objectName);
252: }
253:
254: protected final TableDescriptor getTableDescriptor(UUID tableId)
255: throws StandardException {
256:
257: TableDescriptor td = getDataDictionary().getTableDescriptor(
258: tableId);
259:
260: td = checkTableDescriptor(td);
261: return td;
262:
263: }
264:
265: /**
266: * Validate that the table is ok for DDL -- e.g.
267: * that it exists, it is not a view, and is not
268: * a system table, and that its schema is ok.
269: *
270: * @return the validated table descriptor, never null
271: *
272: * @exception StandardException on error
273: */
274: protected final TableDescriptor getTableDescriptor(
275: TableName tableName) throws StandardException {
276: String schemaName = tableName.getSchemaName();
277: SchemaDescriptor sd = getSchemaDescriptor(schemaName);
278:
279: TableDescriptor td = getTableDescriptor(tableName
280: .getTableName(), sd);
281:
282: if (td == null) {
283: throw StandardException.newException(
284: SQLState.LANG_OBJECT_DOES_NOT_EXIST,
285: statementToString(), tableName);
286: }
287:
288: /* beetle 4444, td may have changed when we obtain shared lock */
289: td = checkTableDescriptor(td);
290: return td;
291:
292: }
293:
294: private TableDescriptor checkTableDescriptor(TableDescriptor td)
295: throws StandardException {
296: String sqlState = null;
297:
298: switch (td.getTableType()) {
299: case TableDescriptor.VTI_TYPE:
300: case TableDescriptor.SYSTEM_TABLE_TYPE:
301:
302: /*
303: ** Not on system tables (though there are no constraints on
304: ** system tables as of the time this is writen
305: */
306: sqlState = SQLState.LANG_INVALID_OPERATION_ON_SYSTEM_TABLE;
307: break;
308:
309: case TableDescriptor.BASE_TABLE_TYPE:
310: /* need to IX lock table if we are a reader in DDL datadictionary
311: * cache mode, otherwise we may interfere with another DDL thread
312: * that is in execution phase; beetle 4343, also see $WS/docs/
313: * language/SolutionsToConcurrencyIssues.txt (point f)
314: */
315: return lockTableForCompilation(td);
316:
317: case TableDescriptor.GLOBAL_TEMPORARY_TABLE_TYPE:
318: return td;
319:
320: /*
321: ** Make sure it is not a view
322: */
323: case TableDescriptor.VIEW_TYPE:
324: sqlState = SQLState.LANG_INVALID_OPERATION_ON_VIEW;
325: break;
326: }
327:
328: throw StandardException.newException(sqlState,
329: statementToString(), td.getQualifiedName());
330:
331: }
332:
333: /**
334: * Bind the object Name. This means filling in the schema name if it
335: * wasn't specified.
336: *
337: * @param dataDictionary Data dictionary to bind against.
338: *
339: * @exception StandardException Thrown on error
340: */
341: public void bindName(DataDictionary dataDictionary)
342: throws StandardException {
343: if (objectName != null)
344: objectName.bind(dataDictionary);
345: }
346: }
|