001: /*
002:
003: Derby - Class org.apache.derby.impl.sql.compile.UnaryDateTimestampOperatorNode
004:
005: Licensed to the Apache Software Foundation (ASF) under one or more
006: contributor license agreements. See the NOTICE file distributed with
007: this work for additional information regarding copyright ownership.
008: The ASF licenses this file to you under the Apache License, Version 2.0
009: (the "License"); you may not use this file except in compliance with
010: the License. You may obtain a copy of the License at
011:
012: http://www.apache.org/licenses/LICENSE-2.0
013:
014: Unless required by applicable law or agreed to in writing, software
015: distributed under the License is distributed on an "AS IS" BASIS,
016: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017: See the License for the specific language governing permissions and
018: limitations under the License.
019:
020: */
021:
022: package org.apache.derby.impl.sql.compile;
023:
024: import org.apache.derby.iapi.types.DataValueFactory;
025: import org.apache.derby.iapi.types.DataTypeDescriptor;
026: import org.apache.derby.iapi.types.DataValueDescriptor;
027: import org.apache.derby.iapi.types.DateTimeDataValue;
028: import org.apache.derby.iapi.services.compiler.MethodBuilder;
029: import org.apache.derby.iapi.error.StandardException;
030:
031: import org.apache.derby.iapi.sql.compile.C_NodeTypes;
032:
033: import org.apache.derby.impl.sql.compile.ExpressionClassBuilder;
034:
035: import org.apache.derby.iapi.reference.ClassName;
036: import org.apache.derby.iapi.reference.SQLState;
037:
038: import org.apache.derby.iapi.services.classfile.VMOpcode;
039: import org.apache.derby.iapi.services.sanity.SanityManager;
040:
041: import java.sql.Types;
042:
043: import java.util.Vector;
044:
045: /**
046: * This class implements the timestamp( x) and date(x) functions.
047: *
048: * These two functions implement a few special cases of string conversions beyond the normal string to
049: * date/timestamp casts.
050: */
051: public class UnaryDateTimestampOperatorNode extends UnaryOperatorNode {
052: private static final String TIMESTAMP_METHOD_NAME = "getTimestamp";
053: private static final String DATE_METHOD_NAME = "getDate";
054:
055: /**
056: * @param operand The operand of the function
057: * @param targetType The type of the result. Timestamp or Date.
058: *
059: * @exception StandardException Thrown on error
060: */
061:
062: public void init(Object operand, Object targetType)
063: throws StandardException {
064: setType((DataTypeDescriptor) targetType);
065: switch (getTypeServices().getJDBCTypeId()) {
066: case Types.DATE:
067: super .init(operand, "date", DATE_METHOD_NAME);
068: break;
069:
070: case Types.TIMESTAMP:
071: super .init(operand, "timestamp", TIMESTAMP_METHOD_NAME);
072: break;
073:
074: default:
075: if (SanityManager.DEBUG)
076: SanityManager.NOTREACHED();
077: super .init(operand);
078: }
079: }
080:
081: /**
082: * Called by UnaryOperatorNode.bindExpression.
083: *
084: * If the operand is a constant then evaluate the function at compile time. Otherwise,
085: * if the operand input type is the same as the output type then discard this node altogether.
086: * If the function is "date" and the input is a timestamp then change this node to a cast.
087: *
088: * @param fromList The FROM list for the query this
089: * expression is in, for binding columns.
090: * @param subqueryList The subquery list being built as we find SubqueryNodes
091: * @param aggregateVector The aggregate vector being built as we find AggregateNodes
092: *
093: * @return The new top of the expression tree.
094: *
095: * @exception StandardException Thrown on error
096: */
097: protected ValueNode bindUnaryOperator(FromList fromList,
098: SubqueryList subqueryList, Vector aggregateVector)
099: throws StandardException {
100: boolean isIdentity = false; // Is this function the identity operator?
101: boolean operandIsNumber = false;
102:
103: super
104: .bindUnaryOperator(fromList, subqueryList,
105: aggregateVector);
106: DataTypeDescriptor operandType = operand.getTypeServices();
107: switch (operandType.getJDBCTypeId()) {
108: case Types.BIGINT:
109: case Types.INTEGER:
110: case Types.SMALLINT:
111: case Types.TINYINT:
112: case Types.DECIMAL:
113: case Types.NUMERIC:
114: case Types.DOUBLE:
115: case Types.FLOAT:
116: if (TIMESTAMP_METHOD_NAME.equals(methodName))
117: invalidOperandType();
118: operandIsNumber = true;
119: break;
120:
121: case Types.CHAR:
122: case Types.VARCHAR:
123: break;
124:
125: case Types.DATE:
126: if (TIMESTAMP_METHOD_NAME.equals(methodName))
127: invalidOperandType();
128: isIdentity = true;
129: break;
130:
131: case Types.NULL:
132: break;
133:
134: case Types.TIMESTAMP:
135: if (TIMESTAMP_METHOD_NAME.equals(methodName))
136: isIdentity = true;
137: break;
138:
139: default:
140: invalidOperandType();
141: }
142:
143: if (operand instanceof ConstantNode) {
144: DataValueFactory dvf = getLanguageConnectionContext()
145: .getDataValueFactory();
146: DataValueDescriptor sourceValue = ((ConstantNode) operand)
147: .getValue();
148: DataValueDescriptor destValue = null;
149: if (sourceValue.isNull()) {
150: destValue = (TIMESTAMP_METHOD_NAME.equals(methodName)) ? dvf
151: .getNullTimestamp((DateTimeDataValue) null)
152: : dvf.getNullDate((DateTimeDataValue) null);
153: } else {
154: destValue = (TIMESTAMP_METHOD_NAME.equals(methodName)) ? dvf
155: .getTimestamp(sourceValue)
156: : dvf.getDate(sourceValue);
157: }
158: return (ValueNode) getNodeFactory().getNode(
159: C_NodeTypes.USERTYPE_CONSTANT_NODE, destValue,
160: getContextManager());
161: }
162:
163: if (isIdentity)
164: return operand;
165: return this ;
166: } // end of bindUnaryOperator
167:
168: private void invalidOperandType() throws StandardException {
169: throw StandardException.newException(
170: SQLState.LANG_UNARY_FUNCTION_BAD_TYPE,
171: getOperatorString(), getOperand().getTypeServices()
172: .getSQLstring());
173: }
174:
175: /**
176: * Do code generation for this unary operator.
177: *
178: * @param acb The ExpressionClassBuilder for the class we're generating
179: * @param mb The method the expression will go into
180: *
181: *
182: * @exception StandardException Thrown on error
183: */
184:
185: public void generateExpression(ExpressionClassBuilder acb,
186: MethodBuilder mb) throws StandardException {
187: acb.pushDataValueFactory(mb);
188: operand.generateExpression(acb, mb);
189: mb.cast(ClassName.DataValueDescriptor);
190: mb.callMethod(VMOpcode.INVOKEINTERFACE, (String) null,
191: methodName, getTypeCompiler().interfaceName(), 1);
192: } // end of generateExpression
193: }
|