/*
* Copyright (c) 2013, OpenCloudDB/MyCAT and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software;Designed and Developed mainly by many Chinese
* opensource volunteers. you can redistribute it and/or modify it under the
* terms of the GNU General Public License version 2 only, as published by the
* Free Software Foundation.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Any questions about this component can be directed to it's project Web address
* https://code.google.com/p/opencloudb/.
*
*/
package com.akiban.sql.parser;
import com.akiban.sql.StandardException;
import com.akiban.sql.types.DataTypeDescriptor;
import com.akiban.sql.types.TypeId;
/**
* A ValueNode is an abstract class for all nodes that can represent data
* values, that is, constants, columns, and expressions.
*
*/
public abstract class ValueNode extends QueryTreeNode
{
/**
* The data type for this node.
*/
private DataTypeDescriptor type;
/*
** Constructor for untyped ValueNodes, for example, untyped NULLs
** and parameter nodes.
**
** Binding will replace all untyped ValueNodes with typed ValueNodes
** when it figures out what their types should be.
*/
public ValueNode() {
}
/**
* Set this node's type from type components.
*/
final void setType(TypeId typeId, boolean isNullable, int maximumWidth)
throws StandardException {
setType(new DataTypeDescriptor(typeId, isNullable, maximumWidth));
}
/**
* Set this node's type from type components.
*/
final void setType(TypeId typeId,
int precision, int scale,
boolean isNullable, int maximumWidth)
throws StandardException {
setType(new DataTypeDescriptor(typeId,
precision, scale,
isNullable, maximumWidth));
}
/**
* Initializer for numeric types.
*
*
* @param typeId The TypeID of this new node
* @param precision The precision of this new node
* @param scale The scale of this new node
* @param isNullable The nullability of this new node
* @param maximumWidth The maximum width of this new node
*
* @exception StandardException
*/
public void init(Object typeId,
Object precision,
Object scale,
Object isNullable,
Object maximumWidth)
throws StandardException {
setType(new DataTypeDescriptor((TypeId)typeId,
((Integer)precision).intValue(),
((Integer)scale).intValue(),
((Boolean)isNullable).booleanValue(),
((Integer)maximumWidth).intValue()));
}
/**
* Fill this node with a deep copy of the given node.
*/
public void copyFrom(QueryTreeNode node) throws StandardException {
super.copyFrom(node);
ValueNode other = (ValueNode)node;
this.type = other.type;
}
/**
* Convert this object to a String. See comments in QueryTreeNode.java
* for how this should be done for tree printing.
*
* @return This object as a String
*/
public String toString() {
return "type: " +
((type != null) ? type.toString() : "null" ) + "\n" +
super.toString();
}
/**
* Get the DataTypeDescriptor from this ValueNode.
*
* @return The DataTypeDescriptor from this ValueNode. This
* may be null if the node isn't bound yet.
*/
public DataTypeDescriptor getType() {
return type;
}
/**
* Set the nullability of this value.
* @throws StandardException
*/
public void setNullability(boolean nullability) throws StandardException {
setType(getType().getNullabilityType(nullability));
}
/**
* Get the TypeId from this ValueNode.
*
* @return The TypeId from this ValueNode. This
* may be null if the node isn't bound yet.
*/
public TypeId getTypeId() throws StandardException {
DataTypeDescriptor dtd = getType();
if (dtd != null)
return dtd.getTypeId();
return null;
}
/**
* Set the DataTypeDescriptor for this ValueNode. This method is
* overridden in ParameterNode.
*
* @param type The DataTypeDescriptor to set in this ValueNode
*/
public void setType(DataTypeDescriptor type) throws StandardException {
this.type = type;
}
/**
* Get the source for this ValueNode.
*
* @return The source of this ValueNode, null if this node
* is not sourced by a column.
*/
public ResultColumn getSourceResultColumn() {
return null;
}
/**
* This returns the user-supplied schema name of the column.
* At this class level, it simply returns null. But, the subclasses
* of ValueNode will overwrite this method to return the
* user-supplied schema name.
*
* When the value node is in a result column of a select list,
* the user can request metadata information. The result column
* won't have a column descriptor, so we return some default
* information through the expression. This lets expressions that
* are simply columns return all of the info, and others use
* this supertype's default values.
*
* @return the default schema name for an expression -- null
*/
public String getSchemaName() throws StandardException {
return null;
}
/**
* This returns the user-supplied table name of the column.
* At this class level, it simply returns null. But, the subclasses
* of ValueNode will overwrite this method to return the
* user-supplied table name.
*
* When the value node is in a result column of a select list,
* the user can request metadata information. The result column
* won't have a column descriptor, so we return some default
* information through the expression. This lets expressions that
* are simply columns return all of the info, and others use
* this supertype's default values.
*
* @return the default table name for an expression -- null
*/
public String getTableName() {
return null;
}
/**
* This is null so that the caller will substitute in the resultset generated
* name as needed.
*
* @return the default column name for an expression -- null.
*/
public String getColumnName() {
return null;
}
/**
* Return whether or not this expression tree represents a constant expression.
*
* @return Whether or not this expression tree represents a constant expression.
*/
public boolean isConstantExpression() {
return false;
}
/**
* Return an Object representing the bind time value of this
* expression tree. If the expression tree does not evaluate to
* a constant at bind time then we return null.
* This is useful for bind time resolution of VTIs.
* RESOLVE: What do we do for primitives?
*
* @return An Object representing the bind time value of this expression tree.
* (null if not a bind time constant.)
*
* @exception StandardException Thrown on error
*/
Object getConstantValueAsObject() throws StandardException {
return null;
}
/**
* Does this represent a true constant.
*
* @return Whether or not this node represents a true constant.
*/
public boolean isBooleanTrue() {
return false;
}
/**
* Does this represent a false constant.
*
* @return Whether or not this node represents a false constant.
*/
public boolean isBooleanFalse() {
return false;
}
/**
* Returns true if this ValueNode is a relational operator. Relational
* Operators are <, <=, =, >, >=, <> as well as IS NULL and IS NOT
* NULL. This is the preferred way of figuring out if a ValueNode is
* relational or not.
* @see RelationalOperator
* @see BinaryRelationalOperatorNode
* @see IsNullNode
*/
public boolean isRelationalOperator() {
return false;
}
/**
* Returns true if this value node is a <em>equals</em> operator.
*
* @see ValueNode#isRelationalOperator
*/
public boolean isBinaryEqualsOperatorNode() {
return false;
}
/**
* Returns true if this value node is an operator created
* for optimized performance of an IN list.
*
* Or more specifically, returns true if this value node is
* an equals operator of the form "col = ?" that we generated
* during preprocessing to allow index multi-probing.
*/
public boolean isInListProbeNode() {
return false;
}
/**
* Returns TRUE if this is a parameter node. We do lots of special things
* with Parameter Nodes.
*
*/
public boolean isParameterNode() {
return false;
}
/**
* Tests if this node is equivalent to the specified ValueNode. Two
* ValueNodes are considered equivalent if they will evaluate to the same
* value during query execution.
* <p>
* This method provides basic expression matching facility for the derived
* class of ValueNode and it is used by the language layer to compare the
* node structural form of the two expressions for equivalence at bind
* phase.
* <p>
* Note that it is not comparing the actual row values at runtime to produce
* a result; hence, when comparing SQL NULLs, they are considered to be
* equivalent and not unknown.
* <p>
* One usage case of this method in this context is to compare the select
* column expression against the group by expression to check if they are
* equivalent. e.g.:
* <p>
* SELECT c1+c2 FROM t1 GROUP BY c1+c2
* <p>
* In general, node equivalence is determined by the derived class of
* ValueNode. But they generally abide to the rules below:
* <ul>
* <li>The two ValueNodes must be of the same node type to be considered
* equivalent. e.g.: CastNode vs. CastNode - equivalent (if their args
* also match), ColumnReference vs CastNode - not equivalent.
*
* <li>If node P contains other ValueNode(s) and so on, those node(s) must
* also be of the same node type to be considered equivalent.
*
* <li>If node P takes a parameter list, then the number of arguments and its
* arguments for the two nodes must also match to be considered
* equivalent. e.g.: CAST(c1 as INTEGER) vs CAST(c1 as SMALLINT), they
* are not equivalent.
*
* <li>When comparing SQL NULLs in this context, they are considered to be
* equivalent.
*
* <li>If this does not apply or it is determined that the two nodes are not
* equivalent then the derived class of this method should return false;
* otherwise, return true.
* </ul>
*
* @param other the node to compare this ValueNode against.
* @return <code>true</code> if the two nodes are equivalent,
* <code>false</code> otherwise.
*
* @throws StandardException
*/
protected abstract boolean isEquivalent(ValueNode other)
throws StandardException;
/**
* Tests if this node is of the same type as the specified node as
* reported by {@link QueryTreeNode#getNodeType()}.
*
* @param other the node to compare this value node against.
*
* @return <code>true</code> if the two nodes are of the same type.
*/
protected final boolean isSameNodeType(ValueNode other) {
if (other != null) {
return other.getNodeType() == getNodeType();
}
return false;
}
}