KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > derby > impl > sql > compile > CastNode


1 /*
2
3    Derby - Class org.apache.derby.impl.sql.compile.CastNode
4
5    Licensed to the Apache Software Foundation (ASF) under one or more
6    contributor license agreements. See the NOTICE file distributed with
7    this work for additional information regarding copyright ownership.
8    The ASF licenses this file to you under the Apache License, Version 2.0
9    (the "License"); you may not use this file except in compliance with
10    the License. You may obtain a copy of the License at
11
12       http://www.apache.org/licenses/LICENSE-2.0
13
14    Unless required by applicable law or agreed to in writing, software
15    distributed under the License is distributed on an "AS IS" BASIS,
16    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17    See the License for the specific language governing permissions and
18    limitations under the License.
19
20  */

21
22 package org.apache.derby.impl.sql.compile;
23
24 import org.apache.derby.iapi.services.context.ContextManager;
25
26 import org.apache.derby.iapi.services.compiler.MethodBuilder;
27 import org.apache.derby.iapi.services.compiler.LocalField;
28
29 import org.apache.derby.iapi.services.monitor.Monitor;
30
31 import org.apache.derby.iapi.services.sanity.SanityManager;
32
33 import org.apache.derby.iapi.error.StandardException;
34
35 import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;
36
37 import org.apache.derby.iapi.sql.compile.CompilerContext;
38 import org.apache.derby.iapi.sql.compile.C_NodeTypes;
39
40 import org.apache.derby.iapi.sql.dictionary.DataDictionary;
41
42 import org.apache.derby.iapi.types.DataTypeUtilities;
43 import org.apache.derby.iapi.types.TypeId;
44
45 import org.apache.derby.iapi.reference.SQLState;
46
47 import org.apache.derby.iapi.types.DataTypeDescriptor;
48 import org.apache.derby.iapi.types.DataValueFactory;
49 import org.apache.derby.iapi.types.DataValueDescriptor;
50 import org.apache.derby.iapi.types.VariableSizeDataValue;
51
52 import org.apache.derby.iapi.sql.compile.TypeCompiler;
53
54 import org.apache.derby.iapi.reference.SQLState;
55 import org.apache.derby.iapi.util.StringUtil;
56
57 import org.apache.derby.iapi.reference.ClassName;
58 import org.apache.derby.iapi.reference.JDBC30Translation;
59 import org.apache.derby.iapi.services.classfile.VMOpcode;
60
61 import org.apache.derby.iapi.types.DataValueDescriptor;
62
63 import org.apache.derby.iapi.services.loader.ClassInspector;
64
65 import org.apache.derby.iapi.sql.compile.Visitable;
66 import org.apache.derby.iapi.sql.compile.Visitor;
67 import org.apache.derby.iapi.sql.compile.C_NodeTypes;
68
69 import java.lang.reflect.Modifier JavaDoc;
70
71 import org.apache.derby.impl.sql.compile.ExpressionClassBuilder;
72 import org.apache.derby.iapi.types.NumberDataType;
73
74 import org.apache.derby.iapi.util.JBitSet;
75 import org.apache.derby.iapi.util.ReuseFactory;
76
77 import org.apache.derby.catalog.AliasInfo;
78 import org.apache.derby.catalog.TypeDescriptor;
79
80 import org.apache.derby.iapi.types.SQLReal;
81
82 import java.sql.Date JavaDoc;
83 import java.sql.Time JavaDoc;
84 import java.sql.Timestamp JavaDoc;
85 import java.sql.Types JavaDoc;
86
87 import java.util.Vector JavaDoc;
88
89 /**
90  * An CastNode represents a cast expressionr.
91  *
92  * @author Jerry Brenner
93  */

