KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*
2
3    Derby - Class org.apache.derby.impl.sql.execute.ConstraintConstantAction
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 import org.apache.derby.catalog.UUID;
27 import org.apache.derby.iapi.services.uuid.UUIDFactory;
28
29 import org.apache.derby.iapi.error.StandardException;
30
31 import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;
32
33 import org.apache.derby.iapi.sql.dictionary.CheckConstraintDescriptor;
34 import org.apache.derby.iapi.sql.dictionary.ConglomerateDescriptor;
35 import org.apache.derby.iapi.sql.dictionary.ConstraintDescriptor;
36 import org.apache.derby.iapi.sql.dictionary.DataDescriptorGenerator;
37 import org.apache.derby.iapi.sql.dictionary.DataDictionary;
38 import org.apache.derby.iapi.sql.dictionary.DataDictionaryContext;
39 import org.apache.derby.iapi.sql.dictionary.ForeignKeyConstraintDescriptor;
40 import org.apache.derby.iapi.sql.dictionary.ReferencedKeyConstraintDescriptor;
41 import org.apache.derby.iapi.sql.dictionary.SchemaDescriptor;
42 import org.apache.derby.iapi.sql.dictionary.TableDescriptor;
43
44 import org.apache.derby.iapi.types.DataValueFactory;
45
46 import org.apache.derby.iapi.reference.SQLState;
47
48 import org.apache.derby.iapi.sql.execute.ConstantAction;
49 import org.apache.derby.iapi.sql.execute.ExecRow;
50
51 import org.apache.derby.iapi.sql.ResultSet;
52 import org.apache.derby.iapi.sql.Statement;
53 import org.apache.derby.iapi.sql.PreparedStatement;
54
55 import org.apache.derby.iapi.types.NumberDataValue;
56
57 import org.apache.derby.iapi.store.access.ConglomerateController;
58 import org.apache.derby.iapi.store.access.GroupFetchScanController;
59 import org.apache.derby.iapi.store.access.ScanController;
60 import org.apache.derby.iapi.store.access.TransactionController;
61
62 import org.apache.derby.iapi.types.DataValueDescriptor;
63
64 import org.apache.derby.catalog.UUID;
65
66 import org.apache.derby.iapi.services.io.FormatableBitSet;
67 /**
68  * This class describes actions that are ALWAYS performed for a
69  * constraint creation at Execution time.
70  *
71  * @version 0.1
72  * @author Jerry Brenner
73  */

