001: /*
002:
003: Derby - Class org.apache.derby.impl.sql.compile.AlterTableNode
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.reference.SQLState;
025: import org.apache.derby.iapi.reference.Limits;
026:
027: import org.apache.derby.iapi.services.sanity.SanityManager;
028:
029: import org.apache.derby.iapi.error.StandardException;
030:
031: import org.apache.derby.iapi.sql.compile.C_NodeTypes;
032:
033: import org.apache.derby.iapi.sql.dictionary.DataDictionary;
034: import org.apache.derby.iapi.sql.dictionary.SchemaDescriptor;
035: import org.apache.derby.iapi.sql.dictionary.TableDescriptor;
036:
037: import org.apache.derby.iapi.sql.execute.ConstantAction;
038:
039: import org.apache.derby.impl.sql.execute.ColumnInfo;
040: import org.apache.derby.impl.sql.execute.ConstraintConstantAction;
041:
042: /**
043: * A AlterTableNode represents a DDL statement that alters a table.
044: * It contains the name of the object to be created.
045: *
046: * @author Jerry Brenner
047: */
048:
049: public class AlterTableNode extends DDLStatementNode {
050: // The alter table action
051: public TableElementList tableElementList = null;
052: public char lockGranularity;
053: public boolean compressTable = false;
054: public boolean sequential = false;
055: public int behavior; // currently for drop column
056:
057: public TableDescriptor baseTable;
058:
059: protected int numConstraints;
060:
061: private int changeType = UNKNOWN_TYPE;
062:
063: private boolean truncateTable = false;
064:
065: // constant action arguments
066:
067: protected SchemaDescriptor schemaDescriptor = null;
068: protected ColumnInfo[] colInfos = null;
069: protected ConstraintConstantAction[] conActions = null;
070:
071: /**
072: * Initializer for a TRUNCATE TABLE
073: *
074: * @param objectName The name of the table being truncated
075: * @exception StandardException Thrown on error
076: */
077:
078: public void init(Object objectName) throws StandardException {
079:
080: //truncate table is not suppotted in this release
081: //semantics are not yet clearly defined by SQL Council yet
082: //truncate will be allowed only in DEBUG builds for testing purposes.
083: if (SanityManager.DEBUG) {
084: initAndCheck(objectName);
085: /* For now, this init() only called for truncate table */
086: truncateTable = true;
087: schemaDescriptor = getSchemaDescriptor();
088: } else {
089: throw StandardException.newException(
090: SQLState.NOT_IMPLEMENTED, "truncate table");
091: }
092: }
093:
094: /**
095: * Initializer for a AlterTableNode for COMPRESS
096: *
097: * @param objectName The name of the table being altered
098: * @param sequential Whether or not the COMPRESS is SEQUENTIAL
099: *
100: * @exception StandardException Thrown on error
101: */
102:
103: public void init(Object objectName, Object sequential)
104: throws StandardException {
105: initAndCheck(objectName);
106:
107: this .sequential = ((Boolean) sequential).booleanValue();
108: /* For now, this init() only called for compress table */
109: compressTable = true;
110:
111: schemaDescriptor = getSchemaDescriptor();
112: }
113:
114: /**
115: * Initializer for a AlterTableNode
116: *
117: * @param objectName The name of the table being altered
118: * @param tableElementList The alter table action
119: * @param lockGranularity The new lock granularity, if any
120: * @param changeType ADD_TYPE or DROP_TYPE
121: *
122: * @exception StandardException Thrown on error
123: */
124:
125: public void init(Object objectName, Object tableElementList,
126: Object lockGranularity, Object changeType, Object behavior,
127: Object sequential) throws StandardException {
128: initAndCheck(objectName);
129: this .tableElementList = (TableElementList) tableElementList;
130: this .lockGranularity = ((Character) lockGranularity)
131: .charValue();
132:
133: int[] ct = (int[]) changeType, bh = (int[]) behavior;
134: this .changeType = ct[0];
135: this .behavior = bh[0];
136: boolean[] seq = (boolean[]) sequential;
137: this .sequential = seq[0];
138: switch (this .changeType) {
139: case ADD_TYPE:
140: case DROP_TYPE:
141: case MODIFY_TYPE:
142: case LOCKING_TYPE:
143:
144: break;
145:
146: default:
147:
148: throw StandardException
149: .newException(SQLState.NOT_IMPLEMENTED);
150: }
151:
152: schemaDescriptor = getSchemaDescriptor();
153: }
154:
155: /**
156: * Convert this object to a String. See comments in QueryTreeNode.java
157: * for how this should be done for tree printing.
158: *
159: * @return This object as a String
160: */
161:
162: public String toString() {
163: if (SanityManager.DEBUG) {
164: return super .toString() + "objectName: " + "\n"
165: + getObjectName() + "\n" + "tableElementList: "
166: + "\n" + tableElementList + "\n"
167: + "lockGranularity: " + "\n" + lockGranularity
168: + "\n" + "compressTable: " + "\n" + compressTable
169: + "\n" + "sequential: " + "\n" + sequential + "\n"
170: + "truncateTable: " + "\n" + truncateTable + "\n";
171: } else {
172: return "";
173: }
174: }
175:
176: public String statementToString() {
177: if (truncateTable)
178: return "TRUNCATE TABLE";
179: else
180: return "ALTER TABLE";
181: }
182:
183: public int getChangeType() {
184: return changeType;
185: }
186:
187: // We inherit the generate() method from DDLStatementNode.
188:
189: /**
190: * Bind this AlterTableNode. This means doing any static error
191: * checking that can be done before actually creating the table.
192: * For example, verifying that the user is not trying to add a
193: * non-nullable column.
194: *
195: * @return The bound query tree
196: *
197: * @exception StandardException Thrown on error
198: */
199: public QueryTreeNode bind() throws StandardException {
200: DataDictionary dd = getDataDictionary();
201: int numCheckConstraints = 0;
202: int numBackingIndexes = 0;
203:
204: /*
205: ** Get the table descriptor. Checks the schema
206: ** and the table.
207: */
208: baseTable = getTableDescriptor();
209: //throw an exception if user is attempting to alter a temporary table
210: if (baseTable.getTableType() == TableDescriptor.GLOBAL_TEMPORARY_TABLE_TYPE) {
211: throw StandardException
212: .newException(SQLState.LANG_NOT_ALLOWED_FOR_DECLARED_GLOBAL_TEMP_TABLE);
213: }
214:
215: /* Statement is dependent on the TableDescriptor */
216: getCompilerContext().createDependency(baseTable);
217:
218: if (tableElementList != null) {
219: tableElementList.validate(this , dd, baseTable);
220:
221: /* Only 1012 columns allowed per table */
222: if ((tableElementList.countNumberOfColumns() + baseTable
223: .getNumberOfColumns()) > Limits.DB2_MAX_COLUMNS_IN_TABLE) {
224: throw StandardException
225: .newException(
226: SQLState.LANG_TOO_MANY_COLUMNS_IN_TABLE_OR_VIEW,
227: String.valueOf(tableElementList
228: .countNumberOfColumns()
229: + baseTable
230: .getNumberOfColumns()),
231: getRelativeName(),
232: String
233: .valueOf(Limits.DB2_MAX_COLUMNS_IN_TABLE));
234: }
235: /* Number of backing indexes in the alter table statment */
236: numBackingIndexes = tableElementList
237: .countConstraints(DataDictionary.PRIMARYKEY_CONSTRAINT)
238: + tableElementList
239: .countConstraints(DataDictionary.FOREIGNKEY_CONSTRAINT)
240: + tableElementList
241: .countConstraints(DataDictionary.UNIQUE_CONSTRAINT);
242: /* Check the validity of all check constraints */
243: numCheckConstraints = tableElementList
244: .countConstraints(DataDictionary.CHECK_CONSTRAINT);
245: }
246:
247: //If the sum of backing indexes for constraints in alter table statement and total number of indexes on the table
248: //so far is more than 32767, then we need to throw an exception
249: if ((numBackingIndexes + baseTable.getTotalNumberOfIndexes()) > Limits.DB2_MAX_INDEXES_ON_TABLE) {
250: throw StandardException.newException(
251: SQLState.LANG_TOO_MANY_INDEXES_ON_TABLE,
252: String.valueOf(numBackingIndexes
253: + baseTable.getTotalNumberOfIndexes()),
254: getRelativeName(), String
255: .valueOf(Limits.DB2_MAX_INDEXES_ON_TABLE));
256: }
257:
258: if (numCheckConstraints > 0) {
259: /* In order to check the validity of the check constraints
260: * we must goober up a FromList containing a single table,
261: * the table being alter, with an RCL containing the existing and
262: * new columns and their types. This will allow us to
263: * bind the constraint definition trees against that
264: * FromList. When doing this, we verify that there are
265: * no nodes which can return non-deterministic results.
266: */
267: FromList fromList = (FromList) getNodeFactory().getNode(
268: C_NodeTypes.FROM_LIST,
269: getNodeFactory().doJoinOrderOptimization(),
270: getContextManager());
271: FromBaseTable table = (FromBaseTable) getNodeFactory()
272: .getNode(C_NodeTypes.FROM_BASE_TABLE,
273: getObjectName(), null, null, null,
274: getContextManager());
275: fromList.addFromTable(table);
276: fromList.bindTables(dd, (FromList) getNodeFactory()
277: .getNode(C_NodeTypes.FROM_LIST,
278: getNodeFactory().doJoinOrderOptimization(),
279: getContextManager()));
280: tableElementList.appendNewColumnsToRCL(table);
281:
282: /* Now that we've finally goobered stuff up, bind and validate
283: * the check constraints.
284: */
285: tableElementList.bindAndValidateCheckConstraints(fromList);
286:
287: }
288:
289: /* Unlike most other DDL, we will make this ALTER TABLE statement
290: * dependent on the table being altered. In general, we try to
291: * avoid this for DDL, but we are already requiring the table to
292: * exist at bind time (not required for create index) and we don't
293: * want the column ids to change out from under us before
294: * execution.
295: */
296: getCompilerContext().createDependency(baseTable);
297:
298: return this ;
299: }
300:
301: /**
302: * Return true if the node references SESSION schema tables (temporary or permanent)
303: *
304: * @return true if references SESSION schema tables, else false
305: *
306: * @exception StandardException Thrown on error
307: */
308: public boolean referencesSessionSchema() throws StandardException {
309: //If alter table is on a SESSION schema table, then return true.
310: return isSessionSchema(baseTable.getSchemaName());
311: }
312:
313: /**
314: * Create the Constant information that will drive the guts of Execution.
315: *
316: * @exception StandardException Thrown on failure
317: */
318: public ConstantAction makeConstantAction() throws StandardException {
319: prepConstantAction();
320:
321: return getGenericConstantActionFactory()
322: .getAlterTableConstantAction(schemaDescriptor,
323: getRelativeName(), baseTable.getUUID(),
324: baseTable.getHeapConglomerateId(),
325: TableDescriptor.BASE_TABLE_TYPE, colInfos,
326: conActions, lockGranularity, compressTable,
327: behavior, sequential, truncateTable);
328: }
329:
330: /**
331: * Generate arguments to constant action. Called by makeConstantAction() in this class and in
332: * our subclass RepAlterTableNode.
333: *
334: *
335: * @exception StandardException Thrown on failure
336: */
337: public void prepConstantAction() throws StandardException {
338: if (tableElementList != null) {
339: genColumnInfo();
340: }
341:
342: /* If we've seen a constraint, then build a constraint list */
343:
344: if (numConstraints > 0) {
345: conActions = new ConstraintConstantAction[numConstraints];
346:
347: tableElementList.genConstraintActions(conActions,
348: getRelativeName(), schemaDescriptor,
349: getDataDictionary());
350: }
351: }
352:
353: /**
354: * Generate the ColumnInfo argument for the constant action. Return the number of constraints.
355: */
356: public void genColumnInfo() {
357: // for each column, stuff system.column
358: colInfos = new ColumnInfo[tableElementList
359: .countNumberOfColumns()];
360:
361: numConstraints = tableElementList.genColumnInfos(colInfos);
362: }
363:
364: /*
365: * class interface
366: */
367: }
|