/****************************************************************************** * Copyright: GPL v3 * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation, either version 3 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see <http://www.gnu.org/licenses/>. * ******************************************************************************/ package dbaCore.logic.Analysis; import dbaCore.data.*; import java.util.ArrayList; /** * Class containing the general Relation-check * * @author Sebastian Theuermann */ public class GeneralRelationCheck extends RelationCheck { /** * Returns the NormalForm of the given Schema */ @Override public NormalForm getNF(RelationSchema schema, ArrayList<FunctionalDependency> violatingFds) { ArrayList<FunctionalDependency> prevViolatingFds = new ArrayList<>(); // BCNF updateFdList(violatingFds, checkForBCNF(schema)); if (violatingFds.isEmpty()) { return NormalForm.BOYCECODD; } updateFdList(prevViolatingFds, violatingFds); // Third NF updateFdList(violatingFds, checkForThirdNF(schema)); if (violatingFds.isEmpty()) { updateFdList(violatingFds, prevViolatingFds); return NormalForm.THIRD; } updateFdList(prevViolatingFds, violatingFds); // Second NF updateFdList(violatingFds, checkForSecondNF(schema)); if (violatingFds.isEmpty()) { updateFdList(violatingFds, prevViolatingFds); return NormalForm.SECOND; } else { return NormalForm.FIRST; } } /** * Returns the highest Normal Form of the given relations * * @param relations relations to be checked * @return the highest NormalForm of the relations */ @Override public NormalForm getNF(ArrayList<RelationSchema> relations) { NormalForm totalNf = NormalForm.BOYCECODD; NormalForm relationNf; for (RelationSchema relation : relations) { relationNf = getNF(relation, new ArrayList<FunctionalDependency>()); if (relationNf.ordinal() < totalNf.ordinal()) { totalNf = relationNf; } } return totalNf; } /** * Updates the source-List with the values of the target-List * * @param target the new values for the source-list * @param source the list to update */ private void updateFdList(ArrayList<FunctionalDependency> target, ArrayList<FunctionalDependency> source) { target.clear(); target.addAll(source); } /** * Returns if a given Schema is in the second NF or not */ @Override public boolean isSecondNF(RelationSchema schema) { return checkForSecondNF(schema).isEmpty(); } /** * Returns all functional dependencies that violate the second NF * * @param schema the RelationSchema to work with * @return a ArrayList containing all fd's that violate 2.NF */ @Override public ArrayList<FunctionalDependency> checkForSecondNF(RelationSchema schema) { ArrayList<FunctionalDependency> violatingFds = new ArrayList<>(); ArrayList<Key> candidateKeys = getAllCandidateKeys(schema); if (candidateKeys.isEmpty()) { candidateKeys.add(RelationUtils.getInstance().getPrimaryKey(schema)); } int numberOfMatches; for (FunctionalDependency fd : schema.getFunctionalDependencies()) { if (isListContainingANonPrimeAttribute(fd.getTargetAttributes(), candidateKeys)) { for (Key key : candidateKeys) { if (key.getAttributes().size() > 1) { numberOfMatches = getNumberOfMatchingAttributes(key.getAttributes(), fd.getSourceAttributes()); if (numberOfMatches > 0 && numberOfMatches < key.getAttributes().size()) { violatingFds.add(fd); } } } } } return violatingFds; } /** * Returns if a given Schema is in third NF */ @Override public boolean isThirdNF(RelationSchema schema) { return checkForThirdNF(schema).isEmpty(); } /** * Returns all functional dependencies that violate the Third NF * * @param schema the RelationSchema to work with * @return a ArrayList containing all fds that violate Third NF */ @Override public ArrayList<FunctionalDependency> checkForThirdNF(RelationSchema schema) { ArrayList<FunctionalDependency> violatingFds = new ArrayList<>(); ArrayList<Key> candidateKeys = getAllCandidateKeys(schema); for (FunctionalDependency fd : schema.getFunctionalDependencies()) { if (isListContainingANonPrimeAttribute(fd.getTargetAttributes(), candidateKeys)) { if (!isCandidateKey(fd.getSourceAttributes(), candidateKeys) && !isSuperKey(fd.getSourceAttributes(), candidateKeys) && !fd.getSourceAttributes().containsAll(fd.getTargetAttributes())) { violatingFds.add(fd); } } } return violatingFds; } /** * Returns if a given schema is in Boyce Codd NF */ @Override public boolean isBCNF(RelationSchema schema) { return checkForBCNF(schema).isEmpty(); } /** * Returns all functional dependencies that violate the BCNF * * @param schema the RelationSchema to work with * @return a ArrayList containing all fds that violate BCNF */ @Override public ArrayList<FunctionalDependency> checkForBCNF(RelationSchema schema) { ArrayList<FunctionalDependency> violatingFds = new ArrayList<>(); ArrayList<Key> candidateKeys = getAllCandidateKeys(schema); for (FunctionalDependency fd : schema.getFunctionalDependencies()) { if (!isCandidateKey(fd.getSourceAttributes(), candidateKeys) && !isSuperKey(fd.getSourceAttributes(), candidateKeys) && !fd.getSourceAttributes().containsAll(fd.getTargetAttributes())) { violatingFds.add(fd); } } return violatingFds; } /** * Returns if a given ArrayList contains a non-Prime Attribute * * @param list the ArrayList to work with * @param candidateKeys the candidateKeys which are used to detect the prime * attributes * @return true if the list contains a nonPrime, false if not */ private boolean isListContainingANonPrimeAttribute(ArrayList<Attribute> list, ArrayList<Key> candidateKeys) { for (Attribute attribute : list) { if (!isPrimeAttribute(attribute, candidateKeys)) { return true; } } return false; } }