package adql.query.constraint; /* * This file is part of ADQLLibrary. * * ADQLLibrary is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * ADQLLibrary 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with ADQLLibrary. If not, see <http://www.gnu.org/licenses/>. * * Copyright 2012-2015 - UDS/Centre de DonnĂ©es astronomiques de Strasbourg (CDS), * Astronomisches Rechen Institute (ARI) */ import java.util.NoSuchElementException; import adql.query.ADQLIterator; import adql.query.ADQLObject; import adql.query.TextPosition; import adql.query.operand.ADQLOperand; /** * Represents a comparison (numeric or not) between two operands. * * @author Grégory Mantelet (CDS;ARI) * @version 1.4 (06/2015) * * @see ComparisonOperator */ public class Comparison implements ADQLConstraint { /** The left part of the comparison. */ private ADQLOperand leftOperand; /** The comparison symbol. */ private ComparisonOperator compOperator; /** The right part of the comparison. */ private ADQLOperand rightOperand; /** Position of this {@link Comparison} in the given ADQL query string. * @since 1.4 */ private TextPosition position = null; /** * Creates a comparison between two operands. * * @param left The left part. * @param comp The comparison symbol. * @param right The right part. * * @throws NullPointerException If one of the given parameter is <i>null</i>. * @throws UnsupportedOperationException If the type of operands and of the operator are incompatibles. * * @see Comparison#setLeftOperand(ADQLOperand) * @see Comparison#setRightOperand(ADQLOperand) */ public Comparison(ADQLOperand left, ComparisonOperator comp, ADQLOperand right) throws NullPointerException, UnsupportedOperationException{ setLeftOperand(left); setRightOperand(right); setOperation(comp); } /** * Builds a comparison by copying the given one. * * @param toCopy The comparison to copy. * @throws Exception If there is an error during the copy. */ public Comparison(Comparison toCopy) throws Exception{ leftOperand = (ADQLOperand)toCopy.leftOperand.getCopy(); compOperator = toCopy.compOperator; rightOperand = (ADQLOperand)toCopy.rightOperand.getCopy(); position = (toCopy.position == null) ? null : new TextPosition(toCopy.position); } /** * Gets the left part of the comparison. * * @return The left operand. */ public final ADQLOperand getLeftOperand(){ return leftOperand; } /** * Changes the left operand of this comparison. * * @param newLeftOperand The new left operand. * @throws NullPointerException If the given operand is <i>null</i>. * @throws UnsupportedOperationException If the type of the given operand is incompatible with the right operand and/or with the comparison operator. */ public void setLeftOperand(ADQLOperand newLeftOperand) throws NullPointerException, UnsupportedOperationException{ if (newLeftOperand == null) throw new NullPointerException("Impossible to update the left operand of the comparison (" + toADQL() + ") with a NULL operand !"); if (rightOperand != null && newLeftOperand.isNumeric() != rightOperand.isNumeric() && newLeftOperand.isString() != rightOperand.isString()) throw new UnsupportedOperationException("Impossible to update the left operand of the comparison (" + toADQL() + ") with \"" + newLeftOperand.toADQL() + "\" because its type is not compatible with the type of the right operand !"); if (compOperator != null && newLeftOperand.isNumeric() && (compOperator == ComparisonOperator.LIKE || compOperator == ComparisonOperator.NOTLIKE)) throw new UnsupportedOperationException("Impossible to update the left operand of the comparison (" + toADQL() + ") with \"" + newLeftOperand.toADQL() + "\" because the comparison operator " + compOperator.toADQL() + " is not applicable on numeric operands !"); leftOperand = newLeftOperand; position = null; } /** * Gets the comparison symbol. * * @return The comparison operator. */ public ComparisonOperator getOperator(){ return compOperator; } /** * Changes the type of this operation. * * @param newOperation The new operation type. * @throws NullPointerException If the given type is <i>null</i>. * @throws UnsupportedOperationException If the given type is incompatible with the two operands. */ public void setOperation(ComparisonOperator newOperation) throws NullPointerException, UnsupportedOperationException{ if (newOperation == null) throw new NullPointerException("Impossible to update the comparison operator (" + compOperator.toADQL() + ") with a NULL operand !"); if ((!leftOperand.isString() || !rightOperand.isString()) && (newOperation == ComparisonOperator.LIKE || newOperation == ComparisonOperator.NOTLIKE)) throw new UnsupportedOperationException("Impossible to update the comparison operator" + ((compOperator != null) ? (" (" + compOperator.toADQL() + ")") : "") + " by " + newOperation.toADQL() + " because the two operands (\"" + leftOperand.toADQL() + "\" & \"" + rightOperand.toADQL() + "\") are not all Strings !"); compOperator = newOperation; position = null; } /** * Gets the right part of the comparison. * * @return The right operand. */ public ADQLOperand getRightOperand(){ return rightOperand; } /** * Changes the right operand of this comparison. * * @param newRightOperand The new right operand. * @throws NullPointerException If the given operand is <i>null</i>. * @throws UnsupportedOperationException If the type of the given operand is incompatible with the left operand and/or with the comparison operator. */ public void setRightOperand(ADQLOperand newRightOperand) throws NullPointerException, UnsupportedOperationException{ if (newRightOperand == null) throw new NullPointerException("Impossible to update the right operand of the comparison (" + toADQL() + ") with a NULL operand !"); if (leftOperand != null && newRightOperand.isNumeric() != leftOperand.isNumeric() && newRightOperand.isString() != leftOperand.isString()) throw new UnsupportedOperationException("Impossible to update the right operand of the comparison (" + toADQL() + ") with \"" + newRightOperand.toADQL() + "\" because its type is not compatible with the type of the left operand !"); if (compOperator != null && newRightOperand.isNumeric() && (compOperator == ComparisonOperator.LIKE || compOperator == ComparisonOperator.NOTLIKE)) throw new UnsupportedOperationException("Impossible to update the right operand of the comparison (" + toADQL() + ") with \"" + newRightOperand.toADQL() + "\" because the comparison operator " + compOperator.toADQL() + " is not applicable on numeric operands !"); rightOperand = newRightOperand; position = null; } @Override public final TextPosition getPosition(){ return position; } /** * Set the position of this {@link Comparison} in the given ADQL query string. * * @param position New position of this {@link Comparison}. * @since 1.4 */ public final void setPosition(final TextPosition position){ this.position = position; } @Override public ADQLObject getCopy() throws Exception{ return new Comparison(this); } @Override public String getName(){ return compOperator.toADQL(); } @Override public ADQLIterator adqlIterator(){ return new ADQLIterator(){ private int index = -1; @Override public ADQLObject next(){ index++; if (index == 0) return leftOperand; else if (index == 1) return rightOperand; else throw new NoSuchElementException(); } @Override public boolean hasNext(){ return index + 1 < 2; } @Override public void replace(ADQLObject replacer) throws UnsupportedOperationException, IllegalStateException{ if (index <= -1) throw new IllegalStateException("replace(ADQLObject) impossible: next() has not yet been called !"); if (replacer == null) remove(); else if (replacer instanceof ADQLOperand){ if (index == 0){ leftOperand = (ADQLOperand)replacer; position = null; }else if (index == 1){ rightOperand = (ADQLOperand)replacer; position = null; } }else throw new UnsupportedOperationException("Impossible to replace an ADQLOperand by a " + replacer.getClass().getName() + " in a comparison !"); } @Override public void remove(){ if (index <= -1) throw new IllegalStateException("remove() impossible: next() has not yet been called !"); else throw new UnsupportedOperationException("Impossible to remove an operand from a comparison !"); } }; } @Override public String toADQL(){ return ((leftOperand == null) ? "NULL" : leftOperand.toADQL()) + " " + ((compOperator == null) ? "NULL" : compOperator.toADQL()) + " " + ((rightOperand == null) ? "NULL" : rightOperand.toADQL()); } }