KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*
2
3    Derby - Class org.apache.derby.impl.sql.compile.LikeEscapeOperatorNode
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.compiler.MethodBuilder;
25 import org.apache.derby.iapi.sql.compile.C_NodeTypes;
26
27 import org.apache.derby.iapi.services.sanity.SanityManager;
28
29 import org.apache.derby.iapi.error.StandardException;
30
31 import org.apache.derby.iapi.sql.dictionary.DataDictionary;
32 import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;
33 import org.apache.derby.iapi.types.TypeId;
34 import org.apache.derby.iapi.types.StringDataValue;
35 import org.apache.derby.iapi.types.DataTypeDescriptor;
36
37 import org.apache.derby.iapi.sql.compile.TypeCompiler;
38
39 import org.apache.derby.iapi.reference.SQLState;
40
41 import org.apache.derby.impl.sql.compile.ExpressionClassBuilder;
42 import org.apache.derby.iapi.services.compiler.LocalField;
43
44 import org.apache.derby.iapi.util.ReuseFactory;
45
46 import java.lang.reflect.Modifier JavaDoc;
47 import org.apache.derby.iapi.services.classfile.VMOpcode;
48
49 import org.apache.derby.iapi.types.Like;
50
51 import java.sql.Types JavaDoc;
52 import org.apache.derby.iapi.reference.ClassName;
53
54 import java.util.Vector JavaDoc;
55
56
57 /**
58  * This node represents a like comparison operator (no escape)
59
60
61     If the like pattern is a constant or a parameter then if possible
62     the like is modified to include a >= and < operator. In some cases
63     the like can be eliminated.
64
65
66     constant or parameter LIKE pattern with prefix followed by optional wild card
67     e.g. Cloudscape%
68
69     CHAR(n), VARCHAR(n) where n < 255
70
71         >= prefix padded with '' to length n -- e.g. Cloudscape
72         <= prefix appended with '?' -- e.g. Cloudscape?
73         
74         [ can eliminate LIKE if constant. ]
75
76     
77     CHAR(n), VARCHAR(n), LONG VARCHAR where n >= 255
78
79         >= prefix backed up one characer
80         <= prefix appended with '?'
81
82         no elimination of like
83
84
85     parameter like pattern starts with wild card
86
87         CHAR(n), VARCHAR(n) where n <= 256
88
89         >= '' padded with '' to length n
90         <= '?'
91
92         no elimination of like
93
94     CHAR(n), VARCHAR(n), LONG VARCHAR where n > 256
95
96
97         >= NULL
98
99         <= '?'
100     
101         
102     Note that the Unicode value is '?' is defined as not a character value
103     and can be used by a program for any purpose. We use it to set an upper
104     bound on a character range with a less than predicate. We only need a single
105     '?' appended because the string 'Cloudscape??' is not a valid
106     String because '?' is not a valid character.
107         
108
109
110
111     
112
113         
114
115
116  *
117  * @author ames
118  * converted to TernaryOperatorNode by been
119  */

