📄 binaryoperatornode.java
字号:
*/ public ValueNode genSQLJavaSQLTree() throws StandardException { TypeId leftTypeId = leftOperand.getTypeId(); if (!(leftTypeId.systemBuiltIn())) leftOperand = leftOperand.genSQLJavaSQLTree(); TypeId rightTypeId = rightOperand.getTypeId(); if (!(rightTypeId.systemBuiltIn())) rightOperand = rightOperand.genSQLJavaSQLTree(); return this; } /** * Preprocess an expression tree. We do a number of transformations * here (including subqueries, IN lists, LIKE and BETWEEN) plus * subquery flattening. * NOTE: This is done before the outer ResultSetNode is preprocessed. * * @param numTables Number of tables in the DML Statement * @param outerFromList FromList from outer query block * @param outerSubqueryList SubqueryList from outer query block * @param outerPredicateList PredicateList from outer query block * * @return The modified expression * * @exception StandardException Thrown on error */ public ValueNode preprocess(int numTables, FromList outerFromList, SubqueryList outerSubqueryList, PredicateList outerPredicateList) throws StandardException { leftOperand = leftOperand.preprocess(numTables, outerFromList, outerSubqueryList, outerPredicateList); rightOperand = rightOperand.preprocess(numTables, outerFromList, outerSubqueryList, outerPredicateList); return this; } /** * Do code generation for this binary operator. * * @param acb The ExpressionClassBuilder for the class we're generating * @param mb The method the code to place the code * * * @exception StandardException Thrown on error */ public void generateExpression(ExpressionClassBuilder acb, MethodBuilder mb) throws StandardException { String resultTypeName; String receiverType;/*** if i have a operator.getOrderableType() == constant, then just cache ** it in a field. if i have QUERY_INVARIANT, then it would be good to** cache it in something that is initialized each execution,** but how?*/ /* ** The receiver is the operand with the higher type precedence. ** Like always makes the left the receiver. ** */ if (leftOperand.getTypeId().typePrecedence() > rightOperand.getTypeId().typePrecedence()) { receiver = leftOperand; /* ** let the receiver type be determined by an ** overridable method so that if methods are ** not implemented on the lowest interface of ** a class, they can note that in the implementation ** of the node that uses the method. */ receiverType = (operatorType == -1) ? getReceiverInterfaceName() : leftInterfaceType; /* ** Generate (with <left expression> only being evaluated once) ** ** <left expression>.method(<left expression>, <right expression>...) */ leftOperand.generateExpression(acb, mb); mb.cast(receiverType); // cast the method instance // stack: left mb.dup(); mb.cast(leftInterfaceType); // stack: left, left rightOperand.generateExpression(acb, mb); mb.cast(rightInterfaceType); // second arg with cast // stack: left, left, right } else { receiver = rightOperand; /* ** let the receiver type be determined by an ** overridable method so that if methods are ** not implemented on the lowest interface of ** a class, they can note that in the implementation ** of the node that uses the method. */ receiverType = (operatorType == -1) ? getReceiverInterfaceName() : rightInterfaceType; /* ** Generate (with <right expression> only being evaluated once) ** ** <right expression>.method(<left expression>, <right expression>) */ rightOperand.generateExpression(acb, mb); mb.cast(receiverType); // cast the method instance // stack: right mb.dup(); mb.cast(rightInterfaceType); // stack: right,right leftOperand.generateExpression(acb, mb); mb.cast(leftInterfaceType); // second arg with cast // stack: right,right,left mb.swap(); // stack: right,left,right } /* Figure out the result type name */ resultTypeName = (operatorType == -1) ? getTypeCompiler().interfaceName() : resultInterfaceType; // Boolean return types don't need a result field boolean needField = !getTypeId().isBooleanTypeId(); if (needField) { /* Allocate an object for re-use to hold the result of the operator */ LocalField resultField = acb.newFieldDeclaration(Modifier.PRIVATE, resultTypeName); /* ** Call the method for this operator. */ mb.getField(resultField); // third arg //following method is special code for concatenation where if field is null, we want it to be initialized to NULL SQLxxx type object //before generating code "field = method(p1, p2, field);" initializeResultField(acb, mb, resultField); /* pass statically calculated scale to decimal divide method to make * result set scale consistent, beetle 3901 */ int jdbcType; if ((dataTypeServices != null) && ((jdbcType = dataTypeServices.getJDBCTypeId()) == java.sql.Types.DECIMAL || jdbcType == java.sql.Types.NUMERIC) && operator.equals("/")) { mb.push(dataTypeServices.getScale()); // 4th arg mb.callMethod(VMOpcode.INVOKEINTERFACE, receiverType, methodName, resultTypeName, 4); } else mb.callMethod(VMOpcode.INVOKEINTERFACE, receiverType, methodName, resultTypeName, 3); //the need for following if was realized while fixing bug 5704 where decimal*decimal was resulting an overflow value but we were not detecting it if (getTypeId().variableLength())//since result type is numeric variable length, generate setWidth code. { if (getTypeId().isNumericTypeId()) { mb.push(getTypeServices().getPrecision()); mb.push(getTypeServices().getScale()); mb.push(true); mb.callMethod(VMOpcode.INVOKEINTERFACE, ClassName.VariableSizeDataValue, "setWidth", ClassName.DataValueDescriptor, 3); mb.cast(resultTypeName); } } /* ** Store the result of the method call in the field, so we can re-use ** the object. */ mb.putField(resultField); } else { mb.callMethod(VMOpcode.INVOKEINTERFACE, receiverType, methodName, resultTypeName, 2); } } //following method is no-op here but in concatenation node, this method is used to check if resultField is null, //and if yes, then we want it to be initialized to NULL SQLxxx type object protected void initializeResultField(ExpressionClassBuilder acb, MethodBuilder mb, LocalField resultField) { } /** * Set the leftOperand to the specified ValueNode * * @param newLeftOperand The new leftOperand * * @return None. */ public void setLeftOperand(ValueNode newLeftOperand) { leftOperand = newLeftOperand; } /** * Get the leftOperand * * @return The current leftOperand. */ public ValueNode getLeftOperand() { return leftOperand; } /** * Set the rightOperand to the specified ValueNode * * @param newRightOperand The new rightOperand * * @return None. */ public void setRightOperand(ValueNode newRightOperand) { rightOperand = newRightOperand; } /** * Get the rightOperand * * @return The current rightOperand. */ public ValueNode getRightOperand() { return rightOperand; } /** * Categorize this predicate. Initially, this means * building a bit map of the referenced tables for each predicate. * If the source of this ColumnReference (at the next underlying level) * is not a ColumnReference or a VirtualColumnNode then this predicate * will not be pushed down. * * For example, in: * select * from (select 1 from s) a (x) where x = 1 * we will not push down x = 1. * NOTE: It would be easy to handle the case of a constant, but if the * inner SELECT returns an arbitrary expression, then we would have to copy * that tree into the pushed predicate, and that tree could contain * subqueries and method calls. * RESOLVE - revisit this issue once we have views. * * @param referencedTabs JBitSet with bit map of referenced FromTables * @param simplePredsOnly Whether or not to consider method * calls, field references and conditional nodes * when building bit map * * @return boolean Whether or not source.expression is a ColumnReference * or a VirtualColumnNode. * @exception StandardException Thrown on error */ public boolean categorize(JBitSet referencedTabs, boolean simplePredsOnly) throws StandardException { boolean pushable; pushable = leftOperand.categorize(referencedTabs, simplePredsOnly); pushable = (rightOperand.categorize(referencedTabs, simplePredsOnly) && pushable); return pushable; } /** * Remap all ColumnReferences in this tree to be clones of the * underlying expression. * * @return ValueNode The remapped expression tree. * * @exception StandardException Thrown on error */ public ValueNode remapColumnReferencesToExpressions() throws StandardException { leftOperand = leftOperand.remapColumnReferencesToExpressions(); rightOperand = rightOperand.remapColumnReferencesToExpressions(); return this; } /** * Return whether or not this expression tree represents a constant expression. * * @return Whether or not this expression tree represents a constant expression. */ public boolean isConstantExpression() { return (leftOperand.isConstantExpression() && rightOperand.isConstantExpression()); } /** @see ValueNode#constantExpression */ public boolean constantExpression(PredicateList whereClause) { return (leftOperand.constantExpression(whereClause) && rightOperand.constantExpression(whereClause)); } /** * Determine the type the binary method is called on. * By default, based on the receiver. * * Override in nodes that use methods on super-interfaces of * the receiver's interface, such as comparisons. * * @exception StandardException Thrown on error */ public String getReceiverInterfaceName() throws StandardException { if (SanityManager.DEBUG) { SanityManager.ASSERT(receiver!=null,"can't get receiver interface name until receiver is set"); } return receiver.getTypeCompiler().interfaceName(); } /** * Return the variant type for the underlying expression. * The variant type can be: * VARIANT - variant within a scan * (method calls and non-static field access) * SCAN_INVARIANT - invariant within a scan * (column references from outer tables) * QUERY_INVARIANT - invariant within the life of a query * CONSTANT - immutable * * @return The variant type for the underlying expression. * @exception StandardException thrown on error */ protected int getOrderableVariantType() throws StandardException { int leftType = leftOperand.getOrderableVariantType(); int rightType = rightOperand.getOrderableVariantType(); return Math.min(leftType, rightType); } /** * Swap the left and right sides. * * @return Nothing. */ void swapOperands() { String tmpInterfaceType = leftInterfaceType; ValueNode tmpVN = leftOperand; leftOperand = rightOperand; rightOperand = tmpVN; leftInterfaceType = rightInterfaceType; rightInterfaceType = tmpInterfaceType; } /** * Accept a visitor, and call v.visit() * on child nodes as necessary. * * @param v the visitor * * @exception StandardException on error */ public Visitable accept(Visitor v) throws StandardException { Visitable returnNode = v.visit(this); if (v.skipChildren(this)) { return returnNode; } if (leftOperand != null && !v.stopTraversal()) { leftOperand = (ValueNode)leftOperand.accept(v); } if (rightOperand != null && !v.stopTraversal()) { rightOperand = (ValueNode)rightOperand.accept(v); } return returnNode; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -