KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > derby > impl > sql > compile > ModifyColumnNode


1 /*
2
3    Derby - Class org.apache.derby.impl.sql.compile.ModifyColumnNode
4
5    Licensed to the Apache Software Foundation (ASF) under one or more
6    contributor license agreements. See the NOTICE file distributed with
7    this work for additional information regarding copyright ownership.
8    The ASF licenses this file to you under the Apache License, Version 2.0
9    (the "License"); you may not use this file except in compliance with
10    the License. You may obtain a copy of the License at
11
12       http://www.apache.org/licenses/LICENSE-2.0
13
14    Unless required by applicable law or agreed to in writing, software
15    distributed under the License is distributed on an "AS IS" BASIS,
16    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17    See the License for the specific language governing permissions and
18    limitations under the License.
19
20  */

21
22 package org.apache.derby.impl.sql.compile;
23
24 import org.apache.derby.iapi.sql.compile.C_NodeTypes;
25
26 import org.apache.derby.iapi.services.sanity.SanityManager;
27
28 import org.apache.derby.iapi.error.StandardException;
29
30 import org.apache.derby.iapi.sql.dictionary.ColumnDescriptor;
31 import org.apache.derby.iapi.sql.dictionary.DataDictionary;
32 import org.apache.derby.iapi.sql.dictionary.DefaultDescriptor;
33 import org.apache.derby.iapi.sql.dictionary.TableDescriptor;
34 import org.apache.derby.iapi.sql.dictionary.ConstraintDescriptorList;
35 import org.apache.derby.iapi.sql.dictionary.KeyConstraintDescriptor;
36 import org.apache.derby.iapi.sql.dictionary.ConstraintDescriptor;
37
38 import org.apache.derby.iapi.types.TypeId;
39 import org.apache.derby.iapi.types.DataTypeDescriptor;
40
41 import org.apache.derby.iapi.reference.SQLState;
42
43 import org.apache.derby.impl.sql.execute.ColumnInfo;
44 import org.apache.derby.catalog.TypeDescriptor;
45 import org.apache.derby.catalog.UUID;
46 import org.apache.derby.catalog.types.DefaultInfoImpl;
47
48 /**
49  * A ModifyColumnNode represents a modify column in an ALTER TABLE statement.
50  *
51  * @author Jerry Brenner
52  */