120
121 public final class LikeEscapeOperatorNode extends TernaryOperatorNode
122 {
123     boolean addedEquals;
124     String JavaDoc escape;
125
126     /**
127      * Initializer for a LikeEscapeOperatorNode
128      *
129      * receiver like pattern [ escape escapeValue ]
130      *
131      * @param receiver The left operand of the like, column, CharConstant or Parameter
132      * @param leftOperand The right operand of the like, the pattern
133      * @param rightOperand The optional escape clause, null if not present
134      */

135
136     public void init(
137             Object JavaDoc receiver,
138             Object JavaDoc leftOperand,
139             Object JavaDoc rightOperand)
140     {
141         /* By convention, the method name for the like operator is "like" */
142         // super.init(leftOperand, rightOperand, new Integer(LIKE), null, null);
143
super.init(receiver, leftOperand, rightOperand, ReuseFactory.getInteger(TernaryOperatorNode.LIKE), null);
144     }
145
146     /**
147      * overrides BindOperatorNode.bindExpression because like has special
148      * requirements for parameter binding.
149      *
150      * @return The new top of the expression tree.
151      *
152      * @exception StandardException thrown on failure
153      */

154     public ValueNode bindExpression(FromList fromList, SubqueryList subqueryList,
155         Vector JavaDoc aggregateVector)
156             throws StandardException
157     {
158         super.bindExpression(fromList, subqueryList, aggregateVector);
159
160         String JavaDoc pattern = null;
161
162         // pattern cannot be a column
163
if (leftOperand instanceof ColumnReference)
164             throw StandardException.newException(SQLState.LANG_DB2_LIKE_SYNTAX_ERROR);
165
166         // pattern must be a string or a parameter
167

168         if (!(leftOperand.requiresTypeFromContext()) && !(leftOperand.getTypeId().isStringTypeId()))
169             throw StandardException.newException(SQLState.LANG_DB2_FUNCTION_INCOMPATIBLE,
170                                                      "LIKE", "FUNCTION");
171
172         // escape cannot be a column
173
if (rightOperand != null && rightOperand instanceof ColumnReference)
174         {
175             throw StandardException.newException(SQLState.LANG_INVALID_ESCAPE_CHARACTER,
176                                          ((ColumnReference) rightOperand).getColumnName());
177         }
178
179         // escape must be a string or a parameter
180
if ((rightOperand != null) &&
181             !(rightOperand.requiresTypeFromContext()) &&
182             !(rightOperand.getTypeId().isStringTypeId()))
183         {
184             throw StandardException.newException(SQLState.LANG_DB2_FUNCTION_INCOMPATIBLE,
185                                          "LIKE", "FUNCTION");
186         }
187
188         // deal with operand parameters
189

190         /*
191          * Is there a ? parameter on the left?
192          * Do left first because its length is always maximum;
193          * a parameter on the right copies its length from
194          * the left, since it won't match if it is any longer than it.
195          */

196
197         if (receiver.requiresTypeFromContext())
198         {
199             receiver.setType(
200                             new DataTypeDescriptor(TypeId.getBuiltInTypeId(Types.VARCHAR), true));
201         }
202
203         /*
204          * Is there a ? parameter for the PATTERN of LIKE?
205          * Copy from the receiver -- legal if both are parameters,
206          * both will be max length.
207          * REMIND: should nullability be copied, or set to true?
208          */

209
210         if (leftOperand.requiresTypeFromContext())
211         {
212             /*
213              * Set the pattern to the type of the left parameter, if
214              * the left is a string, otherwise set it to be VARCHAR.
215              */

216             if (receiver.getTypeId().isStringTypeId())
217             {
218                 leftOperand.setType(receiver.getTypeServices());
219             }
220             else
221             {
222                 leftOperand.setType(
223                             new DataTypeDescriptor(TypeId.getBuiltInTypeId(Types.VARCHAR), true));
224             }
225         }
226
227         /*
228          * Is there a ? parameter for the ESCAPE of LIKE?
229          * Copy from the receiver -- legal if both are parameters,
230          * both will be max length. nullability is set to true.
231          */

232
233         if (rightOperand != null && rightOperand.requiresTypeFromContext())
234         {
235             /*
236              * Set the pattern to the type of the left parameter, if
237              * the left is a string, otherwise set it to be VARCHAR.
238              */

239             if (receiver.getTypeId().isStringTypeId())
240             {
241                 rightOperand.setType(receiver.getTypeServices());
242             }
243             else
244             {
245                 rightOperand.setType(
246                             new DataTypeDescriptor(TypeId.getBuiltInTypeId(Types.VARCHAR), true));
247             }
248         }
249
250         bindToBuiltIn();
251
252         TypeCompiler receiverTC = receiver.getTypeCompiler();
253         TypeCompiler leftTC = leftOperand.getTypeCompiler();
254
255         /* The receiver must be a string type
256          */

257         if (! receiver.getTypeId().isStringTypeId())
258         {
259             throw StandardException.newException(SQLState.LANG_DB2_FUNCTION_INCOMPATIBLE, "LIKE", "FUNCTION");
260
261         }
262
263         /* If either the left or right operands are non-string types,
264          * then we generate an implicit cast to VARCHAR.
265          */

266         if (! leftOperand.getTypeId().isStringTypeId())
267         {
268             leftOperand = castArgToString(leftOperand);
269             leftTC = leftOperand.getTypeCompiler();
270         }
271
272         if (rightOperand != null)
273         {
274             rightOperand = castArgToString(rightOperand);
275         }
276
277         /* Remember whether or not right side is a string constant.
278          * We need to remember here so that we can transform
279          * LIKE 'constant' into = 'constant' for national char
280          * columns.
281          */

282         boolean leftConstant = (leftOperand instanceof CharConstantNode);
283         if (leftConstant)
284         {
285             pattern = ((CharConstantNode) leftOperand).getString();
286         }
287
288         boolean rightConstant = (rightOperand instanceof CharConstantNode);
289
290         if (rightConstant)
291         {
292             escape = ((CharConstantNode) rightOperand).getString();
293             if (escape.length() != 1)
294             {
295                 throw StandardException.newException(SQLState.LANG_INVALID_ESCAPE_CHARACTER,
296                         escape);
297             }
298         }
299         else if (rightOperand == null)
300         {
301             // No Escape clause: Let optimization continue for the = case below
302
rightConstant = true;
303         }
304
305         /* If the left side of LIKE is a ColumnReference and
306          * the right side is a string constant without
307          * a wildcard then we transform the LIKE into the
308          * equivalent LIKE AND =.
309          * If we have an escape clause it also must be a constant.
310          * These types of transformations are normally done
311          * at preprocess time, but we make an exception
312          * and do this one at bind time because we transform
313          * a NOT LIKE 'a' into (a LIKE 'a') = false prior to
314          * preprocessing.
315          * The transformed tree will become:
316          * AND
317          * / \
318          * LIKE =
319          */

320
321         if (receiver instanceof ColumnReference &&
322             leftConstant && rightConstant)
323         {
324             if (Like.isOptimizable(pattern))
325             {
326                 String JavaDoc newPattern = null;
327
328                 /*
329                  * If our pattern has no pattern chars (after stripping them out
330                  * for the ESCAPE case), we are good to apply = to this match
331                  */

332
333                 if (escape != null)
334                 {
335                     /* we return a new pattern stripped of ESCAPE chars */
336                     newPattern =
337                             Like.stripEscapesNoPatternChars(pattern, escape.charAt(0));
338                 }
339                 else if (pattern.indexOf('_') == -1 && pattern.indexOf('%') == -1)
340                 {
341                     newPattern = pattern;
342                 }
343
344                 if (newPattern != null)
345                 {
346                     AndNode newAnd = null;
347                     BinaryComparisonOperatorNode equals = null;
348                     ValueNode leftClone = receiver.getClone();
349
350                     // Remember that we did xform, see preprocess()
351
addedEquals = true;
352
353                     equals =
354                         (BinaryComparisonOperatorNode) getNodeFactory().getNode(
355                             C_NodeTypes.BINARY_EQUALS_OPERATOR_NODE,
356                             leftClone,
357                             (ValueNode) getNodeFactory().getNode(
358                                                 C_NodeTypes.CHAR_CONSTANT_NODE,
359                                                 newPattern,
360                                                 getContextManager()),
361                             getContextManager());
362
363                     // Set forQueryRewrite to bypass comparability checks
364
equals.setForQueryRewrite(true);
365                     equals = (BinaryComparisonOperatorNode) equals.bindExpression(fromList, subqueryList, aggregateVector);
366                     
367                     newAnd = (AndNode) getNodeFactory().getNode(
368                                                         C_NodeTypes.AND_NODE,
369                                                         this,
370                                                         equals,
371                                                         getContextManager());
372                     finishBindExpr();
373                     newAnd.postBindFixup();
374                     return newAnd;
375                 }
376             }
377         }
378
379         /* If we are comparing a char with a national char then
380          * we generate a cast above the reciever to force preprocess to
381          * not attempt any of the > <= optimizations since there is no
382          * way to determine the 'next' character for the <= operand.
383          */

384
385         TypeId leftTypeId = leftOperand.getTypeId();
386         TypeId receiverTypeId = receiver.getTypeId();
387
388         if (receiverTypeId.isNationalStringTypeId() && ! leftTypeId.isNationalStringTypeId())
389         {
390             receiver = castArgToNationalString(receiver, receiverTC, receiverTypeId);
391         }
392         else if (leftTypeId.isNationalStringTypeId() && ! receiverTypeId.isNationalStringTypeId())
393         {
394             leftOperand = castArgToNationalString(leftOperand, leftTC, leftTypeId);
395         }
396
397         finishBindExpr();
398
399         return this;
400     }
401     private ValueNode castArgToNationalString(ValueNode vn, TypeCompiler vnTC, TypeId vnTypeId)
402         throws StandardException
403     {
404         ValueNode newNode = (ValueNode)
405             getNodeFactory().getNode(
406             C_NodeTypes.CAST_NODE,
407             vn,
408             new DataTypeDescriptor(vnTypeId,
409             true,
410             vnTC.getCastToCharWidth(vn.getTypeServices())), getContextManager());
411         ((CastNode) newNode).bindCastNodeOnly();
412         return newNode;
413     }
414     private void finishBindExpr()
415         throws StandardException
416     {
417         // deal with compatability of operands and result type
418
bindComparisonOperator();
419
420         /*
421         ** The result type of LIKE is Boolean
422         */

423
424         boolean nullableResult =
425             receiver.getTypeServices().isNullable() || leftOperand.getTypeServices().isNullable();
426
427         if (rightOperand != null)
428         {
429             nullableResult |= rightOperand.getTypeServices().isNullable();
430         }
431
432         setType(new DataTypeDescriptor(
433                         TypeId.BOOLEAN_ID,
434                         nullableResult
435                     )
436                 );
437     }
438
439     /**
440      * Bind this operator
441      *
442      * @exception StandardException Thrown on error
443      */

444
445     public void bindComparisonOperator()
446             throws StandardException
447     {
448         TypeId receiverType = receiver.getTypeId();
449         TypeId leftType = leftOperand.getTypeId();
450
451         /*
452         ** Check the type of the operands - this function is allowed only on
453         ** string types.
454         */

455
456         if ( ! receiverType.isStringTypeId())
457         {
458             throw StandardException.newException(SQLState.LANG_LIKE_BAD_TYPE,
459                                                 receiverType.getSQLTypeName());
460         }
461
462         if (! leftType.isStringTypeId())
463         {
464             throw StandardException.newException(SQLState.LANG_LIKE_BAD_TYPE,
465                                                 leftType.getSQLTypeName());
466         }
467
468         if (rightOperand != null && ! rightOperand.getTypeId().isStringTypeId())
469         {
470             throw StandardException.newException(SQLState.LANG_LIKE_BAD_TYPE,
471                                                 rightOperand.getTypeId().getSQLTypeName());
472         }
473
474     }
475
476     /**
477      * Preprocess an expression tree. We do a number of transformations
478      * here (including subqueries, IN lists, LIKE and BETWEEN) plus
479      * subquery flattening.
480      * NOTE: This is done before the outer ResultSetNode is preprocessed.
481      *
482      * @param numTables Number of tables in the DML Statement
483      * @param outerFromList FromList from outer query block
484      * @param outerSubqueryList SubqueryList from outer query block
485      * @param outerPredicateList PredicateList from outer query block
486      *
487      * @return The modified expression
488      *
489      * @exception StandardException Thrown on error
490      */

491     public ValueNode preprocess(int numTables,
492                                 FromList outerFromList,
493                                 SubqueryList outerSubqueryList,
494                                 PredicateList outerPredicateList)
495                     throws StandardException
496     {
497         boolean eliminateLikeComparison = false;
498         String JavaDoc greaterEqualString = null;
499         String JavaDoc lessThanString = null;
500         String JavaDoc pattern;
501
502         /* We must 1st preprocess the component parts */
503         super.preprocess(numTables,
504                          outerFromList, outerSubqueryList,
505                          outerPredicateList);
506
507         /* Don't try to optimize for (C)LOB type since it
508          * doesn't allow comparison.
509          */

510         if (receiver.getTypeId().getSQLTypeName().equals("CLOB")) {
511             return this;
512         }
513         /* No need to consider transformation if we
514          * already did transformation that added =
515          * at bind time.
516          */

517         if (addedEquals)
518         {
519             return this;
520         }
521
522         /* This is where we do the transformation for LIKE to make it optimizable.
523          * c1 LIKE 'asdf%' -> c1 LIKE 'asdf%' AND c1 >= 'asdf' AND c1 < 'asdg'
524          * c1 LIKE ? -> c1 LIKE ? and c1 >= ?', where ?' gets calculated at the
525          * beginning of execution.
526          */

527         if (!(leftOperand instanceof CharConstantNode) &&
528             !(leftOperand.requiresTypeFromContext()))
529         {
530             return this;
531         }
532
533         /* This transformation is only worth doing if it is pushable, ie, if
534          * the receiver is a ColumnReference.
535          */

536         if (!(receiver instanceof ColumnReference))
537         {
538             //
539
// We also do an early return here if in bindExpression we found we had
540
// a National Char and put a CAST above the receiver.
541
//
542
return this;
543         }
544
545
546         // Build String constants if right side is a constant
547
if (leftOperand instanceof CharConstantNode)
548         {
549             pattern = ((CharConstantNode) leftOperand).getString();
550
551             if (! Like.isOptimizable(pattern))
552             {
553                 return this;
554             }
555
556             int maxWidth = receiver.getTypeServices().getMaximumWidth();
557             greaterEqualString = Like.greaterEqualString(pattern, escape,
558                                                          maxWidth);
559
560
561
562             /* We do not generate the < and we cannot drop the LIKE
563              * when doing LIKE on a national char column.
564              */

565             if ( ! receiver.getTypeId().isNationalStringTypeId() )
566             {
567                 lessThanString = Like.lessThanString(pattern, escape, maxWidth);
568                 eliminateLikeComparison = ! Like.isLikeComparisonNeeded(pattern);
569             }
570         }
571
572         //System.out.println(receiver.getTypeServices());
573
//System.out.println("MAX WIDTH " + receiver.getTypeServices().getMaximumWidth());
574

575         /* For some unknown reason we need to clone the receiver if it is
576          * a ColumnReference because reusing them in Qualifiers for a scan
577          * does not work.
578          */

579
580         /* The transformed tree has to be normalized. Either:
581          * AND AND
582          * / \ / \
583          * LIKE AND OR: LIKE AND
584          * / \ / \
585          * >= AND >= TRUE
586          * / \
587          * < TRUE
588          * unless the like string is of the form CONSTANT%, in which
589          * case we can do away with the LIKE altogether:
590          * AND AND
591          * / \ / \
592          * >= AND OR: >= TRUE
593          * / \
594          * < TRUE
595          */

596
597         AndNode newAnd = null;
598         ValueNode trueNode = (ValueNode) getNodeFactory().getNode(
599                                             C_NodeTypes.BOOLEAN_CONSTANT_NODE,
600                                             Boolean.TRUE,
601                                             getContextManager());
602
603         /* Create the AND <, if lessThanString is non-null or
604          * leftOperand is a parameter.
605            Currently for a national string we do not add a < than operator
606            since we don't know (?) how to calculate such a string.
607          */

608         if ( lessThanString != null || ( leftOperand.requiresTypeFromContext() &&
609                                          ! receiver.getTypeId().isNationalStringTypeId() ))
610         {
611             QueryTreeNode likeLTopt;
612             if (leftOperand.requiresTypeFromContext())
613             {
614                 int maxWidth = receiver.getTypeServices().getMaximumWidth();
615                 likeLTopt = setupOptimizeStringFromParameter(leftOperand, rightOperand,
616                                 "lessThanStringFromParameter", maxWidth);
617             }
618             else
619             {
620                 likeLTopt = getNodeFactory().getNode(
621                                                 C_NodeTypes.CHAR_CONSTANT_NODE,
622                                                 lessThanString,
623                                                 getContextManager());
624             }
625
626             BinaryComparisonOperatorNode lessThan =
627                     (BinaryComparisonOperatorNode) getNodeFactory().getNode(
628                             C_NodeTypes.BINARY_LESS_THAN_OPERATOR_NODE,
629                             receiver.getClone(),
630                             likeLTopt,
631                             getContextManager());
632
633             // Disable comparability checks
634
lessThan.setForQueryRewrite(true);
635             /* Set type info for the operator node */
636             lessThan.bindComparisonOperator();
637
638             // Use between selectivity for the <
639
lessThan.setBetweenSelectivity();
640
641             /* Create the AND */
642             newAnd = (AndNode) getNodeFactory().getNode(
643                                                     C_NodeTypes.AND_NODE,
644                                                     lessThan,
645                                                     trueNode,
646                                                     getContextManager());
647             newAnd.postBindFixup();
648         }
649
650         /* Create the AND >=. Right side could
651          * be a CharConstantNode or a ParameterNode.
652          */

653
654         ValueNode likeGEopt;
655         if (leftOperand.requiresTypeFromContext()) {
656
657             // Create an expression off the parameter
658
// new SQLChar(Like.greaterEqualString(?));
659

660             int maxWidth = receiver.getTypeServices().getMaximumWidth();
661             likeGEopt = setupOptimizeStringFromParameter(leftOperand, rightOperand,
662                                 "greaterEqualStringFromParameter", maxWidth);
663
664         } else {
665
666
667
668             likeGEopt = (ValueNode) getNodeFactory().getNode(C_NodeTypes.CHAR_CONSTANT_NODE,
669                                                 greaterEqualString,
670                                                 getContextManager());
671         }
672
673         BinaryComparisonOperatorNode greaterEqual =
674                 (BinaryComparisonOperatorNode) getNodeFactory().getNode(
675                         C_NodeTypes.BINARY_GREATER_EQUALS_OPERATOR_NODE,
676                         receiver.getClone(),
677                         likeGEopt,
678                         getContextManager());
679
680
681         // Disable comparability checks
682
greaterEqual.setForQueryRewrite(true);
683         /* Set type info for the operator node */
684         greaterEqual.bindComparisonOperator();
685
686         // Use between selectivity for the >=
687
greaterEqual.setBetweenSelectivity();
688
689         /* Create the AND */
690         if (newAnd == null)
691         {
692             newAnd = (AndNode) getNodeFactory().getNode(
693                                                     C_NodeTypes.AND_NODE,
694                                                     greaterEqual,
695                                                     trueNode,
696                                                     getContextManager());
697         }
698         else
699         {
700             newAnd = (AndNode) getNodeFactory().getNode(
701                                                     C_NodeTypes.AND_NODE,
702                                                     greaterEqual,
703                                                     newAnd,
704                                                     getContextManager());
705         }
706         newAnd.postBindFixup();
707
708         /* Finally, we put a AND LIKE on top of the left deep tree, but
709          * only if it is still necessary.
710          */

711         if (! eliminateLikeComparison)
712         {
713             newAnd = (AndNode) getNodeFactory().getNode(
714                                                     C_NodeTypes.AND_NODE,
715                                                     this,
716                                                     newAnd,
717                                                     getContextManager());
718             newAnd.postBindFixup();
719         }
720
721         /* Mark this node as transformed so that we don't get
722          * calculated into the selectivity mulitple times.
723          */

724         setTransformed();
725
726         return newAnd;
727     }
728
729     /**
730      * Do code generation for this binary operator.
731      *
732      * This code was copied from BinaryOperatorNode and stripped down
733      *
734      * @param acb The ExpressionClassBuilder for the class we're generating
735      * @param mb The method the code to place the code
736      *
737      *
738      * @exception StandardException Thrown on error
739      */

740
741     public void generateExpression(ExpressionClassBuilder acb,
742                                             MethodBuilder mb)
743         throws StandardException
744     {
745
746 /*
747 ** if i have a operator.getOrderableType() == constant, then just cache
748 ** it in a field. if i have QUERY_INVARIANT, then it would be good to
749 ** cache it in something that is initialized each execution,
750 ** but how?
751 */

752
753         /*
754         ** let the receiver type be determined by an
755         ** overridable method so that if methods are
756         ** not implemented on the lowest interface of
757         ** a class, they can note that in the implementation
758         ** of the node that uses the method.
759         */

760         // receiverType = getReceiverInterfaceName();
761

762         /*
763         ** Generate LHS (field = <receiver operand>). This assignment is
764         ** used as the receiver of the method call for this operator.
765         **
766         ** (<receiver operand>).method(<left operand>,
767         ** <right operand>, [<escaperightOp>,]
768         ** <result field>)
769         */

770
771         receiver.generateExpression(acb, mb); // first arg
772

773         receiverInterfaceType = receiver.getTypeCompiler().interfaceName();
774
775         mb.upCast(receiverInterfaceType); // cast the method instance
776

777         leftOperand.generateExpression(acb, mb);
778         mb.upCast(leftInterfaceType); // first arg with cast
779

780         if (rightOperand != null)
781         {
782             rightOperand.generateExpression(acb, mb);
783             mb.upCast(rightInterfaceType); // second arg with cast
784
}
785
786         /* Figure out the result type name */
787         // resultTypeName = getTypeCompiler().interfaceName();
788

789         mb.callMethod(VMOpcode.INVOKEINTERFACE, null,
790             methodName, resultInterfaceType,
791             rightOperand == null ? 1 : 2);
792     }
793
794     private ValueNode setupOptimizeStringFromParameter(ValueNode parameterNode,
795                         ValueNode escapeNode,String JavaDoc methodName, int maxWidth)
796         throws StandardException {
797
798         Vector JavaDoc param;
799
800         if (escapeNode != null)
801         {
802             param = new Vector JavaDoc(2);
803             methodName += "WithEsc";
804         }
805         else param = new Vector JavaDoc(1);
806
807         StaticMethodCallNode methodCall = (StaticMethodCallNode)
808                         getNodeFactory().getNode(C_NodeTypes.STATIC_METHOD_CALL_NODE,
809                                             methodName,
810                                             "org.apache.derby.iapi.types.Like",
811                                             getContextManager());
812
813         // using a method call directly, thus need internal sql capability
814
methodCall.internalCall = true;
815
816         param.addElement(parameterNode);
817         if (escapeNode != null)
818             param.addElement(escapeNode);
819
820         QueryTreeNode maxWidthNode = getNodeFactory().getNode(
821                                         C_NodeTypes.INT_CONSTANT_NODE,
822                                         new Integer JavaDoc(maxWidth),
823                                         getContextManager());
824         param.addElement(maxWidthNode);
825
826         methodCall.addParms(param);
827
828
829         ValueNode java2SQL = (ValueNode) getNodeFactory().getNode(
830                                     C_NodeTypes.JAVA_TO_SQL_VALUE_NODE,
831                                     methodCall,
832                                     getContextManager());
833
834
835         java2SQL = (ValueNode) java2SQL.bindExpression(null, null, null);
836
837         CastNode likeOpt = (CastNode)
838             getNodeFactory().getNode(
839                 C_NodeTypes.CAST_NODE,
840                 java2SQL,
841                 parameterNode.getTypeServices(),
842                 getContextManager());
843
844         likeOpt.bindCastNodeOnly();
845
846         return likeOpt;
847     }
848 }
849
Popular Tags