74
75 public abstract class ConstraintConstantAction extends DDLSingleTableConstantAction
76 {
77
78     protected String JavaDoc constraintName;
79     protected int constraintType;
80     protected String JavaDoc tableName;
81     protected String JavaDoc schemaName;
82     protected UUID schemaId;
83     protected IndexConstantAction indexAction;
84
85     // CONSTRUCTORS
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 schema that table and constraint lives in.
94      * @param indexAction IndexConstantAction for constraint (if necessary)
95      * RESOLVE - the next parameter should go away once we use UUIDs
96      * (Generated constraint names will be based off of uuids)
97      */

98     ConstraintConstantAction(
99                        String JavaDoc constraintName,
100                        int constraintType,
101                        String JavaDoc tableName,
102                        UUID tableId,
103                        String JavaDoc schemaName,
104                        IndexConstantAction indexAction)
105     {
106         super(tableId);
107         this.constraintName = constraintName;
108         this.constraintType = constraintType;
109         this.tableName = tableName;
110         this.indexAction = indexAction;
111         this.schemaName = schemaName;
112
113         if (SanityManager.DEBUG)
114         {
115             SanityManager.ASSERT(schemaName != null, "Constraint schema name is null");
116         }
117     }
118
119     // Class implementation
120

121     /**
122      * Get the constraint type.
123      *
124      * @return The constraint type
125      */

126     public int getConstraintType()
127     {
128         return constraintType;
129     }
130
131     /**
132       * Get the constraint name
133       *
134       * @return the constraint name
135       */

136     public String JavaDoc getConstraintName() { return constraintName; }
137
138     /**
139       * Get the associated index constant action.
140       *
141       * @return the constant action for the backing index
142       */

143     public IndexConstantAction getIndexAction() { return indexAction; }
144
145     /**
146      * Make sure that the foreign key constraint is valid
147      * with the existing data in the target table. Open
148      * the table, if there aren't any rows, ok. If there
149      * are rows, open a scan on the referenced key with
150      * table locking at level 2. Pass in the scans to
151      * the BulkRIChecker. If any rows fail, barf.
152      *
153      * @param tc transaction controller
154      * @param dd data dictionary
155      * @param fk foreign key constraint
156      * @param refcd referenced key
157      * @param indexTemplateRow index template row
158      *
159      * @exception StandardException on error
160      */

161     static void validateFKConstraint
162     (
163         TransactionController tc,
164         DataDictionary dd,
165         ForeignKeyConstraintDescriptor fk,
166         ReferencedKeyConstraintDescriptor refcd,
167         ExecRow indexTemplateRow
168     )
169         throws StandardException
170     {
171
172         GroupFetchScanController refScan = null;
173
174         GroupFetchScanController fkScan =
175             tc.openGroupFetchScan(
176                 fk.getIndexConglomerateDescriptor(dd).getConglomerateNumber(),
177                 false, // hold
178
0, // read only
179
tc.MODE_TABLE, // already locked
180
tc.ISOLATION_READ_COMMITTED, // whatever
181
(FormatableBitSet)null, // retrieve all fields
182
(DataValueDescriptor[])null, // startKeyValue
183
ScanController.GE, // startSearchOp
184
null, // qualifier
185
(DataValueDescriptor[])null, // stopKeyValue
186
ScanController.GT // stopSearchOp
187
);
188
189         try
190         {
191             /*
192             ** If we have no rows, then we are ok. This will
193             ** catch the CREATE TABLE T (x int references P) case
194             ** (as well as an ALTER TABLE ADD CONSTRAINT where there
195             ** are no rows in the target table).
196             */

197             if (!fkScan.next())
198             {
199                 fkScan.close();
200                 return;
201             }
202
203             fkScan.reopenScan(
204                     (DataValueDescriptor[])null, // startKeyValue
205
ScanController.GE, // startSearchOp
206
null, // qualifier
207
(DataValueDescriptor[])null, // stopKeyValue
208
ScanController.GT // stopSearchOp
209
);
210
211             /*
212             ** Make sure each row in the new fk has a matching
213             ** referenced key. No need to get any special locking
214             ** on the referenced table because it cannot delete
215             ** any keys we match because it will block on the table
216             ** lock on the fk table (we have an ex tab lock on
217             ** the target table of this ALTER TABLE command).
218             ** Note that we are doing row locking on the referenced
219             ** table. We could speed things up and get table locking
220             ** because we are likely to be hitting a lot of rows
221             ** in the referenced table, but we are going to err
222             ** on the side of concurrency here.
223             */

224             refScan =
225                 tc.openGroupFetchScan(
226                     refcd.getIndexConglomerateDescriptor(dd).getConglomerateNumber(),
227                         false, // hold
228
0, // read only
229
tc.MODE_RECORD,
230                         tc.ISOLATION_READ_COMMITTED, // read committed is good enough
231
(FormatableBitSet)null, // retrieve all fields
232
(DataValueDescriptor[])null, // startKeyValue
233
ScanController.GE, // startSearchOp
234
null, // qualifier
235
(DataValueDescriptor[])null, // stopKeyValue
236
ScanController.GT // stopSearchOp
237
);
238
239             RIBulkChecker riChecker = new RIBulkChecker(refScan,
240                                         fkScan,
241                                         indexTemplateRow,
242                                         true, // fail on 1st failure
243
(ConglomerateController)null,
244                                         (ExecRow)null);
245
246             int numFailures = riChecker.doCheck();
247             if (numFailures > 0)
248             {
249                 StandardException se = StandardException.newException(SQLState.LANG_ADD_FK_CONSTRAINT_VIOLATION,
250                                     fk.getConstraintName(),
251                                     fk.getTableDescriptor().getName());
252                 throw se;
253             }
254         }
255         finally
256         {
257             if (fkScan != null)
258             {
259                 fkScan.close();
260                 fkScan = null;
261             }
262             if (refScan != null)
263             {
264                 refScan.close();
265                 refScan = null;
266             }
267         }
268     }
269
270     /**
271      * Evaluate a check constraint or not null column constraint.
272      * Generate a query of the
273      * form SELECT COUNT(*) FROM t where NOT(<check constraint>)
274      * and run it by compiling and executing it. Will
275      * work ok if the table is empty and query returns null.
276      *
277      * @param constraintName constraint name
278      * @param constraintText constraint text
279      * @param td referenced table
280      * @param lcc the language connection context
281      * @param isCheckConstraint the constraint is a check constraint
282      *
283      * @return true if null constraint passes, false otherwise
284      *
285      * @exception StandardException if check constraint fails
286      */

287      static boolean validateConstraint
288     (
289         String JavaDoc constraintName,
290         String JavaDoc constraintText,
291         TableDescriptor td,
292         LanguageConnectionContext lcc,
293         boolean isCheckConstraint
294     )
295         throws StandardException
296     {
297         StringBuffer JavaDoc checkStmt = new StringBuffer JavaDoc();
298         /* should not use select sum(not(<check-predicate>) ? 1: 0) because
299          * that would generate much more complicated code and may exceed Java
300          * limits if we have a large number of check constraints, beetle 4347
301          */

302         checkStmt.append("SELECT COUNT(*) FROM ");
303         checkStmt.append(td.getQualifiedName());
304         checkStmt.append(" WHERE NOT(");
305         checkStmt.append(constraintText);
306         checkStmt.append(")");
307     
308         ResultSet rs = null;
309         try
310         {
311             PreparedStatement ps = lcc.prepareInternalStatement(checkStmt.toString());
312
313             // This is a substatement; for now, we do not set any timeout
314
// for it. We might change this behaviour later, by linking
315
// timeout to its parent statement's timeout settings.
316
rs = ps.execute(lcc, false, 0L);
317             ExecRow row = rs.getNextRow();
318             if (SanityManager.DEBUG)
319             {
320                 if (row == null)
321                 {
322                     SanityManager.THROWASSERT("did not get any rows back from query: "+checkStmt.toString());
323                 }
324             }
325
326             DataValueDescriptor[] rowArray = row.getRowArray();
327             Number JavaDoc value = ((Number JavaDoc)((NumberDataValue)row.getRowArray()[0]).getObject());
328             /*
329             ** Value may be null if there are no rows in the
330             ** table.
331             */

332             if ((value != null) && (value.longValue() != 0))
333             {
334                 //check constraint violated
335
if (isCheckConstraint)
336                     throw StandardException.newException(SQLState.LANG_ADD_CHECK_CONSTRAINT_FAILED,
337                         constraintName, td.getQualifiedName(), value.toString());
338                 /*
339                  * for not null constraint violations exception will be thrown in caller
340                  * check constraint will not get here since exception is thrown
341                  * above
342                  */

343                 return false;
344             }
345         }
346         finally
347         {
348             if (rs != null)
349             {
350                 rs.close();
351             }
352         }
353         return true;
354     }
355 }
356
Popular Tags