001: /*
002:
003: Derby - Class org.apache.derby.impl.sql.compile.DB2LengthOperatorNode
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.services.sanity.SanityManager;
025:
026: import org.apache.derby.iapi.types.TypeId;
027: import org.apache.derby.iapi.types.DataTypeDescriptor;
028: import org.apache.derby.iapi.error.StandardException;
029: import org.apache.derby.iapi.services.compiler.MethodBuilder;
030: import org.apache.derby.iapi.services.compiler.LocalField;
031: import org.apache.derby.iapi.types.DataValueDescriptor;
032: import org.apache.derby.iapi.types.DataValueFactory;
033: import org.apache.derby.iapi.types.DataTypeDescriptor;
034:
035: import org.apache.derby.impl.sql.compile.ExpressionClassBuilder;
036:
037: import org.apache.derby.iapi.reference.SQLState;
038: import org.apache.derby.iapi.reference.ClassName;
039:
040: import org.apache.derby.iapi.services.classfile.VMOpcode;
041:
042: import java.lang.reflect.Modifier;
043:
044: import java.sql.Types;
045:
046: import java.util.Vector;
047:
048: /**
049: * This node represents a unary DB2 compatible length operator
050: *
051: * @author Jack Klebanoff
052: */
053:
054: public final class DB2LengthOperatorNode extends UnaryOperatorNode {
055:
056: /**
057: * Initializer for a DB2LengthOperatorNode
058: *
059: * @param operand The operand of the node
060: */
061: public void init(Object operand) {
062: super .init(operand, "length", "getDB2Length");
063: }
064:
065: /**
066: * Bind this operator
067: *
068: * @param fromList The query's FROM list
069: * @param subqueryList The subquery list being built as we find SubqueryNodes
070: * @param aggregateVector The aggregate vector being built as we find AggregateNodes
071: *
072: * @return The new top of the expression tree.
073: *
074: * @exception StandardException Thrown on error
075: */
076:
077: public ValueNode bindExpression(FromList fromList,
078: SubqueryList subqueryList, Vector aggregateVector)
079: throws StandardException {
080: ValueNode boundExpression = super .bindExpression(fromList,
081: subqueryList, aggregateVector);
082:
083: // This operator is not allowed on XML types.
084: TypeId operandType = operand.getTypeId();
085: if (operandType.isXMLTypeId()) {
086: throw StandardException.newException(
087: SQLState.LANG_UNARY_FUNCTION_BAD_TYPE,
088: getOperatorString(), operandType.getSQLTypeName());
089: }
090:
091: setType(new DataTypeDescriptor(TypeId
092: .getBuiltInTypeId(Types.INTEGER), operand
093: .getTypeServices().isNullable()));
094: return boundExpression;
095: }
096:
097: /**
098: * This is a length operator node. Overrides this method
099: * in UnaryOperatorNode for code generation purposes.
100: */
101: public String getReceiverInterfaceName() {
102: return ClassName.ConcatableDataValue;
103: }
104:
105: /**
106: * Do code generation for this unary operator.
107: *
108: * @param acb The ExpressionClassBuilder for the class we're generating
109: * @param mb The method the expression will go into
110: *
111: *
112: * @exception StandardException Thrown on error
113: */
114:
115: public void generateExpression(ExpressionClassBuilder acb,
116: MethodBuilder mb) throws StandardException {
117: if (operand == null)
118: return;
119:
120: int constantLength = getConstantLength();
121: // -1 if the length of a non-null operand depends on the data
122:
123: String resultTypeName = getTypeCompiler().interfaceName();
124:
125: mb.pushThis();
126: operand.generateExpression(acb, mb);
127: mb.upCast(ClassName.DataValueDescriptor);
128: mb.push(constantLength);
129:
130: /* Allocate an object for re-use to hold the result of the operator */
131: LocalField field = acb.newFieldDeclaration(Modifier.PRIVATE,
132: resultTypeName);
133: mb.getField(field);
134: mb.callMethod(VMOpcode.INVOKEVIRTUAL, ClassName.BaseActivation,
135: methodName, resultTypeName, 3);
136:
137: /*
138: ** Store the result of the method call in the field, so we can re-use
139: ** the object.
140: */
141: mb.putField(field);
142: } // end of generateExpression
143:
144: private int getConstantLength() throws StandardException {
145: DataTypeDescriptor typeDescriptor = operand.getTypeServices();
146:
147: switch (typeDescriptor.getJDBCTypeId()) {
148: case Types.BIGINT:
149: return 8;
150: case org.apache.derby.iapi.reference.JDBC30Translation.SQL_TYPES_BOOLEAN:
151: case Types.BIT:
152: return 1;
153: case Types.BINARY:
154: case Types.CHAR:
155: return typeDescriptor.getMaximumWidth();
156: case Types.DATE:
157: return 4;
158: case Types.DECIMAL:
159: case Types.NUMERIC:
160: return typeDescriptor.getPrecision() / 2 + 1;
161: case Types.DOUBLE:
162: return 8;
163: case Types.FLOAT:
164: case Types.REAL:
165: case Types.INTEGER:
166: return 4;
167: case Types.SMALLINT:
168: return 2;
169: case Types.TIME:
170: return 3;
171: case Types.TIMESTAMP:
172: return 10;
173: case Types.TINYINT:
174: return 1;
175: case Types.LONGVARCHAR:
176: case Types.VARCHAR:
177: case Types.LONGVARBINARY:
178: case Types.VARBINARY:
179: case Types.BLOB:
180: return getConstantNodeLength();
181: default:
182: return -1;
183: }
184: } // end of getConstantLength
185:
186: private int getConstantNodeLength() throws StandardException {
187: if (operand instanceof ConstantNode)
188: return ((ConstantNode) operand).getValue().getLength();
189: return -1;
190: }
191: }
|