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.services.compiler.LocalField; 26 import org.apache.derby.iapi.services.io.StoredFormatIds; 27 import org.apache.derby.iapi.services.sanity.SanityManager; 28 import org.apache.derby.iapi.sql.compile.C_NodeTypes; 29 import org.apache.derby.iapi.sql.compile.Visitable; 30 import org.apache.derby.iapi.sql.compile.Visitor; 31 import org.apache.derby.iapi.sql.dictionary.DataDictionary; 32 import org.apache.derby.iapi.store.access.Qualifier; 33 import org.apache.derby.iapi.error.StandardException; 34 35 import org.apache.derby.iapi.sql.compile.TypeCompiler; 36 import org.apache.derby.iapi.types.NumberDataValue; 37 import org.apache.derby.iapi.types.StringDataValue; 38 import org.apache.derby.iapi.types.TypeId; 39 import org.apache.derby.iapi.types.DataTypeDescriptor; 40 41 import org.apache.derby.iapi.store.access.Qualifier; 42 import org.apache.derby.iapi.reference.SQLState; 43 import org.apache.derby.iapi.reference.ClassName; 44 import org.apache.derby.iapi.services.classfile.VMOpcode; 45 46 import org.apache.derby.impl.sql.compile.ExpressionClassBuilder; 47 import org.apache.derby.iapi.util.JBitSet; 48 import org.apache.derby.iapi.util.ReuseFactory; 49 50 import java.lang.reflect.Modifier ; 51 52 import java.sql.Types ; 53 import java.util.Vector ; 54 62 63 public class TernaryOperatorNode extends ValueNode 64 { 65 String operator; 66 String methodName; 67 int operatorType; 68 ValueNode receiver; 69 70 ValueNode leftOperand; 71 ValueNode rightOperand; 72 73 String resultInterfaceType; 74 String receiverInterfaceType; 75 String leftInterfaceType; 76 String rightInterfaceType; 77 int trimType; 78 79 public static final int TRIM = 0; 80 public static final int LOCATE = 1; 81 public static final int SUBSTRING = 2; 82 public static final int LIKE = 3; 83 public static final int TIMESTAMPADD = 4; 84 public static final int TIMESTAMPDIFF = 5; 85 static final String [] TernaryOperators = {"trim", "LOCATE", "substring", "like", "TIMESTAMPADD", "TIMESTAMPDIFF"}; 86 static final String [] TernaryMethodNames = {"trim", "locate", "substring", "like", "timestampAdd", "timestampDiff"}; 87 static final String [] TernaryResultType = {ClassName.StringDataValue, 88 ClassName.NumberDataValue, 89 ClassName.ConcatableDataValue, 90 ClassName.BooleanDataValue, 91 ClassName.DateTimeDataValue, 92 ClassName.NumberDataValue}; 93 static final String [][] TernaryArgType = { 94 {ClassName.StringDataValue, ClassName.StringDataValue, "java.lang.Integer"}, 95 {ClassName.StringDataValue, ClassName.StringDataValue, ClassName.NumberDataValue}, 96 {ClassName.ConcatableDataValue, ClassName.NumberDataValue, ClassName.NumberDataValue}, 97 {ClassName.DataValueDescriptor, ClassName.DataValueDescriptor, ClassName.DataValueDescriptor}, 98 {ClassName.DateTimeDataValue, "java.lang.Integer", ClassName.NumberDataValue}, {ClassName.DateTimeDataValue, "java.lang.Integer", ClassName.DateTimeDataValue} }; 101 102 110 111 public void init( 112 Object receiver, 113 Object leftOperand, 114 Object rightOperand, 115 Object operatorType, 116 Object trimType) 117 { 118 this.receiver = (ValueNode) receiver; 119 this.leftOperand = (ValueNode) leftOperand; 120 this.rightOperand = (ValueNode) rightOperand; 121 this.operatorType = ((Integer ) operatorType).intValue(); 122 this.operator = (String ) TernaryOperators[this.operatorType]; 123 this.methodName = (String ) TernaryMethodNames[this.operatorType]; 124 this.resultInterfaceType = (String ) TernaryResultType[this.operatorType]; 125 this.receiverInterfaceType = (String ) TernaryArgType[this.operatorType][0]; 126 this.leftInterfaceType = (String ) TernaryArgType[this.operatorType][1]; 127 this.rightInterfaceType = (String ) TernaryArgType[this.operatorType][2]; 128 if (trimType != null) 129 this.trimType = ((Integer ) trimType).intValue(); 130 } 131 132 138 139 public String toString() 140 { 141 if (SanityManager.DEBUG) 142 { 143 return "operator: " + operator + "\n" + 144 "methodName: " + methodName + "\n" + 145 "resultInterfaceType: " + resultInterfaceType + "\n" + 146 "receiverInterfaceType: " + receiverInterfaceType + "\n" + 147 "leftInterfaceType: " + leftInterfaceType + "\n" + 148 "rightInterfaceType: " + rightInterfaceType + "\n" + 149 super.toString(); 150 } 151 else 152 { 153 return ""; 154 } 155 } 156 157 162 public void setClause(int clause) 163 { 164 super.setClause(clause); 165 receiver.setClause(clause); 166 leftOperand.setClause(clause); 167 if (rightOperand != null) 168 { 169 rightOperand.setClause(clause); 170 } 171 } 172 173 179 180 public void printSubNodes(int depth) 181 { 182 if (SanityManager.DEBUG) 183 { 184 super.printSubNodes(depth); 185 186 if (receiver != null) 187 { 188 printLabel(depth, "receiver: "); 189 receiver.treePrint(depth + 1); 190 } 191 192 if (leftOperand != null) 193 { 194 printLabel(depth, "leftOperand: "); 195 leftOperand.treePrint(depth + 1); 196 } 197 198 if (rightOperand != null) 199 { 200 printLabel(depth, "rightOperand: "); 201 rightOperand.treePrint(depth + 1); 202 } 203 } 204 } 205 206 219 220 public ValueNode bindExpression(FromList fromList, SubqueryList subqueryList, 221 Vector aggregateVector) 222 throws StandardException 223 { 224 receiver = receiver.bindExpression(fromList, subqueryList, 225 aggregateVector); 226 leftOperand = leftOperand.bindExpression(fromList, subqueryList, 227 aggregateVector); 228 229 if (rightOperand != null) 230 { 231 rightOperand = rightOperand.bindExpression(fromList, subqueryList, 232 aggregateVector); 233 } 234 if (operatorType == TRIM) 235 trimBind(); 236 else if (operatorType == LOCATE) 237 locateBind(); 238 else if (operatorType == SUBSTRING) 239 substrBind(); 240 else if (operatorType == TIMESTAMPADD) 241 timestampAddBind(); 242 else if (operatorType == TIMESTAMPDIFF) 243 timestampDiffBind(); 244 245 return this; 246 } 247 248 263 public ValueNode preprocess(int numTables, 264 FromList outerFromList, 265 SubqueryList outerSubqueryList, 266 PredicateList outerPredicateList) 267 throws StandardException 268 { 269 receiver = receiver.preprocess(numTables, 270 outerFromList, outerSubqueryList, 271 outerPredicateList); 272 273 leftOperand = leftOperand.preprocess(numTables, 274 outerFromList, outerSubqueryList, 275 outerPredicateList); 276 if (rightOperand != null) 277 { 278 rightOperand = rightOperand.preprocess(numTables, 279 outerFromList, outerSubqueryList, 280 outerPredicateList); 281 } 282 return this; 283 } 284 293 294 public void generateExpression(ExpressionClassBuilder acb, 295 MethodBuilder mb) 296 throws StandardException 297 { 298 int nargs = 0; 299 String receiverType = null; 300 301 302 LocalField field = acb.newFieldDeclaration(Modifier.PRIVATE, resultInterfaceType); 303 304 receiver.generateExpression(acb, mb); 305 if (operatorType == TRIM) 306 { 307 mb.push(trimType); 308 mb.getField(field); 309 nargs = 2; 310 receiverType = receiverInterfaceType; 311 } 312 else if (operatorType == LOCATE) 313 { 314 leftOperand.generateExpression(acb, mb); 315 mb.upCast(leftInterfaceType); 316 rightOperand.generateExpression(acb, mb); 317 mb.upCast(rightInterfaceType); 318 mb.getField(field); 319 nargs = 3; 320 321 } 322 else if (operatorType == SUBSTRING) 323 { 324 leftOperand.generateExpression(acb, mb); 325 mb.upCast(leftInterfaceType); 326 if (rightOperand != null) 327 { 328 rightOperand.generateExpression(acb, mb); 329 mb.upCast(rightInterfaceType); 330 } 331 else 332 { 333 mb.pushNull(rightInterfaceType); 334 } 335 336 mb.getField(field); mb.push(receiver.getTypeServices().getMaximumWidth()); 338 nargs = 4; 339 receiverType = receiverInterfaceType; 340 } 341 else if (operatorType == TIMESTAMPADD || operatorType == TIMESTAMPDIFF) 342 { 343 Object intervalType = leftOperand.getConstantValueAsObject(); 344 if( SanityManager.DEBUG) 345 SanityManager.ASSERT( intervalType != null && intervalType instanceof Integer , 346 "Invalid interval type used for " + operator); 347 mb.push( ((Integer ) intervalType).intValue()); 348 rightOperand.generateExpression( acb, mb); 349 mb.upCast( TernaryArgType[ operatorType][2]); 350 acb.getCurrentDateExpression( mb); 351 mb.getField(field); 352 nargs = 4; 353 receiverType = receiverInterfaceType; 354 } 355 356 mb.callMethod(VMOpcode.INVOKEINTERFACE, receiverType, methodName, resultInterfaceType, nargs); 357 358 362 mb.putField(field); 363 } 364 365 370 public void setLeftOperand(ValueNode newLeftOperand) 371 { 372 leftOperand = newLeftOperand; 373 } 374 375 380 public ValueNode getLeftOperand() 381 { 382 return leftOperand; 383 } 384 385 390 public void setRightOperand(ValueNode newRightOperand) 391 { 392 rightOperand = newRightOperand; 393 } 394 395 400 public ValueNode getRightOperand() 401 { 402 return rightOperand; 403 } 404 405 430 public boolean categorize(JBitSet referencedTabs, boolean simplePredsOnly) 431 throws StandardException 432 { 433 boolean pushable; 434 pushable = receiver.categorize(referencedTabs, simplePredsOnly); 435 pushable = (leftOperand.categorize(referencedTabs, simplePredsOnly) && pushable); 436 if (rightOperand != null) 437 { 438 pushable = (rightOperand.categorize(referencedTabs, simplePredsOnly) && pushable); 439 } 440 return pushable; 441 } 442 443 451 public ValueNode remapColumnReferencesToExpressions() 452 throws StandardException 453 { 454 receiver = receiver.remapColumnReferencesToExpressions(); 455 leftOperand = leftOperand.remapColumnReferencesToExpressions(); 456 if (rightOperand != null) 457 { 458 rightOperand = rightOperand.remapColumnReferencesToExpressions(); 459 } 460 return this; 461 } 462 463 468 public boolean isConstantExpression() 469 { 470 return (receiver.isConstantExpression() && 471 leftOperand.isConstantExpression() && 472 (rightOperand == null || rightOperand.isConstantExpression())); 473 } 474 475 476 public boolean constantExpression(PredicateList whereClause) 477 { 478 return (receiver.constantExpression(whereClause) && 479 leftOperand.constantExpression(whereClause) && 480 (rightOperand == null || 481 rightOperand.constantExpression(whereClause))); 482 } 483 484 492 public Visitable accept(Visitor v) 493 throws StandardException 494 { 495 Visitable returnNode = v.visit(this); 496 497 if (v.skipChildren(this)) 498 { 499 return returnNode; 500 } 501 502 if (receiver != null && !v.stopTraversal()) 503 { 504 receiver = (ValueNode)receiver.accept(v); 505 } 506 507 if (leftOperand != null && !v.stopTraversal()) 508 { 509 leftOperand = (ValueNode)leftOperand.accept(v); 510 } 511 512 if (rightOperand != null && !v.stopTraversal()) 513 { 514 rightOperand = (ValueNode)rightOperand.accept(v); 515 } 516 517 return returnNode; 518 } 519 525 526 private ValueNode trimBind() 527 throws StandardException 528 { 529 TypeId receiverType; 530 TypeId resultType = TypeId.getBuiltInTypeId(Types.VARCHAR); 531 532 534 535 if (receiver.requiresTypeFromContext()) 536 { 537 542 543 receiver.setType(getVarcharDescriptor()); 544 } 545 546 547 if (leftOperand.requiresTypeFromContext()) 548 { 549 550 leftOperand.setType(getVarcharDescriptor()); 551 } 552 553 bindToBuiltIn(); 554 555 559 receiverType = receiver.getTypeId(); 560 if (receiverType.userType()) 561 throwBadType("trim", receiverType.getSQLTypeName()); 562 563 receiver = castArgToString(receiver); 564 565 if ((receiverType.getTypeFormatId() == StoredFormatIds.CLOB_TYPE_ID) || 566 (receiverType.getTypeFormatId() == StoredFormatIds.NCLOB_TYPE_ID)) { 567 resultType = receiverType; 573 } 574 575 579 TypeId leftCTI; 580 leftCTI = leftOperand.getTypeId(); 581 if (leftCTI.userType()) 582 throwBadType("trim", leftCTI.getSQLTypeName()); 583 584 leftOperand = castArgToString(leftOperand); 585 586 589 setResultType(resultType); 590 591 return this; 592 } 593 596 private void setResultType(TypeId resultType) throws StandardException 597 { 598 setType(new DataTypeDescriptor( 599 resultType, 600 true, 601 receiver.getTypeServices().getMaximumWidth() 602 ) 603 ); 604 } 605 612 613 public ValueNode locateBind() throws StandardException 614 { 615 TypeId firstOperandType, secondOperandType, offsetType; 616 617 622 if( receiver.requiresTypeFromContext()) 623 { 624 if( leftOperand.requiresTypeFromContext()) 625 { 626 receiver.setType(getVarcharDescriptor()); 627 } 628 else 629 { 630 if( leftOperand.getTypeId().isStringTypeId() ) 631 { 632 receiver.setType( 633 leftOperand.getTypeServices()); 634 } 635 } 636 } 637 638 642 if(leftOperand.requiresTypeFromContext()) 643 { 644 if(receiver.requiresTypeFromContext()) 645 { 646 leftOperand.setType(getVarcharDescriptor()); 647 } 648 else 649 { 650 if( receiver.getTypeId().isStringTypeId() ) 651 { 652 leftOperand.setType( 653 receiver.getTypeServices()); 654 } 655 } 656 } 657 658 661 if( rightOperand.requiresTypeFromContext()) 662 { 663 rightOperand.setType( 664 new DataTypeDescriptor(TypeId.INTEGER_ID, true)); 665 } 666 667 bindToBuiltIn(); 668 669 675 secondOperandType = leftOperand.getTypeId(); 676 offsetType = rightOperand.getTypeId(); 677 firstOperandType = receiver.getTypeId(); 678 679 if (!firstOperandType.isStringTypeId() || 680 !secondOperandType.isStringTypeId() || 681 offsetType.getJDBCTypeId() != Types.INTEGER) 682 throw StandardException.newException(SQLState.LANG_DB2_FUNCTION_INCOMPATIBLE, 683 "LOCATE", "FUNCTION"); 684 685 688 setType(new DataTypeDescriptor(TypeId.INTEGER_ID, 689 receiver.getTypeServices().isNullable())); 690 691 return this; 692 } 693 694 695 protected ValueNode castArgToString(ValueNode vn) throws StandardException 696 { 697 TypeCompiler vnTC = vn.getTypeCompiler(); 698 if (! vn.getTypeId().isStringTypeId()) 699 { 700 ValueNode newNode = (ValueNode) 701 getNodeFactory().getNode( 702 C_NodeTypes.CAST_NODE, 703 vn, 704 DataTypeDescriptor.getBuiltInDataTypeDescriptor(Types.VARCHAR, true, 705 vnTC.getCastToCharWidth( 706 vn.getTypeServices())), 707 getContextManager()); 708 ((CastNode) newNode).bindCastNodeOnly(); 709 return newNode; 710 } 711 return vn; 712 } 713 714 721 722 public ValueNode substrBind() 723 throws StandardException 724 { 725 TypeId receiverType; 726 TypeId resultType; 727 728 730 731 if (receiver.requiresTypeFromContext()) 732 { 733 738 739 receiver.setType(getVarcharDescriptor()); 740 } 741 742 743 if (leftOperand.requiresTypeFromContext()) 744 { 745 746 leftOperand.setType( 747 new DataTypeDescriptor(TypeId.INTEGER_ID, true)); 748 } 749 750 751 if ((rightOperand != null) && rightOperand.requiresTypeFromContext()) 752 { 753 754 rightOperand.setType( 755 new DataTypeDescriptor(TypeId.INTEGER_ID, true)); 756 } 757 758 bindToBuiltIn(); 759 760 if (!leftOperand.getTypeId().isNumericTypeId() || 761 (rightOperand != null && !rightOperand.getTypeId().isNumericTypeId())) 762 throw StandardException.newException(SQLState.LANG_DB2_FUNCTION_INCOMPATIBLE, "SUBSTR", "FUNCTION"); 763 764 768 resultType = receiverType = receiver.getTypeId(); 769 switch (receiverType.getJDBCTypeId()) 770 { 771 case Types.CHAR: 772 case Types.VARCHAR: 773 case Types.LONGVARCHAR: 774 case Types.CLOB: 775 break; 776 default: 777 { 778 throwBadType("SUBSTR", receiverType.getSQLTypeName()); 779 } 780 } 781 782 int resultLen = receiver.getTypeServices().getMaximumWidth(); 784 785 if (rightOperand != null && rightOperand instanceof ConstantNode) 786 { 787 if (((ConstantNode)rightOperand).getValue().getInt() < resultLen) 788 resultLen = ((ConstantNode)rightOperand).getValue().getInt(); 789 } 790 791 794 setType(new DataTypeDescriptor( 795 resultType, 796 true, 797 resultLen 798 )); 799 800 return this; 801 } 802 803 804 811 812 private ValueNode timestampAddBind() 813 throws StandardException 814 { 815 if( ! bindParameter( rightOperand, Types.INTEGER)) 816 { 817 int jdbcType = rightOperand.getTypeId().getJDBCTypeId(); 818 if( jdbcType != Types.TINYINT && jdbcType != Types.SMALLINT && 819 jdbcType != Types.INTEGER && jdbcType != Types.BIGINT) 820 throw StandardException.newException(SQLState.LANG_INVALID_FUNCTION_ARG_TYPE, 821 rightOperand.getTypeId().getSQLTypeName(), 822 ReuseFactory.getInteger( 2), 823 operator); 824 } 825 bindDateTimeArg( receiver, 3); 826 setType(DataTypeDescriptor.getBuiltInDataTypeDescriptor( Types.TIMESTAMP)); 827 return this; 828 } 830 837 838 private ValueNode timestampDiffBind() 839 throws StandardException 840 { 841 bindDateTimeArg( rightOperand, 2); 842 bindDateTimeArg( receiver, 3); 843 setType(DataTypeDescriptor.getBuiltInDataTypeDescriptor( Types.INTEGER)); 844 return this; 845 } 847 private void bindDateTimeArg( ValueNode arg, int argNumber) throws StandardException 848 { 849 if( ! bindParameter( arg, Types.TIMESTAMP)) 850 { 851 if( ! arg.getTypeId().isDateTimeTimeStampTypeId()) 852 throw StandardException.newException(SQLState.LANG_INVALID_FUNCTION_ARG_TYPE, 853 arg.getTypeId().getSQLTypeName(), 854 ReuseFactory.getInteger( argNumber), 855 operator); 856 } 857 } 859 private boolean bindParameter( ValueNode arg, int jdbcType) throws StandardException 860 { 861 if( arg.requiresTypeFromContext() && arg.getTypeId() == null) 862 { 863 arg.setType( new DataTypeDescriptor(TypeId.getBuiltInTypeId( jdbcType), true)); 864 return true; 865 } 866 return false; 867 } 869 public ValueNode getReceiver() 870 { 871 return receiver; 872 } 873 874 875 private void throwBadType(String funcName, String type) 876 throws StandardException 877 { 878 throw StandardException.newException(SQLState.LANG_UNARY_FUNCTION_BAD_TYPE, 879 funcName, 880 type); 881 } 882 883 884 protected void bindToBuiltIn() 885 throws StandardException 886 { 887 890 if (receiver.getTypeId().userType()) 891 { 892 receiver = receiver.genSQLJavaSQLTree(); 893 } 894 895 898 if (leftOperand.getTypeId().userType()) 899 { 900 leftOperand = leftOperand.genSQLJavaSQLTree(); 901 } 902 903 906 if (rightOperand != null) 907 { 908 if (rightOperand.getTypeId().userType()) 909 { 910 rightOperand = rightOperand.genSQLJavaSQLTree(); 911 } 912 } 913 } 914 915 private DataTypeDescriptor getVarcharDescriptor() { 916 return new DataTypeDescriptor(TypeId.getBuiltInTypeId(Types.VARCHAR), true); 917 } 918 919 protected boolean isEquivalent(ValueNode o) throws StandardException 920 { 921 if (isSameNodeType(o)) 922 { 923 TernaryOperatorNode other = (TernaryOperatorNode)o; 924 925 930 return (other.methodName.equals(methodName) 931 && other.receiver.isEquivalent(receiver) 932 && other.leftOperand.isEquivalent(leftOperand) 933 && ( (rightOperand == null && other.rightOperand == null) || 934 (other.rightOperand != null && 935 other.rightOperand.isEquivalent(rightOperand)) ) ); 936 } 937 return false; 938 } 939 } 940 | Popular Tags |