Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ public class SQLServerPreparedStatement extends SQLServerStatement implements IS
/** Processed SQL statement text, may not be same as what user initially passed. */
final String userSQL;

private boolean isExecCommand;

/** Parameter positions in processed SQL statement text. */
final int[] userSQLParamPositions;

Expand Down Expand Up @@ -253,6 +255,7 @@ private boolean resetPrepStmtHandle(boolean discardCurrentCacheItem) {
procedureName = parsedSQL.procedureName;
bReturnValueSyntax = parsedSQL.bReturnValueSyntax;
userSQL = parsedSQL.processedSQL;
isExecCommand = isExecCommand(sql);
userSQLParamPositions = parsedSQL.parameterPositions;
initParams(userSQLParamPositions.length);
useBulkCopyForBatchInsert = conn.getUseBulkCopyForBatchInsert();
Expand Down Expand Up @@ -1210,7 +1213,13 @@ else if (needsPrepare && !connection.getEnablePrepareOnFirstPreparedStatementCal
*/
boolean callRPCDirectly(Parameter[] params) throws SQLServerException {
int paramCount = SQLServerConnection.countParams(userSQL);
return (null != procedureName && paramCount != 0 && !isTVPType(params));

// In order to execute sprocs directly the following must be true:
// 1. There must be a sproc name
// 2. There must be parameters
// 3. Parameters must not be a TVP typ
// Note: isExecCommand check is a workaround to allow prior behaviour of doing EXEC calls
return (null != procedureName && paramCount != 0 && !isTVPType(params) && !isExecCommand);
}

/**
Expand All @@ -1230,6 +1239,11 @@ private boolean isTVPType(Parameter[] params) throws SQLServerException {
return false;
}

private boolean isExecCommand(String sql) {
String command = sql.split(" ")[0];
return command.equalsIgnoreCase("exec") || command.equalsIgnoreCase("execute");
}

/**
* Executes sp_prepare to prepare a parameterized statement and sets the prepared statement handle
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ public class CallableStatementTest extends AbstractTest {

/**
* Setup before test
*
*
* @throws SQLException
*/
@BeforeAll
Expand Down Expand Up @@ -201,7 +201,7 @@ public void testCallableStatementSpPrepare() throws SQLException {

/**
* Tests CallableStatement.getString() with uniqueidentifier parameter
*
*
* @throws SQLException
*/
@Test
Expand All @@ -226,7 +226,7 @@ public void getStringGUIDTest() throws SQLException {

/**
* test for setNull(index, varchar) to behave as setNull(index, nvarchar) when SendStringParametersAsUnicode is true
*
*
* @throws SQLException
*/
@Test
Expand Down Expand Up @@ -302,7 +302,7 @@ public void testGetObjectAsLocalDateTime() throws SQLException {

/**
* Tests getObject(n, java.time.OffsetDateTime.class) and getObject(n, java.time.OffsetTime.class).
*
*
* @throws SQLException
*/
@Test
Expand Down Expand Up @@ -332,7 +332,7 @@ public void testGetObjectAsOffsetDateTime() throws SQLException {

/**
* recognize parameter names with and without leading '@'
*
*
* @throws SQLException
*/
@Test
Expand Down Expand Up @@ -1067,9 +1067,80 @@ public void testRegisteringOutputByIndexandAcquiringOutputParamByName() throws S
}
}

@Test
public void testExecuteSystemStoredProcedureNamedParametersAndIndexedParameterNoResultset() throws SQLException {
String call = "EXEC sp_getapplock @Resource=?, @LockTimeout='0', @LockMode='Exclusive', @LockOwner='Session'";

try (CallableStatement cstmt = connection.prepareCall(call)) {
cstmt.setString(1, "Resource-" + UUID.randomUUID());
cstmt.execute();
}
}

@Test
public void testExecSystemStoredProcedureNamedParametersAndIndexedParameterResultSet() throws SQLException {
String call = "exec sp_sproc_columns_100 ?, @ODBCVer=3, @fUsePattern=0";

try (CallableStatement cstmt = connection.prepareCall(call)) {
cstmt.setString(1, "sp_getapplock");

try (ResultSet rs = cstmt.executeQuery()) {
while (rs.next()) {
assertTrue(TestResource.getResource("R_resultSetEmpty"), !rs.getString(4).isEmpty());
}
}
}
}

@Test
public void testExecSystemStoredProcedureNoIndexedParametersResultSet() throws SQLException {
String call = "execute sp_sproc_columns_100 sp_getapplock, @ODBCVer=3, @fUsePattern=0";

try (CallableStatement cstmt = connection.prepareCall(call);
ResultSet rs = cstmt.executeQuery()) {
while (rs.next()) {
assertTrue(TestResource.getResource("R_resultSetEmpty"), !rs.getString(4).isEmpty());
}
}
}

@Test
public void testExecDocumentedSystemStoredProceduresIndexedParameters() throws SQLException {
String serverName;
String testTableName = "testTable";
Integer integer = new Integer(1);

try (Statement stmt = connection.createStatement(); ResultSet rs = stmt.executeQuery("SELECT @@SERVERNAME")) {
rs.next();
serverName = rs.getString(1);
}

String[] sprocs = {"EXEC sp_column_privileges ?",
"exec sp_catalogs ?", "execute sp_column_privileges ?", "EXEC sp_column_privileges_ex ?",
"EXECUTE sp_columns ?", "execute sp_datatype_info ?",
"EXEC sp_sproc_columns ?", "EXECUTE sp_server_info ?", "exec sp_special_columns ?",
"execute sp_statistics ?", "EXEC sp_table_privileges ?", "exec sp_tables ?"};

Object[] params = {testTableName, serverName, testTableName, serverName,
testTableName, integer, "sp_column_privileges", integer, testTableName,
testTableName, testTableName, testTableName};

int paramIndex = 0;

for (String sproc : sprocs) {
try (CallableStatement cstmt = connection.prepareCall(sproc)) {
cstmt.setObject(1, params[paramIndex]);
cstmt.execute();
paramIndex++;
} catch (Exception e) {
fail("Failed executing '" + sproc + "' with indexed parameter '" + params[paramIndex]);
}
}
}

/**
* Cleanup after test
*
*
* @throws SQLException
*/
@AfterAll
Expand Down