From 3cf32c84d8498cb5942ae020a46fca3b17d02337 Mon Sep 17 00:00:00 2001 From: MohamedSabthar Date: Fri, 11 Oct 2024 10:23:55 +0530 Subject: [PATCH 1/7] [Automated] Update native jar versions in toml files --- ballerina/Ballerina.toml | 8 ++++---- ballerina/CompilerPlugin.toml | 2 +- ballerina/Dependencies.toml | 11 ++++++----- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/ballerina/Ballerina.toml b/ballerina/Ballerina.toml index b03d1ee0..526b8187 100644 --- a/ballerina/Ballerina.toml +++ b/ballerina/Ballerina.toml @@ -1,7 +1,7 @@ [package] org = "ballerina" name = "sql" -version = "1.12.2" +version = "1.12.3" authors = ["Ballerina"] keywords = ["database", "client", "network", "SQL", "RDBMS"] repository = "https://github.com/ballerina-platform/module-ballerina-sql" @@ -15,11 +15,11 @@ graalvmCompatible = true [[platform.java17.dependency]] groupId = "io.ballerina.stdlib" artifactId = "sql-native" -version = "1.12.2" -path = "../native/build/libs/sql-native-1.12.2.jar" +version = "1.12.3" +path = "../native/build/libs/sql-native-1.12.3-SNAPSHOT.jar" [[platform.java17.dependency]] -path = "../test-utils/build/libs/sql-test-utils-1.12.2.jar" +path = "../test-utils/build/libs/sql-test-utils-1.12.3-SNAPSHOT.jar" scope = "testOnly" [[platform.java17.dependency]] diff --git a/ballerina/CompilerPlugin.toml b/ballerina/CompilerPlugin.toml index 16d30f4a..6c36c62b 100644 --- a/ballerina/CompilerPlugin.toml +++ b/ballerina/CompilerPlugin.toml @@ -3,4 +3,4 @@ id = "sql-compiler-plugin" class = "io.ballerina.stdlib.sql.compiler.SQLCompilerPlugin" [[dependency]] -path = "../compiler-plugin/build/libs/sql-compiler-plugin-1.12.2.jar" +path = "../compiler-plugin/build/libs/sql-compiler-plugin-1.12.3-SNAPSHOT.jar" diff --git a/ballerina/Dependencies.toml b/ballerina/Dependencies.toml index 5f8eed62..b040466c 100644 --- a/ballerina/Dependencies.toml +++ b/ballerina/Dependencies.toml @@ -23,7 +23,7 @@ dependencies = [ [[package]] org = "ballerina" name = "cache" -version = "3.7.0" +version = "3.7.1" scope = "testOnly" dependencies = [ {org = "ballerina", name = "constraint"}, @@ -69,7 +69,7 @@ modules = [ [[package]] org = "ballerina" name = "http" -version = "2.10.0" +version = "2.10.16" scope = "testOnly" dependencies = [ {org = "ballerina", name = "auth"}, @@ -98,7 +98,7 @@ dependencies = [ [[package]] org = "ballerina" name = "io" -version = "1.6.0" +version = "1.6.1" dependencies = [ {org = "ballerina", name = "jballerina.java"}, {org = "ballerina", name = "lang.value"} @@ -281,7 +281,7 @@ dependencies = [ [[package]] org = "ballerina" name = "observe" -version = "1.2.0" +version = "1.2.3" scope = "testOnly" dependencies = [ {org = "ballerina", name = "jballerina.java"} @@ -300,7 +300,7 @@ dependencies = [ [[package]] org = "ballerina" name = "sql" -version = "1.12.2" +version = "1.12.3" dependencies = [ {org = "ballerina", name = "file"}, {org = "ballerina", name = "io"}, @@ -344,6 +344,7 @@ modules = [ org = "ballerina" name = "time" version = "2.4.0" +scope = "testOnly" dependencies = [ {org = "ballerina", name = "jballerina.java"} ] From ed6254db814da78a9fa9f999704d6508f473e51c Mon Sep 17 00:00:00 2001 From: MohamedSabthar Date: Fri, 11 Oct 2024 17:33:34 +0530 Subject: [PATCH 2/7] Fix stored procedure call having output parameter failing with error --- ballerina/tests/call-procedures-test.bal | 161 ++++++++---- changelog.md | 5 + .../io/ballerina/stdlib/sql/Constants.java | 3 + .../stdlib/sql/nativeimpl/CallProcessor.java | 245 +++++++++--------- .../sql/nativeimpl/OutParameterProcessor.java | 20 +- 5 files changed, 265 insertions(+), 169 deletions(-) diff --git a/ballerina/tests/call-procedures-test.bal b/ballerina/tests/call-procedures-test.bal index bd51a717..223c3401 100644 --- a/ballerina/tests/call-procedures-test.bal +++ b/ballerina/tests/call-procedures-test.bal @@ -130,15 +130,16 @@ function testCallWithStringTypesOutParams() returns error? { ParameterizedCallQuery callProcedureQuery = `call SelectStringDataWithOutParams(${paraID}, ${paraVarchar}, ${paraCharmax}, ${paraChar}, ${paraCharactermax}, ${paraCharacter}, ${paraNvarcharmax})`; - ProcedureCallResult ret = check getProcedureCallResultFromMockClient(callProcedureQuery); - check ret.close(); - + MockClient dbClient = check new (url = proceduresDB, user = user, password = password); + ProcedureCallResult ret = check dbClient->call(callProcedureQuery); test:assertEquals(paraVarchar.get(string), "test0", "2nd out parameter of procedure did not match."); test:assertEquals(paraCharmax.get(string), "test1 ", "3rd out parameter of procedure did not match."); test:assertEquals(paraChar.get(string), "a", "4th out parameter of procedure did not match."); test:assertEquals(paraCharactermax.get(string), "test2 ", "5th out parameter of procedure did not match."); test:assertEquals(paraCharacter.get(string), "b", "6th out parameter of procedure did not match."); test:assertEquals(paraNvarcharmax.get(string), "test3", "7th out parameter of procedure did not match."); + check ret.close(); + check dbClient.close(); } @test:Config { @@ -162,9 +163,8 @@ function testCallWithNumericTypesOutParams() returns error? { ${paraBigInt}, ${paraSmallInt}, ${paraTinyInt}, ${paraBit}, ${paraDecimal}, ${paraNumeric}, ${paraFloat}, ${paraReal}, ${paraDouble})`; - ProcedureCallResult ret = check getProcedureCallResultFromMockClient(callProcedureQuery); - check ret.close(); - + MockClient dbClient = check new (url = proceduresDB, user = user, password = password); + ProcedureCallResult ret = check dbClient->call(callProcedureQuery); decimal paraDecimalVal = 1234.56; test:assertEquals(paraInt.get(int), 2147483647, "2nd out parameter of procedure did not match."); @@ -177,6 +177,8 @@ function testCallWithNumericTypesOutParams() returns error? { test:assertTrue((check paraFloat.get(float)) > 1234.0, "9th out parameter of procedure did not match."); test:assertTrue((check paraReal.get(float)) > 1234.0, "10th out parameter of procedure did not match."); test:assertEquals(paraDouble.get(float), 1234.56, "11th out parameter of procedure did not match."); + check ret.close(); + check dbClient.close(); } @test:Config { @@ -200,9 +202,8 @@ function testCallWithNumericTypesOutParamsForInvalidInValue() returns error? { ${paraBigInt}, ${paraSmallInt}, ${paraTinyInt}, ${paraBit}, ${paraDecimal}, ${paraNumeric}, ${paraFloat}, ${paraReal}, ${paraDouble})`; - ProcedureCallResult ret = check getProcedureCallResultFromMockClient(callProcedureQuery); - check ret.close(); - + MockClient dbClient = check new (url = proceduresDB, user = user, password = password); + ProcedureCallResult ret = check dbClient->call(callProcedureQuery); test:assertEquals(paraInt.get(int), 0, "2nd out parameter of procedure did not match."); test:assertEquals(paraBigInt.get(int), 0, "3rd out parameter of procedure did not match."); test:assertEquals(paraSmallInt.get(int), 0, "4th out parameter of procedure did not match."); @@ -213,6 +214,8 @@ function testCallWithNumericTypesOutParamsForInvalidInValue() returns error? { test:assertTrue((check paraFloat.get(float)) >= 0.0, "9th out parameter of procedure did not match."); test:assertTrue((check paraReal.get(float)) >= 0.0, "10th out parameter of procedure did not match."); test:assertEquals(paraDouble.get(float), 0.0, "11th out parameter of procedure did not match."); + check ret.close(); + check dbClient.close(); } @test:Config { @@ -231,15 +234,16 @@ function testCallWithStringTypesInoutParams() returns error? { ParameterizedCallQuery callProcedureQuery = `call SelectStringDataWithInoutParams(${paraID}, ${paraVarchar}, ${paraCharmax}, ${paraChar}, ${paraCharactermax}, ${paraCharacter}, ${paraNvarcharmax})`; - ProcedureCallResult ret = check getProcedureCallResultFromMockClient(callProcedureQuery); - check ret.close(); - + MockClient dbClient = check new (url = proceduresDB, user = user, password = password); + ProcedureCallResult ret = check dbClient->call(callProcedureQuery); test:assertEquals(paraVarchar.get(string), "test0", "2nd out parameter of procedure did not match."); test:assertEquals(paraCharmax.get(string), "test1 ", "3rd out parameter of procedure did not match."); test:assertEquals(paraChar.get(string), "a", "4th out parameter of procedure did not match."); test:assertEquals(paraCharactermax.get(string), "test2 ", "5th out parameter of procedure did not match."); test:assertEquals(paraCharacter.get(string), "b", "6th out parameter of procedure did not match."); test:assertEquals(paraNvarcharmax.get(string), "test3", "7th out parameter of procedure did not match."); + check ret.close(); + check dbClient.close(); } @test:Config { @@ -265,9 +269,8 @@ function testCallWithNumericTypesInoutParams() returns error? { ${paraSmallInt}, ${paraTinyInt}, ${paraBit}, ${paraDecimal}, ${paraNumeric}, ${paraFloat}, ${paraReal}, ${paraDouble})`; - ProcedureCallResult ret = check getProcedureCallResultFromMockClient(callProcedureQuery); - check ret.close(); - + MockClient dbClient = check new (url = proceduresDB, user = user, password = password); + ProcedureCallResult ret = check dbClient->call(callProcedureQuery); decimal paraDecimalVal = 1234.56; test:assertEquals(paraInt.get(int), 2147483647, "2nd out parameter of procedure did not match."); @@ -280,6 +283,8 @@ function testCallWithNumericTypesInoutParams() returns error? { test:assertTrue((check paraFloat.get(float)) > 1234.0, "9th out parameter of procedure did not match."); test:assertTrue((check paraReal.get(float)) > 1234.0, "10th out parameter of procedure did not match."); test:assertEquals(paraDouble.get(float), 1234.56, "11th out parameter of procedure did not match."); + check ret.close(); + check dbClient.close(); } @test:Config { @@ -350,9 +355,8 @@ function testCallWithAllTypesInoutParamsAsObjectValues() returns error? { ${paraTimestamp}, ${paraIntArray}, ${paraStrArray}, ${paraFloArray}, ${paraDecArray}, ${paraBooArray}, ${paraByteArray}, ${paraEmptyArray})`; - ProcedureCallResult ret = check getProcedureCallResultFromMockClient(callProcedureQuery); - check ret.close(); - + MockClient dbClient = check new (url = proceduresDB, user = user, password = password); + ProcedureCallResult ret = check dbClient->call(callProcedureQuery); string clobType = "very long text"; byte[] varBinaryType = "77736f322062616c6c6572696e612062696e61727920746573742e".toBytes(); time:Civil dateTimeRecord = {year: 2017, month: 1, day: 25, hour: 16, minute: 33, second: 55}; @@ -360,6 +364,8 @@ function testCallWithAllTypesInoutParamsAsObjectValues() returns error? { test:assertEquals(paraClob.get(string), clobType, "Clob out parameter of procedure did not match."); test:assertEquals(paraVarBinary.get(byte), varBinaryType, "VarBinary out parameter of procedure did not match."); test:assertEquals(paraDateTime.get(time:Civil), dateTimeRecord, "DateTime out parameter of procedure did not match."); + check ret.close(); + check dbClient.close(); } @test:Config { @@ -437,8 +443,8 @@ function testCallWithInoutParams() returns error? { ${paraTimestamp}, ${paraIntArray}, ${paraStrArray}, ${paraFloArray}, ${paraDecArray}, ${paraBooArray}, ${paraByteArray}, ${paraEmptyArray})`; - ProcedureCallResult ret = check getProcedureCallResultFromMockClient(callProcedureQuery); - check ret.close(); + MockClient dbClient = check new (url = proceduresDB, user = user, password = password); + ProcedureCallResult ret = check dbClient->call(callProcedureQuery); decimal[] decimalArray = [245, 5559, 8796]; byte[][] byteArray = [[119, 115, 111, 50, 32, 98, 97, 108, 108, 101, 114, 105, 110, 97, 32, 98, 108, 111, 98, 32, 116, 101, 115, 116, 46]]; test:assertEquals(paraIntArray.get(IntArray), [1, 2, 3], "Int array out parameter of procedure did not match."); @@ -452,6 +458,8 @@ function testCallWithInoutParams() returns error? { "of procedure did not match."); test:assertEquals(paraByteArray.get(ByteArray), byteArray, "Byte array out parameter of " + "procedure did not match."); + check ret.close(); + check dbClient.close(); } @test:Config { @@ -462,7 +470,8 @@ function testErroneousCallWithNumericTypesInoutParams() returns error? { IntegerValue paraID = new (1); ParameterizedCallQuery callProcedureQuery = `call SelectNumericDataWithInoutParams(${paraID})`; - ProcedureCallResult|error ret = getProcedureCallResultFromMockClient(callProcedureQuery); + MockClient dbClient = check new (url = proceduresDB, user = user, password = password); + ProcedureCallResult|error ret = dbClient->call(callProcedureQuery); test:assertTrue(ret is error); if ret is DatabaseError { @@ -490,13 +499,15 @@ function testCallWithDateTimeTypesWithOutParams() returns error? { ParameterizedCallQuery callProcedureQuery = `call SelectDateTimeDataWithOutParams(${paraID}, ${paraDate}, ${paraTime}, ${paraDateTime}, ${paraTimeWithTz}, ${paraTimestamp}, ${paraTimestampWithTz})`; - ProcedureCallResult ret = check getProcedureCallResultFromMockClient(callProcedureQuery); - check ret.close(); + MockClient dbClient = check new (url = proceduresDB, user = user, password = password); + ProcedureCallResult ret = check dbClient->call(callProcedureQuery); test:assertEquals(paraDate.get(string), "2017-05-23", "Date out parameter of procedure did not match."); test:assertEquals(paraTime.get(string), "14:15:23", "Time out parameter of procedure did not match."); test:assertEquals(paraTimeWithTz.get(string), "16:33:55+06:30", "Time out parameter of procedure did not match."); test:assertEquals(paraTimestamp.get(string), "2017-01-25 16:33:55.0", "Timestamp out parameter of procedure did not match."); test:assertEquals(paraTimestampWithTz.get(string), "2017-01-25T16:33:55-08:00", "Date Time out parameter of procedure did not match."); + check ret.close(); + check dbClient.close(); } @test:Config { @@ -515,9 +526,8 @@ function testCallWithDateTimeTypeRecordsWithOutParams() returns error? { ParameterizedCallQuery callProcedureQuery = `call SelectDateTimeDataWithOutParams(${paraID}, ${paraDate}, ${paraTime}, ${paraDateTime}, ${paraTimeWithTz}, ${paraTimestamp}, ${paraTimestampWithTz})`; - ProcedureCallResult ret = check getProcedureCallResultFromMockClient(callProcedureQuery); - check ret.close(); - + MockClient dbClient = check new (url = proceduresDB, user = user, password = password); + ProcedureCallResult ret = check dbClient->call(callProcedureQuery); time:Date dateRecord = {year: 2017, month: 5, day: 23}; time:TimeOfDay timeRecord = {hour: 14, minute: 15, second: 23}; time:Civil timestampRecord = {year: 2017, month: 1, day: 25, hour: 16, minute: 33, second: 55}; @@ -539,6 +549,8 @@ function testCallWithDateTimeTypeRecordsWithOutParams() returns error? { test:assertEquals(paraTimeWithTz.get(time:TimeOfDay), timeWithTzRecord, "Time with Timezone out parameter of procedure did not match."); test:assertEquals(paraTimestamp.get(time:Civil), timestampRecord, "Timestamp out parameter of procedure did not match."); test:assertEquals(paraTimestampWithTz.get(time:Civil), timestampWithTzRecord, "Timestamp with Timezone out parameter of procedure did not match."); + check ret.close(); + check dbClient.close(); } @test:Config { @@ -551,9 +563,8 @@ function testCallWithTimestampTZRetrievalWithOutParams() returns error? { ParameterizedCallQuery callProcedureQuery = `call SelectTimestampTZWithOutParams(${paraID}, ${paraTimestampWithTz})`; - ProcedureCallResult ret = check getProcedureCallResultFromMockClient(callProcedureQuery); - check ret.close(); - + MockClient dbClient = check new (url = proceduresDB, user = user, password = password); + ProcedureCallResult ret = check dbClient->call(callProcedureQuery); string timestampWithTzRecordString = "2017-01-25T16:33:55-08:00"; time:Civil timestampWithTzRecordCivil = { utcOffset: {hours: -8, minutes: 0}, @@ -570,6 +581,8 @@ function testCallWithTimestampTZRetrievalWithOutParams() returns error? { test:assertEquals(paraTimestampWithTz.get(string), timestampWithTzRecordString, "Timestamp with Timezone out parameter of procedure did not match."); test:assertEquals(paraTimestampWithTz.get(time:Civil), timestampWithTzRecordCivil, "Timestamp with Timezone out parameter of procedure did not match."); test:assertEquals(paraTimestampWithTz.get(time:Utc), timestampWithTzRecordUtc, "Timestamp with Timezone out parameter of procedure did not match."); + check ret.close(); + check dbClient.close(); } @test:Config { @@ -588,9 +601,8 @@ function testCallWithOtherDataTypesWithOutParams() returns error? { ParameterizedCallQuery callProcedureQuery = `call SelectOtherDataTypesWithOutParams(${paraID}, ${paraClob}, ${paraVarBinary}, ${paraIntArray}, ${paraStringArray}, ${paraBinary}, ${paraBoolean})`; - ProcedureCallResult ret = check getProcedureCallResultFromMockClient(callProcedureQuery); - check ret.close(); - + MockClient dbClient = check new (url = proceduresDB, user = user, password = password); + ProcedureCallResult ret = check dbClient->call(callProcedureQuery); string clobType = "very long text"; byte[] varBinaryType = "77736f322062616c6c6572696e612062696e61727920746573742e".toBytes(); int[] int_array = [1, 2, 3]; @@ -603,6 +615,8 @@ function testCallWithOtherDataTypesWithOutParams() returns error? { test:assertEquals(paraBoolean.get(boolean), true, "Boolean out parameter of procedure did not match."); test:assertEquals(paraIntArray.get(IntArray), int_array, "Int array out parameter of procedure did not match."); test:assertEquals(paraStringArray.get(StringArray), string_array, "String array out parameter of procedure did not match."); + check ret.close(); + check dbClient.close(); } distinct class RandomOutParameter { @@ -629,7 +643,8 @@ function testCallWithOtherDataTypesWithInvalidOutParams() returns error? { ParameterizedCallQuery callProcedureQuery = `call SelectOtherDataTypesWithOutParams(${paraID}, ${paraClob}, ${paraVarBinary} , ${paraIntArray}, ${paraStringArray}, ${paraBinary}, ${paraBoolean})`; - ProcedureCallResult|error ret = getProcedureCallResultFromMockClient(callProcedureQuery); + MockClient dbClient = check new (url = proceduresDB, user = user, password = password); + ProcedureCallResult|error ret = dbClient->call(callProcedureQuery); test:assertTrue(ret is error); } @@ -1059,15 +1074,13 @@ function testCallWithAllArrayTypesInoutParamsAsObjectValues() returns error? { END `; validateProcedureResult(check createSqlProcedure(createProcedure), 0, ()); - + MockClient dbClient = check new (url = proceduresDB, user = user, password = password); ParameterizedCallQuery callProcedureQuery = `call SelectArrayDataWithInoutParams(${rowId}, ${smallint_array}, ${int_array}, ${real_array}, ${numeric_array}, ${nvarchar_array}, ${long_array}, ${float_array}, ${double_array}, ${decimal_array}, ${boolean_array}, ${char_array}, ${varchar_array}, ${string_array}, ${date_array}, ${time_array}, ${timestamp_array}, ${datetime_array})`; - ProcedureCallResult ret = check getProcedureCallResultFromMockClient(callProcedureQuery); - check ret.close(); - + ProcedureCallResult ret = check dbClient->call(callProcedureQuery); int[] smallIntArray = [12, 232]; int[] intArray = [1, 2, 3]; float[] floatArray = [199.33, 2399.1]; @@ -1080,6 +1093,8 @@ function testCallWithAllArrayTypesInoutParamsAsObjectValues() returns error? { test:assertEquals(numeric_array.get(FloatArray), numericArray, "Numeric array out parameter of procedure did not match."); test:assertEquals(nvarchar_array.get(StringArray), nVarcharArray, "Nvarchar array out parameter of procedure did not match."); test:assertEquals(datetime_array.get(CivilArray), civilArray, "Nvarchar array out parameter of procedure did not match."); + check ret.close(); + check dbClient.close(); } @test:Config { @@ -1164,14 +1179,11 @@ function testCallWithAllArrayTypesOutParamsAsObjectValues() returns error? { ${char_array}, ${varchar_array}, ${string_array}, ${date_array}, ${time_array}, ${timestamp_array}, ${datetime_array}, ${bit_array}, ${time_tz_array}, ${timestamp_tz_array}, ${binary_array})`; - ProcedureCallResult ret = check getProcedureCallResultFromMockClient(callProcedureQuery); - check ret.close(); - MockClient dbClient = check new (url = proceduresDB, user = user, password = password); + ProcedureCallResult ret = check dbClient->call(callProcedureQuery); stream streamData = dbClient->query(`SELECT * FROM ProArrayTypes WHERE row_id = 1`); _ = check streamData.next(); check streamData.close(); - check dbClient.close(); int[] smallIntArray = [12, 232]; int[] intArray = [1, 2, 3]; @@ -1276,6 +1288,8 @@ function testCallWithAllArrayTypesOutParamsAsObjectValues() returns error? { test:assertEquals(binary_array.get(ByteArray), binaryArray, "Timestamp with timezone array out parameter of " + "procedure did not match."); test:assertFalse((binary_array.get(StringArray) is Error)); + check ret.close(); + check dbClient.close(); } @test:Config { @@ -1311,8 +1325,8 @@ function negativeOutParamsTest() returns error? { ${char_array}, ${varchar_array}, ${string_array}, ${date_array}, ${time_array}, ${timestamp_array}, ${datetime_array}, ${bit_array}, ${time_tz_array}, ${timestamp_tz_array}, ${binary_array})`; - ProcedureCallResult ret = check getProcedureCallResultFromMockClient(callProcedureQuery); - check ret.close(); + MockClient dbClient = check new (url = proceduresDB, user = user, password = password); + ProcedureCallResult ret = check dbClient->call(callProcedureQuery); byte[][]|Error result = smallint_array.get(ByteArray); if result is TypeMismatchError { test:assertEquals(result.message(), @@ -1472,7 +1486,8 @@ function negativeOutParamsTest() returns error? { } else { test:assertFail("Result is not mismatch"); } - + check ret.close(); + check dbClient.close(); } @test:Config { @@ -1508,8 +1523,9 @@ function unionTypeOutParamsTest() returns error? { ${char_array}, ${varchar_array}, ${string_array}, ${date_array}, ${time_array}, ${timestamp_array}, ${datetime_array}, ${bit_array}, ${time_tz_array}, ${timestamp_tz_array}, ${binary_array})`; - ProcedureCallResult ret = check getProcedureCallResultFromMockClient(callProcedureQuery); - check ret.close(); + + MockClient dbClient = check new (url = proceduresDB, user = user, password = password); + ProcedureCallResult ret = check dbClient->call(callProcedureQuery); byte[][]|string|Error result = smallint_array.get(); if result is ApplicationError { test:assertEquals(result.message(), "OutParameter 'get' function does not support union return type.", @@ -1517,13 +1533,8 @@ function unionTypeOutParamsTest() returns error? { } else { test:assertFail("Result is not ApplicationError"); } -} - -function getProcedureCallResultFromMockClient(ParameterizedCallQuery sqlQuery) returns ProcedureCallResult|error { - MockClient dbClient = check new (url = proceduresDB, user = user, password = password); - ProcedureCallResult result = check dbClient->call(sqlQuery); + check ret.close(); check dbClient.close(); - return result; } function createSqlProcedure(ParameterizedQuery sqlQuery) returns ExecutionResult|Error { @@ -1547,3 +1558,49 @@ isolated function validateProcedureResult(ExecutionResult result, int rowCount, } } } + +@test:Config { + groups: ["procedures"] +} +function testOutParameterReturingErrorWhenResultIsClosed() returns error? { + IntegerValue paraID = new (1); + VarcharOutParameter paraVarchar = new; + CharOutParameter paraCharmax = new; + CharOutParameter paraChar = new; + CharOutParameter paraCharactermax = new; + CharOutParameter paraCharacter = new; + NVarcharOutParameter paraNvarcharmax = new; + + ParameterizedCallQuery callProcedureQuery = `call SelectStringDataWithOutParams(${paraID}, ${paraVarchar}, + ${paraCharmax}, ${paraChar}, ${paraCharactermax}, ${paraCharacter}, ${paraNvarcharmax})`; + MockClient dbClient = check new (url = proceduresDB, user = user, password = password); + ProcedureCallResult ret = check dbClient->call(callProcedureQuery); + 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.")); + check dbClient.close(); +} + +@test:Config { + groups: ["procedures"] +} +function testInOutParameterReturingErrorWhenResultIsClosed() returns error? { + IntegerValue paraID = new (1); + InOutParameter paraVarchar = new ("test varchar"); + InOutParameter paraCharmax = new ("test char"); + InOutParameter paraChar = new ("T"); + InOutParameter paraCharactermax = new ("test c_max"); + InOutParameter paraCharacter = new ("C"); + InOutParameter paraNvarcharmax = new ("test_nchar"); + + ParameterizedCallQuery callProcedureQuery = `call SelectStringDataWithInoutParams(${paraID}, ${paraVarchar}, + ${paraCharmax}, ${paraChar}, ${paraCharactermax}, ${paraCharacter}, ${paraNvarcharmax})`; + MockClient dbClient = check new (url = proceduresDB, user = user, password = password); + ProcedureCallResult ret = check dbClient->call(callProcedureQuery); + 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.")); + check dbClient.close(); +} diff --git a/changelog.md b/changelog.md index 64f94726..d7bbdd58 100644 --- a/changelog.md +++ b/changelog.md @@ -6,6 +6,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Changed +- [Fix stored procedure call having output parameter failing with result set closed error](https://github.com/ballerina-platform/ballerina-library/issues/7255) + +## [1.12.0] - 2024-02-25 + ### Added - Support for Cursor based result set retrieval in procedure calls diff --git a/native/src/main/java/io/ballerina/stdlib/sql/Constants.java b/native/src/main/java/io/ballerina/stdlib/sql/Constants.java index 195e5047..355a5db0 100644 --- a/native/src/main/java/io/ballerina/stdlib/sql/Constants.java +++ b/native/src/main/java/io/ballerina/stdlib/sql/Constants.java @@ -74,6 +74,9 @@ private Constants() { public static final String READ_BYTE_CHANNEL_STRUCT = "ReadableByteChannel"; public static final String READ_CHAR_CHANNEL_STRUCT = "ReadableCharacterChannel"; + public static final String RESULT_PARAMETER_PROCESSOR = "ResultParameterProcessor"; + public static final String PARAMETER_INDEX_META_DATA = "parameterIndex"; + public static final String USERNAME = "user"; public static final String PASSWORD = "password"; diff --git a/native/src/main/java/io/ballerina/stdlib/sql/nativeimpl/CallProcessor.java b/native/src/main/java/io/ballerina/stdlib/sql/nativeimpl/CallProcessor.java index a539fc9b..7465c561 100644 --- a/native/src/main/java/io/ballerina/stdlib/sql/nativeimpl/CallProcessor.java +++ b/native/src/main/java/io/ballerina/stdlib/sql/nativeimpl/CallProcessor.java @@ -52,8 +52,10 @@ import static io.ballerina.stdlib.sql.Constants.CONNECTION_NATIVE_DATA_FIELD; import static io.ballerina.stdlib.sql.Constants.DATABASE_CLIENT; +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.QUERY_RESULT_FIELD; +import static io.ballerina.stdlib.sql.Constants.RESULT_PARAMETER_PROCESSOR; import static io.ballerina.stdlib.sql.Constants.RESULT_SET_COUNT_NATIVE_DATA_FIELD; import static io.ballerina.stdlib.sql.Constants.RESULT_SET_TOTAL_NATIVE_DATA_FIELD; import static io.ballerina.stdlib.sql.Constants.STATEMENT_NATIVE_DATA_FIELD; @@ -159,7 +161,7 @@ private static Object nativeCallExecutable(BObject client, BObject paramSQLStrin updateProcedureCallExecutionResult(statement, procedureCallResult); } - populateOutParameters(statement, paramSQLString, outputParamTypes, + populateOutParametersMetaData(statement, paramSQLString, outputParamTypes, resultParameterProcessor, procedureCallResult); procedureCallResult.addNativeData(STATEMENT_NATIVE_DATA_FIELD, statement); @@ -229,133 +231,144 @@ private static void setCallParameters(Connection connection, CallableStatement s } } - private static void populateOutParameters(CallableStatement statement, BObject paramSQLString, - HashMap outputParamTypes, - AbstractResultParameterProcessor resultParameterProcessor, - BObject procedureCallResult) + private static void populateOutParametersMetaData(CallableStatement statement, BObject paramSQLString, + HashMap outputParamTypes, + AbstractResultParameterProcessor resultParameterProcessor, + BObject procedureCallResult) throws SQLException, ApplicationError { if (outputParamTypes.size() == 0) { return; } BArray arrayValue = paramSQLString.getArrayValue(Constants.ParameterizedQueryFields.INSERTIONS); - for (Map.Entry entry : outputParamTypes.entrySet()) { int paramIndex = entry.getKey(); int sqlType = entry.getValue(); - BObject parameter = (BObject) arrayValue.get(paramIndex - 1); + parameter.addNativeData(PARAMETER_INDEX_META_DATA, paramIndex); parameter.addNativeData(Constants.ParameterObject.SQL_TYPE_NATIVE_DATA, sqlType); - Object result; - switch (sqlType) { - case Types.CHAR: - result = resultParameterProcessor.processChar(statement, paramIndex); - break; - case Types.VARCHAR: - result = resultParameterProcessor.processVarchar(statement, paramIndex); - break; - case Types.LONGVARCHAR: - result = resultParameterProcessor.processLongVarchar(statement, paramIndex); - break; - case Types.NCHAR: - result = resultParameterProcessor.processNChar(statement, paramIndex); - break; - case Types.NVARCHAR: - result = resultParameterProcessor.processNVarchar(statement, paramIndex); - break; - case Types.LONGNVARCHAR: - result = resultParameterProcessor.processLongNVarchar(statement, paramIndex); - break; - case Types.BINARY: - result = resultParameterProcessor.processBinary(statement, paramIndex); - break; - case Types.VARBINARY: - result = resultParameterProcessor.processVarBinary(statement, paramIndex); - break; - case Types.LONGVARBINARY: - result = resultParameterProcessor.processLongVarBinary(statement, paramIndex); - break; - case Types.BLOB: - result = resultParameterProcessor.processBlob(statement, paramIndex); - break; - case Types.CLOB: - result = resultParameterProcessor.processClob(statement, paramIndex); - break; - case Types.NCLOB: - result = resultParameterProcessor.processNClob(statement, paramIndex); - break; - case Types.DATE: - result = resultParameterProcessor.processDate(statement, paramIndex); - break; - case Types.TIME: - result = resultParameterProcessor.processTime(statement, paramIndex); - break; - case Types.TIME_WITH_TIMEZONE: - result = resultParameterProcessor.processTimeWithTimeZone(statement, paramIndex); - break; - case Types.TIMESTAMP: - result = resultParameterProcessor.processTimestamp(statement, paramIndex); - break; - case Types.TIMESTAMP_WITH_TIMEZONE: - result = resultParameterProcessor.processTimestampWithTimeZone(statement, paramIndex); - break; - case Types.ARRAY: - result = resultParameterProcessor.processArray(statement, paramIndex); - break; - case Types.ROWID: - result = resultParameterProcessor.processRowID(statement, paramIndex); - break; - case Types.TINYINT: - result = resultParameterProcessor.processTinyInt(statement, paramIndex); - break; - case Types.SMALLINT: - result = resultParameterProcessor.processSmallInt(statement, paramIndex); - break; - case Types.INTEGER: - result = resultParameterProcessor.processInteger(statement, paramIndex); - break; - case Types.BIGINT: - result = resultParameterProcessor.processBigInt(statement, paramIndex); - break; - case Types.REAL: - result = resultParameterProcessor.processReal(statement, paramIndex); - break; - case Types.FLOAT: - result = resultParameterProcessor.processFloat(statement, paramIndex); - break; - case Types.DOUBLE: - result = resultParameterProcessor.processDouble(statement, paramIndex); - break; - case Types.NUMERIC: - result = resultParameterProcessor.processNumeric(statement, paramIndex); - break; - case Types.DECIMAL: - result = resultParameterProcessor.processDecimal(statement, paramIndex); - break; - case Types.BIT: - result = resultParameterProcessor.processBit(statement, paramIndex); - break; - case Types.BOOLEAN: - result = resultParameterProcessor.processBoolean(statement, paramIndex); - break; - case Types.REF: - case Types.REF_CURSOR: - result = resultParameterProcessor.processRef(statement, paramIndex); - // This is to clean up the result set attached to the ref cursor out parameter - // when procedure call result is closed. - procedureCallResult.addNativeData(Constants.REF_CURSOR_VALUE_NATIVE_DATA, result); - break; - case Types.STRUCT: - result = resultParameterProcessor.processStruct(statement, paramIndex); - break; - case Types.SQLXML: - result = resultParameterProcessor.processXML(statement, paramIndex); - break; - default: - result = resultParameterProcessor.processCustomOutParameters(statement, paramIndex, sqlType); - } - parameter.addNativeData(Constants.ParameterObject.VALUE_NATIVE_DATA, result); + parameter.addNativeData(RESULT_PARAMETER_PROCESSOR, resultParameterProcessor); + parameter.addNativeData(STATEMENT_NATIVE_DATA_FIELD, statement); + parameter.addNativeData(PROCEDURE_CALL_RESULT, procedureCallResult); + } + } + + public static void 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); + BObject procedureCallResult = (BObject) parameter.getNativeData(PROCEDURE_CALL_RESULT); + AbstractResultParameterProcessor resultParameterProcessor = (AbstractResultParameterProcessor) parameter + .getNativeData(RESULT_PARAMETER_PROCESSOR); + Object result; + switch (sqlType) { + case Types.CHAR: + result = resultParameterProcessor.processChar(statement, paramIndex); + break; + case Types.VARCHAR: + result = resultParameterProcessor.processVarchar(statement, paramIndex); + break; + case Types.LONGVARCHAR: + result = resultParameterProcessor.processLongVarchar(statement, paramIndex); + break; + case Types.NCHAR: + result = resultParameterProcessor.processNChar(statement, paramIndex); + break; + case Types.NVARCHAR: + result = resultParameterProcessor.processNVarchar(statement, paramIndex); + break; + case Types.LONGNVARCHAR: + result = resultParameterProcessor.processLongNVarchar(statement, paramIndex); + break; + case Types.BINARY: + result = resultParameterProcessor.processBinary(statement, paramIndex); + break; + case Types.VARBINARY: + result = resultParameterProcessor.processVarBinary(statement, paramIndex); + break; + case Types.LONGVARBINARY: + result = resultParameterProcessor.processLongVarBinary(statement, paramIndex); + break; + case Types.BLOB: + result = resultParameterProcessor.processBlob(statement, paramIndex); + break; + case Types.CLOB: + result = resultParameterProcessor.processClob(statement, paramIndex); + break; + case Types.NCLOB: + result = resultParameterProcessor.processNClob(statement, paramIndex); + break; + case Types.DATE: + result = resultParameterProcessor.processDate(statement, paramIndex); + break; + case Types.TIME: + result = resultParameterProcessor.processTime(statement, paramIndex); + break; + case Types.TIME_WITH_TIMEZONE: + result = resultParameterProcessor.processTimeWithTimeZone(statement, paramIndex); + break; + case Types.TIMESTAMP: + result = resultParameterProcessor.processTimestamp(statement, paramIndex); + break; + case Types.TIMESTAMP_WITH_TIMEZONE: + result = resultParameterProcessor.processTimestampWithTimeZone(statement, paramIndex); + break; + case Types.ARRAY: + result = resultParameterProcessor.processArray(statement, paramIndex); + break; + case Types.ROWID: + result = resultParameterProcessor.processRowID(statement, paramIndex); + break; + case Types.TINYINT: + result = resultParameterProcessor.processTinyInt(statement, paramIndex); + break; + case Types.SMALLINT: + result = resultParameterProcessor.processSmallInt(statement, paramIndex); + break; + case Types.INTEGER: + result = resultParameterProcessor.processInteger(statement, paramIndex); + break; + case Types.BIGINT: + result = resultParameterProcessor.processBigInt(statement, paramIndex); + break; + case Types.REAL: + result = resultParameterProcessor.processReal(statement, paramIndex); + break; + case Types.FLOAT: + result = resultParameterProcessor.processFloat(statement, paramIndex); + break; + case Types.DOUBLE: + result = resultParameterProcessor.processDouble(statement, paramIndex); + break; + case Types.NUMERIC: + result = resultParameterProcessor.processNumeric(statement, paramIndex); + break; + case Types.DECIMAL: + result = resultParameterProcessor.processDecimal(statement, paramIndex); + break; + case Types.BIT: + result = resultParameterProcessor.processBit(statement, paramIndex); + break; + case Types.BOOLEAN: + result = resultParameterProcessor.processBoolean(statement, paramIndex); + break; + case Types.REF: + case Types.REF_CURSOR: + result = resultParameterProcessor.processRef(statement, paramIndex); + // This is to clean up the result set attached to the ref cursor out parameter + // when procedure call result is closed. + procedureCallResult.addNativeData(Constants.REF_CURSOR_VALUE_NATIVE_DATA, result); + break; + case Types.STRUCT: + result = resultParameterProcessor.processStruct(statement, paramIndex); + break; + case Types.SQLXML: + result = resultParameterProcessor.processXML(statement, paramIndex); + break; + default: + result = resultParameterProcessor.processCustomOutParameters(statement, paramIndex, sqlType); } + parameter.addNativeData(Constants.ParameterObject.VALUE_NATIVE_DATA, result); } private static int getOutParameterType(BObject typedValue, 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 6871a8a8..357e83d5 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 @@ -48,6 +48,7 @@ import java.time.OffsetDateTime; import java.time.OffsetTime; +import static io.ballerina.stdlib.sql.utils.Utils.getErrorStream; import static io.ballerina.stdlib.sql.utils.Utils.getString; /** @@ -61,14 +62,31 @@ private OutParameterProcessor() { } public static Object getOutParameterValue(BObject result, BTypedesc typeDesc) { + try { + CallProcessor.populateOutParameter(result); + } catch (Throwable 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 { + CallProcessor.populateOutParameter(result); + } catch (Throwable 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 { + CallProcessor.populateOutParameter(result); + } catch (Throwable e) { + return ErrorGenerator.getSQLError(e, "Failed to read INOUT parameter value."); + } return get(result, typeDesc, DefaultResultParameterProcessor.getInstance(), "InOutParameter"); } @@ -81,7 +99,7 @@ public static BStream get(BObject result, Object recordType, } public static Object get(BObject result, BTypedesc typeDesc, - AbstractResultParameterProcessor resultParameterProcessor, String parameterType) { + AbstractResultParameterProcessor resultParameterProcessor, String parameterType) { int sqlType = (int) result.getNativeData(Constants.ParameterObject.SQL_TYPE_NATIVE_DATA); Object value = result.getNativeData(Constants.ParameterObject.VALUE_NATIVE_DATA); Type ballerinaType = TypeUtils.getReferredType(typeDesc.getDescribingType()); From c3b1cdf8775ee8d2c80a2d53faaafd3fa7c564d5 Mon Sep 17 00:00:00 2001 From: MohamedSabthar Date: Fri, 11 Oct 2024 17:34:21 +0530 Subject: [PATCH 3/7] Bump minor version --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 6fb6ba2f..bbe66588 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ group=io.ballerina.stdlib -version=1.12.3-SNAPSHOT +version=1.13.0-SNAPSHOT puppycrawlCheckstyleVersion=10.12.1 hikkariLibVersion=3.3.1 From de398f3e1ed4f17cefbbd3e80feb9422f5029ac7 Mon Sep 17 00:00:00 2001 From: MohamedSabthar Date: Fri, 11 Oct 2024 17:34:38 +0530 Subject: [PATCH 4/7] [Automated] Update native jar versions in toml files --- ballerina/Ballerina.toml | 8 ++++---- ballerina/CompilerPlugin.toml | 2 +- ballerina/Dependencies.toml | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/ballerina/Ballerina.toml b/ballerina/Ballerina.toml index 526b8187..63dfe5f2 100644 --- a/ballerina/Ballerina.toml +++ b/ballerina/Ballerina.toml @@ -1,7 +1,7 @@ [package] org = "ballerina" name = "sql" -version = "1.12.3" +version = "1.13.0" authors = ["Ballerina"] keywords = ["database", "client", "network", "SQL", "RDBMS"] repository = "https://github.com/ballerina-platform/module-ballerina-sql" @@ -15,11 +15,11 @@ graalvmCompatible = true [[platform.java17.dependency]] groupId = "io.ballerina.stdlib" artifactId = "sql-native" -version = "1.12.3" -path = "../native/build/libs/sql-native-1.12.3-SNAPSHOT.jar" +version = "1.13.0" +path = "../native/build/libs/sql-native-1.13.0-SNAPSHOT.jar" [[platform.java17.dependency]] -path = "../test-utils/build/libs/sql-test-utils-1.12.3-SNAPSHOT.jar" +path = "../test-utils/build/libs/sql-test-utils-1.13.0-SNAPSHOT.jar" scope = "testOnly" [[platform.java17.dependency]] diff --git a/ballerina/CompilerPlugin.toml b/ballerina/CompilerPlugin.toml index 6c36c62b..8a12f262 100644 --- a/ballerina/CompilerPlugin.toml +++ b/ballerina/CompilerPlugin.toml @@ -3,4 +3,4 @@ id = "sql-compiler-plugin" class = "io.ballerina.stdlib.sql.compiler.SQLCompilerPlugin" [[dependency]] -path = "../compiler-plugin/build/libs/sql-compiler-plugin-1.12.3-SNAPSHOT.jar" +path = "../compiler-plugin/build/libs/sql-compiler-plugin-1.13.0-SNAPSHOT.jar" diff --git a/ballerina/Dependencies.toml b/ballerina/Dependencies.toml index b040466c..ce2c6d0b 100644 --- a/ballerina/Dependencies.toml +++ b/ballerina/Dependencies.toml @@ -300,7 +300,7 @@ dependencies = [ [[package]] org = "ballerina" name = "sql" -version = "1.12.3" +version = "1.13.0" dependencies = [ {org = "ballerina", name = "file"}, {org = "ballerina", name = "io"}, From 455d1bcd83ab742e496bb3acdd059cc44b9d8bc5 Mon Sep 17 00:00:00 2001 From: MohamedSabthar Date: Fri, 11 Oct 2024 17:44:28 +0530 Subject: [PATCH 5/7] Update spec --- docs/spec/spec.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/spec/spec.md b/docs/spec/spec.md index d68946f1..7d0e3e11 100644 --- a/docs/spec/spec.md +++ b/docs/spec/spec.md @@ -258,6 +258,8 @@ In addition to the above parameters, it has `CursorOutParameter` to retrieve the stream resultStream = cursor.get(); ``` +> **_Note:_** In the case of a stored procedure query that returns a result set along with the mentioned parameters, the `get()` method of these parameters should only be invoked after consuming the result set. Otherwise, consuming the result set fails with a 'Error when iterating the SQL result. The result set is closed.' error. + ## 3.3. Query concatenation `sql:ParameterizedQuery` can be concatenated using util methods such as `sql:queryConcat()` and From d204863c1f7b50f0cddaf4d71b9f043917bd3211 Mon Sep 17 00:00:00 2001 From: MohamedSabthar Date: Fri, 11 Oct 2024 17:49:31 +0530 Subject: [PATCH 6/7] Relpace throwable with exception --- .../stdlib/sql/nativeimpl/OutParameterProcessor.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) 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 357e83d5..a0ff03ba 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 @@ -64,7 +64,7 @@ private OutParameterProcessor() { public static Object getOutParameterValue(BObject result, BTypedesc typeDesc) { try { CallProcessor.populateOutParameter(result); - } catch (Throwable e) { + } catch (SQLException | ApplicationError e) { return ErrorGenerator.getSQLError(e, "Failed to read OUT parameter value."); } @@ -74,7 +74,7 @@ public static Object getOutParameterValue(BObject result, BTypedesc typeDesc) { public static BStream getOutCursorValue(BObject result, BTypedesc typeDesc) { try { CallProcessor.populateOutParameter(result); - } catch (Throwable e) { + } catch (SQLException | ApplicationError e) { return getErrorStream(typeDesc, ErrorGenerator.getSQLError(e, "Failed to read parameter value.")); } @@ -84,7 +84,7 @@ public static BStream getOutCursorValue(BObject result, BTypedesc typeDesc) { public static Object getInOutParameterValue(BObject result, BTypedesc typeDesc) { try { CallProcessor.populateOutParameter(result); - } catch (Throwable e) { + } catch (SQLException | ApplicationError e) { return ErrorGenerator.getSQLError(e, "Failed to read INOUT parameter value."); } return get(result, typeDesc, DefaultResultParameterProcessor.getInstance(), "InOutParameter"); From 1b6c29c801e042c27d11104fc8dfe0d50ce9242f Mon Sep 17 00:00:00 2001 From: MohamedSabthar Date: Sun, 13 Oct 2024 12:51:36 +0530 Subject: [PATCH 7/7] Refactor java code --- .../stdlib/sql/nativeimpl/CallProcessor.java | 118 ---------------- .../sql/nativeimpl/OutParameterProcessor.java | 131 +++++++++++++++++- 2 files changed, 128 insertions(+), 121 deletions(-) diff --git a/native/src/main/java/io/ballerina/stdlib/sql/nativeimpl/CallProcessor.java b/native/src/main/java/io/ballerina/stdlib/sql/nativeimpl/CallProcessor.java index 7465c561..507a1fc9 100644 --- a/native/src/main/java/io/ballerina/stdlib/sql/nativeimpl/CallProcessor.java +++ b/native/src/main/java/io/ballerina/stdlib/sql/nativeimpl/CallProcessor.java @@ -253,124 +253,6 @@ private static void populateOutParametersMetaData(CallableStatement statement, B } } - public static void 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); - BObject procedureCallResult = (BObject) parameter.getNativeData(PROCEDURE_CALL_RESULT); - AbstractResultParameterProcessor resultParameterProcessor = (AbstractResultParameterProcessor) parameter - .getNativeData(RESULT_PARAMETER_PROCESSOR); - Object result; - switch (sqlType) { - case Types.CHAR: - result = resultParameterProcessor.processChar(statement, paramIndex); - break; - case Types.VARCHAR: - result = resultParameterProcessor.processVarchar(statement, paramIndex); - break; - case Types.LONGVARCHAR: - result = resultParameterProcessor.processLongVarchar(statement, paramIndex); - break; - case Types.NCHAR: - result = resultParameterProcessor.processNChar(statement, paramIndex); - break; - case Types.NVARCHAR: - result = resultParameterProcessor.processNVarchar(statement, paramIndex); - break; - case Types.LONGNVARCHAR: - result = resultParameterProcessor.processLongNVarchar(statement, paramIndex); - break; - case Types.BINARY: - result = resultParameterProcessor.processBinary(statement, paramIndex); - break; - case Types.VARBINARY: - result = resultParameterProcessor.processVarBinary(statement, paramIndex); - break; - case Types.LONGVARBINARY: - result = resultParameterProcessor.processLongVarBinary(statement, paramIndex); - break; - case Types.BLOB: - result = resultParameterProcessor.processBlob(statement, paramIndex); - break; - case Types.CLOB: - result = resultParameterProcessor.processClob(statement, paramIndex); - break; - case Types.NCLOB: - result = resultParameterProcessor.processNClob(statement, paramIndex); - break; - case Types.DATE: - result = resultParameterProcessor.processDate(statement, paramIndex); - break; - case Types.TIME: - result = resultParameterProcessor.processTime(statement, paramIndex); - break; - case Types.TIME_WITH_TIMEZONE: - result = resultParameterProcessor.processTimeWithTimeZone(statement, paramIndex); - break; - case Types.TIMESTAMP: - result = resultParameterProcessor.processTimestamp(statement, paramIndex); - break; - case Types.TIMESTAMP_WITH_TIMEZONE: - result = resultParameterProcessor.processTimestampWithTimeZone(statement, paramIndex); - break; - case Types.ARRAY: - result = resultParameterProcessor.processArray(statement, paramIndex); - break; - case Types.ROWID: - result = resultParameterProcessor.processRowID(statement, paramIndex); - break; - case Types.TINYINT: - result = resultParameterProcessor.processTinyInt(statement, paramIndex); - break; - case Types.SMALLINT: - result = resultParameterProcessor.processSmallInt(statement, paramIndex); - break; - case Types.INTEGER: - result = resultParameterProcessor.processInteger(statement, paramIndex); - break; - case Types.BIGINT: - result = resultParameterProcessor.processBigInt(statement, paramIndex); - break; - case Types.REAL: - result = resultParameterProcessor.processReal(statement, paramIndex); - break; - case Types.FLOAT: - result = resultParameterProcessor.processFloat(statement, paramIndex); - break; - case Types.DOUBLE: - result = resultParameterProcessor.processDouble(statement, paramIndex); - break; - case Types.NUMERIC: - result = resultParameterProcessor.processNumeric(statement, paramIndex); - break; - case Types.DECIMAL: - result = resultParameterProcessor.processDecimal(statement, paramIndex); - break; - case Types.BIT: - result = resultParameterProcessor.processBit(statement, paramIndex); - break; - case Types.BOOLEAN: - result = resultParameterProcessor.processBoolean(statement, paramIndex); - break; - case Types.REF: - case Types.REF_CURSOR: - result = resultParameterProcessor.processRef(statement, paramIndex); - // This is to clean up the result set attached to the ref cursor out parameter - // when procedure call result is closed. - procedureCallResult.addNativeData(Constants.REF_CURSOR_VALUE_NATIVE_DATA, result); - break; - case Types.STRUCT: - result = resultParameterProcessor.processStruct(statement, paramIndex); - break; - case Types.SQLXML: - result = resultParameterProcessor.processXML(statement, paramIndex); - break; - default: - result = resultParameterProcessor.processCustomOutParameters(statement, paramIndex, sqlType); - } - parameter.addNativeData(Constants.ParameterObject.VALUE_NATIVE_DATA, result); - } - private static int getOutParameterType(BObject typedValue, AbstractStatementParameterProcessor statementParameterProcessor) throws ApplicationError, SQLException { 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 a0ff03ba..959ac358 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 @@ -34,6 +34,7 @@ import java.math.BigDecimal; import java.sql.Array; import java.sql.Blob; +import java.sql.CallableStatement; import java.sql.Clob; import java.sql.Date; import java.sql.NClob; @@ -48,6 +49,12 @@ import java.time.OffsetDateTime; import java.time.OffsetTime; +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; import static io.ballerina.stdlib.sql.utils.Utils.getErrorStream; import static io.ballerina.stdlib.sql.utils.Utils.getString; @@ -63,7 +70,7 @@ private OutParameterProcessor() { public static Object getOutParameterValue(BObject result, BTypedesc typeDesc) { try { - CallProcessor.populateOutParameter(result); + populateOutParameter(result); } catch (SQLException | ApplicationError e) { return ErrorGenerator.getSQLError(e, "Failed to read OUT parameter value."); } @@ -73,7 +80,7 @@ public static Object getOutParameterValue(BObject result, BTypedesc typeDesc) { public static BStream getOutCursorValue(BObject result, BTypedesc typeDesc) { try { - CallProcessor.populateOutParameter(result); + populateOutParameter(result); } catch (SQLException | ApplicationError e) { return getErrorStream(typeDesc, ErrorGenerator.getSQLError(e, "Failed to read parameter value.")); @@ -83,13 +90,131 @@ public static BStream getOutCursorValue(BObject result, BTypedesc typeDesc) { public static Object getInOutParameterValue(BObject result, BTypedesc typeDesc) { try { - CallProcessor.populateOutParameter(result); + 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 { + 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); + BObject procedureCallResult = (BObject) parameter.getNativeData(PROCEDURE_CALL_RESULT); + AbstractResultParameterProcessor resultParameterProcessor = (AbstractResultParameterProcessor) parameter + .getNativeData(RESULT_PARAMETER_PROCESSOR); + Object result; + switch (sqlType) { + case Types.CHAR: + result = resultParameterProcessor.processChar(statement, paramIndex); + break; + case Types.VARCHAR: + result = resultParameterProcessor.processVarchar(statement, paramIndex); + break; + case Types.LONGVARCHAR: + result = resultParameterProcessor.processLongVarchar(statement, paramIndex); + break; + case Types.NCHAR: + result = resultParameterProcessor.processNChar(statement, paramIndex); + break; + case Types.NVARCHAR: + result = resultParameterProcessor.processNVarchar(statement, paramIndex); + break; + case Types.LONGNVARCHAR: + result = resultParameterProcessor.processLongNVarchar(statement, paramIndex); + break; + case Types.BINARY: + result = resultParameterProcessor.processBinary(statement, paramIndex); + break; + case Types.VARBINARY: + result = resultParameterProcessor.processVarBinary(statement, paramIndex); + break; + case Types.LONGVARBINARY: + result = resultParameterProcessor.processLongVarBinary(statement, paramIndex); + break; + case Types.BLOB: + result = resultParameterProcessor.processBlob(statement, paramIndex); + break; + case Types.CLOB: + result = resultParameterProcessor.processClob(statement, paramIndex); + break; + case Types.NCLOB: + result = resultParameterProcessor.processNClob(statement, paramIndex); + break; + case Types.DATE: + result = resultParameterProcessor.processDate(statement, paramIndex); + break; + case Types.TIME: + result = resultParameterProcessor.processTime(statement, paramIndex); + break; + case Types.TIME_WITH_TIMEZONE: + result = resultParameterProcessor.processTimeWithTimeZone(statement, paramIndex); + break; + case Types.TIMESTAMP: + result = resultParameterProcessor.processTimestamp(statement, paramIndex); + break; + case Types.TIMESTAMP_WITH_TIMEZONE: + result = resultParameterProcessor.processTimestampWithTimeZone(statement, paramIndex); + break; + case Types.ARRAY: + result = resultParameterProcessor.processArray(statement, paramIndex); + break; + case Types.ROWID: + result = resultParameterProcessor.processRowID(statement, paramIndex); + break; + case Types.TINYINT: + result = resultParameterProcessor.processTinyInt(statement, paramIndex); + break; + case Types.SMALLINT: + result = resultParameterProcessor.processSmallInt(statement, paramIndex); + break; + case Types.INTEGER: + result = resultParameterProcessor.processInteger(statement, paramIndex); + break; + case Types.BIGINT: + result = resultParameterProcessor.processBigInt(statement, paramIndex); + break; + case Types.REAL: + result = resultParameterProcessor.processReal(statement, paramIndex); + break; + case Types.FLOAT: + result = resultParameterProcessor.processFloat(statement, paramIndex); + break; + case Types.DOUBLE: + result = resultParameterProcessor.processDouble(statement, paramIndex); + break; + case Types.NUMERIC: + result = resultParameterProcessor.processNumeric(statement, paramIndex); + break; + case Types.DECIMAL: + result = resultParameterProcessor.processDecimal(statement, paramIndex); + break; + case Types.BIT: + result = resultParameterProcessor.processBit(statement, paramIndex); + break; + case Types.BOOLEAN: + result = resultParameterProcessor.processBoolean(statement, paramIndex); + break; + case Types.REF: + case Types.REF_CURSOR: + result = resultParameterProcessor.processRef(statement, paramIndex); + // This is to clean up the result set attached to the ref cursor out parameter + // when procedure call result is closed. + procedureCallResult.addNativeData(REF_CURSOR_VALUE_NATIVE_DATA, result); + break; + case Types.STRUCT: + result = resultParameterProcessor.processStruct(statement, paramIndex); + break; + case Types.SQLXML: + result = resultParameterProcessor.processXML(statement, paramIndex); + break; + default: + result = resultParameterProcessor.processCustomOutParameters(statement, paramIndex, sqlType); + } + parameter.addNativeData(ParameterObject.VALUE_NATIVE_DATA, result); + } + public static BStream get(BObject result, Object recordType, AbstractResultParameterProcessor resultParameterProcessor) { Object value = result.getNativeData(Constants.ParameterObject.VALUE_NATIVE_DATA);