use of org.apache.derby.iapi.services.compiler.LocalField in project derby by apache.
the class BinaryOperatorNode method generateExpression.
/**
* 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
*/
@Override
void generateExpression(ExpressionClassBuilder acb, MethodBuilder mb) throws StandardException {
/* If this BinaryOperatorNode was created as a part of an IN-list
* "probe predicate" then we do not want to generate the relational
* operator itself; instead we want to generate the underlying
* IN-list for which this operator node was created.
*
* We'll get here in situations where the optimizer chooses a plan
* for which the probe predicate is *not* a useful start/stop key
* and thus is not being used for execution-time index probing.
* In this case we are effectively "reverting" the probe predicate
* back to the InListOperatorNode from which it was created. Or put
* another way, we are "giving up" on index multi-probing and simply
* generating the original IN-list as a regular restriction.
*/
if (this instanceof BinaryRelationalOperatorNode) {
InListOperatorNode ilon = ((BinaryRelationalOperatorNode) this).getInListOp();
if (ilon != null) {
ilon.generateExpression(acb, mb);
return;
}
}
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 number of arguments to pass to the method that implements the
// operator, depends on the type of the operator.
int numArgs;
// If we're dealing with XMLEXISTS or XMLQUERY, there is some
// additional work to be done.
boolean xmlGen = (kind == K_XMLQUERY) || (kind == K_XMLEXISTS);
/*
** 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 = (kind == K_BASE) ? getReceiverInterfaceName() : leftInterfaceType;
/*
** Generate (with <left expression> only being evaluated once)
**
** <left expression>.method(<left expression>, <right expression>...)
*/
leftOperand.generateExpression(acb, mb);
// cast the method instance
mb.cast(receiverType);
// stack: left
mb.dup();
mb.cast(leftInterfaceType);
// stack: left, left
rightOperand.generateExpression(acb, mb);
// second arg with cast
mb.cast(rightInterfaceType);
// stack: left, left, right
// We've pushed two arguments
numArgs = 2;
} 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 = (kind == K_BASE) ? getReceiverInterfaceName() : rightInterfaceType;
/*
** Generate (with <right expression> only being evaluated once)
**
** <right expression>.method(<left expression>, <right expression>)
**
** UNLESS we're generating an XML operator such as XMLEXISTS.
** In that case we want to generate
**
** <right expression>.method(sqlXmlUtil)
*/
rightOperand.generateExpression(acb, mb);
// cast the method instance
mb.cast(receiverType);
if (xmlGen) {
// Push one argument (the SqlXmlUtil instance)
numArgs = 1;
pushSqlXmlUtil(acb, mb, xmlQuery, operator);
// stack: right,sqlXmlUtil
} else {
// Push two arguments (left, right)
numArgs = 2;
mb.dup();
mb.cast(rightInterfaceType);
// stack: right,right
leftOperand.generateExpression(acb, mb);
// second arg with cast
mb.cast(leftInterfaceType);
// stack: right,right,left
mb.swap();
// stack: right,left,right
}
}
/* Figure out the result type name */
resultTypeName = (kind == K_BASE) ? getTypeCompiler().interfaceName() : resultInterfaceType;
// Boolean return types don't need a result field. For other types,
// allocate an object for re-use to hold the result of the operator.
LocalField resultField = getTypeId().isBooleanTypeId() ? null : acb.newFieldDeclaration(Modifier.PRIVATE, resultTypeName);
// Push the result field onto the stack, if there is a result field.
if (resultField != null) {
/*
** Call the method for this operator.
*/
// third arg
mb.getField(resultField);
// Adjust number of arguments for the result field
numArgs++;
/* pass statically calculated scale to decimal divide method to make
* result set scale consistent, beetle 3901
*/
int jdbcType;
if ((getTypeServices() != null) && ((jdbcType = getTypeServices().getJDBCTypeId()) == java.sql.Types.DECIMAL || jdbcType == java.sql.Types.NUMERIC) && operator.equals("/")) {
// 4th arg
mb.push(getTypeServices().getScale());
numArgs++;
}
}
mb.callMethod(VMOpcode.INVOKEINTERFACE, receiverType, methodName, resultTypeName, numArgs);
// Store the result of the method call, if there is a result field.
if (resultField != null) {
// 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 (// since result type is numeric variable length, generate setWidth code.
getTypeId().variableLength()) {
if (getTypeId().isNumericTypeId()) {
// to leave the DataValueDescriptor value on the stack, since setWidth is void
mb.dup();
mb.push(getTypeServices().getPrecision());
mb.push(getTypeServices().getScale());
mb.push(true);
mb.callMethod(VMOpcode.INVOKEINTERFACE, ClassName.VariableSizeDataValue, "setWidth", "void", 3);
}
}
/*
** Store the result of the method call in the field, so we can re-use
** the object.
*/
mb.putField(resultField);
}
}
use of org.apache.derby.iapi.services.compiler.LocalField in project derby by apache.
the class CastNode method genDataValueConversion.
private void genDataValueConversion(ExpressionClassBuilder acb, MethodBuilder mb) throws StandardException {
MethodBuilder acbConstructor = acb.getConstructor();
String resultTypeName = getTypeCompiler().interfaceName();
/* field = method call */
/* Allocate an object for re-use to hold the result of the operator */
LocalField field = acb.newFieldDeclaration(Modifier.PRIVATE, resultTypeName);
/*
** Store the result of the method call in the field, so we can re-use
** the object.
*/
acb.generateNull(acbConstructor, getTypeCompiler(getTypeId()), getTypeServices().getCollationType());
acbConstructor.setField(field);
if (!sourceCTI.userType() && !getTypeId().userType()) {
// targetDVD reference for the setValue method call
mb.getField(field);
mb.swap();
mb.upCast(ClassName.DataValueDescriptor);
mb.callMethod(VMOpcode.INVOKEINTERFACE, ClassName.DataValueDescriptor, "setValue", "void", 1);
} else {
/*
** generate: expr.getObject()
*/
mb.callMethod(VMOpcode.INVOKEINTERFACE, ClassName.DataValueDescriptor, "getObject", "java.lang.Object", 0);
// castExpr
// instance for the setValue/setObjectForCast method call
mb.getField(field);
// push it before the value
mb.swap();
/*
** We are casting a java type, generate:
**
** DataValueDescriptor.setObjectForCast(java.lang.Object castExpr, boolean instanceOfExpr, destinationClassName)
** where instanceOfExpr is "source instanceof destinationClass".
**
*/
String destinationType = getTypeId().getCorrespondingJavaTypeName();
// at this point method instance and cast result are on the stack
// we duplicate the cast value in order to perform the instanceof check
mb.dup();
mb.isInstanceOf(destinationType);
mb.push(destinationType);
mb.callMethod(VMOpcode.INVOKEINTERFACE, ClassName.DataValueDescriptor, "setObjectForCast", "void", 3);
}
mb.getField(field);
/*
** If we are casting to a variable length datatype, we
** have to make sure we have set it to the correct
** length.
*/
if (getTypeId().variableLength()) {
boolean isNumber = getTypeId().isNumericTypeId();
// to leave the DataValueDescriptor value on the stack, since setWidth is void
mb.dup();
/* setWidth() is on VSDV - upcast since
* decimal implements subinterface
* of VSDV.
*/
mb.push(isNumber ? getTypeServices().getPrecision() : getTypeServices().getMaximumWidth());
mb.push(getTypeServices().getScale());
mb.push(!sourceCTI.variableLength() || isNumber || assignmentSemantics);
mb.callMethod(VMOpcode.INVOKEINTERFACE, ClassName.VariableSizeDataValue, "setWidth", "void", 3);
}
}
use of org.apache.derby.iapi.services.compiler.LocalField in project derby by apache.
the class ExpressionClassBuilder method getCurrentDateExpression.
// /////////////////////////////////////////////////////////////////////
//
// CURRENT DATE/TIME SUPPORT
//
// /////////////////////////////////////////////////////////////////////
/**
* This utility method returns an expression for CURRENT_DATE.
* Get the expression this way, because the activation needs to
* generate support information for CURRENT_DATE,
* that would otherwise be painful to create manually.
*/
void getCurrentDateExpression(MethodBuilder mb) {
// do any needed setup
LocalField lf = getCurrentSetup();
// generated Java:
// this.cdt.getCurrentDate();
mb.getField(lf);
mb.callMethod(VMOpcode.INVOKEVIRTUAL, (String) null, "getCurrentDate", "java.sql.Date", 0);
}
use of org.apache.derby.iapi.services.compiler.LocalField in project derby by apache.
the class ExpressionClassBuilder method getCurrentTimeExpression.
/**
* This utility method returns an expression for CURRENT_TIME.
* Get the expression this way, because the activation needs to
* generate support information for CURRENT_TIME,
* that would otherwise be painful to create manually.
*/
void getCurrentTimeExpression(MethodBuilder mb) {
// do any needed setup
LocalField lf = getCurrentSetup();
// generated Java:
// this.cdt.getCurrentTime();
mb.getField(lf);
mb.callMethod(VMOpcode.INVOKEVIRTUAL, (String) null, "getCurrentTime", "java.sql.Time", 0);
}
use of org.apache.derby.iapi.services.compiler.LocalField in project derby by apache.
the class ExpressionClassBuilder method getCurrentTimestampExpression.
/**
* This utility method generates an expression for CURRENT_TIMESTAMP.
* Get the expression this way, because the activation needs to
* generate support information for CURRENT_TIMESTAMP,
* that would otherwise be painful to create manually.
*/
void getCurrentTimestampExpression(MethodBuilder mb) {
// do any needed setup
LocalField lf = getCurrentSetup();
// generated Java:
// this.cdt.getCurrentTimestamp();
mb.getField(lf);
mb.callMethod(VMOpcode.INVOKEVIRTUAL, (String) null, "getCurrentTimestamp", "java.sql.Timestamp", 0);
}
Aggregations