001: /*
002:
003: Derby - Class org.apache.derby.impl.sql.compile.CastNode
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.context.ContextManager;
025:
026: import org.apache.derby.iapi.services.compiler.MethodBuilder;
027: import org.apache.derby.iapi.services.compiler.LocalField;
028:
029: import org.apache.derby.iapi.services.monitor.Monitor;
030:
031: import org.apache.derby.iapi.services.sanity.SanityManager;
032:
033: import org.apache.derby.iapi.error.StandardException;
034:
035: import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;
036:
037: import org.apache.derby.iapi.sql.compile.CompilerContext;
038: import org.apache.derby.iapi.sql.compile.C_NodeTypes;
039:
040: import org.apache.derby.iapi.sql.dictionary.DataDictionary;
041:
042: import org.apache.derby.iapi.types.DataTypeUtilities;
043: import org.apache.derby.iapi.types.TypeId;
044:
045: import org.apache.derby.iapi.reference.SQLState;
046:
047: import org.apache.derby.iapi.types.DataTypeDescriptor;
048: import org.apache.derby.iapi.types.DataValueFactory;
049: import org.apache.derby.iapi.types.DataValueDescriptor;
050: import org.apache.derby.iapi.types.VariableSizeDataValue;
051:
052: import org.apache.derby.iapi.sql.compile.TypeCompiler;
053:
054: import org.apache.derby.iapi.reference.SQLState;
055: import org.apache.derby.iapi.util.StringUtil;
056:
057: import org.apache.derby.iapi.reference.ClassName;
058: import org.apache.derby.iapi.reference.JDBC30Translation;
059: import org.apache.derby.iapi.services.classfile.VMOpcode;
060:
061: import org.apache.derby.iapi.types.DataValueDescriptor;
062:
063: import org.apache.derby.iapi.services.loader.ClassInspector;
064:
065: import org.apache.derby.iapi.sql.compile.Visitable;
066: import org.apache.derby.iapi.sql.compile.Visitor;
067: import org.apache.derby.iapi.sql.compile.C_NodeTypes;
068:
069: import java.lang.reflect.Modifier;
070:
071: import org.apache.derby.impl.sql.compile.ExpressionClassBuilder;
072: import org.apache.derby.iapi.types.NumberDataType;
073:
074: import org.apache.derby.iapi.util.JBitSet;
075: import org.apache.derby.iapi.util.ReuseFactory;
076:
077: import org.apache.derby.catalog.AliasInfo;
078: import org.apache.derby.catalog.TypeDescriptor;
079:
080: import org.apache.derby.iapi.types.SQLReal;
081:
082: import java.sql.Date;
083: import java.sql.Time;
084: import java.sql.Timestamp;
085: import java.sql.Types;
086:
087: import java.util.Vector;
088:
089: /**
090: * An CastNode represents a cast expressionr.
091: *
092: * @author Jerry Brenner
093: */
094:
095: public class CastNode extends ValueNode {
096: DataTypeDescriptor castTarget;
097: ValueNode castOperand;
098: int targetCharType;
099: TypeId destCTI = null;
100: TypeId sourceCTI = null;
101: boolean forDataTypeFunction = false;
102:
103: /*
104: ** Static array of valid casts. Dimentions
105: ** produce a single boolean which indicates
106: ** whether the case is possible or not.
107: */
108:
109: /**
110: * Initializer for a CastNode
111: *
112: * @param castOperand The operand of the node
113: * @param castTarget DataTypeServices (target type of cast)
114: *
115: * @exception StandardException Thrown on error
116: */
117:
118: public void init(Object castOperand, Object castTarget)
119: throws StandardException {
120: this .castOperand = (ValueNode) castOperand;
121: this .castTarget = (DataTypeDescriptor) castTarget;
122: }
123:
124: /**
125: * Initializer for a CastNode
126: *
127: * @param castOperand The operand of the node
128: * @param charType CHAR or VARCHAR JDBC type as target
129: * @param charLength target type length
130: *
131: * @exception StandardException Thrown on error
132: */
133:
134: public void init(Object castOperand, Object charType,
135: Object charLength) throws StandardException {
136: this .castOperand = (ValueNode) castOperand;
137: int charLen = ((Integer) charLength).intValue();
138: targetCharType = ((Integer) charType).intValue();
139: if (charLen < 0) // unknown, figure out later
140: return;
141: this .castTarget = DataTypeDescriptor
142: .getBuiltInDataTypeDescriptor(targetCharType, charLen);
143: }
144:
145: /**
146: * Convert this object to a String. See comments in QueryTreeNode.java
147: * for how this should be done for tree printing.
148: *
149: * @return This object as a String
150: */
151:
152: public String toString() {
153: if (SanityManager.DEBUG) {
154: return "castTarget: " + castTarget + "\n"
155: + super .toString();
156: } else {
157: return "";
158: }
159: }
160:
161: /**
162: * Prints the sub-nodes of this object. See QueryTreeNode.java for
163: * how tree printing is supposed to work.
164: *
165: * @param depth The depth of this node in the tree
166: */
167:
168: public void printSubNodes(int depth) {
169: if (SanityManager.DEBUG) {
170: super .printSubNodes(depth);
171:
172: if (castOperand != null) {
173: printLabel(depth, "castOperand: ");
174: castOperand.treePrint(depth + 1);
175: }
176: }
177: }
178:
179: protected int getOrderableVariantType() throws StandardException {
180: return castOperand.getOrderableVariantType();
181: }
182:
183: /**
184: * Set the clause that this node appears in.
185: *
186: * @param clause The clause that this node appears in.
187: */
188: public void setClause(int clause) {
189: super .setClause(clause);
190: castOperand.setClause(clause);
191: }
192:
193: /**
194: * Bind this expression. This means binding the sub-expressions,
195: * as well as figuring out what the return type is for this expression.
196: *
197: * @param fromList The FROM list for the query this
198: * expression is in, for binding columns.
199: * @param subqueryList The subquery list being built as we find SubqueryNodes
200: * @param aggregateVector The aggregate vector being built as we find AggregateNodes
201: *
202: * @return The new top of the expression tree.
203: *
204: * @exception StandardException Thrown on error
205: */
206:
207: public ValueNode bindExpression(FromList fromList,
208: SubqueryList subqueryList, Vector aggregateVector)
209: throws StandardException {
210: castOperand = castOperand.bindExpression(fromList,
211: subqueryList, aggregateVector);
212:
213: if (castTarget == null) //CHAR or VARCHAR function without specifying target length
214: {
215: DataTypeDescriptor opndType = castOperand.getTypeServices();
216: int length = -1;
217: TypeId srcTypeId = opndType.getTypeId();
218: if (opndType != null) {
219: if (srcTypeId.isNumericTypeId()) {
220: length = opndType.getPrecision() + 1; // 1 for the sign
221: if (opndType.getScale() > 0)
222: length += 1; // 1 for the decimal .
223:
224: } else {
225: TypeId typeid = opndType.getTypeId();
226: if (length < 0)
227: length = DataTypeUtilities
228: .getColumnDisplaySize(typeid
229: .getJDBCTypeId(), -1);
230:
231: }
232: }
233: if (length < 0)
234: length = 1; // same default as in parser
235: castTarget = DataTypeDescriptor
236: .getBuiltInDataTypeDescriptor(targetCharType,
237: length);
238:
239: }
240:
241: /*
242: ** If castOperand is an untyped null,
243: ** then we must set the type.
244: */
245: if (castOperand instanceof UntypedNullConstantNode) {
246: castOperand.setType(castTarget);
247: }
248:
249: bindCastNodeOnly();
250:
251: /* We can't chop out cast above an untyped null because
252: * the store can't handle it.
253: */
254: if ((castOperand instanceof ConstantNode)
255: && !(castOperand instanceof UntypedNullConstantNode)) {
256: /* If the castOperand is a typed constant then we do the cast at
257: * bind time and return a constant of the correct type.
258: * NOTE: This could return an exception, but we're prepared to
259: * deal with that. (NumberFormatException, etc.)
260: * We only worry about the easy (and useful)
261: * converions at bind time.
262: * Here's what we support:
263: * source destination
264: * ------ -----------
265: * boolean boolean
266: * boolean char
267: * char boolean
268: * char date/time/ts
269: * char non-decimal numeric
270: * date/time/ts char
271: * numeric char
272: * numeric non-decimal numeric
273: */
274: /* RESOLVE - to be filled in. */
275: ValueNode retNode = this ;
276: int sourceJDBCTypeId = sourceCTI.getJDBCTypeId();
277: int destJDBCTypeId = destCTI.getJDBCTypeId();
278:
279: switch (sourceJDBCTypeId) {
280: case Types.BIT:
281: case JDBC30Translation.SQL_TYPES_BOOLEAN:
282: // (BIT is boolean)
283: if (destJDBCTypeId == Types.BIT
284: || destJDBCTypeId == JDBC30Translation.SQL_TYPES_BOOLEAN) {
285: retNode = castOperand;
286: } else if (destJDBCTypeId == Types.CHAR) {
287: BooleanConstantNode bcn = (BooleanConstantNode) castOperand;
288: String booleanString = bcn.getValueAsString();
289: retNode = (ValueNode) getNodeFactory().getNode(
290: C_NodeTypes.CHAR_CONSTANT_NODE,
291: booleanString,
292: ReuseFactory.getInteger(castTarget
293: .getMaximumWidth()),
294: getContextManager());
295: }
296: break;
297:
298: case Types.CHAR:
299: retNode = getCastFromCharConstant(destJDBCTypeId);
300: break;
301:
302: case Types.DATE:
303: case Types.TIME:
304: case Types.TIMESTAMP:
305: if (destJDBCTypeId == Types.CHAR) {
306: String castValue = ((UserTypeConstantNode) castOperand)
307: .getObjectValue().toString();
308: retNode = (ValueNode) getNodeFactory().getNode(
309: C_NodeTypes.CHAR_CONSTANT_NODE,
310: castValue,
311: ReuseFactory.getInteger(castTarget
312: .getMaximumWidth()),
313: getContextManager());
314: }
315: break;
316:
317: case Types.DECIMAL:
318: // ignore decimal -> decimal casts for now
319: if (destJDBCTypeId == Types.DECIMAL
320: || destJDBCTypeId == Types.NUMERIC)
321: break;
322: // fall through
323: case Types.TINYINT:
324: case Types.SMALLINT:
325: case Types.INTEGER:
326: case Types.BIGINT:
327: case Types.DOUBLE:
328: case Types.REAL:
329: retNode = getCastFromNumericType(
330: ((ConstantNode) castOperand).getValue(),
331: destJDBCTypeId);
332: break;
333:
334: }
335:
336: // Return the new constant if the cast was performed
337: return retNode;
338: }
339:
340: return this ;
341: }
342:
343: /**
344: * Bind this node but not its child. Caller has already bound
345: * the child.
346: * This is useful for when we generate a CastNode during binding
347: * after having already bound the child.
348: *
349: * @exception StandardException Thrown on error
350: */
351: public void bindCastNodeOnly() throws StandardException {
352:
353: /*
354: ** The result type is always castTarget.
355: */
356: setType(castTarget);
357: destCTI = castTarget.getTypeId();
358: sourceCTI = castOperand.getTypeId();
359:
360: /*
361: ** If it is a java cast, do some work to make sure
362: ** the classes are ok and that they are compatible
363: */
364: if (destCTI.userType()) {
365: String className = ((TypeId) dataTypeServices.getTypeId())
366: .getCorrespondingJavaTypeName();
367:
368: boolean convertCase = !destCTI
369: .getClassNameWasDelimitedIdentifier();
370:
371: className = verifyClassExist(className, convertCase);
372:
373: castTarget = new DataTypeDescriptor(TypeId
374: .getUserDefinedTypeId(className, false), true /* assume nullable for now, change it if not nullable */
375: );
376: setType(castTarget);
377: destCTI = castTarget.getTypeId();
378: }
379:
380: if (castOperand.requiresTypeFromContext()) {
381: bindParameter();
382: }
383:
384: /*
385: ** If it isn't null, then we have
386: ** a cast from one JBMS type to another. So we
387: ** have to figure out if it is legit.
388: */
389: else if (!(castOperand instanceof UntypedNullConstantNode)) {
390: /*
391: ** Make sure we can assign the two classes
392: */
393: TypeCompiler tc = castOperand.getTypeCompiler();
394: if (!tc.convertible(destCTI, forDataTypeFunction)) {
395: throw StandardException.newException(
396: SQLState.LANG_INVALID_CAST, sourceCTI
397: .getSQLTypeName(), destCTI
398: .getSQLTypeName());
399: }
400: }
401: }
402:
403: /**
404: * Get a constant representing the cast from a CHAR to another
405: * type. If this is not an "easy" cast to perform, then just
406: * return this cast node.
407: * Here's what we think is "easy":
408: * source destination
409: * ------ -----------
410: * char boolean
411: * char date/time/ts
412: * char non-decimal numeric
413: *
414: * @param destJDBCTypeId The destination JDBC TypeId
415: *
416: * @return The new top of the tree (this CastNode or a new Constant)
417: *
418: * @exception StandardException Thrown on error
419: */
420: private ValueNode getCastFromCharConstant(int destJDBCTypeId)
421: throws StandardException {
422: String charValue = ((CharConstantNode) castOperand).getString();
423: String cleanCharValue = StringUtil.SQLToUpperCase(charValue
424: .trim());
425: ValueNode retNode = this ;
426:
427: switch (destJDBCTypeId) {
428: case Types.BIT:
429: case JDBC30Translation.SQL_TYPES_BOOLEAN:
430: if (cleanCharValue.equals("TRUE")) {
431: return (ValueNode) getNodeFactory().getNode(
432: C_NodeTypes.BOOLEAN_CONSTANT_NODE,
433: Boolean.TRUE, getContextManager());
434: } else if (cleanCharValue.equals("FALSE")) {
435: return (ValueNode) getNodeFactory().getNode(
436: C_NodeTypes.BOOLEAN_CONSTANT_NODE,
437: Boolean.FALSE, getContextManager());
438: } else {
439: throw StandardException.newException(
440: SQLState.LANG_FORMAT_EXCEPTION, "boolean");
441: }
442:
443: case Types.DATE:
444: return (ValueNode) getNodeFactory().getNode(
445: C_NodeTypes.USERTYPE_CONSTANT_NODE,
446: getDataValueFactory().getDateValue(cleanCharValue,
447: false), getContextManager());
448:
449: case Types.TIMESTAMP:
450: return (ValueNode) getNodeFactory()
451: .getNode(
452: C_NodeTypes.USERTYPE_CONSTANT_NODE,
453: getDataValueFactory().getTimestampValue(
454: cleanCharValue, false),
455: getContextManager());
456:
457: case Types.TIME:
458: return (ValueNode) getNodeFactory().getNode(
459: C_NodeTypes.USERTYPE_CONSTANT_NODE,
460: getDataValueFactory().getTimeValue(cleanCharValue,
461: false), getContextManager());
462:
463: case Types.TINYINT:
464: case Types.SMALLINT:
465: case Types.INTEGER:
466: case Types.BIGINT:
467: try {
468: // #3756 - Truncate decimal portion for casts to integer
469: return getCastFromIntegralType((new Double(
470: cleanCharValue)).longValue(), destJDBCTypeId);
471: } catch (NumberFormatException nfe) {
472: String sqlName = TypeId
473: .getBuiltInTypeId(destJDBCTypeId)
474: .getSQLTypeName();
475: throw StandardException.newException(
476: SQLState.LANG_FORMAT_EXCEPTION, sqlName);
477: }
478: case Types.REAL:
479: Float floatValue;
480: try {
481: floatValue = Float.valueOf(cleanCharValue);
482: } catch (NumberFormatException nfe) {
483: throw StandardException.newException(
484: SQLState.LANG_FORMAT_EXCEPTION, "float");
485: }
486: return (ValueNode) getNodeFactory().getNode(
487: C_NodeTypes.FLOAT_CONSTANT_NODE, floatValue,
488: getContextManager());
489: case Types.DOUBLE:
490: Double doubleValue;
491: try {
492: doubleValue = new Double(cleanCharValue);
493: } catch (NumberFormatException nfe) {
494: throw StandardException.newException(
495: SQLState.LANG_FORMAT_EXCEPTION, "double");
496: }
497: return (ValueNode) getNodeFactory().getNode(
498: C_NodeTypes.DOUBLE_CONSTANT_NODE, doubleValue,
499: getContextManager());
500: }
501:
502: return retNode;
503: }
504:
505: /**
506: * Get a constant representing the cast from an integral type to another
507: * type. If this is not an "easy" cast to perform, then just
508: * return this cast node.
509: * Here's what we think is "easy":
510: * source destination
511: * ------ -----------
512: * integral type non-decimal numeric
513: * integral type char
514: *
515: * @param longValue integral type as a long to cast from
516: * @param destJDBCTypeId The destination JDBC TypeId
517: *
518: * @return The new top of the tree (this CastNode or a new Constant)
519: *
520: * @exception StandardException Thrown on error
521: */
522: private ValueNode getCastFromIntegralType(long longValue,
523: int destJDBCTypeId) throws StandardException {
524: ValueNode retNode = this ;
525:
526: switch (destJDBCTypeId) {
527: case Types.CHAR:
528: return (ValueNode) getNodeFactory().getNode(
529: C_NodeTypes.CHAR_CONSTANT_NODE,
530: Long.toString(longValue),
531: ReuseFactory.getInteger(castTarget
532: .getMaximumWidth()), getContextManager());
533: case Types.TINYINT:
534: if (longValue < Byte.MIN_VALUE
535: || longValue > Byte.MAX_VALUE) {
536: throw StandardException.newException(
537: SQLState.LANG_OUTSIDE_RANGE_FOR_DATATYPE,
538: "TINYINT");
539: }
540: return (ValueNode) getNodeFactory().getNode(
541: C_NodeTypes.TINYINT_CONSTANT_NODE,
542: ReuseFactory.getByte((byte) longValue),
543: getContextManager());
544:
545: case Types.SMALLINT:
546: if (longValue < Short.MIN_VALUE
547: || longValue > Short.MAX_VALUE) {
548: throw StandardException.newException(
549: SQLState.LANG_OUTSIDE_RANGE_FOR_DATATYPE,
550: "SHORT");
551: }
552: return (ValueNode) getNodeFactory().getNode(
553: C_NodeTypes.SMALLINT_CONSTANT_NODE,
554: ReuseFactory.getShort((short) longValue),
555: getContextManager());
556:
557: case Types.INTEGER:
558: if (longValue < Integer.MIN_VALUE
559: || longValue > Integer.MAX_VALUE) {
560: throw StandardException.newException(
561: SQLState.LANG_OUTSIDE_RANGE_FOR_DATATYPE,
562: "INTEGER");
563: }
564: return (ValueNode) getNodeFactory().getNode(
565: C_NodeTypes.INT_CONSTANT_NODE,
566: ReuseFactory.getInteger((int) longValue),
567: getContextManager());
568:
569: case Types.BIGINT:
570: return (ValueNode) getNodeFactory().getNode(
571: C_NodeTypes.LONGINT_CONSTANT_NODE,
572: ReuseFactory.getLong(longValue),
573: getContextManager());
574:
575: case Types.REAL:
576: if (Math.abs(longValue) > Float.MAX_VALUE) {
577: throw StandardException.newException(
578: SQLState.LANG_OUTSIDE_RANGE_FOR_DATATYPE,
579: "REAL");
580: }
581: return (ValueNode) getNodeFactory().getNode(
582: C_NodeTypes.FLOAT_CONSTANT_NODE,
583: new Float((float) longValue), getContextManager());
584:
585: case Types.DOUBLE:
586: return (ValueNode) getNodeFactory()
587: .getNode(C_NodeTypes.DOUBLE_CONSTANT_NODE,
588: new Double((double) longValue),
589: getContextManager());
590: }
591:
592: return retNode;
593: }
594:
595: /**
596: * Get a constant representing the cast from a non-integral type to another
597: * type. If this is not an "easy" cast to perform, then just
598: * return this cast node.
599: * Here's what we think is "easy":
600: * source destination
601: * ------ -----------
602: * non-integral type non-decimal numeric
603: * non-integral type char
604: *
605: * @param constantValue non-integral type a a double to cast from
606: * @param destJDBCTypeId The destination JDBC TypeId
607: *
608: * @return The new top of the tree (this CastNode or a new Constant)
609: *
610: * @exception StandardException Thrown on error
611: */
612: private ValueNode getCastFromNumericType(
613: DataValueDescriptor constantValue, int destJDBCTypeId)
614: throws StandardException {
615: int nodeType = -1;
616: Object constantObject = null;
617:
618: switch (destJDBCTypeId) {
619: case Types.CHAR:
620: nodeType = C_NodeTypes.CHAR_CONSTANT_NODE;
621: constantObject = constantValue.getString();
622: return (ValueNode) getNodeFactory().getNode(
623: nodeType,
624: constantObject,
625: ReuseFactory.getInteger(castTarget
626: .getMaximumWidth()), getContextManager());
627:
628: case Types.TINYINT:
629: nodeType = C_NodeTypes.TINYINT_CONSTANT_NODE;
630: constantObject = new Byte(constantValue.getByte());
631: break;
632:
633: case Types.SMALLINT:
634: nodeType = C_NodeTypes.SMALLINT_CONSTANT_NODE;
635: constantObject = ReuseFactory.getShort(constantValue
636: .getShort());
637: break;
638:
639: case Types.INTEGER:
640: nodeType = C_NodeTypes.INT_CONSTANT_NODE;
641: constantObject = ReuseFactory.getInteger(constantValue
642: .getInt());
643: break;
644:
645: case Types.BIGINT:
646: nodeType = C_NodeTypes.LONGINT_CONSTANT_NODE;
647: constantObject = ReuseFactory.getLong(constantValue
648: .getLong());
649: break;
650:
651: case Types.REAL:
652: nodeType = C_NodeTypes.FLOAT_CONSTANT_NODE;
653: constantObject = new Float(NumberDataType
654: .normalizeREAL(constantValue.getDouble()));
655: break;
656:
657: case Types.DOUBLE:
658: // no need to normalize here because no constant could be out of range for a double
659: nodeType = C_NodeTypes.DOUBLE_CONSTANT_NODE;
660: constantObject = new Double(constantValue.getDouble());
661: break;
662: }
663:
664: if (nodeType == -1)
665: return this ;
666:
667: return (ValueNode) getNodeFactory().getNode(nodeType,
668: constantObject, getContextManager());
669:
670: }
671:
672: /**
673: * Preprocess an expression tree. We do a number of transformations
674: * here (including subqueries, IN lists, LIKE and BETWEEN) plus
675: * subquery flattening.
676: * NOTE: This is done before the outer ResultSetNode is preprocessed.
677: *
678: * @param numTables Number of tables in the DML Statement
679: * @param outerFromList FromList from outer query block
680: * @param outerSubqueryList SubqueryList from outer query block
681: * @param outerPredicateList PredicateList from outer query block
682: *
683: * @return The modified expression
684: *
685: * @exception StandardException Thrown on error
686: */
687: public ValueNode preprocess(int numTables, FromList outerFromList,
688: SubqueryList outerSubqueryList,
689: PredicateList outerPredicateList) throws StandardException {
690: castOperand = castOperand.preprocess(numTables, outerFromList,
691: outerSubqueryList, outerPredicateList);
692: return this ;
693: }
694:
695: /**
696: * Categorize this predicate. Initially, this means
697: * building a bit map of the referenced tables for each predicate.
698: * If the source of this ColumnReference (at the next underlying level)
699: * is not a ColumnReference or a VirtualColumnNode then this predicate
700: * will not be pushed down.
701: *
702: * For example, in:
703: * select * from (select 1 from s) a (x) where x = 1
704: * we will not push down x = 1.
705: * NOTE: It would be easy to handle the case of a constant, but if the
706: * inner SELECT returns an arbitrary expression, then we would have to copy
707: * that tree into the pushed predicate, and that tree could contain
708: * subqueries and method calls.
709: * RESOLVE - revisit this issue once we have views.
710: *
711: * @param referencedTabs JBitSet with bit map of referenced FromTables
712: * @param simplePredsOnly Whether or not to consider method
713: * calls, field references and conditional nodes
714: * when building bit map
715: *
716: * @return boolean Whether or not source.expression is a ColumnReference
717: * or a VirtualColumnNode.
718: *
719: * @exception StandardException Thrown on error
720: */
721: public boolean categorize(JBitSet referencedTabs,
722: boolean simplePredsOnly) throws StandardException {
723: return castOperand.categorize(referencedTabs, simplePredsOnly);
724: }
725:
726: /**
727: * Remap all ColumnReferences in this tree to be clones of the
728: * underlying expression.
729: *
730: * @return ValueNode The remapped expression tree.
731: *
732: * @exception StandardException Thrown on error
733: */
734: public ValueNode remapColumnReferencesToExpressions()
735: throws StandardException {
736: castOperand = castOperand.remapColumnReferencesToExpressions();
737: return this ;
738: }
739:
740: /**
741: * Return whether or not this expression tree represents a constant expression.
742: *
743: * @return Whether or not this expression tree represents a constant expression.
744: */
745: public boolean isConstantExpression() {
746: return castOperand.isConstantExpression();
747: }
748:
749: /** @see ValueNode#constantExpression */
750: public boolean constantExpression(PredicateList whereClause) {
751: return castOperand.constantExpression(whereClause);
752: }
753:
754: /**
755: * By default unary operators don't accept ? parameters as operands.
756: * This can be over-ridden for particular unary operators.
757: *
758: * @exception StandardException Always thrown to indicate a
759: * ? parameter where it isn't allowed.
760: */
761:
762: void bindParameter() throws StandardException {
763: castOperand.setType(castTarget);
764: }
765:
766: /**
767: * Return an Object representing the bind time value of this
768: * expression tree. If the expression tree does not evaluate to
769: * a constant at bind time then we return null.
770: * This is useful for bind time resolution of VTIs.
771: * RESOLVE: What do we do for primitives?
772: *
773: * @return An Object representing the bind time value of this expression tree.
774: * (null if not a bind time constant.)
775: *
776: * @exception StandardException Thrown on error
777: */
778: Object getConstantValueAsObject() throws StandardException {
779: Object sourceObject = castOperand.getConstantValueAsObject();
780:
781: // RESOLVE - need to figure out how to handle casts
782: if (sourceObject == null) {
783: return null;
784: }
785:
786: // Simple if source and destination are of same type
787: if (sourceCTI.getCorrespondingJavaTypeName().equals(
788: destCTI.getCorrespondingJavaTypeName())) {
789: return sourceObject;
790: }
791:
792: // RESOLVE - simply return null until we can figure out how to
793: // do the cast
794: return null;
795: }
796:
797: /**
798: * Do code generation for this unary operator.
799: *
800: * @param acb The ExpressionClassBuilder for the class we're generating
801: * @param mb The method the code to place the code
802: *
803: * @exception StandardException Thrown on error
804: */
805:
806: public void generateExpression(ExpressionClassBuilder acb,
807: MethodBuilder mb) throws StandardException {
808: castOperand.generateExpression(acb, mb);
809:
810: /* No need to generate code for null constants */
811: if (castOperand instanceof UntypedNullConstantNode) {
812: return;
813: }
814: /* HACK ALERT. When casting a parameter, there
815: * is not sourceCTI. Code generation requires one,
816: * so we simply set it to be the same as the
817: * destCTI. The user can still pass whatever
818: * type they'd like in as a parameter.
819: * They'll get an exception, as expected, if the
820: * conversion cannot be performed.
821: */
822: else if (castOperand.requiresTypeFromContext()) {
823: sourceCTI = destCTI;
824: }
825:
826: genDataValueConversion(acb, mb);
827: }
828:
829: private void genDataValueConversion(ExpressionClassBuilder acb,
830: MethodBuilder mb) throws StandardException {
831: MethodBuilder acbConstructor = acb.getConstructor();
832:
833: String resultTypeName = getTypeCompiler().interfaceName();
834:
835: /* field = method call */
836: /* Allocate an object for re-use to hold the result of the operator */
837: LocalField field = acb.newFieldDeclaration(Modifier.PRIVATE,
838: resultTypeName);
839:
840: /*
841: ** Store the result of the method call in the field, so we can re-use
842: ** the object.
843: */
844:
845: acb.generateNull(acbConstructor, getTypeCompiler(destCTI));
846: acbConstructor.setField(field);
847:
848: /*
849: For most types generate
850:
851: targetDVD.setValue(sourceDVD);
852:
853: For source or destination java types generate
854:
855: Object o = sourceDVD.getObject();
856: targetDVD.setObjectForCast(o, o instanceof dest java type, dest java type);
857:
858: // optional for variable length types
859: targetDVD.setWidth();
860: */
861:
862: if (!sourceCTI.userType() && !destCTI.userType()) {
863: mb.getField(field); // targetDVD reference for the setValue method call
864: mb.swap();
865: mb.upCast(ClassName.DataValueDescriptor);
866: mb.callMethod(VMOpcode.INVOKEINTERFACE,
867: ClassName.DataValueDescriptor, "setValue", "void",
868: 1);
869: } else {
870: /*
871: ** generate: expr.getObject()
872: */
873: mb.callMethod(VMOpcode.INVOKEINTERFACE,
874: ClassName.DataValueDescriptor, "getObject",
875: "java.lang.Object", 0);
876:
877: //castExpr
878:
879: mb.getField(field); // instance for the setValue/setObjectForCast method call
880: mb.swap(); // push it before the value
881:
882: /*
883: ** We are casting a java type, generate:
884: **
885: ** DataValueDescriptor.setObjectForCast(java.lang.Object castExpr, boolean instanceOfExpr, destinationClassName)
886: ** where instanceOfExpr is "source instanceof destinationClass".
887: **
888: */
889: String destinationType = getTypeId()
890: .getCorrespondingJavaTypeName();
891:
892: // at this point method instance and cast result are on the stack
893: // we duplicate the cast value in order to perform the instanceof check
894: mb.dup();
895: mb.isInstanceOf(destinationType);
896: mb.push(destinationType);
897: mb.callMethod(VMOpcode.INVOKEINTERFACE,
898: ClassName.DataValueDescriptor, "setObjectForCast",
899: "void", 3);
900:
901: }
902:
903: mb.getField(field);
904:
905: /*
906: ** If we are casting to a variable length datatype, we
907: ** have to make sure we have set it to the correct
908: ** length.
909: */
910: if (destCTI.variableLength()) {
911: boolean isNumber = destCTI.isNumericTypeId();
912:
913: // to leave the DataValueDescriptor value on the stack, since setWidth is void
914: mb.dup();
915:
916: /* setWidth() is on VSDV - upcast since
917: * decimal implements subinterface
918: * of VSDV.
919: */
920:
921: mb.push(isNumber ? castTarget.getPrecision() : castTarget
922: .getMaximumWidth());
923: mb.push(castTarget.getScale());
924: mb.push(!sourceCTI.variableLength() || isNumber);
925: mb.callMethod(VMOpcode.INVOKEINTERFACE,
926: ClassName.VariableSizeDataValue, "setWidth",
927: "void", 3);
928:
929: }
930: }
931:
932: /**
933: * Accept a visitor, and call v.visit()
934: * on child nodes as necessary.
935: *
936: * @param v the visitor
937: *
938: * @exception StandardException on error
939: */
940: public Visitable accept(Visitor v) throws StandardException {
941: Visitable returnNode = v.visit(this );
942:
943: if (v.skipChildren(this )) {
944: return returnNode;
945: }
946:
947: if (castOperand != null && !v.stopTraversal()) {
948: castOperand = (ValueNode) castOperand.accept(v);
949: }
950:
951: return returnNode;
952: }
953:
954: /** set this to be a dataTypeScalarFunction
955: *
956: * @param b true to use function conversion rules
957: */
958: public void setForDataTypeFunction(boolean b) {
959: forDataTypeFunction = b;
960: }
961:
962: /** is this a cast node for a data type scalar function?
963: * @return true if this is a function, false for regular cast node
964: *
965: */
966: public boolean getForDataTypeFunction() {
967: return forDataTypeFunction;
968: }
969:
970: /**
971: * {@inheritDoc}
972: * @throws StandardException
973: */
974: protected boolean isEquivalent(ValueNode o)
975: throws StandardException {
976: if (isSameNodeType(o)) {
977: CastNode other = (CastNode) o;
978: return castTarget.equals(other.castTarget)
979: && castOperand.isEquivalent(other.castOperand);
980: }
981: return false;
982: }
983: }
|