use of org.apache.derby.iapi.services.compiler.LocalField in project derby by apache.
the class SpecialFunctionNode method generateExpression.
/**
* Generate an expression that returns a DataValueDescriptor and
* calls a method off the language connection or the activation.
*
* @param acb The ExpressionClassBuilder for the class being built
* @param mb The method the code to place the code
*
* @exception StandardException Thrown on error
*/
@Override
void generateExpression(ExpressionClassBuilder acb, MethodBuilder mb) throws StandardException {
mb.pushThis();
mb.callMethod(VMOpcode.INVOKEINTERFACE, ClassName.Activation, "getLanguageConnectionContext", ClassName.LanguageConnectionContext, 0);
int argCount = 0;
if (methodName.equals("getCurrentRoleIdDelimited") || methodName.equals("getCurrentSchemaName") || methodName.equals("getCurrentUserId")) {
acb.pushThisAsActivation(mb);
argCount++;
}
mb.callMethod(VMOpcode.INVOKEINTERFACE, (String) null, methodName, methodType, argCount);
String fieldType = getTypeCompiler().interfaceName();
LocalField field = acb.newFieldDeclaration(Modifier.PRIVATE, fieldType);
acb.generateDataValue(mb, getTypeCompiler(), getTypeServices().getCollationType(), field);
}
use of org.apache.derby.iapi.services.compiler.LocalField in project derby by apache.
the class StaticMethodCallNode method generateExpression.
/**
* Do code generation for this method call
*
* @param acb The ExpressionClassBuilder for the class we're generating
* @param mb The method the expression will go into
*
* @exception StandardException Thrown on error
*/
void generateExpression(ExpressionClassBuilder acb, MethodBuilder mb) throws StandardException {
if (routineInfo != null) {
if (!routineInfo.calledOnNullInput() && routineInfo.getParameterCount() != 0)
returnsNullOnNullState = acb.newFieldDeclaration(Modifier.PRIVATE, "boolean");
}
// reset the parameters are null indicator.
if (returnsNullOnNullState != null) {
mb.push(false);
mb.setField(returnsNullOnNullState);
// for the call to the generated method below.
mb.pushThis();
}
int nargs = generateParameters(acb, mb);
LocalField functionEntrySQLAllowed = null;
if (routineInfo != null) {
short sqlAllowed = routineInfo.getSQLAllowed();
if (sqlAllowed != RoutineAliasInfo.NO_SQL) {
int sqlOperation;
if (sqlAllowed == RoutineAliasInfo.READS_SQL_DATA)
sqlOperation = Authorizer.SQL_SELECT_OP;
else if (sqlAllowed == RoutineAliasInfo.MODIFIES_SQL_DATA)
sqlOperation = Authorizer.SQL_WRITE_OP;
else
sqlOperation = Authorizer.SQL_ARBITARY_OP;
generateAuthorizeCheck((ActivationClassBuilder) acb, mb, sqlOperation);
}
int statmentContextReferences = isSystemCode ? 2 : 1;
boolean isFunction = routineInfo.getReturnType() != null;
if (isFunction)
statmentContextReferences++;
if (statmentContextReferences != 0) {
acb.pushThisAsActivation(mb);
mb.callMethod(VMOpcode.INVOKEINTERFACE, null, "getLanguageConnectionContext", ClassName.LanguageConnectionContext, 0);
mb.callMethod(VMOpcode.INVOKEINTERFACE, null, "getStatementContext", "org.apache.derby.iapi.sql.conn.StatementContext", 0);
for (int scc = 1; scc < statmentContextReferences; scc++) mb.dup();
}
/**
* Set the statement context to reflect we are running
* System procedures, so that we can execute non-standard SQL.
*/
if (isSystemCode) {
mb.callMethod(VMOpcode.INVOKEINTERFACE, null, "setSystemCode", "void", 0);
}
// context.
if (sqlAllowed != RoutineAliasInfo.NO_SQL) {
generatePushNestedSessionContext((ActivationClassBuilder) acb, mb, routineInfo.hasDefinersRights(), routineDefiner);
}
//
if (isFunction) {
functionEntrySQLAllowed = acb.newFieldDeclaration(Modifier.PRIVATE, "short");
mb.callMethod(VMOpcode.INVOKEINTERFACE, null, "getSQLAllowed", "short", 0);
mb.setField(functionEntrySQLAllowed);
}
// Set up the statement context to reflect the
// restricted SQL execution allowed by this routine.
mb.push(sqlAllowed);
mb.push(false);
mb.callMethod(VMOpcode.INVOKEINTERFACE, null, "setSQLAllowed", "void", 2);
}
// a routine may make use of both varargs and dynamic ResultSets.
if (routineInfo != null && !hasVarargs()) {
int compiledResultSets = methodParameterTypes.length - methodParms.length;
if (compiledResultSets != 0) {
// Add a method that indicates the maxium number of dynamic result sets.
int maxDynamicResults = routineInfo.getMaxDynamicResultSets();
if (maxDynamicResults > 0) {
MethodBuilder gdr = acb.getClassBuilder().newMethodBuilder(Modifier.PUBLIC, "int", "getMaxDynamicResults");
gdr.push(maxDynamicResults);
gdr.methodReturn();
gdr.complete();
}
// add a method to return all the dynamic result sets (unordered)
MethodBuilder gdr = acb.getClassBuilder().newMethodBuilder(Modifier.PUBLIC, "java.sql.ResultSet[][]", "getDynamicResults");
MethodBuilder cons = acb.getConstructor();
// if (procDef.getParameterStyle() == RoutineAliasInfo.PS_JAVA)
{
// PARAMETER STYLE JAVA
LocalField procedureResultSetsHolder = acb.newFieldDeclaration(Modifier.PRIVATE, "java.sql.ResultSet[][]");
// getDynamicResults body
gdr.getField(procedureResultSetsHolder);
// create the holder of all the ResultSet arrays, new java.sql.ResultSet[][compiledResultSets]
cons.pushNewArray("java.sql.ResultSet[]", compiledResultSets);
cons.setField(procedureResultSetsHolder);
// arguments for the dynamic result sets
for (int i = 0; i < compiledResultSets; i++) {
mb.pushNewArray("java.sql.ResultSet", 1);
mb.dup();
mb.getField(procedureResultSetsHolder);
mb.swap();
mb.setArrayElement(i);
}
}
// complete the method that returns the ResultSet[][] to the
gdr.methodReturn();
gdr.complete();
nargs += compiledResultSets;
}
}
String javaReturnType = getJavaTypeName();
MethodBuilder mbnc = null;
MethodBuilder mbcm = mb;
// do not call the method, just return null.
if (returnsNullOnNullState != null) {
mbnc = acb.newGeneratedFun(javaReturnType, Modifier.PRIVATE, methodParameterTypes);
// add the throws clause for the public static method we are going to call.
Class[] throwsSet = ((java.lang.reflect.Method) method).getExceptionTypes();
for (int te = 0; te < throwsSet.length; te++) {
mbnc.addThrownException(throwsSet[te].getName());
}
mbnc.getField(returnsNullOnNullState);
mbnc.conditionalIf();
// set up for a null!!
// for objects is easy.
mbnc.pushNull(javaReturnType);
mbnc.startElseCode();
if (!actualMethodReturnType.equals(javaReturnType))
mbnc.pushNewStart(javaReturnType);
// fetch all the arguments
for (int pa = 0; pa < nargs; pa++) {
mbnc.getParameter(pa);
}
mbcm = mbnc;
}
mbcm.callMethod(VMOpcode.INVOKESTATIC, method.getDeclaringClass().getName(), methodName, actualMethodReturnType, nargs);
if (returnsNullOnNullState != null) {
// compatible with their function return types.
if (!actualMethodReturnType.equals(javaReturnType)) {
if (actualMethodReturnType.equals("short") && javaReturnType.equals("java.lang.Integer"))
mbnc.upCast("int");
mbnc.pushNewComplete(1);
}
mbnc.completeConditional();
mbnc.methodReturn();
mbnc.complete();
// now call the wrapper method
mb.callMethod(VMOpcode.INVOKEVIRTUAL, acb.getClassBuilder().getFullName(), mbnc.getName(), javaReturnType, nargs);
mbnc = null;
}
if (routineInfo != null) {
// entry to the method.
if (functionEntrySQLAllowed != null) {
acb.pushThisAsActivation(mb);
mb.callMethod(VMOpcode.INVOKEINTERFACE, null, "getLanguageConnectionContext", ClassName.LanguageConnectionContext, 0);
mb.callMethod(VMOpcode.INVOKEINTERFACE, null, "getStatementContext", "org.apache.derby.iapi.sql.conn.StatementContext", 0);
mb.getField(functionEntrySQLAllowed);
// override as we are ending the control set by this function all.
mb.push(true);
mb.callMethod(VMOpcode.INVOKEINTERFACE, null, "setSQLAllowed", "void", 2);
}
if (outParamArrays != null) {
MethodBuilder constructor = acb.getConstructor();
// constructor - setting up correct parameter type info
acb.pushThisAsActivation(constructor);
constructor.callMethod(VMOpcode.INVOKEINTERFACE, null, "getParameterValueSet", ClassName.ParameterValueSet, 0);
// execute - passing out parameters back.
acb.pushThisAsActivation(mb);
mb.callMethod(VMOpcode.INVOKEINTERFACE, null, "getParameterValueSet", ClassName.ParameterValueSet, 0);
int[] parameterModes = routineInfo.getParameterModes();
for (int i = 0; i < outParamArrays.length; i++) {
int parameterMode = parameterModes[getRoutineArgIdx(i)];
if (parameterMode != (ParameterMetaData.parameterModeIn)) {
// must be a parameter if it is INOUT or OUT.
ValueNode sqlParamNode = ((SQLToJavaValueNode) methodParms[i]).getSQLValueNode();
int applicationParameterNumber = applicationParameterNumbers[i];
// Set the correct parameter nodes in the ParameterValueSet at constructor time.
constructor.dup();
constructor.push(applicationParameterNumber);
constructor.push(parameterMode);
constructor.callMethod(VMOpcode.INVOKEINTERFACE, null, "setParameterMode", "void", 2);
// Pass the value of the outparameters back to the calling code
LocalField lf = outParamArrays[i];
mb.dup();
mb.push(applicationParameterNumber);
mb.callMethod(VMOpcode.INVOKEINTERFACE, null, "getParameter", ClassName.DataValueDescriptor, 1);
// see if we need to set the desired length/scale/precision of the type
DataTypeDescriptor paramdtd = sqlParamNode.getTypeServices();
boolean isNumericType = paramdtd.getTypeId().isNumericTypeId();
boolean isAnsiUDT = paramdtd.getTypeId().getBaseTypeId().isAnsiUDT();
// is the underlying type for the OUT/INOUT parameter primitive.
// if this is a varargs arg then we have to strip off another array level
Class<?> cellType = ((Method) method).getParameterTypes()[getRoutineArgIdx(i)].getComponentType();
if (isVararg(i)) {
cellType = cellType.getComponentType();
}
boolean isPrimitive = cellType.isPrimitive();
if (isNumericType) {
if (!isPrimitive)
mb.cast(ClassName.NumberDataValue);
} else if (paramdtd.getTypeId().isBooleanTypeId()) {
// need to cast as the setValue(Boolean) method only exists on BooleanDataValue
if (!isPrimitive)
mb.cast(ClassName.BooleanDataValue);
}
if (paramdtd.getTypeId().variableLength()) {
// need another DVD reference for the set width below.
mb.dup();
}
// pvs, dvd, array
mb.getField(lf);
// pvs, dvd, value
mb.getArrayElement(0);
// The value needs to be set thorugh the setValue(Number) method.
if (isNumericType && !isPrimitive) {
mb.upCast("java.lang.Number");
}
// The value needs to be set thorugh the setValue(Object) method.
if (isAnsiUDT) {
mb.upCast("java.lang.Object");
}
mb.callMethod(VMOpcode.INVOKEINTERFACE, null, "setValue", "void", 1);
if (paramdtd.getTypeId().variableLength()) {
mb.push(isNumericType ? paramdtd.getPrecision() : paramdtd.getMaximumWidth());
mb.push(paramdtd.getScale());
mb.push(isNumericType);
mb.callMethod(VMOpcode.INVOKEINTERFACE, ClassName.VariableSizeDataValue, "setWidth", "void", 3);
// mb.endStatement();
}
}
}
constructor.endStatement();
mb.endStatement();
}
}
}
use of org.apache.derby.iapi.services.compiler.LocalField in project derby by apache.
the class StaticMethodCallNode method generateOneParameter.
/**
* Push extra code to generate the casts within the
* arrays for the parameters passed as arrays.
*/
@Override
void generateOneParameter(ExpressionClassBuilder acb, MethodBuilder mb, int parameterNumber) throws StandardException {
int parameterMode;
SQLToJavaValueNode sql2j = null;
if (methodParms[parameterNumber] instanceof SQLToJavaValueNode)
sql2j = (SQLToJavaValueNode) methodParms[parameterNumber];
if (routineInfo != null) {
parameterMode = routineInfo.getParameterModes()[getRoutineArgIdx(parameterNumber)];
} else {
// for a static method call the parameter always starts out as a in parameter, but
// may be registered as an IN OUT parameter. For a static method argument to be
// a dynmaically registered out parameter it must be a simple ? parameter
parameterMode = (ParameterMetaData.parameterModeIn);
if (sql2j != null) {
if (sql2j.getSQLValueNode().requiresTypeFromContext()) {
ParameterNode pn;
if (sql2j.getSQLValueNode() instanceof UnaryOperatorNode)
pn = ((UnaryOperatorNode) sql2j.getSQLValueNode()).getParameterOperand();
else
pn = (ParameterNode) (sql2j.getSQLValueNode());
// applicationParameterNumbers is only set up for a procedure.
int applicationParameterNumber = pn.getParameterNumber();
String parameterType = methodParameterTypes[getRoutineArgIdx(parameterNumber)];
if (parameterType.endsWith("[]")) {
// constructor - setting up correct parameter type info
MethodBuilder constructor = acb.getConstructor();
acb.pushThisAsActivation(constructor);
constructor.callMethod(VMOpcode.INVOKEINTERFACE, null, "getParameterValueSet", ClassName.ParameterValueSet, 0);
constructor.push(applicationParameterNumber);
constructor.push(ParameterMetaData.parameterModeUnknown);
constructor.callMethod(VMOpcode.INVOKEINTERFACE, null, "setParameterMode", "void", 2);
constructor.endStatement();
}
}
}
}
switch(parameterMode) {
case (ParameterMetaData.parameterModeIn):
case (ParameterMetaData.parameterModeInOut):
case (ParameterMetaData.parameterModeUnknown):
if (sql2j != null)
sql2j.returnsNullOnNullState = returnsNullOnNullState;
super.generateOneParameter(acb, mb, parameterNumber);
break;
case (ParameterMetaData.parameterModeOut):
// method call from the parameter node.
break;
}
switch(parameterMode) {
case (ParameterMetaData.parameterModeIn):
case (ParameterMetaData.parameterModeUnknown):
break;
case (ParameterMetaData.parameterModeInOut):
case (ParameterMetaData.parameterModeOut):
{
// Create the array used to pass into the method. We create a
// new array for each call as there is a small chance the
// application could retain a reference to it and corrupt
// future calls with the same CallableStatement object.
String methodParameterType = methodParameterTypes[getRoutineArgIdx(parameterNumber)];
String arrayType = methodParameterType.substring(0, methodParameterType.length() - 2);
// if a varargs arg, then strip off the extra array dimension added by varargs
if (isVararg(parameterNumber)) {
methodParameterType = stripOneArrayLevel(methodParameterType);
arrayType = stripOneArrayLevel(arrayType);
}
LocalField lf = acb.newFieldDeclaration(Modifier.PRIVATE, methodParameterType);
if (outParamArrays == null) {
outParamArrays = new LocalField[methodParms.length];
}
outParamArrays[parameterNumber] = lf;
mb.pushNewArray(arrayType, 1);
mb.putField(lf);
// set the IN part of the parameter into the INOUT parameter.
if (parameterMode != (ParameterMetaData.parameterModeOut)) {
mb.swap();
mb.setArrayElement(0);
mb.getField(lf);
}
break;
}
}
}
use of org.apache.derby.iapi.services.compiler.LocalField in project derby by apache.
the class SubqueryNode method generateExpression.
/**
* Do code generation for this subquery.
*
* @param expressionBuilder The ExpressionClassBuilder for the class being built
* @param mbex The method the expression will go into
*
* @exception StandardException Thrown on error
*/
@Override
void generateExpression(ExpressionClassBuilder expressionBuilder, MethodBuilder mbex) throws StandardException {
CompilerContext cc = getCompilerContext();
String resultSetString;
if (SanityManager.DEBUG) {
SanityManager.ASSERT(expressionBuilder instanceof ActivationClassBuilder, "Expecting an ActivationClassBuilder");
}
ActivationClassBuilder acb = (ActivationClassBuilder) expressionBuilder;
/* Generate the appropriate (Any or Once) ResultSet */
if (subqueryType == EXPRESSION_SUBQUERY) {
resultSetString = "getOnceResultSet";
} else {
resultSetString = "getAnyResultSet";
}
// Get cost estimate for underlying subquery
CostEstimate costEstimate = resultSet.getFinalCostEstimate();
/* Generate a new method. It's only used within the other
* exprFuns, so it could be private. but since we don't
* generate the right bytecodes to invoke private methods,
* we just make it protected. This generated class won't
* have any subclasses, certainly! (nat 12/97)
*/
String subqueryTypeString = getTypeCompiler().interfaceName();
MethodBuilder mb = acb.newGeneratedFun(subqueryTypeString, Modifier.PROTECTED);
/* Declare the field to hold the suquery's ResultSet tree */
LocalField rsFieldLF = acb.newFieldDeclaration(Modifier.PRIVATE, ClassName.NoPutResultSet);
ResultSetNode subNode = null;
if (!isMaterializable()) {
MethodBuilder executeMB = acb.getExecuteMethod();
if (pushedNewPredicate && (!hasCorrelatedCRs())) {
/* We try to materialize the subquery if it can fit in the memory. We
* evaluate the subquery first. If the result set fits in the memory,
* we replace the resultset with in-memory unions of row result sets.
* We do this trick by replacing the child result with a new node --
* MaterializeSubqueryNode, which essentially generates the suitable
* code to materialize the subquery if possible. This may have big
* performance improvement. See beetle 4373.
*/
if (SanityManager.DEBUG) {
SanityManager.ASSERT(resultSet instanceof ProjectRestrictNode, "resultSet expected to be a ProjectRestrictNode!");
}
subNode = ((ProjectRestrictNode) resultSet).getChildResult();
LocalField subRS = acb.newFieldDeclaration(Modifier.PRIVATE, ClassName.NoPutResultSet);
mb.getField(subRS);
mb.conditionalIfNull();
ResultSetNode materialSubNode = new MaterializeSubqueryNode(subRS, getContextManager());
// Propagate the resultSet's cost estimate to the new node.
materialSubNode.setCostEstimate(resultSet.getFinalCostEstimate());
((ProjectRestrictNode) resultSet).setChildResult(materialSubNode);
/* Evaluate subquery resultset here first. Next time when we come to
* this subquery it may be replaced by a bunch of unions of rows.
*/
subNode.generate(acb, mb);
mb.startElseCode();
mb.getField(subRS);
mb.completeConditional();
mb.setField(subRS);
executeMB.pushNull(ClassName.NoPutResultSet);
executeMB.setField(subRS);
}
executeMB.pushNull(ClassName.NoPutResultSet);
executeMB.setField(rsFieldLF);
// now we fill in the body of the conditional
mb.getField(rsFieldLF);
mb.conditionalIfNull();
}
acb.pushGetResultSetFactoryExpression(mb);
// start of args
int nargs;
/* Inside here is where subquery could already have been materialized. 4373
*/
resultSet.generate(acb, mb);
/* Get the next ResultSet #, so that we can number the subquery's
* empty row ResultColumnList and Once/Any ResultSet.
*/
int subqResultSetNumber = cc.getNextResultSetNumber();
/* We will be reusing the RCL from the subquery's ResultSet for the
* empty row function. We need to reset the resultSetNumber in the
* RCL, before we generate that function. Now that we've called
* generate() on the subquery's ResultSet, we can reset that
* resultSetNumber.
*/
resultSet.getResultColumns().setResultSetNumber(subqResultSetNumber);
/* Generate code for empty row */
resultSet.getResultColumns().generateNulls(acb, mb);
/*
* arg1: suqueryExpress - Expression for subquery's
* ResultSet
* arg2: Activation
* arg3: Method to generate Row with null(s) if subquery
* Result Set is empty
*/
if (subqueryType == EXPRESSION_SUBQUERY) {
int cardinalityCheck;
/* No need to do sort if subquery began life as a distinct expression subquery.
* (We simply check for a single unique value at execution time.)
* No need for cardinality check if we know that underlying
* ResultSet can contain at most 1 row.
* RESOLVE - Not necessary if we know we
* are getting a single row because of a unique index.
*/
if (distinctExpression) {
cardinalityCheck = OnceResultSet.UNIQUE_CARDINALITY_CHECK;
} else if (resultSet.returnsAtMostOneRow()) {
cardinalityCheck = OnceResultSet.NO_CARDINALITY_CHECK;
} else {
cardinalityCheck = OnceResultSet.DO_CARDINALITY_CHECK;
}
/* arg4: int - whether or not cardinality check is required
* DO_CARDINALITY_CHECK - required
* NO_CARDINALITY_CHECK - not required
* UNIQUE_CARDINALITY_CHECK - verify single
* unique value
*/
mb.push(cardinalityCheck);
nargs = 8;
} else {
nargs = 7;
}
mb.push(subqResultSetNumber);
mb.push(subqueryNumber);
mb.push(pointOfAttachment);
mb.push(costEstimate.rowCount());
mb.push(costEstimate.getEstimatedCost());
mb.callMethod(VMOpcode.INVOKEINTERFACE, (String) null, resultSetString, ClassName.NoPutResultSet, nargs);
if (!isMaterializable()) {
/* put it back
*/
if (pushedNewPredicate && (!hasCorrelatedCRs()))
((ProjectRestrictNode) resultSet).setChildResult(subNode);
// now we fill in the body of the conditional
mb.startElseCode();
mb.getField(rsFieldLF);
mb.completeConditional();
}
mb.setField(rsFieldLF);
/* rs.openCore() */
mb.getField(rsFieldLF);
mb.callMethod(VMOpcode.INVOKEINTERFACE, (String) null, "openCore", "void", 0);
/* r = rs.next() */
mb.getField(rsFieldLF);
mb.callMethod(VMOpcode.INVOKEINTERFACE, (String) null, "getNextRowCore", ClassName.ExecRow, 0);
// mb.putVariable(rVar);
// mb.endStatement();
/* col = (<Datatype interface>) r.getColumn(1) */
// mb.getVariable(rVar);
// both the Row interface and columnId are 1-based
mb.push(1);
mb.callMethod(VMOpcode.INVOKEINTERFACE, ClassName.Row, "getColumn", ClassName.DataValueDescriptor, 1);
mb.cast(subqueryTypeString);
/* Only generate the close() method for materialized
* subqueries. All others will be closed when the
* close() method is called on the top ResultSet.
*/
if (isMaterializable()) {
/* rs.close() */
mb.getField(rsFieldLF);
mb.callMethod(VMOpcode.INVOKEINTERFACE, ClassName.ResultSet, "close", "void", 0);
}
/* return col */
// mb.getVariable(colVar);
mb.methodReturn();
mb.complete();
/*
** If we have an expression subquery, then we
** can materialize it if it has no correlated
** column references and is invariant.
*/
if (isMaterializable()) {
LocalField lf = generateMaterialization(acb, mb, subqueryTypeString);
mbex.getField(lf);
} else {
/* Generate the call to the new method */
mbex.pushThis();
mbex.callMethod(VMOpcode.INVOKEVIRTUAL, (String) null, mb.getName(), subqueryTypeString, 0);
}
}
use of org.apache.derby.iapi.services.compiler.LocalField in project derby by apache.
the class UserTypeConstantNode method generateExpression.
/**
* For a UserTypeConstantNode, we have to store away the object somewhere
* and have a way to get it back at runtime.
* These objects are serializable. This gives us at least two options:
* 1) serialize it out into a byte array field, and serialize
* it back in when needed, from the field.
* 2) have an array of objects in the prepared statement and a #,
* to find the object directly. Because it is serializable, it
* will store with the rest of the executable just fine.
* Choice 2 gives better performance -- the ser/deser cost is paid
* on database access for the statement, not for each execution of it.
* However, it requires some infrastructure support from prepared
* statements. For now, we take choice 3, and make some assumptions
* about available methods on the user type. This choice has the
* shortcoming that it will not work for arbitrary user types.
* REVISIT and implement choice 2 when a general solution is needed.
* <p>
* A null is generated as a Null value cast to the type of
* the constant node.
*
* @param acb The ExpressionClassBuilder for the class being built
* @param mb The method the expression will go into
*
* @exception StandardException Thrown on error
*/
@Override
void generateExpression(ExpressionClassBuilder acb, MethodBuilder mb) throws StandardException {
TypeCompiler tc = getTypeCompiler();
String fieldType = tc.interfaceName();
/* Are we generating a SQL null value? */
if (val == null) {
acb.generateNull(mb, tc, getTypeServices().getCollationType());
} else // The code generated here is invoked when the generated class is constructed. However the prepared statement
// is not set into the activation class when it is constructed, but later. So we cannot use the getSavedObject
// method to retrieve the value.
// else if( value instanceof DataValueDescriptor)
// {
// acb.pushThisAsActivation( mb);
// mb.callMethod( VMOpcode.INVOKEINTERFACE,
// null,
// "getPreparedStatement",
// ClassName.ExecPreparedStatement,
// 0);
// mb.push( acb.addItem( value));
// mb.callMethod( VMOpcode.INVOKEINTERFACE,
// null,
// "getSavedObject",
// "java.lang.Object",
// 1);
// mb.cast( fieldType);
// }
{
/*
The generated java is the expression:
<java type name>.valueOf("<value.toString>")
super.generateValue will wrap this expression in
the appropriate column constructor.
If the type doesn't have a valueOf method, then we will
give an error. We have to assume that valueOf will
reconstruct the object from a String literal. If this is
a false assumption, some other object may be constructed,
or a runtime error may result due to valueOf failing.
*/
String typeName = getTypeId().getCorrespondingJavaTypeName();
mb.push(val.toString());
mb.callMethod(VMOpcode.INVOKESTATIC, typeName, "valueOf", typeName, 1);
LocalField field = acb.newFieldDeclaration(Modifier.PRIVATE, fieldType);
acb.generateDataValue(mb, tc, getTypeServices().getCollationType(), field);
}
}
Aggregations