Normalize function return parameter lookup in CallMetaDataContext - #37206
Open
junhyeong9812 wants to merge 1 commit into
Open
Normalize function return parameter lookup in CallMetaDataContext#37206junhyeong9812 wants to merge 1 commit into
junhyeong9812 wants to merge 1 commit into
Conversation
CallMetaDataContext.reconcileParameters keys the map of declared parameters by lowerCase(provider.parameterNameToUse(name)), but the branch that matches the return parameter reported by the database metadata did not apply the same rule. It looked up the function return name as declared (original case) and fell back to the first declared out parameter name with a plain toLowerCase, without the provider transformation that strips the '@' prefix on SQL Server and Sybase. The first lookup therefore always missed on Oracle, so the fallback silently used whichever out parameter was declared first. Declaring an additional out parameter before the return parameter of a function made that parameter double as the return slot: the declared return parameter was dropped from the call parameters, the wrong parameter was bound at position 1, and executeFunction returned the value of the other out parameter. On SQL Server, a procedure compiled with withReturnValue() and an '@'-prefixed out parameter declared before the return parameter failed with InvalidDataAccessApiUsageException because neither lookup could find the declared parameter. The return parameter branch now looks up the metadata-derived name first and normalizes both the function return name and the first out parameter fallback with the same rule as the declared parameter map. Tests cover both declaration orders for an Oracle function and for a SQL Server procedure with a return value. Signed-off-by: junhyeong9812 <pickjog@gmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Overview
CallMetaDataContext.reconcileParametersmatches the return parameter reported by the database metadata against the declared parameters with lookup keys that do not follow the map's own key rule. When a function has an additional out parameter declared before the return parameter, the return slot is silently bound to the wrong parameter andexecuteFunctionreturns the wrong value; on SQL Server the same declaration order withwithReturnValue()fails withInvalidDataAccessApiUsageException. This PR normalizes the lookups with the same rule used to build the map.Problem
The declared parameter map is keyed by
lowerCase(provider.parameterNameToUse(name)), so a declaredRESULTis stored underresultand a SQL Server@out_totalunderout_total. The return parameter branch, however, looked upgetFunctionReturnName()as declared (original case, so it never matched on Oracle) and then fell back togetOutParameterNames().get(0).toLowerCase(), i.e. the first declared out parameter without the provider transformation.Because the first lookup always missed, the fallback decided the result, and it only happens to be right when the return parameter is the first declared out parameter:
GET_TOTAL)SqlOutParameter("RESULT"),SqlOutParameter("out_status")[RESULT, AMOUNT, out_status]SqlOutParameter("out_status"),SqlOutParameter("RESULT")[out_status, AMOUNT, out_status],executeFunctionreturns theout_statusvalue[RESULT, AMOUNT, out_status]On SQL Server,
withProcedureName(...).withReturnValue()withSqlOutParameter("@out_total")declared beforeSqlOutParameter("RETURN_VALUE")threwUnable to locate declared parameter for function return value - add an SqlOutParameter with name 'return', since"@out_total".toLowerCase()does not match the stored keyout_total.The first-out-parameter fallback itself dates back to the 4.x behavior restored in #25707 and is kept as is; only the lookup keys change.
Fix
The return parameter branch now looks up the metadata-derived name (
paramNameToCheck) first, then the function return name, then the first declared out parameter, with all three keys normalized bylowerCase(provider.parameterNameToUse(...))exactly like the map keys. Parameter names themselves are not modified, so existing call parameter names and call strings are unchanged. Applications that declared an additional out parameter before the return parameter of a function now receive the actual return value under the declared return parameter name instead of the value of that other out parameter. As before, this lookup only decides which declared parameter represents the return slot; whether a return slot is bound at all is still governed bywithFunctionName()andwithReturnValue().SimpleJdbcCallTestsgains four tests: an Oracle function and a SQL Server procedure with return value, each with the additional out parameter declared before and after the return parameter. The two "before" cases failed prior to this change; the two "after" cases guard the previously working declaration order. The fullspring-jdbctest suite passes.