KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > derby > impl > sql > execute > CreateConstraintConstantAction


1 /*
2
3    Derby - Class org.apache.derby.impl.sql.execute.CreateConstraintConstantAction
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.execute;
23
24 import org.apache.derby.iapi.services.sanity.SanityManager;
25
26
27 import org.apache.derby.catalog.UUID;
28 import org.apache.derby.iapi.services.uuid.UUIDFactory;
29 import org.apache.derby.catalog.types.ReferencedColumnsDescriptorImpl;
30
31 import org.apache.derby.iapi.error.StandardException;
32
33 import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;
34
35 import org.apache.derby.iapi.sql.dictionary.DDUtils;
36 import org.apache.derby.iapi.sql.dictionary.ColumnDescriptor;
37 import org.apache.derby.iapi.sql.dictionary.ConglomerateDescriptor;
38 import org.apache.derby.iapi.sql.dictionary.ConstraintDescriptor;
39 import org.apache.derby.iapi.sql.dictionary.DataDescriptorGenerator;
40 import org.apache.derby.iapi.sql.dictionary.DataDictionary;
41 import org.apache.derby.iapi.sql.dictionary.ForeignKeyConstraintDescriptor;
42 import org.apache.derby.iapi.sql.dictionary.ReferencedKeyConstraintDescriptor;
43 import org.apache.derby.iapi.sql.dictionary.SchemaDescriptor;
44 import org.apache.derby.iapi.sql.dictionary.TableDescriptor;
45
46 import org.apache.derby.iapi.reference.SQLState;
47
48 import org.apache.derby.iapi.sql.depend.DependencyManager;
49 import org.apache.derby.iapi.sql.depend.Provider;
50 import org.apache.derby.iapi.sql.depend.ProviderInfo;
51
52 import org.apache.derby.iapi.sql.execute.ConstantAction;
53
54 import org.apache.derby.iapi.sql.Activation;
55
56 import org.apache.derby.iapi.store.access.TransactionController;
57 import org.apache.derby.iapi.services.loader.ClassFactory;
58
59 /**
60  * This class describes actions that are ALWAYS performed for a
61  * constraint creation at Execution time.
62  *
63  * @version 0.1
64  * @author Jerry Brenner
65  */

