KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > h2 > command > ddl > AlterTableAddConstraint


1 /*
2  * Copyright 2004-2006 H2 Group. Licensed under the H2 License, Version 1.0 (http://h2database.com/html/license.html).
3  * Initial Developer: H2 Group
4  */

5 package org.h2.command.ddl;
6
7 import java.sql.SQLException JavaDoc;
8 import java.util.Arrays JavaDoc;
9 import java.util.HashSet JavaDoc;
10
11 import org.h2.constraint.Constraint;
12 import org.h2.constraint.ConstraintCheck;
13 import org.h2.constraint.ConstraintReferential;
14 import org.h2.constraint.ConstraintUnique;
15 import org.h2.engine.Database;
16 import org.h2.engine.Right;
17 import org.h2.engine.Session;
18 import org.h2.expression.Expression;
19 import org.h2.index.Index;
20 import org.h2.index.IndexType;
21 import org.h2.message.Message;
22 import org.h2.schema.Schema;
23 import org.h2.table.Column;
24 import org.h2.table.Table;
25 import org.h2.table.TableFilter;
26 import org.h2.util.ObjectArray;
27
28 /**
29  * @author Thomas
30  */

31
32 public class AlterTableAddConstraint extends SchemaCommand {
33
34     public static final int CHECK = 0, UNIQUE = 1, REFERENTIAL = 2, PRIMARY_KEY = 3;
35     public static final int REFERENTIAL_INTEGRITY_TRUE = 4;
36     public static final int REFERENTIAL_INTEGRITY_FALSE = 5;
37     private int type;
38     private String JavaDoc constraintName;
39     private String JavaDoc tableName;
40     private String JavaDoc[] columnNames;
41     private int deleteAction;
42     private int updateAction;
43     private Schema refSchema;
44     private String JavaDoc refTableName;
45     private String JavaDoc[] refColumnNames;
46     private Expression checkExpression;
47     private Index index, refIndex;
48     private String JavaDoc comment;
49
50     public AlterTableAddConstraint(Session session, Schema schema) {
51         super(session, schema);
52     }
53     
54     private String JavaDoc generateConstraintName(int id) throws SQLException JavaDoc {
55         if(constraintName == null) {
56             constraintName = getSchema().getUniqueConstraintName();
57         }
58         return constraintName;
59     }
60     
61     public int update() throws SQLException JavaDoc {
62         session.commit();
63         Database db = session.getDatabase();
64         if(getSchema().findConstraint(constraintName)!=null) {
65             throw Message.getSQLException(Message.CONSTRAINT_ALREADY_EXISTS_1,
66                     constraintName);
67         }
68         Constraint constraint;
69         Table table = getSchema().getTableOrView(session, tableName);
70         session.getUser().checkRight(table, Right.ALL);
71         table.lock(session, true);
72         switch(type) {
73         case CHECK: {
74             int id = getObjectId(true, true);
75             String JavaDoc name = generateConstraintName(id);
76             ConstraintCheck check = new ConstraintCheck(getSchema(), id, name, table);
77             TableFilter filter = new TableFilter(session, table, null, false);
78             checkExpression.mapColumns(filter, 0);
79             checkExpression = checkExpression.optimize(session);
80             check.setExpression(checkExpression);
81             check.setTableFilter(filter);
82             constraint = check;
83             break;
84         }
85         case UNIQUE: {
86             Column[] columns = table.getColumns(columnNames);
87             boolean isOwner = false;
88             if(index != null && canUseUniqueIndex(index, table, columns)) {
89                 isOwner = true;
90                 index.getIndexType().setBelongsToConstraint(true);
91             } else {
92                 index = getUniqueIndex(table, columns);
93                 if(index == null) {
94                     index = createIndex(table, columns, true);
95                     isOwner = true;
96                 }
97             }
98             int id = getObjectId(true, true);
99             String JavaDoc name = generateConstraintName(id);
100             ConstraintUnique unique = new ConstraintUnique(getSchema(), id, name, table);
101             unique.setColumns(columns);
102             unique.setIndex(index, isOwner);
103             constraint = unique;
104             break;
105         }
106         case REFERENTIAL: {
107             Table refTable = refSchema.getTableOrView(session, refTableName);
108             session.getUser().checkRight(refTable, Right.ALL);
109             boolean isOwner = false;
110             Column[] columns = table.getColumns(columnNames);
111             if(index != null && canUseIndex(index, table, columns)) {
112                 isOwner = true;
113                 index.getIndexType().setBelongsToConstraint(true);
114             } else {
115                 index = getIndex(table, columns);
116                 if(index == null) {
117                     index = createIndex(table, columns, false);
118                     isOwner = true;
119                 }
120             }
121             Column[] refColumns;
122             if(refColumnNames == null) {
123                 Index refIdx = refTable.getPrimaryKey();
124                 refColumns = refIdx.getColumns();
125             } else {
126                 refColumns = refTable.getColumns(refColumnNames);
127             }
128             if(refColumns.length != columns.length) {
129                 throw Message.getSQLException(Message.COLUMN_COUNT_DOES_NOT_MATCH);
130             }
131             boolean isRefOwner = false;
132             if(refIndex != null && refIndex.getTable() == refTable) {
133                 isRefOwner = true;
134                 refIndex.getIndexType().setBelongsToConstraint(true);
135             } else {
136                 refIndex = null;
137             }
138             if(refIndex == null) {
139                 refIndex = getUniqueIndex(refTable, refColumns);
140                 if(refIndex == null) {
141                     refIndex = createIndex(refTable, refColumns, true);
142                     isRefOwner = true;
143                 }
144             }
145             int id = getObjectId(true, true);
146             String JavaDoc name = generateConstraintName(id);
147             ConstraintReferential ref = new ConstraintReferential(getSchema(), id, name, table);
148             ref.setColumns(columns);
149             ref.setIndex(index, isOwner);
150             ref.setRefTable(refTable);
151             ref.setRefColumns(refColumns);
152             ref.setRefIndex(refIndex, isRefOwner);
153             constraint = ref;
154             refTable.addConstraint(constraint);
155             ref.setDeleteAction(session, deleteAction);
156             ref.setUpdateAction(session, updateAction);
157             break;
158         }
159         case REFERENTIAL_INTEGRITY_TRUE:
160             table.setCheckForeignKeyConstraints(true);
161             return 0;
162         case REFERENTIAL_INTEGRITY_FALSE:
163             table.setCheckForeignKeyConstraints(false);
164             return 0;
165         default:
166             throw Message.getInternalError("type="+type);
167         }
168         // parent relationship is already set with addConstraint
169
constraint.setComment(comment);
170         db.addSchemaObject(session, constraint);
171         table.addConstraint(constraint);
172         return 0;
173     }
174
175     private Index createIndex(Table t, Column[] cols, boolean unique) throws SQLException JavaDoc {
176         int indexId = getObjectId(true, false);
177         IndexType indexType;
178         if(unique) {
179             // TODO default index (hash or not; memory or not or same as table) for unique constraints
180
indexType = IndexType.createUnique(t.isPersistent(), false);
181         } else {
182             // TODO default index (memory or not or same as table) for unique constraints
183
indexType = IndexType.createNonUnique(t.isPersistent());
184         }
185         indexType.setBelongsToConstraint(true);
186         String JavaDoc prefix = constraintName == null ? "CONSTRAINT" : constraintName;
187         String JavaDoc indexName = getSchema().getUniqueIndexName(prefix + "_INDEX_");
188         return t.addIndex(session, indexName, indexId, cols, indexType, Index.EMPTY_HEAD, null);
189     }
190
191     public void setDeleteAction(int action) {
192         this.deleteAction = action;
193     }
194
195     public void setUpdateAction(int action) {
196         this.updateAction = action;
197     }
198
199     private Index getUniqueIndex(Table t, Column[] cols) {
200         ObjectArray list = t.getIndexes();
201         for(int i=0; i<list.size(); i++) {
202             Index index = (Index) list.get(i);
203             if(canUseUniqueIndex(index, t, cols)) {
204                 return index;
205             }
206         }
207         return null;
208     }
209     
210     private boolean canUseUniqueIndex(Index index, Table table, Column[] cols) {
211         if(index.getTable() != table || !index.getIndexType().isUnique()) {
212             return false;
213         }
214         if(index.getIndexType().belongsToConstraint()) {
215             // the constraint might be dropped (also in an alter table statement)
216
return false;
217         }
218         Column[] indexCols = index.getColumns();
219         if(indexCols.length > cols.length) {
220             return false;
221         }
222         HashSet JavaDoc set = new HashSet JavaDoc(Arrays.asList(cols));
223         for(int j=0; j<indexCols.length; j++) {
224             // all columns of the index must be part of the list,
225
// but not all columns of the list need to be part of the index
226
if(!set.contains(indexCols[j])) {
227                 return false;
228             }
229         }
230         return true;
231     }
232
233     private Index getIndex(Table t, Column[] cols) {
234         ObjectArray list = t.getIndexes();
235         for(int i=0; i<list.size(); i++) {
236             Index index = (Index) list.get(i);
237             if(canUseIndex(index, t, cols)) {
238                 return index;
239             }
240         }
241         return null;
242     }
243     
244     private boolean canUseIndex(Index index, Table table, Column[] cols) {
245         if(index.getTable() != table || index.getCreateSQL() == null) {
246             // can't use the scan index or index of another table
247
return false;
248         }
249         Column[] indexCols = index.getColumns();
250         if(indexCols.length < cols.length) {
251             return false;
252         }
253         for(int j=0; j<cols.length; j++) {
254             // all columns of the list must be part of the index,
255
// but not all columns of the index need to be part of the list
256
// holes are not allowed (index=a,b,c & list=a,b is ok; but list=a,c is not)
257
int idx = index.getColumnIndex(cols[j]);
258             if(idx < 0 || idx >= cols.length) {
259                 return false;
260             }
261         }
262         return true;
263     }
264
265     public void setConstraintName(String JavaDoc constraintName) {
266         this.constraintName = constraintName;
267     }
268
269     public void setType(int type) {
270         this.type = type;
271     }
272
273     public void setCheckExpression(Expression expression) {
274         this.checkExpression = expression;
275     }
276
277     public void setTableName(String JavaDoc tableName) {
278         this.tableName = tableName;
279     }
280
281     public void setColumnNames(String JavaDoc[] columnNames) {
282         this.columnNames = columnNames;
283     }
284
285     public void setRefTableName(Schema refSchema, String JavaDoc ref) {
286         this.refSchema = refSchema;
287         this.refTableName = ref;
288     }
289
290     public void setRefColumnNames(String JavaDoc[] cols) {
291         this.refColumnNames = cols;
292     }
293
294     public void setIndex(Index index) {
295         this.index = index;
296     }
297
298     public void setRefIndex(Index refIndex) {
299         this.refIndex = refIndex;
300     }
301     
302     public void setComment(String JavaDoc comment) {
303         this.comment = comment;
304     }
305     
306 }
307
Popular Tags