1 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 ; 47 import org.apache.derby.iapi.services.classfile.VMOpcode; 48 49 import org.apache.derby.iapi.types.Like; 50 51 import java.sql.Types ; 52 import org.apache.derby.iapi.reference.ClassName; 53 54 import java.util.Vector ; 55 56 57 120 121 public final class LikeEscapeOperatorNode extends TernaryOperatorNode 122 { 123 boolean addedEquals; 124 String escape; 125 126 135 136 public void init( 137 Object receiver, 138 Object leftOperand, 139 Object rightOperand) 140 { 141 142 super.init(receiver, leftOperand, rightOperand, ReuseFactory.getInteger(TernaryOperatorNode.LIKE), null); 144 } 145 146 154 public ValueNode bindExpression(FromList fromList, SubqueryList subqueryList, 155 Vector aggregateVector) 156 throws StandardException 157 { 158 super.bindExpression(fromList, subqueryList, aggregateVector); 159 160 String pattern = null; 161 162 if (leftOperand instanceof ColumnReference) 164 throw StandardException.newException(SQLState.LANG_DB2_LIKE_SYNTAX_ERROR); 165 166 168 if (!(leftOperand.requiresTypeFromContext()) && !(leftOperand.getTypeId().isStringTypeId())) 169 throw StandardException.newException(SQLState.LANG_DB2_FUNCTION_INCOMPATIBLE, 170 "LIKE", "FUNCTION"); 171 172 if (rightOperand != null && rightOperand instanceof ColumnReference) 174 { 175 throw StandardException.newException(SQLState.LANG_INVALID_ESCAPE_CHARACTER, 176 ((ColumnReference) rightOperand).getColumnName()); 177 } 178 179 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 190 196 197 if (receiver.requiresTypeFromContext()) 198 { 199 receiver.setType( 200 new DataTypeDescriptor(TypeId.getBuiltInTypeId(Types.VARCHAR), true)); 201 } 202 203 209 210 if (leftOperand.requiresTypeFromContext()) 211 { 212 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 232 233 if (rightOperand != null && rightOperand.requiresTypeFromContext()) 234 { 235 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 257 if (! receiver.getTypeId().isStringTypeId()) 258 { 259 throw StandardException.newException(SQLState.LANG_DB2_FUNCTION_INCOMPATIBLE, "LIKE", "FUNCTION"); 260 261 } 262 263 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 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 rightConstant = true; 303 } 304 305 320 321 if (receiver instanceof ColumnReference && 322 leftConstant && rightConstant) 323 { 324 if (Like.isOptimizable(pattern)) 325 { 326 String newPattern = null; 327 328 332 333 if (escape != null) 334 { 335 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 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 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 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 bindComparisonOperator(); 419 420 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 444 445 public void bindComparisonOperator() 446 throws StandardException 447 { 448 TypeId receiverType = receiver.getTypeId(); 449 TypeId leftType = leftOperand.getTypeId(); 450 451 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 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 greaterEqualString = null; 499 String lessThanString = null; 500 String pattern; 501 502 503 super.preprocess(numTables, 504 outerFromList, outerSubqueryList, 505 outerPredicateList); 506 507 510 if (receiver.getTypeId().getSQLTypeName().equals("CLOB")) { 511 return this; 512 } 513 517 if (addedEquals) 518 { 519 return this; 520 } 521 522 527 if (!(leftOperand instanceof CharConstantNode) && 528 !(leftOperand.requiresTypeFromContext())) 529 { 530 return this; 531 } 532 533 536 if (!(receiver instanceof ColumnReference)) 537 { 538 return this; 543 } 544 545 546 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 565 if ( ! receiver.getTypeId().isNationalStringTypeId() ) 566 { 567 lessThanString = Like.lessThanString(pattern, escape, maxWidth); 568 eliminateLikeComparison = ! Like.isLikeComparisonNeeded(pattern); 569 } 570 } 571 572 575 579 580 596 597 AndNode newAnd = null; 598 ValueNode trueNode = (ValueNode) getNodeFactory().getNode( 599 C_NodeTypes.BOOLEAN_CONSTANT_NODE, 600 Boolean.TRUE, 601 getContextManager()); 602 603 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 lessThan.setForQueryRewrite(true); 635 636 lessThan.bindComparisonOperator(); 637 638 lessThan.setBetweenSelectivity(); 640 641 642 newAnd = (AndNode) getNodeFactory().getNode( 643 C_NodeTypes.AND_NODE, 644 lessThan, 645 trueNode, 646 getContextManager()); 647 newAnd.postBindFixup(); 648 } 649 650 653 654 ValueNode likeGEopt; 655 if (leftOperand.requiresTypeFromContext()) { 656 657 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 greaterEqual.setForQueryRewrite(true); 683 684 greaterEqual.bindComparisonOperator(); 685 686 greaterEqual.setBetweenSelectivity(); 688 689 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 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 724 setTransformed(); 725 726 return newAnd; 727 } 728 729 740 741 public void generateExpression(ExpressionClassBuilder acb, 742 MethodBuilder mb) 743 throws StandardException 744 { 745 746 752 753 760 762 770 771 receiver.generateExpression(acb, mb); 773 receiverInterfaceType = receiver.getTypeCompiler().interfaceName(); 774 775 mb.upCast(receiverInterfaceType); 777 leftOperand.generateExpression(acb, mb); 778 mb.upCast(leftInterfaceType); 780 if (rightOperand != null) 781 { 782 rightOperand.generateExpression(acb, mb); 783 mb.upCast(rightInterfaceType); } 785 786 787 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 methodName, int maxWidth) 796 throws StandardException { 797 798 Vector param; 799 800 if (escapeNode != null) 801 { 802 param = new Vector (2); 803 methodName += "WithEsc"; 804 } 805 else param = new Vector (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 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 (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 |