📄 likeescapeoperatornode.java
字号:
if (rightOperand != null) { nullableResult |= rightOperand.getTypeServices().isNullable(); } setType(new DataTypeDescriptor( TypeId.BOOLEAN_ID, nullableResult ) ); } /** * Bind this operator * * @return Nothing * * @exception StandardException Thrown on error */ public void bindComparisonOperator() throws StandardException { TypeId receiverType = receiver.getTypeId(); TypeId leftType = leftOperand.getTypeId(); /* ** Check the type of the operands - this function is allowed only on ** string types. */ if ( ! receiverType.isStringTypeId()) { throw StandardException.newException(SQLState.LANG_LIKE_BAD_TYPE, receiverType.getSQLTypeName()); } if (! leftType.isStringTypeId()) { throw StandardException.newException(SQLState.LANG_LIKE_BAD_TYPE, leftType.getSQLTypeName()); } if (rightOperand != null && ! rightOperand.getTypeId().isStringTypeId()) { throw StandardException.newException(SQLState.LANG_LIKE_BAD_TYPE, rightOperand.getTypeId().getSQLTypeName()); } } /** * 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 { boolean eliminateLikeComparison = false; String greaterEqualString = null; String lessThanString = null; String pattern; /* We must 1st preprocess the component parts */ super.preprocess(numTables, outerFromList, outerSubqueryList, outerPredicateList); /* Don't try to optimize for (C)LOB type since it * doesn't allow comparison. */ if (receiver.getTypeId().getSQLTypeName().equals("CLOB")) { return this; } /* No need to consider transformation if we * already did transformation that added = * at bind time. */ if (addedEquals) { return this; } /* This is where we do the transformation for LIKE to make it optimizable. * c1 LIKE 'asdf%' -> c1 LIKE 'asdf%' AND c1 >= 'asdf' AND c1 < 'asdg' * c1 LIKE ? -> c1 LIKE ? and c1 >= ?', where ?' gets calculated at the * beginning of execution. */ if (!(leftOperand instanceof CharConstantNode) && !(leftOperand.isParameterNode())) { return this; } /* This transformation is only worth doing if it is pushable, ie, if * the receiver is a ColumnReference. */ if (!(receiver instanceof ColumnReference)) { // // We also do an early return here if in bindExpression we found we had // a National Char and put a CAST above the receiver. // return this; } // Build String constants if right side is a constant if (leftOperand instanceof CharConstantNode) { pattern = ((CharConstantNode) leftOperand).getString(); if (! Like.isOptimizable(pattern)) { return this; } int maxWidth = receiver.getTypeServices().getMaximumWidth(); greaterEqualString = Like.greaterEqualString(pattern, escape, maxWidth); /* We do not generate the < and we cannot drop the LIKE * when doing LIKE on a national char column. */ if ( ! receiver.getTypeId().isNationalStringTypeId() ) { lessThanString = Like.lessThanString(pattern, escape, maxWidth); eliminateLikeComparison = ! Like.isLikeComparisonNeeded(pattern); } } //System.out.println(receiver.getTypeServices()); //System.out.println("MAX WIDTH " + receiver.getTypeServices().getMaximumWidth()); /* For some unknown reason we need to clone the receiver if it is * a ColumnReference because reusing them in Qualifiers for a scan * does not work. */ /* The transformed tree has to be normalized. Either: * AND AND * / \ / \ * LIKE AND OR: LIKE AND * / \ / \ * >= AND >= TRUE * / \ * < TRUE * unless the like string is of the form CONSTANT%, in which * case we can do away with the LIKE altogether: * AND AND * / \ / \ * >= AND OR: >= TRUE * / \ * < TRUE */ AndNode newAnd = null; ValueNode trueNode = (ValueNode) getNodeFactory().getNode( C_NodeTypes.BOOLEAN_CONSTANT_NODE, Boolean.TRUE, getContextManager()); /* Create the AND <, if lessThanString is non-null or * leftOperand is a parameter. Currently for a national string we do not add a < than operator since we don't know (?) how to calculate such a string. */ if ( lessThanString != null || ( leftOperand.isParameterNode() && ! receiver.getTypeId().isNationalStringTypeId() )) { QueryTreeNode likeLTopt; if (leftOperand.isParameterNode()) { int maxWidth = receiver.getTypeServices().getMaximumWidth(); likeLTopt = setupOptimizeStringFromParameter(leftOperand, rightOperand, "lessThanStringFromParameter", maxWidth); } else { likeLTopt = getNodeFactory().getNode( C_NodeTypes.CHAR_CONSTANT_NODE, lessThanString, getContextManager()); } BinaryComparisonOperatorNode lessThan = (BinaryComparisonOperatorNode) getNodeFactory().getNode( C_NodeTypes.BINARY_LESS_THAN_OPERATOR_NODE, receiver.getClone(), likeLTopt, getContextManager()); // Disable comparability checks lessThan.setForQueryRewrite(true); /* Set type info for the operator node */ lessThan.bindComparisonOperator(); // Use between selectivity for the < lessThan.setBetweenSelectivity(); /* Create the AND */ newAnd = (AndNode) getNodeFactory().getNode( C_NodeTypes.AND_NODE, lessThan, trueNode, getContextManager()); newAnd.postBindFixup(); } /* Create the AND >=. Right side could * be a CharConstantNode or a ParameterNode. */ ValueNode likeGEopt; if (leftOperand.isParameterNode()) { // Create an expression off the parameter // new SQLChar(Like.greaterEqualString(?)); int maxWidth = receiver.getTypeServices().getMaximumWidth(); likeGEopt = setupOptimizeStringFromParameter(leftOperand, rightOperand, "greaterEqualStringFromParameter", maxWidth); } else { likeGEopt = (ValueNode) getNodeFactory().getNode(C_NodeTypes.CHAR_CONSTANT_NODE, greaterEqualString, getContextManager()); } BinaryComparisonOperatorNode greaterEqual = (BinaryComparisonOperatorNode) getNodeFactory().getNode( C_NodeTypes.BINARY_GREATER_EQUALS_OPERATOR_NODE, receiver.getClone(), likeGEopt, getContextManager()); // Disable comparability checks greaterEqual.setForQueryRewrite(true); /* Set type info for the operator node */ greaterEqual.bindComparisonOperator(); // Use between selectivity for the >= greaterEqual.setBetweenSelectivity(); /* Create the AND */ if (newAnd == null) { newAnd = (AndNode) getNodeFactory().getNode( C_NodeTypes.AND_NODE, greaterEqual, trueNode, getContextManager()); } else { newAnd = (AndNode) getNodeFactory().getNode( C_NodeTypes.AND_NODE, greaterEqual, newAnd, getContextManager()); } newAnd.postBindFixup(); /* Finally, we put a AND LIKE on top of the left deep tree, but * only if it is still necessary. */ if (! eliminateLikeComparison) { newAnd = (AndNode) getNodeFactory().getNode( C_NodeTypes.AND_NODE, this, newAnd, getContextManager()); newAnd.postBindFixup(); } /* Mark this node as transformed so that we don't get * calculated into the selectivity mulitple times. */ setTransformed(); return newAnd; } /** * Do code generation for this binary operator. * * This code was copied from BinaryOperatorNode and stripped down * * @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 {/*** 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?*/ /* ** 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 = getReceiverInterfaceName(); /* ** Generate LHS (field = <receiver operand>). This assignment is ** used as the receiver of the method call for this operator. ** ** (<receiver operand>).method(<left operand>, ** <right operand>, [<escaperightOp>,] ** <result field>) */ receiver.generateExpression(acb, mb); // first arg receiverInterfaceType = receiver.getTypeCompiler().interfaceName(); mb.upCast(receiverInterfaceType); // cast the method instance leftOperand.generateExpression(acb, mb); mb.upCast(leftInterfaceType); // first arg with cast if (rightOperand != null) { rightOperand.generateExpression(acb, mb); mb.upCast(rightInterfaceType); // second arg with cast } /* Figure out the result type name */ // resultTypeName = getTypeCompiler().interfaceName(); mb.callMethod(VMOpcode.INVOKEINTERFACE, null, methodName, resultInterfaceType, rightOperand == null ? 1 : 2); } private ValueNode setupOptimizeStringFromParameter(ValueNode parameterNode, ValueNode escapeNode,String methodName, int maxWidth) throws StandardException { Vector param; if (escapeNode != null) { param = new Vector(2); methodName += "WithEsc"; } else param = new Vector(1); StaticMethodCallNode methodCall = (StaticMethodCallNode) getNodeFactory().getNode(C_NodeTypes.STATIC_METHOD_CALL_NODE, methodName, "org.apache.derby.iapi.types.Like", getContextManager()); // using a method call directly, thus need internal sql capability methodCall.internalCall = true; param.addElement(parameterNode); if (escapeNode != null) param.addElement(escapeNode); QueryTreeNode maxWidthNode = getNodeFactory().getNode( C_NodeTypes.INT_CONSTANT_NODE, new Integer(maxWidth), getContextManager()); param.addElement(maxWidthNode); methodCall.addParms(param); ValueNode java2SQL = (ValueNode) getNodeFactory().getNode( C_NodeTypes.JAVA_TO_SQL_VALUE_NODE, methodCall, getContextManager()); java2SQL = (ValueNode) java2SQL.bindExpression(null, null, null); CastNode likeOpt = (CastNode) getNodeFactory().getNode( C_NodeTypes.CAST_NODE, java2SQL, parameterNode.getTypeServices(), getContextManager()); likeOpt.bindCastNodeOnly(); return likeOpt; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -