void JavaArgContainer::CreateOdbcArgObject()

in language-extensions/java/src/JavaArgContainer.cpp [792:1193]


void JavaArgContainer::CreateOdbcArgObject(
	JNIEnv  *env,
	jobject jObj,
	JavaArg *arg)
{
	// Auto cleanup any local references
	// 1 reference for the class
	// 2 references for the additional classes/temp objects required by other types (guid, string)
	//
	AutoJniLocalFrame jFrame(env, 2);

	switch (arg->GetType())
	{
	case SQL_C_SLONG:
	{
		jclass objectClass = env->FindClass("java/lang/Integer");
		ValidateOutputClass(env, arg->GetId(), jObj, objectClass, "java/lang/Integer");

		jmethodID getValueMethod = JniHelper::FindMethod(env,
														 objectClass,
														 "intValue",
														 "()I");

		jint val = env->CallIntMethod(jObj, getValueMethod);
		JniHelper::ThrowOnJavaException(env);

		arg->m_value = new int(static_cast<int>(val));
		arg->m_strLenOrInd = sizeof(int);

		break;
	}

	case SQL_C_BIT:
	{
		jclass objectClass = env->FindClass("java/lang/Boolean");
		ValidateOutputClass(env, arg->GetId(), jObj, objectClass, "java/lang/Boolean");

		jmethodID getValueMethod = JniHelper::FindMethod(env,
														 objectClass,
														 "booleanValue",
														 "()Z");

		jboolean val = env->CallBooleanMethod(jObj, getValueMethod);
		JniHelper::ThrowOnJavaException(env);

		arg->m_value = new bool(static_cast<bool>(val));
		arg->m_strLenOrInd = sizeof(bool);

		break;
	}

	case SQL_C_DOUBLE:
	{
		jclass objectClass = env->FindClass("java/lang/Double");
		ValidateOutputClass(env, arg->GetId(), jObj, objectClass, "java/lang/Double");

		jmethodID getValueMethod = JniHelper::FindMethod(env,
														 objectClass,
														 "doubleValue",
														 "()D");

		jdouble val = env->CallDoubleMethod(jObj, getValueMethod);
		JniHelper::ThrowOnJavaException(env);

		arg->m_value = new double(static_cast<double>(val));
		arg->m_strLenOrInd = sizeof(double);

		break;
	}

	case SQL_C_FLOAT:
	{
		jclass objectClass = env->FindClass("java/lang/Float");
		ValidateOutputClass(env, arg->GetId(), jObj, objectClass, "java/lang/Float");

		jmethodID getValueMethod = JniHelper::FindMethod(env,
														 objectClass,
														 "floatValue",
														 "()F");

		jfloat val = env->CallFloatMethod(jObj, getValueMethod);
		JniHelper::ThrowOnJavaException(env);

		arg->m_value = new float(static_cast<float>(val));
		arg->m_strLenOrInd = sizeof(float);

		break;
	}

	case SQL_C_SBIGINT:
	{
		jclass objectClass = env->FindClass("java/lang/Long");
		ValidateOutputClass(env, arg->GetId(), jObj, objectClass, "java/lang/Long");

		jmethodID getValueMethod = JniHelper::FindMethod(env,
														 objectClass,
														 "longValue",
														 "()J");

		jlong val = env->CallLongMethod(jObj, getValueMethod);
		JniHelper::ThrowOnJavaException(env);

		arg->m_value = new long long(static_cast<long long>(val));
		arg->m_strLenOrInd = sizeof(long long);

		break;
	}

	case SQL_C_UTINYINT:
	{
		jclass objectClass = env->FindClass("java/lang/Short");
		ValidateOutputClass(env, arg->GetId(), jObj, objectClass, "java/lang/Short");

		jmethodID getValueMethod = JniHelper::FindMethod(env,
														 objectClass,
														 "shortValue",
														 "()S");

		jshort val = env->CallShortMethod(jObj, getValueMethod);
		JniHelper::ThrowOnJavaException(env);

		if (0 <= val && val <= 255)
		{
			arg->m_value = new unsigned char(static_cast<unsigned char>(val));
			arg->m_strLenOrInd = sizeof(char);
		}
		else
		{
			throw runtime_error(
					"The value of output parameter #" +
					to_string(arg->GetId()) +
					" is out of range for tinyint data type");
		}

		break;
	}

	case SQL_C_SSHORT:
	{
		jclass objectClass = env->FindClass("java/lang/Short");
		ValidateOutputClass(env, arg->GetId(), jObj, objectClass, "java/lang/Short");

		jmethodID getValueMethod = JniHelper::FindMethod(env,
														 objectClass,
														 "shortValue",
														 "()S");

		jshort val = env->CallShortMethod(jObj, getValueMethod);
		JniHelper::ThrowOnJavaException(env);

		arg->m_value = new short(static_cast<short>(val));
		arg->m_strLenOrInd = sizeof(short);

		break;
	}

	case SQL_C_GUID:
	{
		jclass stringClass = env->FindClass("java/lang/String");
		ValidateOutputClass(env, arg->GetId(), jObj, stringClass, "java/lang/String");

		jclass uuidClass = env->FindClass("java/util/UUID");
		jmethodID fromStringMethod = env->GetStaticMethodID(uuidClass,
															"fromString",
															"(Ljava/lang/String;)Ljava/util/UUID;");

		jmethodID lsbMethod = JniHelper::FindMethod(env,
													uuidClass,
													"getLeastSignificantBits",
													"()J");

		jmethodID msbMethod = JniHelper::FindMethod(env,
													uuidClass,
													"getMostSignificantBits",
													"()J");

		arg->m_value = JniTypeHelper::JavaStringToGuidStruct(
			env,
			reinterpret_cast<jstring>(jObj),
			uuidClass,
			fromStringMethod,
			lsbMethod,
			msbMethod);
		arg->m_strLenOrInd = sizeof(SQLGUID);

		break;
	}

	case SQL_C_BINARY:
	{
		jclass objectClass = env->FindClass("[B");
		ValidateOutputClass(env, arg->GetId(), jObj, objectClass, "[B");

		// Get the size of the parameter
		//
		jbyteArray byteArray = reinterpret_cast<jbyteArray>(jObj);
		jsize jNumOfBytes = env->GetArrayLength(byteArray);

		// Allocate space for the parameter
		//
		std::unique_ptr<jbyte[]> tempArr(new jbyte[jNumOfBytes]);

		// Copy the value to the output buffer
		//
		jbyte *byteData = static_cast<jbyte*>(env->GetPrimitiveArrayCritical(byteArray, nullptr));
		if (byteData)
		{
			memcpy(tempArr.get(),
				   byteData,
				   jNumOfBytes);

			env->ReleasePrimitiveArrayCritical(byteArray, byteData, 0);
		}
		else
		{
			JniHelper::ThrowOnJavaException(env);
		}

		arg->m_value = tempArr.release();
		arg->m_strLenOrInd = jNumOfBytes;

		break;
	}

	case SQL_C_CHAR:
	{
		jclass objectClass = env->FindClass("java/lang/String");
		ValidateOutputClass(env, arg->GetId(), jObj, objectClass, "java/lang/String");

		jstring jStr = reinterpret_cast<jstring>(jObj);

		const jstring jUtf8Str = env->NewStringUTF("UTF-8");
		JniHelper::ThrowOnJavaException(env);

		jmethodID jMethod = JniHelper::FindMethod(env,
												  objectClass,
												  "getBytes",
												  "(Ljava/lang/String;)[B");

		// Get the string in UTF-8 encoding
		//
		jbyteArray jUtf8BytesArr =
			static_cast<jbyteArray>(env->CallObjectMethod(jStr, jMethod, jUtf8Str));
		JniHelper::ThrowOnJavaException(env);

		// Get the size of the string
		//
		jsize jNumOfBytes = env->GetArrayLength(static_cast<jarray>(jUtf8BytesArr));

		// Allocate space for the string
		//
		std::unique_ptr<jbyte[]> tempArr(new jbyte[jNumOfBytes]);

		// Copy the string to the output buffer
		//
		jbyte *byteData =
			static_cast<jbyte*>(env->GetPrimitiveArrayCritical(jUtf8BytesArr, nullptr));
		if (byteData)
		{
			memcpy(tempArr.get(),
				   byteData,
				   jNumOfBytes);

			env->ReleasePrimitiveArrayCritical(jUtf8BytesArr, byteData, 0);
		}
		else
		{
			JniHelper::ThrowOnJavaException(env);
		}

		arg->m_value = tempArr.release();
		arg->m_strLenOrInd = jNumOfBytes;

		break;
	}

	case SQL_C_WCHAR:
	{
		jclass objectClass = env->FindClass("java/lang/String");
		ValidateOutputClass(env, arg->GetId(), jObj, objectClass, "java/lang/String");

		jstring jStr = reinterpret_cast<jstring>(jObj);

		// Get the size of the string
		//
		jsize strLenInChars = env->GetStringLength(jStr);

		// Allocate space for the string
		//
		std::unique_ptr<jchar[]> tempArr(new jchar[strLenInChars]);

		// Copy the string to the output buffer
		//
		env->GetStringRegion(jStr, 0, strLenInChars, tempArr.get());

		SQLINTEGER strLenInBytes = static_cast<SQLINTEGER>(strLenInChars * sizeof(jchar));

		arg->m_value = tempArr.release();
		arg->m_strLenOrInd = strLenInBytes;

		break;
	}

	case SQL_C_TYPE_DATE:
	{
		jclass objectClass = env->FindClass("java/sql/Date");
		ValidateOutputClass(env, arg->GetId(), jObj, objectClass, "java/sql/Date");

		jmethodID dateToStringMethod = env->GetMethodID(objectClass,
														"toString",
														"()Ljava/lang/String;");
		jmethodID dateValueOfMethod = env->GetStaticMethodID(objectClass,
															 "valueOf",
															 "(Ljava/lang/String;)Ljava/sql/Date;");

		std::unique_ptr<SQL_DATE_STRUCT> tempValue(new SQL_DATE_STRUCT());
		JniTypeHelper::JavaSqlDateToDateStruct(
			env,
			jObj,
			objectClass,
			dateToStringMethod,
			dateValueOfMethod,
			*tempValue.get());

		arg->m_value = tempValue.release();
		arg->m_strLenOrInd = sizeof(SQL_DATE_STRUCT);

		break;
	}

	case SQL_C_TYPE_TIMESTAMP:
	{
		jclass objectClass = env->FindClass("java/sql/Timestamp");
		ValidateOutputClass(env, arg->GetId(), jObj, objectClass, "java/sql/Timestamp");

		jmethodID tsToStringMethod = JniHelper::FindMethod(env,
														   objectClass,
														   "toString",
														   "()Ljava/lang/String;");
		jmethodID tsGetNanosMethod = JniHelper::FindMethod(env, objectClass, "getNanos", "()I");

		jmethodID tsValueOfMethod = env->GetStaticMethodID(objectClass,
														   "valueOf",
														   "(Ljava/lang/String;)Ljava/sql/Timestamp;");
		JniHelper::ThrowOnJavaException(env);

		std::unique_ptr<SQL_TIMESTAMP_STRUCT> tempValue(new SQL_TIMESTAMP_STRUCT());
		JniTypeHelper::JavaTimestampToTimestampStruct(
			env,
			jObj,
			objectClass,
			tsToStringMethod,
			tsGetNanosMethod,
			tsValueOfMethod,
			*tempValue.get());

		arg->m_value = tempValue.release();
		arg->m_strLenOrInd = sizeof(SQL_TIMESTAMP_STRUCT);

		break;
	}

	case SQL_C_NUMERIC:
	{
		jclass objectClass = env->FindClass("java/math/BigDecimal");
		ValidateOutputClass(env, arg->GetId(), jObj, objectClass, "java/math/BigDecimal");

		jmethodID bigDecUnscaledValue = JniHelper::FindMethod(env,
															  objectClass,
															  "unscaledValue",
															  "()Ljava/math/BigInteger;");
		jclass bigIntegerClass = env->FindClass("java/math/BigInteger");
		jmethodID bigIntToByteArr = JniHelper::FindMethod(env, bigIntegerClass, "toByteArray", "()[B");
		jmethodID bigIntSignum = JniHelper::FindMethod(env, bigIntegerClass, "signum", "()I");
		jmethodID bigIntAbs = JniHelper::FindMethod(env,
													bigIntegerClass,
													"abs",
													"()Ljava/math/BigInteger;");

		std::unique_ptr<SQL_NUMERIC_STRUCT> tempValue(new SQL_NUMERIC_STRUCT());
		JniTypeHelper::BigDecimalToNumericStruct(
			env,
			jObj,
			static_cast<SQLCHAR>(arg->GetSize()),
			arg->GetDecimalDigits(),
			bigDecUnscaledValue,
			bigIntToByteArr,
			bigIntSignum,
			bigIntAbs,
			"output parameter ID " + std::to_string(arg->GetId()),
			*tempValue.get());

		arg->m_value = tempValue.release();
		arg->m_strLenOrInd = sizeof(SQL_NUMERIC_STRUCT);

		break;
	}

	default:
		throw runtime_error("Unsupported output parameter type encountered");
	}
}