KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*
2
3    Derby - Class org.apache.derby.impl.sql.execute.SetConstraintsConstantAction
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.context.ContextManager;
25
26 import org.apache.derby.iapi.services.sanity.SanityManager;
27
28 import org.apache.derby.catalog.UUID;
29 import org.apache.derby.iapi.services.uuid.UUIDFactory;
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.StatementType;
36
37 import org.apache.derby.iapi.sql.dictionary.CheckConstraintDescriptor;
38 import org.apache.derby.iapi.sql.dictionary.ConglomerateDescriptor;
39 import org.apache.derby.iapi.sql.dictionary.ConstraintDescriptor;
40 import org.apache.derby.iapi.sql.dictionary.ConstraintDescriptorList;
41 import org.apache.derby.iapi.sql.dictionary.DataDescriptorGenerator;
42 import org.apache.derby.iapi.sql.dictionary.DataDictionary;
43 import org.apache.derby.iapi.sql.dictionary.DataDictionaryContext;
44 import org.apache.derby.iapi.sql.dictionary.ForeignKeyConstraintDescriptor;
45 import org.apache.derby.iapi.sql.dictionary.IndexRowGenerator;
46 import org.apache.derby.iapi.sql.dictionary.ReferencedKeyConstraintDescriptor;
47 import org.apache.derby.iapi.sql.dictionary.SchemaDescriptor;
48 import org.apache.derby.iapi.sql.dictionary.TableDescriptor;
49
50
51 import org.apache.derby.iapi.types.DataValueFactory;
52 import org.apache.derby.iapi.types.RowLocation;
53
54 import org.apache.derby.iapi.sql.depend.DependencyManager;
55
56 import org.apache.derby.iapi.sql.execute.ConstantAction;
57 import org.apache.derby.iapi.sql.execute.ExecIndexRow;
58 import org.apache.derby.iapi.sql.execute.ExecRow;
59
60 import org.apache.derby.iapi.sql.Activation;
61
62 import org.apache.derby.iapi.store.access.ConglomerateController;
63 import org.apache.derby.iapi.store.access.TransactionController;
64
65 import org.apache.derby.iapi.services.io.FormatableBitSet;
66
67 import java.util.Hashtable JavaDoc;
68 import java.util.Enumeration JavaDoc;
69
70 /**
71  * This class describes actions that are performed for a
72  * set constraint at Execution time.
73  * <p>
74  * Note that the dependency action we send is SET_CONSTRAINTS
75  * rather than ALTER_TABLE. We do this because we want
76  * to distinguish SET_CONSTRAINTS from ALTER_TABLE for
77  * error messages.
78  *
79  * @author jamie
80  */

