/*
* JBoss, Home of Professional Open Source.
* See the COPYRIGHT.txt file distributed with this work for information
* regarding copyright ownership. Some portions may be licensed
* to Red Hat, Inc. under one or more contributor license agreements.
*
* This library 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 2.1 of the License, or (at your option) any later version.
*
* This library 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 this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301 USA.
*/
package org.teiid.query.sql.symbol;
import org.teiid.api.exception.query.QueryValidatorException;
import org.teiid.core.util.Assertion;
import org.teiid.query.metadata.TempMetadataID;
import org.teiid.query.sql.LanguageVisitor;
import org.teiid.query.sql.visitor.SQLStringVisitor;
/**
* This class represents a reference (positional from the user query, or
* to an element from another scope). This reference may resolve to many different values
* during evaluation. For any particular bound value, it is treated as a constant.
*/
public class Reference implements Expression, ContextReference {
public interface Constraint {
public void validate(Object value) throws QueryValidatorException;
}
private boolean positional;
private boolean optional;
private int refIndex;
private Class<?> type;
private ElementSymbol expression;
private Constraint constraint;
/**
* Constructor for a positional Reference.
*/
public Reference(int refIndex) {
this.refIndex = refIndex;
this.positional = true;
}
public Constraint getConstraint() {
return constraint;
}
public void setConstraint(Constraint constraint) {
this.constraint = constraint;
}
/**
* Constructor for an element Reference.
*/
public Reference(ElementSymbol expression) {
this.expression = expression;
this.positional = false;
}
private Reference(Reference ref) {
this.refIndex = ref.refIndex;
this.positional = ref.positional;
this.type = ref.type;
if (ref.expression != null) {
this.expression = ref.expression.clone();
}
this.constraint = ref.constraint;
this.optional = ref.optional;
}
public int getIndex() {
return this.refIndex;
}
@Override
public String getContextSymbol() {
return "$param/pos" + this.refIndex; //$NON-NLS-1$
}
public ElementSymbol getExpression() {
return this.expression;
}
public Class<?> getType() {
if (this.isPositional() && this.expression == null) {
return type;
}
return expression.getType();
}
public void acceptVisitor(LanguageVisitor visitor) {
visitor.visit(this);
}
/**
* @see java.lang.Object#clone()
*/
public Object clone() {
return new Reference(this);
}
/**
* Compare this constant to another constant for equality.
* @param obj Other object
* @return True if constants are equal
*/
public boolean equals(Object obj) {
if(this == obj) {
return true;
}
if(!(obj instanceof Reference)) {
return false;
}
Reference other = (Reference) obj;
if (this.positional != other.positional) {
return false;
}
if (this.positional) {
return other.getIndex() == getIndex();
}
// Compare based on name
return this.expression.equals(other.expression);
}
public void setType(Class<?> type) {
Assertion.assertTrue(this.positional);
this.type = type;
}
/**
* Define hash code to be that of the underlying object to make it stable.
* @return Hash code, based on value
*/
public int hashCode() {
if (this.isPositional()) {
return getIndex();
}
return this.expression.hashCode();
}
/**
* Return a String representation of this object using SQLStringVisitor.
* @return String representation using SQLStringVisitor
*/
public String toString() {
return SQLStringVisitor.getSQLString(this);
}
public boolean isCorrelated() {
if (this.isPositional()) {
return false;
}
//metadata hack
if (this.expression.getGroupSymbol() == null || !(this.expression.getGroupSymbol().getMetadataID() instanceof TempMetadataID)) {
return true;
}
TempMetadataID tid = (TempMetadataID)this.expression.getGroupSymbol().getMetadataID();
return !tid.isScalarGroup();
}
public boolean isPositional() {
return this.positional;
}
public void setExpression(ElementSymbol expression) {
assert this.expression != null && !this.positional;
this.expression = expression;
}
public boolean isOptional() {
return optional;
}
public void setOptional(boolean optional) {
this.optional = optional;
}
}