KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > mckoi > database > interpret > AlterTable


1 /**
2  * com.mckoi.database.interpret.AlterTable 14 Sep 2001
3  *
4  * Mckoi SQL Database ( http://www.mckoi.com/database )
5  * Copyright (C) 2000, 2001, 2002 Diehl and Associates, Inc.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * Version 2 as published by the Free Software Foundation.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License Version 2 for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * Version 2 along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19  *
20  * Change Log:
21  *
22  *
23  */

24
25 package com.mckoi.database.interpret;
26
27 import com.mckoi.database.*;
28 import com.mckoi.util.IntegerVector;
29 import java.util.ArrayList JavaDoc;
30 import java.util.List JavaDoc;
31
32 /**
33  * Logic for the ALTER TABLE SQL statement.
34  *
35  * @author Tobias Downer
36  */

37
38 public class AlterTable extends Statement {
39
40   /**
41    * The create statement that we use to alter the current table. This is
42    * only for compatibility reasons.
43    */

44   StatementTree create_statement;
45
46   /**
47    * The name of the table we are altering.
48    */

49   String JavaDoc table_name;
50
51   /**
52    * The list of actions to perform in this alter statement.
53    */

54   private ArrayList JavaDoc actions;
55
56   /**
57    * The TableName object.
58    */

59   private TableName tname;
60
61   /**
62    * The prepared create table statement.
63    */

64   CreateTable create_stmt;
65
66
67
68   /**
69    * Adds an action to perform in this alter statement.
70    */

71   public void addAction(AlterTableAction action) {
72     if (actions == null) {
73       actions = new ArrayList JavaDoc();
74     }
75     actions.add(action);
76   }
77
78   /**
79    * Returns true if the column names match. If the database is in case
80    * insensitive mode then the columns will match if the case insensitive
81    * search matches.
82    */

83   public boolean checkColumnNamesMatch(DatabaseConnection db,
84                                        String JavaDoc col1, String JavaDoc col2) {
85     if (db.isInCaseInsensitiveMode()) {
86       return col1.equalsIgnoreCase(col2);
87     }
88     return col1.equals(col2);
89   }
90
91   private void checkColumnConstraint(String JavaDoc col_name, String JavaDoc[] cols,
92                                      TableName table, String JavaDoc constraint_name) {
93     for (int i = 0; i < cols.length; ++i) {
94       if (col_name.equals(cols[i])) {
95         throw new DatabaseConstraintViolationException(
96                 DatabaseConstraintViolationException.DROP_COLUMN_VIOLATION,
97                   "Constraint violation (" + constraint_name +
98                   ") dropping column " + col_name + " because of " +
99                   "referential constraint in " + table);
100       }
101     }
102
103   }
104
105
106
107   // ---------- Implemented from Statement ----------
108

109   public void prepare() throws DatabaseException {
110
111     // Get variables from the model
112
table_name = (String JavaDoc) cmd.getObject("table_name");
113     addAction((AlterTableAction) cmd.getObject("alter_action"));
114     create_statement = (StatementTree) cmd.getObject("create_statement");
115
116     // ---
117

118     if (create_statement != null) {
119       create_stmt = new CreateTable();
120       create_stmt.init(database, create_statement, null);
121       create_stmt.prepare();
122       this.table_name = create_stmt.table_name;
123 // create_statement.doPrepare(db, user);
124
}
125     else {
126       // If we don't have a create statement, then this is an SQL alter
127
// command.
128
}
129
130 // tname = TableName.resolve(db.getCurrentSchema(), table_name);
131
tname = resolveTableName(table_name, database);
132     if (tname.getName().indexOf('.') != -1) {
133       throw new DatabaseException("Table name can not contain '.' character.");
134     }
135
136   }
137
138   public Table evaluate() throws DatabaseException {
139
140     DatabaseQueryContext context = new DatabaseQueryContext(database);
141
142     String JavaDoc schema_name = database.getCurrentSchema();
143
144     // Does the user have privs to alter this tables?
145
if (!database.getDatabase().canUserAlterTableObject(context, user, tname)) {
146       throw new UserAccessException(
147          "User not permitted to alter table: " + table_name);
148     }
149
150     if (create_statement != null) {
151
152       // Create the data table definition and tell the database to update it.
153
DataTableDef table_def = create_stmt.createDataTableDef();
154       TableName tname = table_def.getTableName();
155       // Is the table in the database already?
156
if (database.tableExists(tname)) {
157         // Drop any schema for this table,
158
database.dropAllConstraintsForTable(tname);
159         database.updateTable(table_def);
160       }
161       // If the table isn't in the database,
162
else {
163         database.createTable(table_def);
164       }
165
166       // Setup the constraints
167
create_stmt.setupAllConstraints();
168
169       // Return '0' if we created the table.
170
return FunctionTable.resultTable(context, 0);
171     }
172     else {
173       // SQL alter command using the alter table actions,
174

175       // Get the table definition for the table name,
176
DataTableDef table_def = database.getTable(tname).getDataTableDef();
177       String JavaDoc table_name = table_def.getName();
178       DataTableDef new_table = table_def.noColumnCopy();
179
180       // Returns a ColumnChecker implementation for this table.
181
ColumnChecker checker =
182                          ColumnChecker.standardColumnChecker(database, tname);
183
184       // Set to true if the table topology is alter, or false if only
185
// the constraints are changed.
186
boolean table_altered = false;
187
188       for (int n = 0; n < table_def.columnCount(); ++n) {
189         DataTableColumnDef column =
190                                 new DataTableColumnDef(table_def.columnAt(n));
191         String JavaDoc col_name = column.getName();
192         // Apply any actions to this column
193
boolean mark_dropped = false;
194         for (int i = 0; i < actions.size(); ++i) {
195           AlterTableAction action = (AlterTableAction) actions.get(i);
196           if (action.getAction().equals("ALTERSET") &&
197               checkColumnNamesMatch(database,
198                                     (String JavaDoc) action.getElement(0),
199                                     col_name)) {
200             Expression exp = (Expression) action.getElement(1);
201             checker.checkExpression(exp);
202             column.setDefaultExpression(exp);
203             table_altered = true;
204           }
205           else if (action.getAction().equals("DROPDEFAULT") &&
206                    checkColumnNamesMatch(database,
207                                          (String JavaDoc) action.getElement(0),
208                                          col_name)) {
209             column.setDefaultExpression(null);
210             table_altered = true;
211           }
212           else if (action.getAction().equals("DROP") &&
213                    checkColumnNamesMatch(database,
214                                          (String JavaDoc) action.getElement(0),
215                                          col_name)) {
216             // Check there are no referential links to this column
217
Transaction.ColumnGroupReference[] refs =
218                       database.queryTableImportedForeignKeyReferences(tname);
219             for (int p = 0; p < refs.length; ++p) {
220               checkColumnConstraint(col_name, refs[p].ref_columns,
221                                     refs[p].ref_table_name, refs[p].name);
222             }
223             // Or from it
224
refs = database.queryTableForeignKeyReferences(tname);
225             for (int p = 0; p < refs.length; ++p) {
226               checkColumnConstraint(col_name, refs[p].key_columns,
227                                     refs[p].key_table_name, refs[p].name);
228             }
229             // Or that it's part of a primary key
230
Transaction.ColumnGroup primary_key =
231                                    database.queryTablePrimaryKeyGroup(tname);
232             if (primary_key != null) {
233               checkColumnConstraint(col_name, primary_key.columns,
234                                     tname, primary_key.name);
235             }
236             // Or that it's part of a unique set
237
Transaction.ColumnGroup[] uniques =
238                                       database.queryTableUniqueGroups(tname);
239             for (int p = 0; p < uniques.length; ++p) {
240               checkColumnConstraint(col_name, uniques[p].columns,
241                                     tname, uniques[p].name);
242             }
243
244             mark_dropped = true;
245             table_altered = true;
246           }
247         }
248         // If not dropped then add to the new table definition.
249
if (!mark_dropped) {
250           new_table.addColumn(column);
251         }
252       }
253
254       // Add any new columns,
255
for (int i = 0; i < actions.size(); ++i) {
256         AlterTableAction action = (AlterTableAction) actions.get(i);
257         if (action.getAction().equals("ADD")) {
258           ColumnDef cdef = (ColumnDef) action.getElement(0);
259           if (cdef.isUnique() || cdef.isPrimaryKey()) {
260             throw new DatabaseException("Can not use UNIQUE or PRIMARY KEY " +
261               "column constraint when altering a column. Use " +
262               "ADD CONSTRAINT instead.");
263           }
264           // Convert to a DataTableColumnDef
265
DataTableColumnDef col = CreateTable.convertColumnDef(cdef);
266
267           checker.checkExpression(
268                              col.getDefaultExpression(database.getSystem()));
269           String JavaDoc col_name = col.getName();
270           // If column name starts with [table_name]. then strip it off
271
col.setName(checker.stripTableName(table_name, col_name));
272           new_table.addColumn(col);
273           table_altered = true;
274         }
275       }
276
277       // Any constraints to drop...
278
for (int i = 0; i < actions.size(); ++i) {
279         AlterTableAction action = (AlterTableAction) actions.get(i);
280         if (action.getAction().equals("DROP_CONSTRAINT")) {
281           String JavaDoc constraint_name = (String JavaDoc) action.getElement(0);
282           int drop_count = database.dropNamedConstraint(tname, constraint_name);
283           if (drop_count == 0) {
284             throw new DatabaseException(
285                  "Named constraint to drop on table " + tname +
286                  " was not found: " + constraint_name);
287           }
288         }
289         else if (action.getAction().equals("DROP_CONSTRAINT_PRIMARY_KEY")) {
290           boolean constraint_dropped =
291                         database.dropPrimaryKeyConstraintForTable(tname, null);
292           if (!constraint_dropped) {
293             throw new DatabaseException(
294                                  "No primary key to delete on table " + tname);
295           }
296         }
297       }
298
299       // Any constraints to add...
300
for (int i = 0; i < actions.size(); ++i) {
301         AlterTableAction action = (AlterTableAction) actions.get(i);
302         if (action.getAction().equals("ADD_CONSTRAINT")) {
303           ConstraintDef constraint = (ConstraintDef) action.getElement(0);
304           boolean foreign_constraint =
305                            (constraint.type == ConstraintDef.FOREIGN_KEY);
306           TableName ref_tname = null;
307           if (foreign_constraint) {
308             ref_tname =
309                  resolveTableName(constraint.reference_table_name, database);
310             if (database.isInCaseInsensitiveMode()) {
311               ref_tname = database.tryResolveCase(ref_tname);
312             }
313             constraint.reference_table_name = ref_tname.toString();
314           }
315
316           checker.stripColumnList(table_name, constraint.column_list);
317           checker.stripColumnList(constraint.reference_table_name,
318                                   constraint.column_list2);
319           checker.checkExpression(constraint.check_expression);
320           checker.checkColumnList(constraint.column_list);
321           if (foreign_constraint && constraint.column_list2 != null) {
322             ColumnChecker referenced_checker =
323                     ColumnChecker.standardColumnChecker(database, ref_tname);
324             referenced_checker.checkColumnList(constraint.column_list2);
325           }
326
327           CreateTable.addSchemaConstraint(database, tname, constraint);
328
329         }
330       }
331
332       // Alter the existing table to the new format...
333
if (table_altered) {
334         if (new_table.columnCount() == 0) {
335           throw new DatabaseException(
336                                    "Can not ALTER table to have 0 columns.");
337         }
338         database.updateTable(new_table);
339       }
340       else {
341         // If the table wasn't physically altered, check the constraints.
342
// Calling this method will also make the transaction check all
343
// deferred constraints during the next commit.
344
database.checkAllConstraints(tname);
345       }
346
347       // Return '0' if everything successful.
348
return FunctionTable.resultTable(context, 0);
349
350     }
351
352   }
353
354
355 }
356
Popular Tags