/* * 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; } }