diff --git a/ballerina/tests/call-procedures-test.bal b/ballerina/tests/call-procedures-test.bal index af52d359c..96bcd7594 100644 --- a/ballerina/tests/call-procedures-test.bal +++ b/ballerina/tests/call-procedures-test.bal @@ -1578,7 +1578,7 @@ function testOutParameterReturingErrorWhenResultIsClosed() returns error? { check ret.close(); string|Error err = paraVarchar.get(string); test:assertTrue(err is Error); - test:assertTrue((err).message().startsWith("Failed to read OUT parameter value.")); + test:assertTrue((err).message().startsWith("Failed to read parameter value.")); check dbClient.close(); } @@ -1601,6 +1601,6 @@ function testInOutParameterReturingErrorWhenResultIsClosed() returns error? { check ret.close(); string|Error err = paraVarchar.get(string); test:assertTrue(err is Error); - test:assertTrue((err).message().startsWith("Failed to read INOUT parameter value.")); + test:assertTrue((err).message().startsWith("Failed to read parameter value.")); check dbClient.close(); -} \ No newline at end of file +} diff --git a/changelog.md b/changelog.md index 6d23d3b06..0ceac54d7 100644 --- a/changelog.md +++ b/changelog.md @@ -11,6 +11,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed - [Fix strand hanging when strand count exceeds BALLERINA_SQL_MAX_POOL_SIZE](https://github.com/ballerina-platform/ballerina-library/issues/7244) - [Fix stored procedure call having output parameter failing with result set closed error](https://github.com/ballerina-platform/ballerina-library/issues/7255) +- [Fix stored procedure call having output parameter failing in PostgreSQL](https://github.com/ballerina-platform/ballerina-library/issues/7380) +- [Fix stored procedure call having output parameter failing in OracleDB](https://github.com/ballerina-platform/ballerina-library/issues/7445) ## [1.14.1] - 2024-08-29 diff --git a/native/src/main/java/io/ballerina/stdlib/sql/nativeimpl/OutParameterProcessor.java b/native/src/main/java/io/ballerina/stdlib/sql/nativeimpl/OutParameterProcessor.java index c4e1f8398..0222b1cc4 100644 --- a/native/src/main/java/io/ballerina/stdlib/sql/nativeimpl/OutParameterProcessor.java +++ b/native/src/main/java/io/ballerina/stdlib/sql/nativeimpl/OutParameterProcessor.java @@ -51,7 +51,6 @@ import static io.ballerina.stdlib.sql.Constants.PARAMETER_INDEX_META_DATA; import static io.ballerina.stdlib.sql.Constants.PROCEDURE_CALL_RESULT; -import static io.ballerina.stdlib.sql.Constants.ParameterObject; import static io.ballerina.stdlib.sql.Constants.REF_CURSOR_VALUE_NATIVE_DATA; import static io.ballerina.stdlib.sql.Constants.RESULT_PARAMETER_PROCESSOR; import static io.ballerina.stdlib.sql.Constants.STATEMENT_NATIVE_DATA_FIELD; @@ -69,35 +68,18 @@ private OutParameterProcessor() { } public static Object getOutParameterValue(BObject result, BTypedesc typeDesc) { - try { - populateOutParameter(result); - } catch (SQLException | ApplicationError e) { - return ErrorGenerator.getSQLError(e, "Failed to read OUT parameter value."); - } - return get(result, typeDesc, DefaultResultParameterProcessor.getInstance(), "OutParameter"); } public static BStream getOutCursorValue(BObject result, BTypedesc typeDesc) { - try { - populateOutParameter(result); - } catch (SQLException | ApplicationError e) { - return getErrorStream(typeDesc, - ErrorGenerator.getSQLError(e, "Failed to read parameter value.")); - } return get(result, typeDesc, DefaultResultParameterProcessor.getInstance()); } public static Object getInOutParameterValue(BObject result, BTypedesc typeDesc) { - try { - populateOutParameter(result); - } catch (SQLException | ApplicationError e) { - return ErrorGenerator.getSQLError(e, "Failed to read INOUT parameter value."); - } return get(result, typeDesc, DefaultResultParameterProcessor.getInstance(), "InOutParameter"); } - private static void populateOutParameter(BObject parameter) throws SQLException, ApplicationError { + private static Object populateOutParameter(BObject parameter) throws SQLException, ApplicationError { int paramIndex = (int) parameter.getNativeData(PARAMETER_INDEX_META_DATA); int sqlType = (int) parameter.getNativeData(Constants.ParameterObject.SQL_TYPE_NATIVE_DATA); CallableStatement statement = (CallableStatement) parameter.getNativeData(STATEMENT_NATIVE_DATA_FIELD); @@ -147,12 +129,18 @@ private static void populateOutParameter(BObject parameter) throws SQLException, case Types.SQLXML -> resultParameterProcessor.processXML(statement, paramIndex); default -> resultParameterProcessor.processCustomOutParameters(statement, paramIndex, sqlType); }; - parameter.addNativeData(ParameterObject.VALUE_NATIVE_DATA, result); + return result; } public static BStream get(BObject result, Object recordType, AbstractResultParameterProcessor resultParameterProcessor) { - Object value = result.getNativeData(Constants.ParameterObject.VALUE_NATIVE_DATA); + Object value; + try { + value = populateOutParameter(result); + } catch (SQLException | ApplicationError e) { + return getErrorStream(recordType, + ErrorGenerator.getSQLError(e, "Failed to read parameter value.")); + } RecordType streamConstraint = (RecordType) TypeUtils.getReferredType( ((BTypedesc) recordType).getDescribingType()); return resultParameterProcessor.convertCursorValue((ResultSet) value, streamConstraint); @@ -161,7 +149,12 @@ public static BStream get(BObject result, Object recordType, public static Object get(BObject result, BTypedesc typeDesc, AbstractResultParameterProcessor resultParameterProcessor, String parameterType) { int sqlType = (int) result.getNativeData(Constants.ParameterObject.SQL_TYPE_NATIVE_DATA); - Object value = result.getNativeData(Constants.ParameterObject.VALUE_NATIVE_DATA); + Object value; + try { + value = populateOutParameter(result); + } catch (SQLException | ApplicationError e) { + return ErrorGenerator.getSQLError(e, "Failed to read parameter value."); + } Type ballerinaType = TypeUtils.getReferredType(typeDesc.getDescribingType()); try { if (ballerinaType.getTag() == TypeTags.UNION_TAG) { diff --git a/native/src/test/java/io/ballerina/stdlib/sql/nativeimpl/OutParameterProcessorTest.java b/native/src/test/java/io/ballerina/stdlib/sql/nativeimpl/OutParameterProcessorTest.java deleted file mode 100644 index a70c1f13c..000000000 --- a/native/src/test/java/io/ballerina/stdlib/sql/nativeimpl/OutParameterProcessorTest.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright (c) 2021, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. - * - * WSO2 Inc. licenses this file to you under the Apache License, - * Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package io.ballerina.stdlib.sql.nativeimpl; - -import io.ballerina.runtime.api.types.PredefinedTypes; -import io.ballerina.runtime.api.values.BMap; -import io.ballerina.runtime.api.values.BObject; -import io.ballerina.runtime.api.values.BString; -import io.ballerina.stdlib.sql.Constants; -import io.ballerina.stdlib.sql.TestUtils; -import io.ballerina.stdlib.sql.parameterprocessor.DefaultResultParameterProcessor; -import org.testng.annotations.Test; - -import static io.ballerina.runtime.api.utils.StringUtils.fromString; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertNull; - -/** - * QueryProcessor class test. - * - * @since 0.6.0-beta.2 - */ -public class OutParameterProcessorTest { - - @Test - void getSmallIntNullTest() { - BObject object = TestUtils.getMockObject("SMALLINT"); - object.addNativeData(Constants.ParameterObject.SQL_TYPE_NATIVE_DATA, 5); - assertNull(OutParameterProcessor.get(object, TestUtils.getBTypedesc(PredefinedTypes.TYPE_INT), - DefaultResultParameterProcessor.getInstance(), "OutParameter")); - } - - @Test - void getIntegerNullTest() { - BObject object = TestUtils.getMockObject("INTEGER"); - object.addNativeData(Constants.ParameterObject.SQL_TYPE_NATIVE_DATA, 4); - assertNull(OutParameterProcessor.get(object, TestUtils.getBTypedesc(PredefinedTypes.TYPE_INT), - DefaultResultParameterProcessor.getInstance(), "OutParameter")); - } - - @Test - void getFloatNullTest() { - BObject object = TestUtils.getMockObject("FLOAT"); - object.addNativeData(Constants.ParameterObject.SQL_TYPE_NATIVE_DATA, 6); - assertNull(OutParameterProcessor.get(object, TestUtils.getBTypedesc(PredefinedTypes.TYPE_FLOAT), - DefaultResultParameterProcessor.getInstance(), "OutParameter")); - } - - @Test - void getDoubleNullTest() { - BObject object = TestUtils.getMockObject("DOUBLE"); - object.addNativeData(Constants.ParameterObject.SQL_TYPE_NATIVE_DATA, 8); - assertNull(OutParameterProcessor.get(object, TestUtils.getBTypedesc(PredefinedTypes.TYPE_FLOAT), - DefaultResultParameterProcessor.getInstance(), "OutParameter")); - } - - @Test - void getBooleanNullTest() { - BObject object = TestUtils.getMockObject("BOOLEAN"); - object.addNativeData(Constants.ParameterObject.SQL_TYPE_NATIVE_DATA, 16); - assertNull(OutParameterProcessor.get(object, TestUtils.getBTypedesc(PredefinedTypes.TYPE_BOOLEAN), - DefaultResultParameterProcessor.getInstance(), "OutParameter")); - } - - @Test - void getStructTest() { - BObject object = TestUtils.getMockObject("STRUCT"); - object.addNativeData(Constants.ParameterObject.SQL_TYPE_NATIVE_DATA, 2002); - object.addNativeData(Constants.ParameterObject.VALUE_NATIVE_DATA, TestUtils.getBooleanStruct()); - Object obj = OutParameterProcessor.get(object, - TestUtils.getBTypedesc(TestUtils.getBooleanStructRecord()), - DefaultResultParameterProcessor.getInstance(), "OutParameter"); - BMap map = (BMap) obj; - assertEquals(map.get(fromString("value1")), false); - } - - @Test - void getRefCursorTest() { - BObject object = TestUtils.getMockObject("REF_CURSOR"); - object.addNativeData(Constants.ParameterObject.SQL_TYPE_NATIVE_DATA, 2012); - object.addNativeData(Constants.ParameterObject.VALUE_NATIVE_DATA, null); - - assertNull(OutParameterProcessor.get(object, TestUtils.getBTypedesc(TestUtils.getStringStructRecord()), - DefaultResultParameterProcessor.getInstance())); - } -} diff --git a/native/src/test/resources/testng.xml b/native/src/test/resources/testng.xml index 4694dc00d..c7fd37d8f 100644 --- a/native/src/test/resources/testng.xml +++ b/native/src/test/resources/testng.xml @@ -25,7 +25,6 @@ -