Source Code Cross Referenced for DDUtils.java in  » Database-DBMS » db-derby-10.2 » org » apache » derby » iapi » sql » dictionary » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Database DBMS » db derby 10.2 » org.apache.derby.iapi.sql.dictionary 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:
003:           Derby - Class org.apache.derby.iapi.sql.dictionary.DDUtils
004:
005:           Licensed to the Apache Software Foundation (ASF) under one or more
006:           contributor license agreements.  See the NOTICE file distributed with
007:           this work for additional information regarding copyright ownership.
008:           The ASF licenses this file to you under the Apache License, Version 2.0
009:           (the "License"); you may not use this file except in compliance with
010:           the License.  You may obtain a copy of the License at
011:
012:              http://www.apache.org/licenses/LICENSE-2.0
013:
014:           Unless required by applicable law or agreed to in writing, software
015:           distributed under the License is distributed on an "AS IS" BASIS,
016:           WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017:           See the License for the specific language governing permissions and
018:           limitations under the License.
019:
020:         */
021:
022:        package org.apache.derby.iapi.sql.dictionary;
023:
024:        import org.apache.derby.iapi.error.StandardException;
025:
026:        import org.apache.derby.iapi.reference.SQLState;
027:        import org.apache.derby.iapi.sql.StatementType;
028:        import java.util.Hashtable;
029:        import org.apache.derby.iapi.services.sanity.SanityManager;
030:        import org.apache.derby.iapi.services.i18n.MessageService;
031:        import java.util.Enumeration;
032:
033:        /**
034:         *	Static Data dictionary utilities.
035:         *
036:         * @version 0.1
037:         * @author Rick Hillegas
038:         */
039:
040:        public class DDUtils {
041:
042:            /*
043:             ** For a foreign key, this is used to locate the referenced
044:             ** key using the ConstraintInfo.  If it doesn't find the
045:             ** correct constraint it will throw an error.
046:             */
047:            public static ReferencedKeyConstraintDescriptor locateReferencedConstraint(
048:                    DataDictionary dd, TableDescriptor td,
049:                    String myConstraintName, // for error messages
050:                    String[] myColumnNames, ConsInfo otherConstraintInfo)
051:                    throws StandardException {
052:                TableDescriptor refTd = otherConstraintInfo
053:                        .getReferencedTableDescriptor(dd);
054:                if (refTd == null) {
055:                    throw StandardException.newException(
056:                            SQLState.LANG_INVALID_FK_NO_REF_TAB,
057:                            myConstraintName, otherConstraintInfo
058:                                    .getReferencedTableName());
059:                }
060:
061:                ReferencedKeyConstraintDescriptor refCd = null;
062:
063:                /*
064:                 ** There were no column names specified, just find
065:                 ** the primary key on the table in question
066:                 */
067:                String[] refColumnNames = otherConstraintInfo
068:                        .getReferencedColumnNames();
069:                if (refColumnNames == null || refColumnNames.length == 0) {
070:                    refCd = refTd.getPrimaryKey();
071:                    if (refCd == null) {
072:                        throw StandardException.newException(
073:                                SQLState.LANG_INVALID_FK_NO_PK,
074:                                myConstraintName, refTd.getQualifiedName());
075:                    }
076:
077:                    ColumnDescriptorList cdl = getColumnDescriptors(dd, td,
078:                            myColumnNames);
079:
080:                    /*
081:                     ** Check the column list length to give a more informative
082:                     ** error in case they aren't the same.
083:                     */
084:                    if (cdl.size() != refCd.getColumnDescriptors().size()) {
085:                        throw StandardException.newException(
086:                                SQLState.LANG_INVALID_FK_DIFFERENT_COL_COUNT,
087:                                myConstraintName, String.valueOf(cdl.size()),
088:                                String.valueOf(refCd.getColumnDescriptors()
089:                                        .size()));
090:                    }
091:
092:                    /*
093:                     ** Make sure all types are the same.
094:                     */
095:                    if (!refCd.areColumnsComparable(cdl)) {
096:                        throw StandardException
097:                                .newException(
098:                                        SQLState.LANG_INVALID_FK_COL_TYPES_DO_NOT_MATCH,
099:                                        myConstraintName);
100:                    }
101:
102:                    return refCd;
103:                }
104:
105:                /*
106:                 ** Check the referenced columns vs. each unique or primary key to
107:                 ** see if they match the foreign key.
108:                 */
109:                else {
110:                    ConstraintDescriptor cd;
111:
112:                    ColumnDescriptorList colDl = getColumnDescriptors(dd, td,
113:                            myColumnNames);
114:                    ConstraintDescriptorList refCDL = dd
115:                            .getConstraintDescriptors(refTd);
116:
117:                    int refCDLSize = refCDL.size();
118:                    for (int index = 0; index < refCDLSize; index++) {
119:                        cd = refCDL.elementAt(index);
120:
121:                        /*
122:                         ** Matches if it is not a check or fk, and
123:                         ** all the types line up.
124:                         */
125:                        if ((cd instanceof  ReferencedKeyConstraintDescriptor)
126:                                && cd.areColumnsComparable(colDl)
127:                                && columnNamesMatch(refColumnNames, cd
128:                                        .getColumnDescriptors())) {
129:                            return (ReferencedKeyConstraintDescriptor) cd;
130:                        }
131:                    }
132:
133:                    /*
134:                     ** If we got here, we didn't find anything
135:                     */
136:                    throw StandardException.newException(
137:                            SQLState.LANG_INVALID_FK_NO_REF_KEY,
138:                            myConstraintName, refTd.getQualifiedName());
139:                }
140:            }
141:
142:            public static ColumnDescriptorList getColumnDescriptors(
143:                    DataDictionary dd, TableDescriptor td, String[] columnNames)
144:                    throws StandardException {
145:                ColumnDescriptorList cdl = new ColumnDescriptorList();
146:                for (int colCtr = 0; colCtr < columnNames.length; colCtr++) {
147:                    ColumnDescriptor cd = td
148:                            .getColumnDescriptor(columnNames[colCtr]);
149:                    cdl.add(td.getUUID(), cd);
150:                }
151:                return cdl;
152:            }
153:
154:            public static boolean columnNamesMatch(String[] columnNames,
155:                    ColumnDescriptorList cdl) throws StandardException {
156:                if (columnNames.length != cdl.size()) {
157:                    return false;
158:                }
159:
160:                String name;
161:                for (int index = 0; index < columnNames.length; index++) {
162:                    name = ((ColumnDescriptor) cdl.elementAt(index))
163:                            .getColumnName();
164:                    if (!name.equals(columnNames[index])) {
165:                        return false;
166:                    }
167:                }
168:
169:                return true;
170:            }
171:
172:            /*
173:             **checks whether the foreign key relation ships referential action
174:             **is violating the restrictions we have in the current system.
175:             **/
176:            public static void validateReferentialActions(DataDictionary dd,
177:                    TableDescriptor td, String myConstraintName, // for error messages
178:                    ConsInfo otherConstraintInfo, String[] columnNames)
179:                    throws StandardException {
180:
181:                int refAction = otherConstraintInfo
182:                        .getReferentialActionDeleteRule();
183:
184:                //Do not allow ON DELETE SET NULL as a referential action 
185:                //if none of the foreign key columns are  nullable.
186:                if (refAction == StatementType.RA_SETNULL) {
187:                    boolean foundNullableColumn = false;
188:                    //check if we have a nullable foreign key column
189:                    for (int colCtr = 0; colCtr < columnNames.length; colCtr++) {
190:                        ColumnDescriptor cd = td
191:                                .getColumnDescriptor(columnNames[colCtr]);
192:                        if ((cd.getType().isNullable())) {
193:                            foundNullableColumn = true;
194:                            break;
195:                        }
196:                    }
197:
198:                    if (!foundNullableColumn) {
199:                        throw StandardException.newException(
200:                                SQLState.LANG_INVALID_FK_COL_FOR_SETNULL,
201:                                myConstraintName);
202:                    }
203:                }
204:
205:                //check whether the foreign key relation ships referential action
206:                //is not violating the restrictions we have in the current system.
207:                TableDescriptor refTd = otherConstraintInfo
208:                        .getReferencedTableDescriptor(dd);
209:                Hashtable deleteConnHashtable = new Hashtable();
210:                //find whether the foreign key is self referencing.
211:                boolean isSelfReferencingFk = (refTd.getUUID().equals(td
212:                        .getUUID()));
213:                String refTableName = refTd.getSchemaName() + "."
214:                        + refTd.getName();
215:                //look for the other foreign key constraints on this table first
216:                int currentSelfRefValue = getCurrentDeleteConnections(dd, td,
217:                        -1, deleteConnHashtable, false, true);
218:                validateDeleteConnection(dd, td, refTd, refAction,
219:                        deleteConnHashtable, (Hashtable) deleteConnHashtable
220:                                .clone(), true, myConstraintName, false,
221:                        new StringBuffer(0), refTableName, isSelfReferencingFk,
222:                        currentSelfRefValue);
223:
224:                //if it not a selfreferencing key check for violation of exiting connections.
225:                if (!isSelfReferencingFk) {
226:                    checkForAnyExistingDeleteConnectionViolations(dd, td,
227:                            refAction, deleteConnHashtable, myConstraintName);
228:                }
229:            }
230:
231:            /*
232:             ** Finds the existing delete connection for the table and the referential
233:             ** actions that will occur  and stores the information in the hash table.
234:             ** HashTable (key , value) = ( table name that this table is delete
235:             ** connected to, referential action that will occur if there is a delete on
236:             ** the table this table connected to[CASACDE, SETNULL , RESTRICT ...etc).)
237:             **/
238:
239:            private static int getCurrentDeleteConnections(DataDictionary dd,
240:                    TableDescriptor td, int refActionType, Hashtable dch,
241:                    boolean prevNotCascade, boolean findSelfRef)
242:                    throws StandardException {
243:
244:                int selfRefValue = -1; //store the self reference referential action 
245:
246:                //make sure we get any foreign key constraints added earlier in the same statement.
247:                td.emptyConstraintDescriptorList();
248:                ConstraintDescriptorList cdl = dd.getConstraintDescriptors(td);
249:                int cdlSize = cdl.size();
250:
251:                boolean passedInPrevNotCascade = prevNotCascade;
252:                for (int index = 0; index < cdlSize; index++) {
253:                    ConstraintDescriptor cd = cdl.elementAt(index);
254:
255:                    //look for  foreign keys
256:                    if ((cd instanceof  ForeignKeyConstraintDescriptor)) {
257:                        ForeignKeyConstraintDescriptor fkcd = (ForeignKeyConstraintDescriptor) cd;
258:                        String constraintName = fkcd.getConstraintName();
259:                        int raDeleteRule = fkcd.getRaDeleteRule();
260:                        int raUpdateRule = fkcd.getRaUpdateRule();
261:
262:                        if (findSelfRef && fkcd.isSelfReferencingFK()) {
263:                            //All self references will have same  referential actions type
264:                            selfRefValue = raDeleteRule;
265:                            findSelfRef = false;
266:                        }
267:
268:                        ReferencedKeyConstraintDescriptor refcd = fkcd
269:                                .getReferencedConstraint();
270:                        TableDescriptor refTd = refcd.getTableDescriptor();
271:                        int childRefAction = refActionType == -1 ? raDeleteRule
272:                                : refActionType;
273:
274:                        String refTableName = refTd.getSchemaName() + "."
275:                                + refTd.getName();
276:                        //check with  the existing references.
277:                        Integer rAction = ((Integer) dch.get(refTableName));
278:                        if (rAction != null) // we already looked at this table
279:                        {
280:                            prevNotCascade = passedInPrevNotCascade;
281:                            continue;
282:                        }
283:
284:                        //if we are not cascading, check whether the link before
285:                        //this was cascade or not. If we travel through  two NON CASCADE ACTION
286:                        //links then the  delete connection is broken(only a delete can have further
287:                        // referential effects)
288:                        if (raDeleteRule != StatementType.RA_CASCADE) {
289:                            if (prevNotCascade) {
290:                                prevNotCascade = passedInPrevNotCascade;
291:                                continue;
292:                            } else
293:                                prevNotCascade = true;
294:                        }
295:
296:                        //store the delete connection info in the hash table,
297:                        //note that the referential action value is not what is
298:                        //not specified on the current link. It is actually the 
299:                        //value of what happens to the table whose delete
300:                        // connections we are finding.
301:                        dch.put(refTableName, (new Integer(childRefAction)));
302:
303:                        //find the next delete conectiions on this path for non
304:                        //self referencig delete connections.
305:                        if (!fkcd.isSelfReferencingFK())
306:                            getCurrentDeleteConnections(dd, refTd,
307:                                    childRefAction, dch, true, false);
308:                        prevNotCascade = passedInPrevNotCascade;
309:                    }
310:                }
311:
312:                return selfRefValue;
313:            }
314:
315:            /*
316:             ** Following function validates whether the new foreign key relation ship
317:             ** violates any restriction on the referential actions. Current refAction
318:             ** implementation does not allow cases where we can possible land up
319:             ** having multiple action for the same row in a table, this happens becase
320:             ** user can possibly define differential action through multiple paths.
321:             ** Following function throws error while creating foreign keys if the new
322:             ** releations ship leads to any such conditions.
323:             ** NOTE : SQL99 standard also does not cleary says what we are suppose to do
324:             ** in these non determenistic cases. 
325:             ** Our implementation just follows what is did in DB2 and throws error
326:             ** messaged similar to DB2 (sql0632N, sql0633N, sql0634N)
327:             */
328:
329:            private static void validateDeleteConnection(
330:                    DataDictionary dd,
331:                    TableDescriptor actualTd, // the table we are adding the foriegn key.
332:                    TableDescriptor refTd,
333:                    int refActionType,
334:                    Hashtable dch,
335:                    Hashtable ech, //existing delete connections
336:                    boolean checkImmediateRefTable, String myConstraintName,
337:                    boolean prevNotCascade, StringBuffer cycleString,
338:                    String currentRefTableName, //the name of the table we are referring too.
339:                    boolean isSelfReferencingFk, int currentSelfRefValue)
340:                    throws StandardException {
341:
342:                Integer rAction;
343:
344:                String refTableName = refTd.getSchemaName() + "."
345:                        + refTd.getName();
346:
347:                /*
348:                 ** Validate the new referentail action value with respect to the 
349:                 ** already existing connections to this table we gathered  from
350:                 ** the getCurrentDeleteConnections() call.
351:                 */
352:
353:                if (checkImmediateRefTable) {
354:                    rAction = ((Integer) dch.get(refTableName));
355:
356:                    // check possible invalide cases incase of self referencing foreign key
357:                    if (isSelfReferencingFk) {
358:                        //All the relation ship referring to a table should have the
359:                        //same refaction except incase of SET NULL. In this case
360:                        //it is the same table , so we have to check with existing self
361:                        //referencing actions.
362:                        if (currentSelfRefValue != -1) {
363:                            if (currentSelfRefValue != refActionType) {
364:                                //If there is a SET NULL relation ship we can not have any
365:                                // other relation ship with it.
366:                                if (currentSelfRefValue == StatementType.RA_SETNULL)
367:                                    throw generateError(
368:                                            SQLState.LANG_CANT_BE_DEPENDENT_ESELF,
369:                                            myConstraintName,
370:                                            currentRefTableName);
371:                                else {
372:                                    /*
373:                                     ** case where we can cleary say what the
374:                                     ** referential actions should be. Like,	   
375:                                     ** if there is NO ACTION relationsip
376:                                     **already, new relation ship also shold be NO ACTION. 
377:                                     */
378:                                    throw generateError(
379:                                            SQLState.LANG_DELETE_RULE_MUSTBE_ESELF,
380:                                            myConstraintName,
381:                                            currentSelfRefValue);
382:                                }
383:                            } else {
384:                                //more than one  ON DELET SET NULL to the same table is not allowed
385:                                if (currentSelfRefValue == StatementType.RA_SETNULL
386:                                        && refActionType == StatementType.RA_SETNULL) {
387:                                    throw generateError(
388:                                            SQLState.LANG_CANT_BE_DEPENDENT_ESELF,
389:                                            myConstraintName,
390:                                            currentRefTableName);
391:                                }
392:                            }
393:                        }
394:
395:                        /*
396:                         ** If the new releation ship is self referencing and if
397:                         ** the current existing relation ship to other tables is
398:                         ** CASCADE type them  new self reference should be of type
399:                         ** CASCADE, otherwise we should throw error.
400:                         */
401:
402:                        if (isSelfReferencingFk
403:                                && dch.contains(new Integer(
404:                                        StatementType.RA_CASCADE))
405:                                && refActionType != StatementType.RA_CASCADE) {
406:                            throw generateError(
407:                                    SQLState.LANG_DELETE_RULE_MUSTBE_ECASCADE,
408:                                    myConstraintName, StatementType.RA_CASCADE);
409:                        }
410:
411:                        //end of possible error case scenarios for self reference key additions
412:                        return;
413:                    }
414:
415:                    //cases where the new  reference is referring to  another table
416:
417:                    //check whether it matched with existing self references.
418:                    // If A self-referencing constraint exists with a delete rule of
419:                    // SET NULL,  NO ACTION or RESTRICT. We can not add CASCADE
420:                    // relationship with another table.
421:
422:                    if (currentSelfRefValue != -1) {
423:                        if (refActionType == StatementType.RA_CASCADE
424:                                && currentSelfRefValue != StatementType.RA_CASCADE) {
425:                            throw generateError(
426:                                    SQLState.LANG_DELETE_RULE_CANT_BE_CASCADE_ESELF,
427:                                    myConstraintName);
428:
429:                        }
430:
431:                    }
432:
433:                    //check for the cases with existing relationships to the
434:                    //referenced table
435:                    if (rAction != null) {
436:                        checkForMultiplePathInvalidCases(rAction.intValue(),
437:                                refActionType, myConstraintName,
438:                                currentRefTableName);
439:                    }
440:
441:                    //mark the current connect to the reference table to identify the cycle.
442:                    if (refActionType != StatementType.RA_CASCADE) {
443:                        prevNotCascade = true;
444:                    }
445:
446:                    /*
447:                     ** cycle string is used to keep track of the referential actions of 
448:                     ** the nodes we visited, this is required to make sure that in case
449:                     ** of cycles , all the nodes in the cycle have same type of
450:                     ** referential action.
451:                     **/
452:                    cycleString = cycleString.append(refActionType);
453:                }
454:
455:                boolean passedInPrevNotCascade = prevNotCascade;
456:
457:                //delete connection is broken for if we see ON DELET SET NULL link
458:                // one level deeper than the table we are adding the foreing key
459:                //Where as to check for cycles we need to go for more level also;
460:                // To check cases like CASCADE CASCADE SET NULL cycle is not valid. 
461:                //Following variable is used make the distinction.
462:                boolean multiPathCheck = true;
463:
464:                // check for cases where the new connection we are forming to the 
465:                // reference table could create invalid any cycles or mutiple paths 
466:                // with the delete-connections the  referencing table might have already.
467:                ConstraintDescriptorList refCDL = dd
468:                        .getConstraintDescriptors(refTd);
469:                int refCDLSize = refCDL.size();
470:                for (int index = 0; index < refCDLSize; index++) {
471:                    ConstraintDescriptor cd = refCDL.elementAt(index);
472:
473:                    if ((cd instanceof  ForeignKeyConstraintDescriptor)) {
474:                        ForeignKeyConstraintDescriptor fkcd = (ForeignKeyConstraintDescriptor) cd;
475:                        String constraintName = fkcd.getConstraintName();
476:                        int raDeleteRule = fkcd.getRaDeleteRule();
477:                        int raUpdateRule = fkcd.getRaUpdateRule();
478:
479:                        ReferencedKeyConstraintDescriptor refcd = fkcd
480:                                .getReferencedConstraint();
481:                        TableDescriptor nextRefTd = refcd.getTableDescriptor();
482:
483:                        //if we are not cascading, check  whether the link before
484:                        //this was cascade or not. If we travel through  two NON CASCADE ACTION
485:                        //links then the delete connection is broken(only a delete can have further
486:                        //referential effects)
487:                        if (raDeleteRule != StatementType.RA_CASCADE) {
488:                            if (prevNotCascade) {
489:                                prevNotCascade = passedInPrevNotCascade;
490:                                continue;
491:                            } else {
492:                                prevNotCascade = true;
493:                                multiPathCheck = false;
494:                            }
495:
496:                        }
497:
498:                        //check whether the current link is a self referencing one
499:                        boolean isSelfRefLink = fkcd.isSelfReferencingFK();
500:
501:                        //check for this is non self referencing cycles case
502:                        //In cases of cycle, whole cycle should have the same refAction
503:                        // value. Other wise we should throw an exception
504:                        cycleString = cycleString.append(raDeleteRule);
505:                        boolean isFormingCycle = (nextRefTd.getUUID()
506:                                .equals(actualTd.getUUID()));
507:                        if (isFormingCycle) {
508:                            //make sure that all the nodes in the cycle have the same
509:                            //referential action  value, otherwise we should throw an error. 
510:                            for (int i = 0; i < cycleString.length(); i++) {
511:                                int otherRefAction = Character
512:                                        .getNumericValue(cycleString.charAt(i));
513:                                if (otherRefAction != refActionType) {
514:                                    //cases where one of the existing relation ships in
515:                                    //the cycle is not cascade , so we can not have
516:                                    // cascade relation ship.
517:                                    if (otherRefAction != StatementType.RA_CASCADE) {
518:                                        throw generateError(
519:                                                SQLState.LANG_DELETE_RULE_CANT_BE_CASCADE_ECYCLE,
520:                                                myConstraintName);
521:                                    } else {
522:                                        //possibly all the other nodes in the cycle has
523:                                        //cascade relationsship , we can not add a non
524:                                        //cascade relation ship.
525:                                        throw generateError(
526:                                                SQLState.LANG_CANT_BE_DEPENDENT_ECYCLE,
527:                                                myConstraintName,
528:                                                currentRefTableName);
529:                                    }
530:                                }
531:                            }
532:                        }
533:
534:                        String nextRefTableName = nextRefTd.getSchemaName()
535:                                + "." + nextRefTd.getName();
536:                        rAction = ((Integer) ech.get(nextRefTableName));
537:                        if (rAction != null) {
538:                            /*
539:                             ** If the table name has entry in the hash table means, there
540:                             ** is already  a path to this table exists from the table
541:                             ** the new foreign key relation ship is being formed.
542:                             ** Note: refValue in the hash table is how the table we are
543:                             ** adding the new relationsship is going to affected not
544:                             ** current path refvalue.
545:                             **/
546:                            if (!isSelfRefLink && multiPathCheck)
547:                                checkForMultiplePathInvalidCases(rAction
548:                                        .intValue(), refActionType,
549:                                        myConstraintName, currentRefTableName);
550:
551:                        } else {
552:                            rAction = ((Integer) dch.get(nextRefTableName));
553:                            if (rAction == null) {
554:                                if (multiPathCheck)
555:                                    dch.put(nextRefTableName, (new Integer(
556:                                            refActionType)));
557:                                if (!isSelfRefLink) {
558:                                    validateDeleteConnection(dd, actualTd,
559:                                            nextRefTd, refActionType, dch, ech,
560:                                            false, myConstraintName,
561:                                            prevNotCascade, cycleString,
562:                                            currentRefTableName,
563:                                            isSelfReferencingFk,
564:                                            currentSelfRefValue);
565:                                }
566:                            }
567:                        }
568:                        prevNotCascade = passedInPrevNotCascade;
569:                        //removes the char added for the current call
570:                        cycleString.setLength(cycleString.length() - 1);
571:
572:                    }
573:                }
574:            }
575:
576:            /*
577:             **Check whether the mulitple path case is valid or not following
578:             ** cases are invalid:
579:             ** case 1: The relationship causes the table to be delete-connected to
580:             ** the indicated table through multiple relationships and the
581:             ** delete rule of the existing relationship is SET NULL. 
582:             ** case 2: The relationship would cause the table to be
583:             ** delete-connected to the same table through multiple
584:             ** relationships and such relationships must have the same 
585:             ** delete rule (NO ACTION, RESTRICT or CASCADE). 
586:             ** case 3: The relationship would cause another table to be
587:             ** delete-connected to the same table through multiple paths
588:             ** with different delete rules or with delete rule equal to SET NULL. 
589:             **/
590:
591:            private static void checkForMultiplePathInvalidCases(
592:                    int currentRefAction, int refActionType,
593:                    String myConstraintName, String currentRefTableName)
594:                    throws StandardException {
595:
596:                //All the relation ship referring to a table should have the
597:                //same refaction except incase of SET NULL
598:                if (currentRefAction != refActionType) {
599:
600:                    //If there is a SET NULL relation ship we can not have any
601:                    // other relation ship with it.
602:                    if (currentRefAction == StatementType.RA_SETNULL)
603:                        throw generateError(
604:                                SQLState.LANG_CANT_BE_DEPENDENT_MPATH,
605:                                myConstraintName, currentRefTableName);
606:                    else
607:                        //This error say what the delete rule must be for the
608:                        // foreign key be valid 
609:                        throw generateError(
610:                                SQLState.LANG_DELETE_RULE_MUSTBE_MPATH,
611:                                myConstraintName, currentRefAction);
612:
613:                } else {
614:                    //more than one  ON DELET SET NULL to the same table is not allowed
615:                    if (currentRefAction == StatementType.RA_SETNULL
616:                            && refActionType == StatementType.RA_SETNULL) {
617:                        throw generateError(
618:                                SQLState.LANG_CANT_BE_DEPENDENT_MPATH,
619:                                myConstraintName, currentRefTableName);
620:                    }
621:                }
622:            }
623:
624:            /*
625:             ** Check whether the delete rule of FOREIGN KEY  must not be CASCADE because
626:             ** the  new relationship would cause another table to be delete-connected to
627:             ** the same table through multiple paths with different delete rules or with 
628:             ** delete rule equal to SET NULL. 
629:             **
630:             ** For example :
631:             **                      t1
632:             **  		 CASCADE   /  \  CASCADE
633:             **                    /    \ 
634:             **                  t2      t3
635:             **                   \      /   
636:             **          SET NULL  \    /  CASCADE (Can we add this one ? NO)
637:             **			          \   /
638:                                   \t4/
639:             **					
640:             **   existing links:
641:             **   t2 references t1   ON DELETE CASCADE  (fkey1)
642:             **   t3 references t1   ON DELETE CASCADE  (fkey2)
643:             **   t2 reference  t4   ON DELETE SET NULL (fkey3)
644:             **   Now if if try to add a new link i.e
645:             **   t4 references t3   ON DELETE SET NULL  (fkey4)
646:             **   Say if we add it,  then if we execute 'delete from t1' 
647:             **   Because of referential actions , we will try to delete a row through
648:             **   one path and tries to update  through another path. 
649:             **   Nothing in standard that say whether we are suppose to delete the row
650:             **   or update the row.  DB2UDB raises error when we try to create the
651:             **   foreign key fkey4, cloudscape also does the same.
652:             ** 
653:             **   How we catch the error case ?
654:             **   Point to note here is the table(t4) we are  adding the foreign key does
655:             **   not have a problem in this scenarion because we are adding a
656:             **   a CASACDE link , some other table(t2) that is referring  
657:             **   can get multiple referential action paths. We can not
658:             **   this error case for self referencing links.
659:             **   Algorithm:
660:             **   -Gather the foreign keys that are
661:             **   referring(ReferencedKeyConstraintDescriptor) to the table we are adding
662:             **   foreign key, in our example case we get (fkey3 - table t2 -t4 link)
663:             **   for each ReferencedKeyConstraintDescriptor
664:             **   {
665:             **    1)find the delete connections of the referring table.
666:             **    [getCurrentDeleteConnections() will return this hash table]
667:             **	  2) we already have collected the Delete connections 
668:             **       in validDeleteConnections() for the actual table we are adding the 
669:             **       foreign key.
670:             **    3) Now check whether the referring table  is also 
671:             **       referring  any table that the table we are adding
672:             **       foreign key has delete connection.
673:             **
674:             **     for each table referring table delete connection hash table
675:             **     {
676:             **      if it is there in the actual table delete connection hash table
677:             **      {
678:             **         //In our example case we find t1 in both the hash tables.
679:             **         make sure we are having valid referential action
680:             **         from the existing path and the new path we got from 
681:             **         new foreign key relation ship.
682:             **        //In our example case t2 has CASCADE relations with t1
683:             **        //Because of new foreign key added we also get 
684:             **        //SET NULL relation ship with t1. This is not valid
685:             **        //so we should throw error.
686:             **      }  
687:             **     }
688:             ** }	
689:             **/
690:
691:            private static void checkForAnyExistingDeleteConnectionViolations(
692:                    DataDictionary dd, TableDescriptor td, int refActionType,
693:                    Hashtable newDconnHashTable, String myConstraintName)
694:                    throws StandardException {
695:
696:                //We need to check for the condition in this function only when we are
697:                //adding ref action of type CASCADE
698:                if (refActionType != StatementType.RA_CASCADE)
699:                    return;
700:
701:                //find the tables that are referring to the table we 
702:                //are adding the foreign key and check whether we violate their existing rules.
703:                String addTableName = td.getSchemaName() + "." + td.getName();
704:                ;
705:                ConstraintDescriptorList refCDL = dd
706:                        .getConstraintDescriptors(td);
707:                int refCDLSize = refCDL.size();
708:                for (int index = 0; index < refCDLSize; index++) {
709:                    ConstraintDescriptor cd = refCDL.elementAt(index);
710:
711:                    if ((cd instanceof  ReferencedKeyConstraintDescriptor)) {
712:                        ConstraintDescriptorList fkcdl = dd
713:                                .getActiveConstraintDescriptors(((ReferencedKeyConstraintDescriptor) cd)
714:                                        .getForeignKeyConstraints(ConstraintDescriptor.ALL));
715:
716:                        int size = fkcdl.size();
717:                        if (size == 0) {
718:                            continue;
719:                        }
720:
721:                        //Note: More than one table can refer to the same
722:                        //ReferencedKeyConstraintDescriptor, so we need to find all the tables.
723:                        Hashtable dConnHashtable = new Hashtable();
724:                        for (int inner = 0; inner < size; inner++) {
725:                            ForeignKeyConstraintDescriptor fkcd = (ForeignKeyConstraintDescriptor) fkcdl
726:                                    .elementAt(inner);
727:                            TableDescriptor fktd = fkcd.getTableDescriptor();
728:                            //Delete rule that we have to the table we are adding the
729:                            // foreign key relation shop
730:                            int raDeleteRuleToAddTable = fkcd.getRaDeleteRule();
731:
732:                            //This check should not be done on self referencing references.
733:                            if (!fkcd.isSelfReferencingFK()) {
734:
735:                                //gather the delete connections of the table that is
736:                                //referring to the table we are adding foreign key relation ship
737:
738:                                getCurrentDeleteConnections(dd, fktd, -1,
739:                                        dConnHashtable, false, true);
740:
741:                                /*
742:                                 **Find out if we introduced more than one delete connection
743:                                 **paths to the table that are referring the table we adding
744:                                 **the foreign key relatiosn ship.
745:                                 **If we have multiple paths they should have the same type
746:                                 **referential action and only one SET NULL path.
747:                                 **/
748:
749:                                for (Enumeration e = dConnHashtable.keys(); e
750:                                        .hasMoreElements();) {
751:                                    String tName = (String) e.nextElement();
752:                                    //we should not check for the table name to which  we are
753:                                    //adding the foreign key relation ship.
754:                                    if (!tName.equals(addTableName)) {
755:                                        if (newDconnHashTable
756:                                                .containsKey(tName)) {
757:                                            int currentDeleteRule = ((Integer) dConnHashtable
758:                                                    .get(tName)).intValue();
759:                                            if ((currentDeleteRule == StatementType.RA_SETNULL && raDeleteRuleToAddTable == StatementType.RA_SETNULL)
760:                                                    || currentDeleteRule != raDeleteRuleToAddTable) {
761:                                                throw generateError(
762:                                                        SQLState.LANG_DELETE_RULE_CANT_BE_CASCADE_MPATH,
763:                                                        myConstraintName);
764:                                            }
765:                                        }
766:                                    }
767:                                }
768:                            }
769:                            //same hash table can be used for the other referring tables
770:                            //so clear the hash table.
771:                            dConnHashtable.clear();
772:                        }
773:                    }
774:                }
775:            }
776:
777:            private static StandardException generateError(String messageId,
778:                    String myConstraintName) {
779:                String message = MessageService.getTextMessage(messageId);
780:                return StandardException.newException(
781:                        SQLState.LANG_DELETE_RULE_VIOLATION, myConstraintName,
782:                        message);
783:            }
784:
785:            private static StandardException generateError(String messageId,
786:                    String myConstraintName, int raRule) {
787:                String raRuleStringId;
788:                switch (raRule) {
789:                case StatementType.RA_CASCADE:
790:                    raRuleStringId = SQLState.LANG_DELETE_RULE_CASCADE;
791:                    break;
792:                case StatementType.RA_RESTRICT:
793:                    raRuleStringId = SQLState.LANG_DELETE_RULE_RESTRICT;
794:                    break;
795:                case StatementType.RA_NOACTION:
796:                    raRuleStringId = SQLState.LANG_DELETE_RULE_NOACTION;
797:                    break;
798:                case StatementType.RA_SETNULL:
799:                    raRuleStringId = SQLState.LANG_DELETE_RULE_SETNULL;
800:                    break;
801:                case StatementType.RA_SETDEFAULT:
802:                    raRuleStringId = SQLState.LANG_DELETE_RULE_SETDEFAULT;
803:                    break;
804:                default:
805:                    raRuleStringId = SQLState.LANG_DELETE_RULE_NOACTION; // NO ACTION (default value)
806:                }
807:
808:                String raRuleMessageString = MessageService
809:                        .getTextMessage(raRuleStringId);
810:                String message = MessageService.getTextMessage(messageId,
811:                        raRuleMessageString);
812:                return StandardException.newException(
813:                        SQLState.LANG_DELETE_RULE_VIOLATION, myConstraintName,
814:                        message);
815:            }
816:
817:            private static StandardException generateError(String messageId,
818:                    String myConstraintName, String refTableName) {
819:
820:                String message = MessageService.getTextMessage(messageId,
821:                        refTableName);
822:                return StandardException.newException(
823:                        SQLState.LANG_DELETE_RULE_VIOLATION, myConstraintName,
824:                        message);
825:            }
826:
827:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.