94
95 public class CastNode extends ValueNode
96 {
97     DataTypeDescriptor castTarget;
98     ValueNode castOperand;
99     int targetCharType;
100     TypeId destCTI = null;
101     TypeId sourceCTI = null;
102     boolean forDataTypeFunction = false;
103
104     /*
105     ** Static array of valid casts. Dimentions
106     ** produce a single boolean which indicates
107     ** whether the case is possible or not.
108     */

109
110     /**
111      * Initializer for a CastNode
112      *
113      * @param castOperand The operand of the node
114      * @param castTarget DataTypeServices (target type of cast)
115      *
116      * @exception StandardException Thrown on error
117      */

118
119     public void init(Object JavaDoc castOperand, Object JavaDoc castTarget)
120         throws StandardException
121     {
122         this.castOperand = (ValueNode) castOperand;
123         this.castTarget = (DataTypeDescriptor) castTarget;
124     }
125
126     /**
127      * Initializer for a CastNode
128      *
129      * @param castOperand The operand of the node
130      * @param charType CHAR or VARCHAR JDBC type as target
131      * @param charLength target type length
132      *
133      * @exception StandardException Thrown on error
134      */

135
136     public void init(Object JavaDoc castOperand, Object JavaDoc charType, Object JavaDoc charLength)
137         throws StandardException
138     {
139         this.castOperand = (ValueNode) castOperand;
140         int charLen = ((Integer JavaDoc) charLength).intValue();
141         targetCharType = ((Integer JavaDoc) charType).intValue();
142         if (charLen < 0) // unknown, figure out later
143
return;
144         this.castTarget = DataTypeDescriptor.getBuiltInDataTypeDescriptor(targetCharType, charLen);
145     }
146
147     /**
148      * Convert this object to a String. See comments in QueryTreeNode.java
149      * for how this should be done for tree printing.
150      *
151      * @return This object as a String
152      */

153
154     public String JavaDoc toString()
155     {
156         if (SanityManager.DEBUG)
157         {
158             return "castTarget: " + castTarget + "\n" +
159                 super.toString();
160         }
161         else
162         {
163             return "";
164         }
165     }
166
167     /**
168      * Prints the sub-nodes of this object. See QueryTreeNode.java for
169      * how tree printing is supposed to work.
170      *
171      * @param depth The depth of this node in the tree
172      */

173
174     public void printSubNodes(int depth)
175     {
176         if (SanityManager.DEBUG)
177         {
178             super.printSubNodes(depth);
179
180             if (castOperand != null)
181             {
182                 printLabel(depth, "castOperand: ");
183                 castOperand.treePrint(depth + 1);
184             }
185         }
186     }
187     protected int getOrderableVariantType() throws StandardException
188     {
189         return castOperand.getOrderableVariantType();
190     }
191
192     /**
193      * Set the clause that this node appears in.
194      *
195      * @param clause The clause that this node appears in.
196      */

197     public void setClause(int clause)
198     {
199         super.setClause(clause);
200         castOperand.setClause(clause);
201     }
202
203     /**
204      * Bind this expression. This means binding the sub-expressions,
205      * as well as figuring out what the return type is for this expression.
206      *
207      * @param fromList The FROM list for the query this
208      * expression is in, for binding columns.
209      * @param subqueryList The subquery list being built as we find SubqueryNodes
210      * @param aggregateVector The aggregate vector being built as we find AggregateNodes
211      *
212      * @return The new top of the expression tree.
213      *
214      * @exception StandardException Thrown on error
215      */

216
217     public ValueNode bindExpression(FromList fromList, SubqueryList subqueryList,
218                                     Vector JavaDoc aggregateVector)
219                 throws StandardException
220     {
221         castOperand = castOperand.bindExpression(
222                                 fromList, subqueryList,
223                                 aggregateVector);
224
225         if (castTarget == null) //CHAR or VARCHAR function without specifying target length
226
{
227             DataTypeDescriptor opndType = castOperand.getTypeServices();
228             int length = -1;
229             TypeId srcTypeId = opndType.getTypeId();
230             if (opndType != null)
231             {
232                 if (srcTypeId.isNumericTypeId())
233                 {
234                     length = opndType.getPrecision() + 1; // 1 for the sign
235
if (opndType.getScale() > 0)
236                         length += 1; // 1 for the decimal .
237

238                 }
239                 else
240                 {
241                     TypeId typeid = opndType.getTypeId();
242                     if (length < 0)
243                         length = DataTypeUtilities.getColumnDisplaySize(typeid.getJDBCTypeId(),-1);
244
245                 }
246             }
247             if (length < 0)
248                 length = 1; // same default as in parser
249
castTarget = DataTypeDescriptor.getBuiltInDataTypeDescriptor(targetCharType, length);
250             
251         }
252
253         /*
254         ** If castOperand is an untyped null,
255         ** then we must set the type.
256         */

257         if (castOperand instanceof UntypedNullConstantNode)
258         {
259             castOperand.setType(castTarget);
260         }
261
262         bindCastNodeOnly();
263         
264         /* We can't chop out cast above an untyped null because
265          * the store can't handle it.
266          */

267         if ((castOperand instanceof ConstantNode) &&
268             !(castOperand instanceof UntypedNullConstantNode))
269         {
270             /* If the castOperand is a typed constant then we do the cast at
271              * bind time and return a constant of the correct type.
272              * NOTE: This could return an exception, but we're prepared to
273              * deal with that. (NumberFormatException, etc.)
274              * We only worry about the easy (and useful)
275              * converions at bind time.
276              * Here's what we support:
277              * source destination
278              * ------ -----------
279              * boolean boolean
280              * boolean char
281              * char boolean
282              * char date/time/ts
283              * char non-decimal numeric
284              * date/time/ts char
285              * numeric char
286              * numeric non-decimal numeric
287              */

288             /* RESOLVE - to be filled in. */
289             ValueNode retNode = this;
290             int sourceJDBCTypeId = sourceCTI.getJDBCTypeId();
291             int destJDBCTypeId = destCTI.getJDBCTypeId();
292
293             switch (sourceJDBCTypeId)
294             {
295                 case Types.BIT:
296                 case JDBC30Translation.SQL_TYPES_BOOLEAN:
297                     // (BIT is boolean)
298
if (destJDBCTypeId == Types.BIT || destJDBCTypeId == JDBC30Translation.SQL_TYPES_BOOLEAN)
299                     {
300                         retNode = castOperand;
301                     }
302                     else if (destJDBCTypeId == Types.CHAR)
303                     {
304                         BooleanConstantNode bcn = (BooleanConstantNode) castOperand;
305                         String JavaDoc booleanString = bcn.getValueAsString();
306                         retNode = (ValueNode) getNodeFactory().getNode(
307                                             C_NodeTypes.CHAR_CONSTANT_NODE,
308                                             booleanString,
309                                             ReuseFactory.getInteger(
310                                                 castTarget.getMaximumWidth()),
311                                             getContextManager());
312                     }
313                     break;
314
315                     case Types.CHAR:
316                         retNode = getCastFromCharConstant(destJDBCTypeId);
317                         break;
318
319                     case Types.DATE:
320                     case Types.TIME:
321                     case Types.TIMESTAMP:
322                         if (destJDBCTypeId == Types.CHAR)
323                         {
324                             String JavaDoc castValue =
325                                 ((UserTypeConstantNode) castOperand).
326                                             getObjectValue().
327                                                 toString();
328                             retNode = (ValueNode) getNodeFactory().getNode(
329                                                 C_NodeTypes.CHAR_CONSTANT_NODE,
330                                                 castValue,
331                                                 ReuseFactory.getInteger(
332                                                   castTarget.getMaximumWidth()),
333                                                 getContextManager());
334                         }
335                         break;
336
337                     case Types.DECIMAL:
338                         // ignore decimal -> decimal casts for now
339
if (destJDBCTypeId == Types.DECIMAL ||
340                             destJDBCTypeId == Types.NUMERIC)
341                             break;
342                         // fall through
343
case Types.TINYINT:
344                     case Types.SMALLINT:
345                     case Types.INTEGER:
346                     case Types.BIGINT:
347                     case Types.DOUBLE:
348                     case Types.REAL:
349                         retNode = getCastFromNumericType(
350                                             ((ConstantNode) castOperand).getValue(),
351                                             destJDBCTypeId);
352                         break;
353
354             }
355
356             // Return the new constant if the cast was performed
357
return retNode;
358         }
359
360         return this;
361     }
362
363     /**
364      * Bind this node but not its child. Caller has already bound
365      * the child.
366      * This is useful for when we generate a CastNode during binding
367      * after having already bound the child.
368      *
369      * @exception StandardException Thrown on error
370      */

371     public void bindCastNodeOnly()
372         throws StandardException
373     {
374
375         /*
376         ** The result type is always castTarget.
377         */

378         setType(castTarget);
379         destCTI = castTarget.getTypeId();
380         sourceCTI = castOperand.getTypeId();
381
382         /*
383         ** If it is a java cast, do some work to make sure
384         ** the classes are ok and that they are compatible
385         */

386         if (destCTI.userType())
387         {
388             String JavaDoc className = ((TypeId) dataTypeServices.getTypeId()).getCorrespondingJavaTypeName();
389
390             boolean convertCase = ! destCTI.getClassNameWasDelimitedIdentifier();
391
392             className = verifyClassExist(className, convertCase);
393
394             castTarget = new DataTypeDescriptor(TypeId.getUserDefinedTypeId(className, false),
395                                                         true /* assume nullable for now, change it if not nullable */
396                                                     );
397             setType(castTarget);
398             destCTI = castTarget.getTypeId();
399         }
400
401         if (castOperand.requiresTypeFromContext())
402         {
403             bindParameter();
404         }
405
406         /*
407         ** If it isn't null, then we have
408         ** a cast from one JBMS type to another. So we
409         ** have to figure out if it is legit.
410         */

411         else if (!(castOperand instanceof UntypedNullConstantNode))
412         {
413             /*
414             ** Make sure we can assign the two classes
415             */

416             TypeCompiler tc = castOperand.getTypeCompiler();
417             if (! tc.convertible(destCTI, forDataTypeFunction))
418             {
419                 throw StandardException.newException(SQLState.LANG_INVALID_CAST,
420                         sourceCTI.getSQLTypeName(),
421                         destCTI.getSQLTypeName());
422             }
423         }
424     }
425
426     /**
427      * Get a constant representing the cast from a CHAR to another
428      * type. If this is not an "easy" cast to perform, then just
429      * return this cast node.
430      * Here's what we think is "easy":
431      * source destination
432      * ------ -----------
433      * char boolean
434      * char date/time/ts
435      * char non-decimal numeric
436      *
437      * @param destJDBCTypeId The destination JDBC TypeId
438      *
439      * @return The new top of the tree (this CastNode or a new Constant)
440      *
441      * @exception StandardException Thrown on error
442      */

443     private ValueNode getCastFromCharConstant(int destJDBCTypeId)
444         throws StandardException
445     {
446         String JavaDoc charValue = ((CharConstantNode) castOperand).getString();
447         String JavaDoc cleanCharValue = StringUtil.SQLToUpperCase(charValue.trim());
448         ValueNode retNode = this;
449
450         switch (destJDBCTypeId)
451         {
452             case Types.BIT:
453             case JDBC30Translation.SQL_TYPES_BOOLEAN:
454                 if (cleanCharValue.equals("TRUE"))
455                 {
456                     return (ValueNode) getNodeFactory().getNode(
457                                             C_NodeTypes.BOOLEAN_CONSTANT_NODE,
458                                             Boolean.TRUE,
459                                             getContextManager());
460                 }
461                 else if (cleanCharValue.equals("FALSE"))
462                 {
463                     return (ValueNode) getNodeFactory().getNode(
464                                             C_NodeTypes.BOOLEAN_CONSTANT_NODE,
465                                             Boolean.FALSE,
466                                             getContextManager());
467                 }
468                 else
469                 {
470                     throw StandardException.newException(SQLState.LANG_FORMAT_EXCEPTION, "boolean");
471                 }
472
473             case Types.DATE:
474                 return (ValueNode) getNodeFactory().getNode(
475                                         C_NodeTypes.USERTYPE_CONSTANT_NODE,
476                                         getDataValueFactory().getDateValue(cleanCharValue, false),
477                                         getContextManager());
478
479             case Types.TIMESTAMP:
480                 return (ValueNode) getNodeFactory().getNode(
481                                     C_NodeTypes.USERTYPE_CONSTANT_NODE,
482                                     getDataValueFactory().getTimestampValue(cleanCharValue, false),
483                                     getContextManager());
484
485             case Types.TIME:
486                 return (ValueNode) getNodeFactory().getNode(
487                                         C_NodeTypes.USERTYPE_CONSTANT_NODE,
488                                         getDataValueFactory().getTimeValue(cleanCharValue, false),
489                                         getContextManager());
490
491             case Types.TINYINT:
492             case Types.SMALLINT:
493             case Types.INTEGER:
494             case Types.BIGINT:
495                 try
496                 {
497                     // #3756 - Truncate decimal portion for casts to integer
498
return getCastFromIntegralType((new Double JavaDoc(cleanCharValue)).longValue(),
499                                                    destJDBCTypeId);
500                 }
501                 catch (NumberFormatException JavaDoc nfe)
502                 {
503                     String JavaDoc sqlName = TypeId.getBuiltInTypeId(destJDBCTypeId).getSQLTypeName();
504                     throw StandardException.newException(SQLState.LANG_FORMAT_EXCEPTION, sqlName);
505                 }
506             case Types.REAL:
507                 Float JavaDoc floatValue;
508                 try
509                 {
510                     floatValue = Float.valueOf(cleanCharValue);
511                 }
512                 catch (NumberFormatException JavaDoc nfe)
513                 {
514                     throw StandardException.newException(SQLState.LANG_FORMAT_EXCEPTION, "float");
515                 }
516                 return (ValueNode) getNodeFactory().getNode(
517                                             C_NodeTypes.FLOAT_CONSTANT_NODE,
518                                             floatValue,
519                                             getContextManager());
520             case Types.DOUBLE:
521                 Double JavaDoc doubleValue;
522                 try
523                 {
524                     doubleValue = new Double JavaDoc(cleanCharValue);
525                 }
526                 catch (NumberFormatException JavaDoc nfe)
527                 {
528                     throw StandardException.newException(SQLState.LANG_FORMAT_EXCEPTION, "double");
529                 }
530                 return (ValueNode) getNodeFactory().getNode(
531                                             C_NodeTypes.DOUBLE_CONSTANT_NODE,
532                                             doubleValue,
533                                             getContextManager());
534         }
535
536         return retNode;
537     }
538
539
540     /**
541      * Get a constant representing the cast from an integral type to another
542      * type. If this is not an "easy" cast to perform, then just
543      * return this cast node.
544      * Here's what we think is "easy":
545      * source destination
546      * ------ -----------
547      * integral type non-decimal numeric
548      * integral type char
549      *
550      * @param longValue integral type as a long to cast from
551      * @param destJDBCTypeId The destination JDBC TypeId
552      *
553      * @return The new top of the tree (this CastNode or a new Constant)
554      *
555      * @exception StandardException Thrown on error
556      */

557     private ValueNode getCastFromIntegralType(
558                                       long longValue,
559                                       int destJDBCTypeId)
560         throws StandardException
561     {
562         ValueNode retNode = this;
563
564         switch (destJDBCTypeId)
565         {
566             case Types.CHAR:
567                 return (ValueNode) getNodeFactory().getNode(
568                                         C_NodeTypes.CHAR_CONSTANT_NODE,
569                                         Long.toString(longValue),
570                                         ReuseFactory.getInteger(
571                                             castTarget.getMaximumWidth()),
572                                         getContextManager());
573             case Types.TINYINT:
574                 if (longValue < Byte.MIN_VALUE ||
575                     longValue > Byte.MAX_VALUE)
576                 {
577                     throw StandardException.newException(SQLState.LANG_OUTSIDE_RANGE_FOR_DATATYPE, "TINYINT");
578                 }
579                 return (ValueNode) getNodeFactory().getNode(
580                                         C_NodeTypes.TINYINT_CONSTANT_NODE,
581                                         ReuseFactory.getByte((byte) longValue),
582                                         getContextManager());
583
584             case Types.SMALLINT:
585                 if (longValue < Short.MIN_VALUE ||
586                     longValue > Short.MAX_VALUE)
587                 {
588                     throw StandardException.newException(SQLState.LANG_OUTSIDE_RANGE_FOR_DATATYPE, "SHORT");
589                 }
590                 return (ValueNode) getNodeFactory().getNode(
591                                             C_NodeTypes.SMALLINT_CONSTANT_NODE,
592                                             ReuseFactory.getShort(
593                                                             (short) longValue),
594                                             getContextManager());
595
596             case Types.INTEGER:
597                 if (longValue < Integer.MIN_VALUE ||
598                     longValue > Integer.MAX_VALUE)
599                 {
600                     throw StandardException.newException(SQLState.LANG_OUTSIDE_RANGE_FOR_DATATYPE, "INTEGER");
601                 }
602                 return (ValueNode) getNodeFactory().getNode(
603                                                 C_NodeTypes.INT_CONSTANT_NODE,
604                                                 ReuseFactory.getInteger(
605                                                             (int) longValue),
606                                                 getContextManager());
607
608             case Types.BIGINT:
609                 return (ValueNode) getNodeFactory().getNode(
610                                 C_NodeTypes.LONGINT_CONSTANT_NODE,
611                                 ReuseFactory.getLong(longValue),
612                                 getContextManager());
613
614             case Types.REAL:
615                 if (Math.abs(longValue) > Float.MAX_VALUE)
616                 {
617                     throw StandardException.newException(SQLState.LANG_OUTSIDE_RANGE_FOR_DATATYPE, "REAL");
618                 }
619                 return (ValueNode) getNodeFactory().getNode(
620                                             C_NodeTypes.FLOAT_CONSTANT_NODE,
621                                             new Float JavaDoc((float) longValue),
622                                             getContextManager());
623
624             case Types.DOUBLE:
625                 return (ValueNode) getNodeFactory().getNode(
626                                     C_NodeTypes.DOUBLE_CONSTANT_NODE,
627                                     new Double JavaDoc((double) longValue),
628                                     getContextManager());
629         }
630
631         return retNode;
632     }
633
634     /**
635      * Get a constant representing the cast from a non-integral type to another
636      * type. If this is not an "easy" cast to perform, then just
637      * return this cast node.
638      * Here's what we think is "easy":
639      * source destination
640      * ------ -----------
641      * non-integral type non-decimal numeric
642      * non-integral type char
643      *
644      * @param constantValue non-integral type a a double to cast from
645      * @param destJDBCTypeId The destination JDBC TypeId
646      *
647      * @return The new top of the tree (this CastNode or a new Constant)
648      *
649      * @exception StandardException Thrown on error
650      */

651     private ValueNode getCastFromNumericType(
652                                       DataValueDescriptor constantValue,
653                                       int destJDBCTypeId)
654         throws StandardException
655     {
656         int nodeType = -1;
657         Object JavaDoc constantObject = null;
658
659         switch (destJDBCTypeId)
660         {
661             case Types.CHAR:
662                 nodeType = C_NodeTypes.CHAR_CONSTANT_NODE;
663                 constantObject = constantValue.getString();
664                 return (ValueNode) getNodeFactory().getNode(
665                                         nodeType,
666                                         constantObject,
667                                         ReuseFactory.getInteger(
668                                             castTarget.getMaximumWidth()),
669                                         getContextManager());
670
671             case Types.TINYINT:
672                 nodeType = C_NodeTypes.TINYINT_CONSTANT_NODE;
673                 constantObject = new Byte JavaDoc(constantValue.getByte());
674                 break;
675
676             case Types.SMALLINT:
677                 nodeType = C_NodeTypes.SMALLINT_CONSTANT_NODE;
678                 constantObject = ReuseFactory.getShort(constantValue.getShort());
679                 break;
680
681             case Types.INTEGER:
682                 nodeType = C_NodeTypes.INT_CONSTANT_NODE;
683                 constantObject = ReuseFactory.getInteger(constantValue.getInt());
684                 break;
685
686             case Types.BIGINT:
687                 nodeType = C_NodeTypes.LONGINT_CONSTANT_NODE;
688                 constantObject = ReuseFactory.getLong(constantValue.getLong());
689                 break;
690
691             case Types.REAL:
692                 nodeType = C_NodeTypes.FLOAT_CONSTANT_NODE;
693                 constantObject = new Float JavaDoc(NumberDataType.normalizeREAL(constantValue.getDouble()));
694                 break;
695
696             case Types.DOUBLE:
697                 // no need to normalize here because no constant could be out of range for a double
698
nodeType = C_NodeTypes.DOUBLE_CONSTANT_NODE;
699                 constantObject = new Double JavaDoc(constantValue.getDouble());
700                 break;
701         }
702
703         if (nodeType == -1)
704             return this;
705
706
707         return (ValueNode) getNodeFactory().getNode(
708                                         nodeType,
709                                         constantObject,
710                                         getContextManager());
711
712     }
713
714     /**
715      * Preprocess an expression tree. We do a number of transformations
716      * here (including subqueries, IN lists, LIKE and BETWEEN) plus
717      * subquery flattening.
718      * NOTE: This is done before the outer ResultSetNode is preprocessed.
719      *
720      * @param numTables Number of tables in the DML Statement
721      * @param outerFromList FromList from outer query block
722      * @param outerSubqueryList SubqueryList from outer query block
723      * @param outerPredicateList PredicateList from outer query block
724      *
725      * @return The modified expression
726      *
727      * @exception StandardException Thrown on error
728      */

729     public ValueNode preprocess(int numTables,
730                                 FromList outerFromList,
731                                 SubqueryList outerSubqueryList,
732                                 PredicateList outerPredicateList)
733                     throws StandardException
734     {
735         castOperand = castOperand.preprocess(numTables,
736                                              outerFromList, outerSubqueryList,
737                                              outerPredicateList);
738         return this;
739     }
740
741     /**
742      * Categorize this predicate. Initially, this means
743      * building a bit map of the referenced tables for each predicate.
744      * If the source of this ColumnReference (at the next underlying level)
745      * is not a ColumnReference or a VirtualColumnNode then this predicate
746      * will not be pushed down.
747      *
748      * For example, in:
749      * select * from (select 1 from s) a (x) where x = 1
750      * we will not push down x = 1.
751      * NOTE: It would be easy to handle the case of a constant, but if the
752      * inner SELECT returns an arbitrary expression, then we would have to copy
753      * that tree into the pushed predicate, and that tree could contain
754      * subqueries and method calls.
755      * RESOLVE - revisit this issue once we have views.
756      *
757      * @param referencedTabs JBitSet with bit map of referenced FromTables
758      * @param simplePredsOnly Whether or not to consider method
759      * calls, field references and conditional nodes
760      * when building bit map
761      *
762      * @return boolean Whether or not source.expression is a ColumnReference
763      * or a VirtualColumnNode.
764      *
765      * @exception StandardException Thrown on error
766      */

767     public boolean categorize(JBitSet referencedTabs, boolean simplePredsOnly)
768         throws StandardException
769     {
770         return castOperand.categorize(referencedTabs, simplePredsOnly);
771     }
772
773     /**
774      * Remap all ColumnReferences in this tree to be clones of the
775      * underlying expression.
776      *
777      * @return ValueNode The remapped expression tree.
778      *
779      * @exception StandardException Thrown on error
780      */

781     public ValueNode remapColumnReferencesToExpressions()
782         throws StandardException
783     {
784         castOperand = castOperand.remapColumnReferencesToExpressions();
785         return this;
786     }
787
788     /**
789      * Return whether or not this expression tree represents a constant expression.
790      *
791      * @return Whether or not this expression tree represents a constant expression.
792      */

793     public boolean isConstantExpression()
794     {
795         return castOperand.isConstantExpression();
796     }
797
798     /** @see ValueNode#constantExpression */
799     public boolean constantExpression(PredicateList whereClause)
800     {
801         return castOperand.constantExpression(whereClause);
802     }
803
804     /**
805      * By default unary operators don't accept ? parameters as operands.
806      * This can be over-ridden for particular unary operators.
807      *
808      * @exception StandardException Always thrown to indicate a
809      * ? parameter where it isn't allowed.
810      */

811
812     void bindParameter()
813                     throws StandardException
814     {
815         castOperand.setType(castTarget);
816     }
817
818     /**
819      * Return an Object representing the bind time value of this
820      * expression tree. If the expression tree does not evaluate to
821      * a constant at bind time then we return null.
822      * This is useful for bind time resolution of VTIs.
823      * RESOLVE: What do we do for primitives?
824      *
825      * @return An Object representing the bind time value of this expression tree.
826      * (null if not a bind time constant.)
827      *
828      * @exception StandardException Thrown on error
829      */

830     Object JavaDoc getConstantValueAsObject()
831         throws StandardException
832     {
833         Object JavaDoc sourceObject = castOperand.getConstantValueAsObject();
834
835         // RESOLVE - need to figure out how to handle casts
836
if (sourceObject == null)
837         {
838             return null;
839         }
840
841         // Simple if source and destination are of same type
842
if (sourceCTI.getCorrespondingJavaTypeName().equals(
843                 destCTI.getCorrespondingJavaTypeName()))
844         {
845             return sourceObject;
846         }
847
848         // RESOLVE - simply return null until we can figure out how to
849
// do the cast
850
return null;
851     }
852
853     /**
854      * Do code generation for this unary operator.
855      *
856      * @param acb The ExpressionClassBuilder for the class we're generating
857      * @param mb The method the code to place the code
858      *
859      * @exception StandardException Thrown on error
860      */

861
862     public void generateExpression(ExpressionClassBuilder acb,
863                                             MethodBuilder mb)
864                                     throws StandardException
865     {
866         castOperand.generateExpression(acb, mb);
867
868         /* No need to generate code for null constants */
869         if (castOperand instanceof UntypedNullConstantNode)
870         {
871             return;
872         }
873         /* HACK ALERT. When casting a parameter, there
874          * is not sourceCTI. Code generation requires one,
875          * so we simply set it to be the same as the
876          * destCTI. The user can still pass whatever
877          * type they'd like in as a parameter.
878          * They'll get an exception, as expected, if the
879          * conversion cannot be performed.
880          */

881         else if (castOperand.requiresTypeFromContext())
882         {
883             sourceCTI = destCTI;
884         }
885     
886         genDataValueConversion(acb, mb);
887     }
888
889     private void genDataValueConversion(ExpressionClassBuilder acb,
890                                               MethodBuilder mb)
891             throws StandardException
892     {
893         MethodBuilder acbConstructor = acb.getConstructor();
894
895         String JavaDoc resultTypeName = getTypeCompiler().interfaceName();
896
897         /* field = method call */
898         /* Allocate an object for re-use to hold the result of the operator */
899         LocalField field = acb.newFieldDeclaration(Modifier.PRIVATE, resultTypeName);
900
901         /*
902         ** Store the result of the method call in the field, so we can re-use
903         ** the object.
904         */

905
906         acb.generateNull(acbConstructor, getTypeCompiler(destCTI));
907         acbConstructor.setField(field);
908
909
910         /*
911             For most types generate
912
913             targetDVD.setValue(sourceDVD);
914             
915             For source or destination java types generate
916             
917             Object o = sourceDVD.getObject();
918             targetDVD.setObjectForCast(o, o instanceof dest java type, dest java type);
919
920             // optional for variable length types
921             targetDVD.setWidth();
922         */

923
924         if (!sourceCTI.userType() && !destCTI.userType()) {
925             mb.getField(field); // targetDVD reference for the setValue method call
926
mb.swap();
927             mb.upCast(ClassName.DataValueDescriptor);
928             mb.callMethod(VMOpcode.INVOKEINTERFACE, ClassName.DataValueDescriptor,
929                     "setValue", "void", 1);
930         }
931         else
932         {
933             /*
934             ** generate: expr.getObject()
935             */

936             mb.callMethod(VMOpcode.INVOKEINTERFACE, ClassName.DataValueDescriptor,
937                     "getObject", "java.lang.Object", 0);
938
939             //castExpr
940

941             mb.getField(field); // instance for the setValue/setObjectForCast method call
942
mb.swap(); // push it before the value
943

944             /*
945             ** We are casting a java type, generate:
946             **
947             ** DataValueDescriptor.setObjectForCast(java.lang.Object castExpr, boolean instanceOfExpr, destinationClassName)
948             ** where instanceOfExpr is "source instanceof destinationClass".
949             **
950             */

951             String JavaDoc destinationType = getTypeId().getCorrespondingJavaTypeName();
952
953             // at this point method instance and cast result are on the stack
954
// we duplicate the cast value in order to perform the instanceof check
955
mb.dup();
956             mb.isInstanceOf(destinationType);
957             mb.push(destinationType);
958             mb.callMethod(VMOpcode.INVOKEINTERFACE, ClassName.DataValueDescriptor,
959                     "setObjectForCast", "void", 3);
960
961         }
962
963         mb.getField(field);
964
965         /*
966         ** If we are casting to a variable length datatype, we
967         ** have to make sure we have set it to the correct
968         ** length.
969         */

970         if (destCTI.variableLength())
971         {
972             boolean isNumber = destCTI.isNumericTypeId();
973             
974             // to leave the DataValueDescriptor value on the stack, since setWidth is void
975
mb.dup();
976
977             /* setWidth() is on VSDV - upcast since
978              * decimal implements subinterface
979              * of VSDV.
980              */

981             
982             mb.push(isNumber ? castTarget.getPrecision() : castTarget.getMaximumWidth());
983             mb.push(castTarget.getScale());
984             mb.push(!sourceCTI.variableLength() || isNumber);
985             mb.callMethod(VMOpcode.INVOKEINTERFACE, ClassName.VariableSizeDataValue,
986                     "setWidth", "void", 3);
987
988         }
989     }
990
991     /**
992      * Accept a visitor, and call v.visit()
993      * on child nodes as necessary.
994      *
995      * @param v the visitor
996      *
997      * @exception StandardException on error
998      */

999     public Visitable accept(Visitor v)
1000        throws StandardException
1001    {
1002        Visitable returnNode = v.visit(this);
1003    
1004        if (v.skipChildren(this))
1005        {
1006            return returnNode;
1007        }
1008
1009        if (castOperand != null && !v.stopTraversal())
1010        {
1011            castOperand = (ValueNode)castOperand.accept(v);
1012        }
1013
1014        return returnNode;
1015    }
1016
1017    /** set this to be a dataTypeScalarFunction
1018     *
1019     * @param b true to use function conversion rules
1020     */

1021    public void setForDataTypeFunction(boolean b)
1022    {
1023        forDataTypeFunction = b;
1024    }
1025
1026    /** is this a cast node for a data type scalar function?
1027     * @return true if this is a function, false for regular cast node
1028     *
1029     */

1030    public boolean getForDataTypeFunction()
1031    {
1032        return forDataTypeFunction;
1033    }
1034        
1035    /**
1036     * {@inheritDoc}
1037     * @throws StandardException
1038     */

1039    protected boolean isEquivalent(ValueNode o) throws StandardException
1040    {
1041        if (isSameNodeType(o))
1042        {
1043            CastNode other = (CastNode)o;
1044            return castTarget.equals(other.castTarget)
1045                && castOperand.isEquivalent(other.castOperand);
1046        }
1047        return false;
1048    }
1049}
1050
1051
1052
Popular Tags