use of org.apache.derby.iapi.sql.compile.TypeCompiler 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);
}
}
use of org.apache.derby.iapi.sql.compile.TypeCompiler in project derby by apache.
the class TernaryOperatorNode method castArgToString.
/* cast arg to a varchar */
protected ValueNode castArgToString(ValueNode vn) throws StandardException {
TypeCompiler vnTC = vn.getTypeCompiler();
if (!vn.getTypeId().isStringTypeId()) {
DataTypeDescriptor dtd = DataTypeDescriptor.getBuiltInDataTypeDescriptor(Types.VARCHAR, true, vnTC.getCastToCharWidth(vn.getTypeServices()));
ValueNode newNode = new CastNode(vn, dtd, getContextManager());
// DERBY-2910 - Match current schema collation for implicit cast as we do for
// explicit casts per SQL Spec 6.12 (10)
newNode.setCollationUsingCompilationSchema();
((CastNode) newNode).bindCastNodeOnly();
return newNode;
}
return vn;
}
use of org.apache.derby.iapi.sql.compile.TypeCompiler in project derby by apache.
the class MethodCallNode method resolveMethodCall.
protected void resolveMethodCall(String javaClassName, boolean staticMethod) throws StandardException {
// only allow direct method calls through routines and internal SQL.
if (routineInfo == null && !internalCall) {
// See if we are being executed in an internal context
if ((getCompilerContext().getReliability() & CompilerContext.INTERNAL_SQL_ILLEGAL) != 0) {
throw StandardException.newException(SQLState.LANG_SYNTAX_ERROR, javaClassName + (staticMethod ? "::" : ".") + methodName);
}
}
int count = signature.length;
ClassInspector classInspector = getClassFactory().getClassInspector();
String[] parmTypeNames;
String[] primParmTypeNames = null;
boolean[] isParam = getIsParam();
boolean hasDynamicResultSets = hasVarargs() ? false : (routineInfo != null) && (count != 0) && (count != methodParms.length);
/*
** Find the matching method that is public.
*/
int signatureOffset = methodName.indexOf('(');
// support Java signatures by checking if the method name contains a '('
if (signatureOffset != -1) {
parmTypeNames = parseValidateSignature(methodName, signatureOffset, hasDynamicResultSets);
methodName = methodName.substring(0, signatureOffset);
// If the signature is specified then Derby resolves to exactly
// that method. Setting this flag to false disables the method
// resolution from automatically optionally repeating the last
// parameter as needed.
hasDynamicResultSets = false;
} else {
parmTypeNames = getObjectSignature();
}
// the actual type of the trailing Java varargs arg is an array
if (hasVarargs()) {
parmTypeNames[count - 1] = parmTypeNames[count - 1] + "[]";
}
try {
method = classInspector.findPublicMethod(javaClassName, methodName, parmTypeNames, null, isParam, staticMethod, hasDynamicResultSets, hasVarargs());
// Also if the DDL specified a signature, then no alternate resolution
if (signatureOffset == -1 && routineInfo == null) {
/* If no match, then retry with combinations of object and
* primitive types.
*/
if (method == null) {
primParmTypeNames = getPrimitiveSignature(false);
method = classInspector.findPublicMethod(javaClassName, methodName, parmTypeNames, primParmTypeNames, isParam, staticMethod, hasDynamicResultSets, hasVarargs());
}
}
} catch (ClassNotFoundException e) {
/*
** If one of the classes couldn't be found, just act like the
** method couldn't be found. The error lists all the class names,
** which should give the user enough info to diagnose the problem.
*/
method = null;
}
/* Throw exception if no matching signature found */
if (method == null) {
throwNoMethodFound(javaClassName, parmTypeNames, primParmTypeNames);
}
String typeName = classInspector.getType(method);
actualMethodReturnType = typeName;
if (routineInfo == null) {
/* void methods are only okay for CALL Statements */
if (typeName.equals("void")) {
if (!forCallStatement)
throw StandardException.newException(SQLState.LANG_VOID_METHOD_CALL);
}
} else {
String promoteName = null;
TypeDescriptorImpl returnType = (TypeDescriptorImpl) routineInfo.getReturnType();
String requiredType;
if (returnType == null) {
// must have a void method for a procedure call.
requiredType = "void";
} else {
TypeId returnTypeId = TypeId.getBuiltInTypeId(returnType.getJDBCTypeId());
if (returnType.isRowMultiSet() && (routineInfo.getParameterStyle() == RoutineAliasInfo.PS_DERBY_JDBC_RESULT_SET)) {
requiredType = ResultSet.class.getName();
} else if (returnType.getTypeId().userType()) {
requiredType = ((UserDefinedTypeIdImpl) returnType.getTypeId()).getClassName();
} else {
requiredType = returnTypeId.getCorrespondingJavaTypeName();
if (!requiredType.equals(typeName)) {
switch(returnType.getJDBCTypeId()) {
case java.sql.Types.BOOLEAN:
case java.sql.Types.SMALLINT:
case java.sql.Types.INTEGER:
case java.sql.Types.BIGINT:
case java.sql.Types.REAL:
case java.sql.Types.DOUBLE:
TypeCompiler tc = getTypeCompiler(returnTypeId);
requiredType = tc.getCorrespondingPrimitiveTypeName();
if (!routineInfo.calledOnNullInput() && routineInfo.getParameterCount() != 0) {
promoteName = returnTypeId.getCorrespondingJavaTypeName();
}
break;
}
}
}
}
boolean foundCorrectType;
if (ResultSet.class.getName().equals(requiredType)) {
// allow subtypes of ResultSet too
try {
Class<?> actualType = classInspector.getClass(typeName);
foundCorrectType = ResultSet.class.isAssignableFrom(actualType);
} catch (ClassNotFoundException cnfe) {
foundCorrectType = false;
}
} else {
foundCorrectType = requiredType.equals(typeName);
}
if (!foundCorrectType) {
throwNoMethodFound(requiredType + " " + javaClassName, parmTypeNames, primParmTypeNames);
}
// type we need to promote to an object so we can return null.
if (promoteName != null)
typeName = promoteName;
// MethodCallNode DERBY-2972
if (routineInfo.getReturnType() != null)
setCollationType(routineInfo.getReturnType().getCollationType());
}
setJavaTypeName(typeName);
methodParameterTypes = classInspector.getParameterTypes(method);
String methodParameter = null;
for (int i = 0; i < methodParameterTypes.length; i++) {
methodParameter = methodParameterTypes[i];
if (routineInfo != null) {
if (i < routineInfo.getParameterCount()) {
int parameterMode = routineInfo.getParameterModes()[getRoutineArgIdx(i)];
switch(parameterMode) {
case (ParameterMetaData.parameterModeIn):
break;
case (ParameterMetaData.parameterModeInOut):
// we need to see if the type of the array is
// primitive, not the array itself.
methodParameter = stripOneArrayLevel(methodParameter);
break;
case (ParameterMetaData.parameterModeOut):
// value is not obtained *from* parameter.
continue;
}
}
}
//
if (hasVarargs() && (i >= getFirstVarargIdx())) {
methodParameter = stripOneArrayLevel(methodParameter);
}
if (ClassInspector.primitiveType(methodParameter)) {
// corresponding to the vararg
if (i < methodParms.length) {
methodParms[i].castToPrimitive(true);
}
}
}
// casting may be needed on the trailing varargs
if (hasVarargs()) {
int firstVarargIdx = getFirstVarargIdx();
int trailingVarargCount = methodParms.length - firstVarargIdx;
// the first vararg was handled in the preceding loop
for (int i = 1; i < trailingVarargCount; i++) {
if (ClassInspector.primitiveType(methodParameter)) {
methodParms[i + firstVarargIdx].castToPrimitive(true);
}
}
}
/* Set type info for any null parameters */
if (someParametersAreNull()) {
setNullParameterInfo(methodParameterTypes);
}
/* bug 4450 - if the callable statement is ? = call form, generate the metadata
infor for the return parameter. We don't really need that info in order to
execute the callable statement. But with jdbc3.0, this information should be
made available for return parameter through ParameterMetaData class.
Parser sets a flag in compilercontext if ? = call. If the flag is set,
we generate the metadata info for the return parameter and reset the flag
in the compilercontext for future call statements*/
DataTypeDescriptor dts = DataTypeDescriptor.getSQLDataTypeDescriptor(typeName);
if (getCompilerContext().getReturnParameterFlag()) {
getParameterTypes()[0] = dts;
}
}
use of org.apache.derby.iapi.sql.compile.TypeCompiler in project derby by apache.
the class MethodCallNode method getPrimitiveSignature.
String[] getPrimitiveSignature(boolean castToPrimitiveAsNecessary) throws StandardException {
int count = signature.length;
String[] primParmTypeNames = new String[count];
JSQLType jsqlTyp;
for (int i = 0; i < count; i++) {
jsqlTyp = signature[i];
if (jsqlTyp == null) {
primParmTypeNames[i] = "";
} else {
switch(jsqlTyp.getCategory()) {
case JSQLType.SQLTYPE:
if ((procedurePrimitiveArrayType != null) && (i < procedurePrimitiveArrayType.length) && (procedurePrimitiveArrayType[i] != null)) {
primParmTypeNames[i] = procedurePrimitiveArrayType[i];
} else {
TypeId ctid = mapToTypeID(jsqlTyp);
if ((ctid.isNumericTypeId() && !ctid.isDecimalTypeId()) || ctid.isBooleanTypeId()) {
TypeCompiler tc = getTypeCompiler(ctid);
primParmTypeNames[i] = tc.getCorrespondingPrimitiveTypeName();
if (castToPrimitiveAsNecessary) {
methodParms[i].castToPrimitive(true);
}
} else {
primParmTypeNames[i] = ctid.getCorrespondingJavaTypeName();
}
}
break;
case JSQLType.JAVA_CLASS:
primParmTypeNames[i] = jsqlTyp.getJavaClassName();
break;
case JSQLType.JAVA_PRIMITIVE:
primParmTypeNames[i] = JSQLType.getPrimitiveName(jsqlTyp.getPrimitiveKind());
if (castToPrimitiveAsNecessary) {
methodParms[i].castToPrimitive(true);
}
break;
default:
if (SanityManager.DEBUG) {
SanityManager.THROWASSERT("Unknown JSQLType: " + jsqlTyp);
}
}
// end switch
}
// end if
}
return primParmTypeNames;
}
use of org.apache.derby.iapi.sql.compile.TypeCompiler in project derby by apache.
the class JavaToSQLValueNode method generateExpression.
/**
* Do code generation for this conversion of a value from the Java to
* the SQL domain.
*
* @param acb The ExpressionClassBuilder for the class we're generating
* @param mb the method the expression will go into
*
* @exception StandardException Thrown on error
*/
@Override
void generateExpression(ExpressionClassBuilder acb, MethodBuilder mb) throws StandardException {
TypeId resultType;
String resultTypeName;
/*
** Tell the Java node that it's value is being returned to the
** SQL domain. This way, it knows whether the checking for a null
** receiver is to be done at the Java level or the SQL level.
*/
javaNode.returnValueToSQLDomain();
/* Generate the receiver, if any. */
boolean hasReceiver = javaNode.generateReceiver(acb, mb);
/*
** If the java expression has a receiver, we want to check whether
** it's null before evaluating the whole expression (to avoid
** a NullPointerException.
*/
if (hasReceiver) {
/*
** There is a receiver. Generate a null SQL value to return
** in case the receiver is null. First, create a field to hold
** the null SQL value.
*/
String nullValueClass = getTypeCompiler().interfaceName();
LocalField nullValueField = acb.newFieldDeclaration(Modifier.PRIVATE, nullValueClass);
/*
** There is a receiver. Generate the following to test
** for null:
**
** (receiverExpression == null) ?
*/
mb.conditionalIfNull();
mb.getField(nullValueField);
acb.generateNullWithExpress(mb, getTypeCompiler(), getTypeServices().getCollationType());
/*
** We have now generated the expression to test, and the
** "true" side of the ?: operator. Finish the "true" side
** so we can generate the "false" side.
*/
mb.startElseCode();
}
resultType = getTypeId();
TypeCompiler tc = getTypeCompiler();
resultTypeName = tc.interfaceName();
/* Allocate an object for re-use to hold the result of the conversion */
LocalField field = acb.newFieldDeclaration(Modifier.PRIVATE, resultTypeName);
/* Generate the expression for the Java value under us */
javaNode.generateExpression(acb, mb);
/* Generate the SQL value, which is always nullable */
acb.generateDataValue(mb, tc, getTypeServices().getCollationType(), field);
/*
** If there was a receiver, the return value will be the result
** of the ?: operator.
*/
if (hasReceiver) {
mb.completeConditional();
}
}
Aggregations