53
54 public class ModifyColumnNode extends ColumnDefinitionNode
55 {
56     int columnPosition = -1;
57     UUID oldDefaultUUID;
58
59     /**
60      * Get the UUID of the old column default.
61      *
62      * @return The UUID of the old column default.
63      */

64     UUID getOldDefaultUUID()
65     {
66         return oldDefaultUUID;
67     }
68
69     /**
70      * Get the column position for the column.
71      *
72      * @return The column position for the column.
73      */

74     public int getColumnPosition()
75     {
76         if (SanityManager.DEBUG)
77         {
78             SanityManager.ASSERT(columnPosition > 0,
79                 "columnPosition expected to be > 0");
80         }
81         return columnPosition;
82     }
83
84     /**
85      * Check the validity of a user type. Checks that
86      * 1. the column type is either varchar, ....
87      * 2. is the same type after the alter.
88      * 3. length is greater than the old length.
89      *
90      * @exception StandardException Thrown on error
91      */

92
93     public void checkUserType(TableDescriptor td)
94         throws StandardException
95     {
96         ColumnDescriptor cd;
97         TypeDescriptor oldType;
98         DataTypeDescriptor newType = dataTypeServices;
99         TypeId oldTypeId;
100         TypeId newTypeId;
101
102         if (getNodeType() != C_NodeTypes.MODIFY_COLUMN_TYPE_NODE)
103             return; // nothing to do if user not changing length
104

105         cd = td.getColumnDescriptor(name);
106         if (cd == null)
107         {
108             throw StandardException.newException(
109                 SQLState.LANG_COLUMN_NOT_FOUND_IN_TABLE, name, td.getName());
110         }
111         
112         oldType = cd.getType();
113         oldTypeId = cd.getType().getTypeId();
114         newTypeId = dataTypeServices.getTypeId();
115         newType.setNullability(oldType.isNullable());
116
117         // can't change types yet.
118
if (!(oldTypeId.equals(newTypeId)))
119         {
120             throw StandardException.newException(
121                      SQLState.LANG_MODIFY_COLUMN_CHANGE_TYPE, name);
122         }
123         
124         // can only alter the length of varchar, nvarchar, bitvarying columns
125
String JavaDoc typeName = dataTypeServices.getTypeName();
126         if (!(typeName.equals(TypeId.NATIONAL_VARCHAR_NAME)) &&
127             !(typeName.equals(TypeId.VARCHAR_NAME)) &&
128             !(typeName.equals(TypeId.VARBIT_NAME)))
129         {
130             throw StandardException.newException(
131                          SQLState.LANG_MODIFY_COLUMN_INVALID_TYPE);
132         }
133         
134         // cannot decrease the length of a column
135
if (newType.getMaximumWidth() < oldType.getMaximumWidth())
136         {
137             throw StandardException.newException(
138                          SQLState.LANG_MODIFY_COLUMN_INVALID_LENGTH, name);
139         }
140     }
141     
142     /**
143      * If the type of a column is being changed (for mulan, the length of the
144      * column is being increased then make sure that this does not violate
145      * any key constraints;
146      * the column being altered is
147      * 1. part of foreign key constraint
148      * ==> ERROR. This references a Primary Key constraint and the
149      * type & lengths of the pkey/fkey must match exactly.
150      * 2. part of a unique/primary key constraint
151      * ==> OK if no fkey references this constraint.
152      * ==> ERROR if any fkey in the system references this constraint.
153      *
154      * @param td The Table Descriptor on which the ALTER is being done.
155      *
156      * @exception StandardException Thrown on Error.
157      *
158      */

159     public void checkExistingConstraints(TableDescriptor td)
160                  throws StandardException
161     {
162         if ((getNodeType() != C_NodeTypes.MODIFY_COLUMN_TYPE_NODE) &&
163             (getNodeType() != C_NodeTypes.MODIFY_COLUMN_CONSTRAINT_NODE) &&
164             (getNodeType() != C_NodeTypes.MODIFY_COLUMN_CONSTRAINT_NOT_NULL_NODE))
165             return;
166
167         DataDictionary dd = getDataDictionary();
168         ConstraintDescriptorList cdl = dd.getConstraintDescriptors(td);
169         int intArray[] = new int[1];
170         intArray[0] = columnPosition;
171
172         for (int index = 0; index < cdl.size(); index++)
173         {
174             ConstraintDescriptor existingConstraint =
175                                                 cdl.elementAt(index);
176             if (!(existingConstraint instanceof KeyConstraintDescriptor))
177                 continue;
178
179             if (!existingConstraint.columnIntersects(intArray))
180                 continue;
181                                                              
182             int constraintType = existingConstraint.getConstraintType();
183
184             // cannot change the length of a column that is part of a
185
// foreign key constraint. Must be an exact match between pkey
186
// and fkey columns.
187
if ((constraintType == DataDictionary.FOREIGNKEY_CONSTRAINT)
188                 &&
189                 (getNodeType() == C_NodeTypes.MODIFY_COLUMN_TYPE_NODE))
190             {
191                 throw StandardException.newException(
192                      SQLState.LANG_MODIFY_COLUMN_FKEY_CONSTRAINT, name, existingConstraint.getConstraintName());
193             }
194             
195             else
196             {
197                 // a column that is part of a primary key or unique constraint
198
// is being made nullable; can't be done.
199
if ((getNodeType() ==
200                      C_NodeTypes.MODIFY_COLUMN_CONSTRAINT_NODE) &&
201                     ((existingConstraint.getConstraintType() ==
202                      DataDictionary.PRIMARYKEY_CONSTRAINT) ||
203                      (existingConstraint.getConstraintType() ==
204                      DataDictionary.UNIQUE_CONSTRAINT)))
205                 {
206                 throw StandardException.newException(
207                      SQLState.LANG_MODIFY_COLUMN_EXISTING_CONSTRAINT, name);
208                 }
209                 // unique key or primary key.
210
ConstraintDescriptorList
211                     refcdl = dd.getForeignKeys(existingConstraint.getUUID());
212                  
213                 if (refcdl.size() > 0)
214                 {
215                     throw StandardException.newException(
216                          SQLState.LANG_MODIFY_COLUMN_REFERENCED, name, refcdl.elementAt(0).getConstraintName());
217                 }
218                 
219                 // Make the statement dependent on the primary key constraint.
220
getCompilerContext().createDependency(existingConstraint);
221             }
222         }
223
224     }
225     /**
226      * Get the action associated with this node.
227      *
228      * @return The action associated with this node.
229      */

230     int getAction()
231     {
232         switch (getNodeType())
233         {
234         case C_NodeTypes.MODIFY_COLUMN_DEFAULT_NODE:
235             if (autoinc_create_or_modify_Start_Increment == ColumnDefinitionNode.MODIFY_AUTOINCREMENT_RESTART_VALUE)
236                 return ColumnInfo.MODIFY_COLUMN_DEFAULT_RESTART;
237             else
238                 return ColumnInfo.MODIFY_COLUMN_DEFAULT_INCREMENT;
239         case C_NodeTypes.MODIFY_COLUMN_TYPE_NODE:
240             return ColumnInfo.MODIFY_COLUMN_TYPE;
241         case C_NodeTypes.MODIFY_COLUMN_CONSTRAINT_NODE:
242             return ColumnInfo.MODIFY_COLUMN_CONSTRAINT;
243         case C_NodeTypes.MODIFY_COLUMN_CONSTRAINT_NOT_NULL_NODE:
244             return ColumnInfo.MODIFY_COLUMN_CONSTRAINT_NOT_NULL;
245         default:
246             if (SanityManager.DEBUG)
247             {
248                 SanityManager.THROWASSERT("Unexpected nodeType = " +
249                                           getNodeType());
250             }
251             return 0;
252         }
253     }
254
255     /**
256      * Check the validity of the default, if any, for this node.
257      *
258      * @param dd The DataDictionary.
259      * @param td The TableDescriptor.
260      *
261      * @exception StandardException Thrown on error
262      */

263     void bindAndValidateDefault(DataDictionary dd, TableDescriptor td)
264         throws StandardException
265     {
266         ColumnDescriptor cd;
267
268         // First verify that the column exists
269
cd = td.getColumnDescriptor(name);
270         if (cd == null)
271         {
272             throw StandardException.newException(SQLState.LANG_COLUMN_NOT_FOUND_IN_TABLE, name, td.getName());
273         }
274
275
276         // Get the UUID for the old default
277
DefaultDescriptor defaultDescriptor = cd.getDefaultDescriptor(dd);
278         
279         oldDefaultUUID = (defaultDescriptor == null) ? null : defaultDescriptor.getUUID();
280
281         // Remember the column position
282
columnPosition = cd.getPosition();
283
284         // No other work to do if no user specified default
285
if (getNodeType() != C_NodeTypes.MODIFY_COLUMN_DEFAULT_NODE)
286         {
287             return;
288         }
289
290         // If the statement is not setting the column's default, then
291
// recover the old default and re-use it. If the statement is
292
// changing the start value for the auto-increment, then recover
293
// the old increment-by value and re-use it. If the statement is
294
// changing the increment-by value, then recover the old start value
295
// and re-use it. This way, the column alteration only changes the
296
// aspects of the autoincrement settings that it intends to change,
297
// and does not lose the other aspecs.
298
if (defaultNode == null)
299             defaultInfo = (DefaultInfoImpl)cd.getDefaultInfo();
300         if (autoinc_create_or_modify_Start_Increment ==
301                 ColumnDefinitionNode.MODIFY_AUTOINCREMENT_RESTART_VALUE)
302             autoincrementIncrement = cd.getAutoincInc();
303         if (autoinc_create_or_modify_Start_Increment ==
304                 ColumnDefinitionNode.MODIFY_AUTOINCREMENT_INC_VALUE)
305             autoincrementStart = cd.getAutoincStart();
306
307         /* Fill in the DataTypeServices from the DataDictionary */
308         dataTypeServices = cd.getType();
309
310         // Now validate the default
311
validateDefault(dd, td);
312     }
313     
314     private ColumnDescriptor getLocalColumnDescriptor(String JavaDoc name, TableDescriptor td)
315              throws StandardException
316     {
317         ColumnDescriptor cd;
318
319         // First verify that the column exists
320
cd = td.getColumnDescriptor(name);
321         if (cd == null)
322         {
323             throw StandardException.newException(
324                 SQLState.LANG_COLUMN_NOT_FOUND_IN_TABLE, name, td.getName());
325         }
326
327         return cd;
328     }
329     /**
330      * check the validity of autoincrement values in the case that we are
331      * modifying an existing column (includes checking if autoincrement is set
332      * when making a column nullable)
333      */

334     public void validateAutoincrement(DataDictionary dd, TableDescriptor td, int tableType)
335              throws StandardException
336     {
337         ColumnDescriptor cd;
338
339         // a column that has an autoincrement default can't be made nullable
340
if (getNodeType() == C_NodeTypes.MODIFY_COLUMN_CONSTRAINT_NODE)
341         {
342             cd = getLocalColumnDescriptor(name, td);
343             if (cd.isAutoincrement())
344             {
345                 throw StandardException.newException(SQLState.LANG_AI_CANNOT_NULL_AI,
346                         getColumnName());
347             }
348         }
349
350         if (autoincrementVerify)
351         {
352             cd = getLocalColumnDescriptor(name, td);
353             if (!cd.isAutoincrement())
354                 throw StandardException.newException(SQLState.LANG_INVALID_ALTER_TABLE_ATTRIBUTES,
355                                 td.getQualifiedName(), name);
356         }
357         if (isAutoincrement == false)
358             return;
359         
360         super.validateAutoincrement(dd, td, tableType);
361         if (dataTypeServices.isNullable())
362             throw StandardException.newException(SQLState.LANG_AI_CANNOT_ADD_AI_TO_NULLABLE,
363                                                 getColumnName());
364     }
365 }
366
Popular Tags