81 class SetConstraintsConstantAction extends DDLConstantAction
82 {
83
84     private boolean enable;
85     private boolean unconditionallyEnforce;
86
87     /*
88     ** For the following fields, never access directly, always
89     ** get the constraint descript list via the private
90     ** method getConstraintDescriptorList() defined herein.
91     */

92     private ConstraintDescriptorList cdl;
93     private UUID[] cuuids;
94     private UUID[] tuuids;
95
96     // CONSTRUCTORS
97
/**
98      *Boilerplate
99      *
100      * @param cdl ConstraintDescriptorList
101      * @param enable true == turn them on, false == turn them off
102      * @param unconditionallyEnforce Replication sets this to true at
103      * the end of REFRESH. This forces us
104      * to run the included foreign key constraints even
105      * if they're already marked ENABLED.
106      */

107     SetConstraintsConstantAction
108     (
109         ConstraintDescriptorList cdl,
110         boolean enable,
111         boolean unconditionallyEnforce
112     )
113     {
114         this.cdl = cdl;
115         this.enable = enable;
116         this.unconditionallyEnforce = unconditionallyEnforce;
117     }
118
119     //////////////////////////////////////////////////////////////
120
//
121
// OBJECT SHADOWS
122
//
123
//////////////////////////////////////////////////////////////
124

125     public String JavaDoc toString()
126     {
127         // Do not put this under SanityManager.DEBUG - it is needed for
128
// error reporting.
129
return "SET CONSTRAINTS";
130     }
131
132     // INTERFACE METHODS
133

134
135     /**
136      * This is the guts of the Execution-time logic for DROP CONSTRAINT.
137      *
138      * @see ConstantAction#executeConstantAction
139      *
140      * @exception StandardException Thrown on failure
141      */

142     public void executeConstantAction( Activation activation )
143                         throws StandardException
144     {
145         ConstraintDescriptor cd;
146         TableDescriptor td;
147         ConstraintDescriptorList tmpCdl;
148         boolean enforceThisConstraint;
149
150         LanguageConnectionContext lcc = activation.getLanguageConnectionContext();
151         DataDictionary dd = lcc.getDataDictionary();
152         DependencyManager dm = dd.getDependencyManager();
153         TransactionController tc = lcc.getTransactionExecute();
154
155         tmpCdl = getConstraintDescriptorList(dd);
156
157         int[] enabledCol = new int[1];
158         enabledCol[0] = ConstraintDescriptor.SYSCONSTRAINTS_STATE_FIELD;
159         /*
160         ** Inform the data dictionary that we are about to write to it.
161         ** There are several calls to data dictionary "get" methods here
162         ** that might be done in "read" mode in the data dictionary, but
163         ** it seemed safer to do this whole operation in "write" mode.
164         **
165         ** We tell the data dictionary we're done writing at the end of
166         ** the transaction.
167         */

168         dd.startWriting(lcc);
169
170         /*
171         ** Callback to rep subclass
172         */

173         publishToTargets(activation);
174
175         boolean skipFKs = false;
176
177         /*
178         ** If the constraint list is empty, then we are getting
179         ** all constraints. In this case, don't bother going
180         ** after referencing keys (foreign keys) when we are
181         ** disabling a referenced key (pk or unique key) since
182         ** we know we'll hit it eventually.
183         */

184         if (tmpCdl == null)
185         {
186             skipFKs = true;
187             tmpCdl = dd.getConstraintDescriptors((TableDescriptor)null);
188         }
189     
190         Hashtable JavaDoc checkConstraintTables = null;
191         int cdlSize = tmpCdl.size();
192         for (int index = 0; index < cdlSize; index++)
193         {
194             cd = tmpCdl.elementAt(index);
195
196             /*
197             ** We are careful to enable this constraint before trying
198             ** to enable constraints that reference it. Similarly,
199             ** we disabled constraints that reference us before we
200             ** disable ourselves, to make sure everything works ok.
201             */

202             if (unconditionallyEnforce)
203             {
204                 enforceThisConstraint = true;
205             }
206             else
207             {
208                 enforceThisConstraint = (enable && !cd.isEnabled());
209             }
210
211             if (enforceThisConstraint)
212             {
213                 if (cd instanceof ForeignKeyConstraintDescriptor)
214                 {
215                     validateFKConstraint((ForeignKeyConstraintDescriptor)cd, dd, tc, lcc.getContextManager());
216                 }
217                 /*
218                 ** For check constraints, we build up a list of check constriants
219                 ** by table descriptor. Once we have collected them all, we
220                 ** execute them in a single query per table descriptor.
221                 */

222                 else if (cd instanceof CheckConstraintDescriptor)
223                 {
224                     td = cd.getTableDescriptor();
225
226                     if (checkConstraintTables == null)
227                     {
228                         checkConstraintTables = new Hashtable JavaDoc(10);
229                     }
230
231                     ConstraintDescriptorList tabCdl = (ConstraintDescriptorList)
232                                                 checkConstraintTables.get(td.getUUID());
233                     if (tabCdl == null)
234                     {
235                         tabCdl = new ConstraintDescriptorList();
236                         checkConstraintTables.put(td.getUUID(), tabCdl);
237                     }
238                     tabCdl.add(cd);
239                 }
240                 /*
241                 ** If we are enabling a constraint, we need to issue
242                 ** the invalidation on the underlying table rather than
243                 ** the constraint we are enabling. This is because
244                 ** stmts that were compiled against a disabled constraint
245                 ** have no depedency on that disabled constriant.
246                 */

247                 dm.invalidateFor(cd.getTableDescriptor(),
248                                     DependencyManager.SET_CONSTRAINTS_ENABLE, lcc);
249                 cd.setEnabled();
250                 dd.updateConstraintDescriptor(cd,
251                                             cd.getUUID(),
252                                             enabledCol,
253                                             tc);
254             }
255     
256             /*
257             ** If we are dealing with a referenced constraint, then
258             ** we find all of the constraints that reference this constraint.
259             ** Turn them on/off based on what we are doing to this
260             ** constraint.
261             */

262             if (!skipFKs &&
263                 (cd instanceof ReferencedKeyConstraintDescriptor))
264             {
265                 ForeignKeyConstraintDescriptor fkcd;
266                 ReferencedKeyConstraintDescriptor refcd;
267                 ConstraintDescriptorList fkcdl;
268     
269                 refcd = (ReferencedKeyConstraintDescriptor)cd;
270                 fkcdl = refcd.getForeignKeyConstraints(ReferencedKeyConstraintDescriptor.ALL);
271
272                 int fkcdlSize = fkcdl.size();
273                 for (int inner = 0; inner < fkcdlSize; inner++)
274                 {
275                     fkcd = (ForeignKeyConstraintDescriptor) fkcdl.elementAt(inner);
276                     if (enable && !fkcd.isEnabled())
277                     {
278                         dm.invalidateFor(fkcd.getTableDescriptor(),
279                                     DependencyManager.SET_CONSTRAINTS_ENABLE, lcc);
280                         validateFKConstraint(fkcd, dd, tc, lcc.getContextManager());
281                         fkcd.setEnabled();
282                         dd.updateConstraintDescriptor(fkcd,
283                                 fkcd.getUUID(),
284                                 enabledCol,
285                                 tc);
286                     }
287                     else if (!enable && fkcd.isEnabled())
288                     {
289                         dm.invalidateFor(fkcd, DependencyManager.SET_CONSTRAINTS_DISABLE,
290                                          lcc);
291                         fkcd.setDisabled();
292                         dd.updateConstraintDescriptor(fkcd,
293                                 fkcd.getUUID(),
294                                 enabledCol,
295                                 tc);
296                     }
297                 }
298             }
299     
300             if (!enable && cd.isEnabled())
301             {
302                 dm.invalidateFor(cd, DependencyManager.SET_CONSTRAINTS_DISABLE,
303                                  lcc);
304                 cd.setDisabled();
305                 dd.updateConstraintDescriptor(cd,
306                                                 cd.getUUID(),
307                                                 enabledCol,
308                                                 tc);
309             }
310         }
311
312         validateAllCheckConstraints(lcc, checkConstraintTables);
313     }
314
315     private void validateAllCheckConstraints(LanguageConnectionContext lcc, Hashtable JavaDoc ht)
316         throws StandardException
317     {
318         ConstraintDescriptorList cdl;
319         ConstraintDescriptor cd = null;
320         TableDescriptor td;
321         StringBuffer JavaDoc text;
322         StringBuffer JavaDoc constraintNames;
323
324         if (ht == null)
325         {
326             return;
327         }
328
329         for (Enumeration JavaDoc e = ht.elements(); e.hasMoreElements(); )
330         {
331         
332             cdl = (ConstraintDescriptorList) e.nextElement();
333             text = null;
334             constraintNames = null;
335
336             /*
337             ** Build up the text of all the constraints into one big
338             ** predicate. Also, we unfortunately have to build up a big
339             ** comma separated list of constraint names in case
340             ** there is an error (we are favoring speed over a very
341             ** explicit check constraint xxxx failed error message).
342             */

343             int cdlSize = cdl.size();
344             for (int index = 0; index < cdlSize; index++)
345             {
346                 cd = (CheckConstraintDescriptor) cdl.elementAt(index);
347                 if (text == null)
348                 {
349                     text = new StringBuffer JavaDoc("(").append(cd.getConstraintText()).append(") ");
350                     constraintNames = new StringBuffer JavaDoc(cd.getConstraintName());
351                 }
352                 else
353                 {
354                     text.append(" AND (").append(cd.getConstraintText()).append(") ");
355                     constraintNames.append(", ").append(cd.getConstraintName());
356                 }
357             }
358
359             if (SanityManager.DEBUG)
360             {
361                 SanityManager.ASSERT(text != null, "internal error, badly built hastable");
362             }
363
364             ConstraintConstantAction.validateConstraint(
365                                                 constraintNames.toString(),
366                                                 text.toString(),
367                                                 cd.getTableDescriptor(),
368                                                 lcc, true);
369         }
370     }
371
372     /*
373     **
374     */

375     private void validateFKConstraint
376     (
377         ForeignKeyConstraintDescriptor fk,
378         DataDictionary dd,
379         TransactionController tc,
380         ContextManager cm
381     )
382         throws StandardException
383     {
384         /*
385         ** Construct a template row
386         */

387         IndexRowGenerator irg = fk.getIndexConglomerateDescriptor(dd).getIndexDescriptor();
388         ExecIndexRow indexTemplateRow = irg.getIndexRowTemplate();
389         TableDescriptor td = fk.getTableDescriptor();
390         ExecRow baseRow = td.getEmptyExecRow(cm);
391         irg.getIndexRow(baseRow, getRowLocation(dd, td, tc),
392                                 indexTemplateRow, (FormatableBitSet)null);
393
394         /*
395         ** The moment of truth
396         */

397         ConstraintConstantAction.validateFKConstraint(tc, dd, fk,
398                             fk.getReferencedConstraint(), indexTemplateRow);
399     }
400             
401     /*
402     ** Get a row location template. Note that we are assuming that
403     ** the same row location can be used for all tables participating
404     ** in the fk. For example, if there are multiple foreign keys,
405     ** we are using the row location of one of the tables and assuming
406     ** that it is the right shape for all tables. Currently, this
407     ** is a legitimate assumption.
408     */

409     private RowLocation getRowLocation
410     (
411         DataDictionary dd,
412         TableDescriptor td,
413         TransactionController tc
414     )
415         throws StandardException
416     {
417         RowLocation rl;
418         ConglomerateController heapCC = null;
419
420         long tableId = td.getHeapConglomerateId();
421         heapCC =
422             tc.openConglomerate(
423                 tableId, false, 0, tc.MODE_RECORD, tc.ISOLATION_READ_COMMITTED);
424         try
425         {
426             rl = heapCC.newRowLocationTemplate();
427         }
428         finally
429         {
430             heapCC.close();
431         }
432
433         return rl;
434     }
435         
436     /*
437     ** Wrapper for constraint descriptor list -- always use
438     ** this to get the constriant descriptor list. It is
439     ** used to hide serialization.
440     */

441     private ConstraintDescriptorList getConstraintDescriptorList(DataDictionary dd)
442         throws StandardException
443     {
444         if (cdl != null)
445         {
446             return cdl;
447         }
448         if (tuuids == null)
449         {
450             return null;
451         }
452
453         /*
454         ** Reconstitute the cdl from the uuids
455         */

456         cdl = new ConstraintDescriptorList();
457
458         for (int i = 0; i < tuuids.length; i++)
459         {
460             TableDescriptor td = dd.getTableDescriptor(tuuids[i]);
461             if (SanityManager.DEBUG)
462             {
463                 if (td == null)
464                 {
465                     SanityManager.THROWASSERT("couldn't locate table descriptor "+
466                         "in SET CONSTRAINTS for uuid "+tuuids[i]);
467                 }
468             }
469
470             ConstraintDescriptor cd = dd.getConstraintDescriptorById(td, cuuids[i]);
471
472             if (SanityManager.DEBUG)
473             {
474                 if (cd == null)
475                 {
476                     SanityManager.THROWASSERT("couldn't locate constraint descriptor "+
477                         " in SET CONSTRAINTS for uuid "+cuuids[i]);
478                 }
479             }
480
481             cdl.add(cd);
482         }
483         return cdl;
484     }
485         
486     ///////////////////////////////////////////////
487
//
488
// MISC
489
//
490
///////////////////////////////////////////////
491

492     /**
493      * Do the work of publishing any this action to any
494      * replication targets. On a non-replicated source,
495      * this is a no-op.
496      *
497      * @param activation the activation
498      *
499      * @exception StandardException on error
500      */

501     protected void publishToTargets(Activation activation)
502         throws StandardException
503     {
504     }
505 }
506
Popular Tags