66
67 public class CreateConstraintConstantAction extends ConstraintConstantAction
68 {
69     String JavaDoc[] columnNames;
70     private String JavaDoc constraintText;
71
72     private ConstraintInfo otherConstraintInfo;
73     private ClassFactory cf;
74
75     /*
76     ** Is this constraint to be created as enabled or not.
77     ** The only way to create a disabled constraint is by
78     ** publishing a disabled constraint.
79     */

80     private boolean enabled;
81
82     private ProviderInfo[] providerInfo;
83
84     // CONSTRUCTORS
85

86     /**
87      * Make one of these puppies.
88      *
89      * @param constraintName Constraint name.
90      * @param constraintType Constraint type.
91      * @param tableName Table name.
92      * @param tableId UUID of table.
93      * @param schemaName the schema that table and constraint lives in.
94      * @param columnNames String[] for column names
95      * @param indexAction IndexConstantAction for constraint (if necessary)
96      * @param constraintText Text for check constraint
97      * RESOLVE - the next parameter should go away once we use UUIDs
98      * (Generated constraint names will be based off of uuids)
99      * @param enabled Should the constraint be created as enabled
100      * (enabled == true), or disabled (enabled == false).
101      * @param otherConstraint information about the constraint that this references
102      * @param providerInfo Information on all the Providers
103      */

104     CreateConstraintConstantAction(
105                        String JavaDoc constraintName,
106                        int constraintType,
107                        String JavaDoc tableName,
108                        UUID tableId,
109                        String JavaDoc schemaName,
110                        String JavaDoc[] columnNames,
111                        IndexConstantAction indexAction,
112                        String JavaDoc constraintText,
113                        boolean enabled,
114                        ConstraintInfo otherConstraint,
115                        ProviderInfo[] providerInfo)
116     {
117         super(constraintName, constraintType, tableName,
118               tableId, schemaName, indexAction);
119         this.columnNames = columnNames;
120         this.constraintText = constraintText;
121         this.enabled = enabled;
122         this.otherConstraintInfo = otherConstraint;
123         this.providerInfo = providerInfo;
124     }
125
126     // INTERFACE METHODS
127

128
129     /**
130      * This is the guts of the Execution-time logic for CREATE CONSTRAINT.
131      *
132      * @see ConstantAction#executeConstantAction
133      *
134      * @exception StandardException Thrown on failure
135      */

136     public void executeConstantAction( Activation activation )
137                         throws StandardException
138     {
139         boolean forCreateTable;
140         ConglomerateDescriptor conglomDesc = null;
141         ConglomerateDescriptor[] conglomDescs = null;
142         ConstraintDescriptor conDesc = null;
143         TableDescriptor td = null;
144         UUID indexId = null;
145         String JavaDoc uniqueName;
146         String JavaDoc backingIndexName;
147
148         /* RESOLVE - blow off not null constraints for now (and probably for ever) */
149         if (constraintType == DataDictionary.NOTNULL_CONSTRAINT)
150         {
151             return;
152         }
153
154         LanguageConnectionContext lcc = activation.getLanguageConnectionContext();
155         DataDictionary dd = lcc.getDataDictionary();
156         DependencyManager dm = dd.getDependencyManager();
157         TransactionController tc = lcc.getTransactionExecute();
158
159         cf = lcc.getLanguageConnectionFactory().getClassFactory();
160
161         /* Remember whether or not we are doing a create table */
162         forCreateTable = activation.getForCreateTable();
163
164         /*
165         ** Inform the data dictionary that we are about to write to it.
166         ** There are several calls to data dictionary "get" methods here
167         ** that might be done in "read" mode in the data dictionary, but
168         ** it seemed safer to do this whole operation in "write" mode.
169         **
170         ** We tell the data dictionary we're done writing at the end of
171         ** the transaction.
172         */

173         dd.startWriting(lcc);
174
175         /* Table gets locked in AlterTableConstantAction */
176
177         /*
178         ** If the schema descriptor is null, then
179         ** we must have just read ourselves in.
180         ** So we will get the corresponding schema
181         ** descriptor from the data dictionary.
182         */

183
184         SchemaDescriptor sd = dd.getSchemaDescriptor(schemaName, tc, true);
185         
186         /* Try to get the TableDescriptor from
187          * the Activation. We will go to the
188          * DD if not there. (It should always be
189          * there except when in a target.)
190          */

191         td = activation.getDDLTableDescriptor();
192
193         if (td == null)
194         {
195             /* tableId will be non-null if adding a
196              * constraint to an existing table.
197              */

198             if (tableId != null)
199             {
200                 td = dd.getTableDescriptor(tableId);
201             }
202             else
203             {
204                 td = dd.getTableDescriptor(tableName, sd);
205             }
206
207             if (td == null)
208             {
209                 throw StandardException.newException(SQLState.LANG_TABLE_NOT_FOUND_DURING_EXECUTION, tableName);
210             }
211             activation.setDDLTableDescriptor(td);
212         }
213
214         /* Generate the UUID for the backing index. This will become the
215          * constraint's name, if no name was specified.
216          */

217         UUIDFactory uuidFactory = dd.getUUIDFactory();
218
219         /* Create the index, if there's one for this constraint */
220         if (indexAction != null)
221         {
222             if ( indexAction.getIndexName() == null )
223             {
224                 /* Set the index name */
225                 backingIndexName = uuidFactory.createUUID().toString();
226                 indexAction.setIndexName(backingIndexName);
227             }
228             else { backingIndexName = indexAction.getIndexName(); }
229
230             /* Create the index */
231             indexAction.executeConstantAction(activation);
232
233             /* Get the conglomerate descriptor for the backing index */
234             conglomDescs = td.getConglomerateDescriptors();
235
236             for (int index = 0; index < conglomDescs.length; index++)
237             {
238                 conglomDesc = conglomDescs[index];
239
240                 /* Check for conglomerate being an index first, since
241                  * name is null for heap.
242                  */

243                 if (conglomDesc.isIndex() &&
244                     backingIndexName.equals(conglomDesc.getConglomerateName()))
245                 {
246                     break;
247                 }
248             }
249
250             if (SanityManager.DEBUG)
251             {
252                 SanityManager.ASSERT(conglomDesc != null,
253                     "conglomDesc is expected to be non-null after search for backing index");
254                 SanityManager.ASSERT(conglomDesc.isIndex(),
255                     "conglomDesc is expected to be indexable after search for backing index");
256                 SanityManager.ASSERT(conglomDesc.getConglomerateName().equals(backingIndexName),
257                "conglomDesc name expected to be the same as backing index name after search for backing index");
258             }
259
260             indexId = conglomDesc.getUUID();
261         }
262
263         // if no constraintId was specified, we should generate one. this handles
264
// the two cases of Source creation and Target replication. At the source
265
// database, we allocate a new UUID. At the Target, we just use the UUID that
266
// the Source sent along.
267
UUID constraintId = uuidFactory.createUUID();
268
269         /* Now, lets create the constraint descriptor */
270         DataDescriptorGenerator ddg = dd.getDataDescriptorGenerator();
271         switch (constraintType)
272         {
273             case DataDictionary.PRIMARYKEY_CONSTRAINT:
274                 conDesc = ddg.newPrimaryKeyConstraintDescriptor(
275                                 td, constraintName,
276                                 false, //deferable,
277
false, //initiallyDeferred,
278
genColumnPositions(td, false), //int[],
279
constraintId,
280                                 indexId,
281                                 sd,
282                                 enabled,
283                                 0 // referenceCount
284
);
285                 dd.addConstraintDescriptor(conDesc, tc);
286                 break;
287
288             case DataDictionary.UNIQUE_CONSTRAINT:
289                 conDesc = ddg.newUniqueConstraintDescriptor(
290                                 td, constraintName,
291                                 false, //deferable,
292
false, //initiallyDeferred,
293
genColumnPositions(td, false), //int[],
294
constraintId,
295                                 indexId,
296                                 sd,
297                                 enabled,
298                                 0 // referenceCount
299
);
300                 dd.addConstraintDescriptor(conDesc, tc);
301                 break;
302
303             case DataDictionary.CHECK_CONSTRAINT:
304                 conDesc = ddg.newCheckConstraintDescriptor(
305                                 td, constraintName,
306                                 false, //deferable,
307
false, //initiallyDeferred,
308
constraintId,
309                                 constraintText,
310                                 new ReferencedColumnsDescriptorImpl(genColumnPositions(td, false)), //int[],
311
sd,
312                                 enabled
313                                 );
314                 dd.addConstraintDescriptor(conDesc, tc);
315                 break;
316
317             case DataDictionary.FOREIGNKEY_CONSTRAINT:
318                 ReferencedKeyConstraintDescriptor referencedConstraint = DDUtils.locateReferencedConstraint
319                     ( dd, td, constraintName, columnNames, otherConstraintInfo );
320                 DDUtils.validateReferentialActions(dd, td, constraintName, otherConstraintInfo,columnNames);
321                 
322                 conDesc = ddg.newForeignKeyConstraintDescriptor(
323                                 td, constraintName,
324                                 false, //deferable,
325
false, //initiallyDeferred,
326
genColumnPositions(td, false), //int[],
327
constraintId,
328                                 indexId,
329                                 sd,
330                                 referencedConstraint,
331                                 enabled,
332                                 otherConstraintInfo.getReferentialActionDeleteRule(),
333                                 otherConstraintInfo.getReferentialActionUpdateRule()
334                                 );
335
336                 // try to create the constraint first, because it
337
// is expensive to do the bulk check, find obvious
338
// errors first
339
dd.addConstraintDescriptor(conDesc, tc);
340
341                 /* No need to do check if we're creating a
342                  * table.
343                  */

344                 if ( (! forCreateTable) &&
345                      dd.activeConstraint( conDesc ) )
346                 {
347                     validateFKConstraint(tc,
348                                          dd,
349                                          (ForeignKeyConstraintDescriptor)conDesc,
350                                          referencedConstraint,
351                                          ((CreateIndexConstantAction)indexAction).getIndexTemplateRow());
352                 }
353                 
354                 /* Create stored dependency on the referenced constraint */
355                 dm.addDependency(conDesc, referencedConstraint, lcc.getContextManager());
356                 //store constraint's dependency on REFERENCES privileges in the dependeny system
357
storeConstraintDependenciesOnPrivileges(activation, conDesc, referencedConstraint.getTableId());
358                 break;
359
360             default:
361                 if (SanityManager.DEBUG)
362                 {
363                     SanityManager.THROWASSERT("contraintType (" + constraintType +
364                         ") has unexpected value");
365                 }
366                 break;
367         }
368
369         /* Create stored dependencies for each provider */
370         if (providerInfo != null)
371         {
372             for (int ix = 0; ix < providerInfo.length; ix++)
373             {
374                 Provider provider = null;
375     
376                 /* We should always be able to find the Provider */
377                 try
378                 {
379                     provider = (Provider) providerInfo[ix].
380                                             getDependableFinder().
381                                                 getDependable(
382                                                     providerInfo[ix].getObjectId());
383                 }
384                 catch(java.sql.SQLException JavaDoc te)
385                 {
386                     if (SanityManager.DEBUG)
387                     {
388                         SanityManager.THROWASSERT("unexpected java.sql.SQLException - " + te);
389                     }
390                 }
391                 dm.addDependency(conDesc, provider, lcc.getContextManager());
392             }
393         }
394
395         /* Finally, invalidate off of the table descriptor(s)
396          * to ensure that any dependent statements get
397          * re-compiled.
398          */

399         if (! forCreateTable)
400         {
401             dm.invalidateFor(td, DependencyManager.CREATE_CONSTRAINT, lcc);
402         }
403         if (constraintType == DataDictionary.FOREIGNKEY_CONSTRAINT)
404         {
405             if (SanityManager.DEBUG)
406             {
407                 SanityManager.ASSERT(conDesc != null,
408                     "conDesc expected to be non-null");
409
410                 if (! (conDesc instanceof ForeignKeyConstraintDescriptor))
411                 {
412                     SanityManager.THROWASSERT(
413                         "conDesc expected to be instance of ForeignKeyConstraintDescriptor, not " +
414                         conDesc.getClass().getName());
415                 }
416             }
417             dm.invalidateFor(
418                 ((ForeignKeyConstraintDescriptor)conDesc).
419                     getReferencedConstraint().
420                         getTableDescriptor(),
421                 DependencyManager.CREATE_CONSTRAINT, lcc);
422         }
423     }
424     
425     /**
426      * Is the constant action for a foreign key
427      *
428      * @return true/false
429      */

430     public boolean isForeignKeyConstraint()
431     {
432         return (constraintType == DataDictionary.FOREIGNKEY_CONSTRAINT);
433     }
434
435     /**
436      * Generate an array of column positions for the column list in
437      * the constraint.
438      *
439      * @param td The TableDescriptor for the table in question
440      * @param columnsMustBeOrderable true for primaryKey and unique constraints
441      *
442      * @return int[] The column positions.
443      */

444     private int[] genColumnPositions(TableDescriptor td,
445                                      boolean columnsMustBeOrderable)
446         throws StandardException
447     {
448         int[] baseColumnPositions;
449
450         // Translate the base column names to column positions
451
baseColumnPositions = new int[columnNames.length];
452         for (int i = 0; i < columnNames.length; i++)
453         {
454             ColumnDescriptor columnDescriptor;
455
456             // Look up the column in the data dictionary
457
columnDescriptor = td.getColumnDescriptor(columnNames[i]);
458             if (columnDescriptor == null)
459             {
460                 throw StandardException.newException(SQLState.LANG_COLUMN_NOT_FOUND_IN_TABLE,
461                                                             columnNames[i],
462                                                             tableName);
463             }
464
465             // Don't allow a column to be created on a non-orderable type
466
// (for primaryKey and unique constraints)
467
if ( columnsMustBeOrderable &&
468                  ( ! columnDescriptor.getType().getTypeId().orderable(
469                                                             cf))
470                )
471             {
472                 throw StandardException.newException(SQLState.LANG_COLUMN_NOT_ORDERABLE_DURING_EXECUTION,
473                     columnDescriptor.getType().getTypeId().getSQLTypeName());
474             }
475
476             // Remember the position in the base table of each column
477
baseColumnPositions[i] = columnDescriptor.getPosition();
478         }
479
480         return baseColumnPositions;
481     }
482     ///////////////////////////////////////////////////////////////////////
483
//
484
// ACCESSORS
485
//
486
///////////////////////////////////////////////////////////////////////
487

488     /**
489       * Get the names of the columns touched by this constraint.
490       *
491       * @return the array of touched column names.
492       */

493     public String JavaDoc[] getColumnNames() { return columnNames; }
494
495
496     /**
497       * Get the text defining this constraint.
498       *
499       * @return constraint text
500       */

501     public String JavaDoc getConstraintText() { return constraintText; }
502
503     public String JavaDoc toString()
504     {
505         // Do not put this under SanityManager.DEBUG - it is needed for
506
// error reporting.
507
StringBuffer JavaDoc strbuf = new StringBuffer JavaDoc();
508         strbuf.append( "CREATE CONSTRAINT " + constraintName );
509         strbuf.append("\n=========================\n");
510
511         if (columnNames == null)
512         {
513             strbuf.append("columnNames == null\n");
514         }
515         else
516         {
517             for (int ix=0; ix < columnNames.length; ix++)
518             {
519                 strbuf.append("\n\tcol["+ix+"]"+columnNames[ix].toString());
520             }
521         }
522         
523         strbuf.append("\n");
524         strbuf.append(constraintText);
525         strbuf.append("\n");
526         if (otherConstraintInfo != null)
527         {
528             strbuf.append(otherConstraintInfo.toString());
529         }
530         strbuf.append("\n");
531         return strbuf.toString();
532     }
533 }
534
Popular Tags