Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Revert Execute Stored Procedure directly feature #2488

Merged
merged 6 commits into from
Aug 21, 2024
Merged
Show file tree
Hide file tree
Changes from 4 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
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
xAzureSQLDW - - - - For tests not compatible with Azure Data Warehouse -
xAzureSQLMI - - - - For tests not compatible with Azure SQL Managed Instance
NTLM - - - - - - - For tests using NTLM Authentication mode (excluded by default)
kerberos - - - - - For tests using Kerberos authentication (excluded by default)
kerberos - - - - - For tests using Kerberos authentication (excluded by default)
tkyc marked this conversation as resolved.
Show resolved Hide resolved
reqExternalSetup - For tests requiring external setup (excluded by default)
clientCertAuth - - For tests requiring client certificate authentication
setup (excluded by default) - - - - - - - - - - - - - - - - - - - - - - -
Expand Down
50 changes: 13 additions & 37 deletions src/main/java/com/microsoft/sqlserver/jdbc/IOBuffer.java
Original file line number Diff line number Diff line change
Expand Up @@ -467,7 +467,6 @@ static final String getEncryptionLevel(int level) {
final static int COLINFO_STATUS_DIFFERENT_NAME = 0x20;

final static int MAX_FRACTIONAL_SECONDS_SCALE = 7;
final static int DEFAULT_FRACTIONAL_SECONDS_SCALE = 3;

final static Timestamp MAX_TIMESTAMP = Timestamp.valueOf("2079-06-06 23:59:59");
final static Timestamp MIN_TIMESTAMP = Timestamp.valueOf("1900-01-01 00:00:00");
Expand Down Expand Up @@ -4854,7 +4853,7 @@ void writeVMaxHeader(long headerLength, boolean isNull, SQLCollation collation)
* Utility for internal writeRPCString calls
*/
void writeRPCStringUnicode(String sValue) throws SQLServerException {
writeRPCStringUnicode(null, sValue, false, null, false);
writeRPCStringUnicode(null, sValue, false, null);
}

/**
Expand All @@ -4869,8 +4868,8 @@ void writeRPCStringUnicode(String sValue) throws SQLServerException {
* @param collation
* the collation of the data value
*/
void writeRPCStringUnicode(String sName, String sValue, boolean bOut, SQLCollation collation,
boolean isNonPLP) throws SQLServerException {
void writeRPCStringUnicode(String sName, String sValue, boolean bOut,
SQLCollation collation) throws SQLServerException {
boolean bValueNull = (sValue == null);
int nValueLen = bValueNull ? 0 : (2 * sValue.length());
// Textual RPC requires a collation. If none is provided, as is the case when
Expand All @@ -4882,9 +4881,10 @@ void writeRPCStringUnicode(String sName, String sValue, boolean bOut, SQLCollati
* Use PLP encoding if either OUT params were specified or if the user query exceeds
* DataTypes.SHORT_VARTYPE_MAX_BYTES
*/
if ((nValueLen > DataTypes.SHORT_VARTYPE_MAX_BYTES || bOut) && !isNonPLP) {
if (nValueLen > DataTypes.SHORT_VARTYPE_MAX_BYTES || bOut) {
writeRPCNameValType(sName, bOut, TDSType.NVARCHAR);

// Handle Yukon v*max type header here.
tkyc marked this conversation as resolved.
Show resolved Hide resolved
writeVMaxHeader(nValueLen, // Length
bValueNull, // Is null?
collation);
Expand Down Expand Up @@ -5482,6 +5482,7 @@ void writeTVPColumnMetaData(TVP value) throws SQLServerException {
// Use PLP encoding on Yukon and later with long values
if (!isShortValue) // PLP
{
// Handle Yukon v*max type header here.
writeShort((short) 0xFFFF);
con.getDatabaseCollation().writeCollation(this);
} else // non PLP
Expand All @@ -5499,6 +5500,7 @@ void writeTVPColumnMetaData(TVP value) throws SQLServerException {
isShortValue = pair.getValue().precision <= DataTypes.SHORT_VARTYPE_MAX_BYTES;
// Use PLP encoding on Yukon and later with long values
if (!isShortValue) // PLP
// Handle Yukon v*max type header here.
writeShort((short) 0xFFFF);
else // non PLP
writeShort((short) DataTypes.SHORT_VARTYPE_MAX_BYTES);
Expand Down Expand Up @@ -5633,8 +5635,8 @@ void writeCryptoMetaData() throws SQLServerException {
writeByte(cryptoMeta.normalizationRuleVersion);
}

void writeRPCByteArray(String sName, byte[] bValue, boolean bOut, JDBCType jdbcType, SQLCollation collation,
boolean isNonPLP) throws SQLServerException {
void writeRPCByteArray(String sName, byte[] bValue, boolean bOut, JDBCType jdbcType,
SQLCollation collation) throws SQLServerException {
boolean bValueNull = (bValue == null);
int nValueLen = bValueNull ? 0 : bValue.length;
boolean isShortValue = (nValueLen <= DataTypes.SHORT_VARTYPE_MAX_BYTES);
Expand Down Expand Up @@ -5680,7 +5682,8 @@ void writeRPCByteArray(String sName, byte[] bValue, boolean bOut, JDBCType jdbcT

writeRPCNameValType(sName, bOut, tdsType);

if (usePLP && !isNonPLP) {
if (usePLP) {
// Handle Yukon v*max type header here.
writeVMaxHeader(nValueLen, bValueNull, collation);

// Send the data.
Expand Down Expand Up @@ -6461,6 +6464,7 @@ void writeRPCInputStream(String sName, InputStream stream, long streamLength, bo

writeRPCNameValType(sName, bOut, jdbcType.isTextual() ? TDSType.BIGVARCHAR : TDSType.BIGVARBINARY);

// Handle Yukon v*max type header here.
writeVMaxHeader(streamLength, false, jdbcType.isTextual() ? collation : null);
}

Expand Down Expand Up @@ -6600,6 +6604,7 @@ void writeRPCReaderUnicode(String sName, Reader re, long reLength, boolean bOut,

writeRPCNameValType(sName, bOut, TDSType.NVARCHAR);

// Handle Yukon v*max type header here.
writeVMaxHeader(
(DataTypes.UNKNOWN_STREAM_LENGTH == reLength) ? DataTypes.UNKNOWN_STREAM_LENGTH : 2 * reLength, // Length
// (in
Expand Down Expand Up @@ -7059,35 +7064,6 @@ final short peekStatusFlag() {
return 0;
}

final int peekReturnValueStatus() throws SQLServerException {
// Ensure that we have a packet to read from.
if (!ensurePayload()) {
throwInvalidTDS();
}

// In order to parse the 'status' value, we need to skip over the following properties in the TDS packet
// payload: TDS token type (1 byte value), ordinal/length (2 byte value), parameter name length value (1 byte value) and
// the number of bytes that make the parameter name (need to be calculated).
//
// 'offset' starts at 4 because tdsTokenType + ordinal/length + parameter name length value is 4 bytes. So, we
// skip 4 bytes immediateley.
int offset = 4;
int paramNameLength = currentPacket.payload[payloadOffset + 3];

// Check if parameter name is set. If it's set, it should be > 0. In which case, we add the
// additional bytes to skip.
if (paramNameLength > 0) {
// Each character in unicode is 2 bytes
offset += 2 * paramNameLength;
}

if (payloadOffset + offset <= currentPacket.payloadLength) {
return currentPacket.payload[payloadOffset + offset] & 0xFF;
}

return -1;
}

final int readUnsignedByte() throws SQLServerException {
// Ensure that we have a packet to read from.
if (!ensurePayload())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -609,25 +609,6 @@ public interface ISQLServerDataSource extends javax.sql.CommonDataSource {
*/
boolean getUseDefaultGSSCredential();

/**
* Sets whether or not sp_sproc_columns will be used for parameter name lookup.
*
* @param useFlexibleCallableStatements
* When set to false, sp_sproc_columns is not used for parameter name lookup
* in callable statements. This eliminates a round trip to the server but imposes limitations
* on how parameters are set. When set to false, applications must either reference
* parameters by name or by index, not both. Parameters must also be set in the same
* order as the stored procedure definition.
*/
void setUseFlexibleCallableStatements(boolean useFlexibleCallableStatements);

/**
* Returns whether or not sp_sproc_columns is being used for parameter name lookup.
*
* @return useFlexibleCallableStatements
*/
boolean getUseFlexibleCallableStatements();

/**
* Sets the GSSCredential.
*
Expand Down
76 changes: 11 additions & 65 deletions src/main/java/com/microsoft/sqlserver/jdbc/Parameter.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,6 @@
// For unencrypted parameters cryptometa will be null. For encrypted parameters it will hold encryption metadata.
CryptoMetadata cryptoMeta = null;

boolean isNonPLP = false;

TypeInfo getTypeInfo() {
return typeInfo;
}
Expand All @@ -51,7 +49,6 @@
private boolean shouldHonorAEForParameter = false;
private boolean userProvidesPrecision = false;
private boolean userProvidesScale = false;
private boolean isReturnValue = false;

// The parameter type definition
private String typeDefinition = null;
Expand All @@ -74,49 +71,11 @@
return null != registeredOutDTV;
}

/**
* Returns true/false if the parameter is of return type
*
* @return isReturnValue
*/
boolean isReturnValue() {
return isReturnValue;
}

/**
* Sets the parameter to be of return type
*
* @param isReturnValue
*/
void setReturnValue(boolean isReturnValue) {
this.isReturnValue = isReturnValue;
}

/**
* Sets the name of the parameter
*
* @param name
*/
void setName(String name) {
this.name = name;
}

/**
* Retrieve the name of the parameter
*
* @return
*/
String getName() {
return this.name;
}

/**
* Returns the `registeredOutDTV` instance of the parameter
*
* @return registeredOutDTV
*/
DTV getRegisteredOutDTV() {
return this.registeredOutDTV;
// Since a parameter can have only one type definition for both sending its value to the server (IN)
// and getting its value from the server (OUT), we use the JDBC type of the IN parameter value if there
// is one; otherwise we use the registered OUT param JDBC type.
JDBCType getJdbcType() {
return (null != inputDTV) ? inputDTV.getJdbcType() : JDBCType.UNKNOWN;
}

/**
Expand All @@ -128,13 +87,6 @@
return this.inputDTV;
}

// Since a parameter can have only one type definition for both sending its value to the server (IN)
// and getting its value from the server (OUT), we use the JDBC type of the IN parameter value if there
// is one; otherwise we use the registered OUT param JDBC type.
JDBCType getJdbcType() {
return (null != inputDTV) ? inputDTV.getJdbcType() : JDBCType.UNKNOWN;
}

/**
* Used when sendStringParametersAsUnicode=true to derive the appropriate National Character Set JDBC type
* corresponding to the specified JDBC type.
Expand Down Expand Up @@ -304,7 +256,7 @@
if (null == getterDTV)
getterDTV = new DTV();

getterDTV.setValue(null, this.getJdbcType(), returnStatus, JavaType.INTEGER, null, null, null, con,
getterDTV.setValue(null, JDBCType.INTEGER, returnStatus, JavaType.INTEGER, null, null, null, con,

Check warning on line 259 in src/main/java/com/microsoft/sqlserver/jdbc/Parameter.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/com/microsoft/sqlserver/jdbc/Parameter.java#L259

Added line #L259 was not covered by tests
getForceEncryption());
}

Expand Down Expand Up @@ -445,14 +397,10 @@

Object getValue(JDBCType jdbcType, InputStreamGetterArgs getterArgs, Calendar cal, TDSReader tdsReader,
SQLServerStatement statement) throws SQLServerException {
if (null == getterDTV) {
if (null == getterDTV)
getterDTV = new DTV();
}

if (null != tdsReader) {
deriveTypeInfo(tdsReader);
}

deriveTypeInfo(tdsReader);
tkyc marked this conversation as resolved.
Show resolved Hide resolved
// If the parameter is not encrypted or column encryption is turned off (either at connection or
// statement level), cryptoMeta would be null.
return getterDTV.getValue(jdbcType, outScale, getterArgs, cal, typeInfo, cryptoMeta, tdsReader, statement);
Expand Down Expand Up @@ -1272,17 +1220,15 @@
return typeDefinition;
}

void sendByRPC(TDSWriter tdsWriter, boolean callRPCDirectly,
SQLServerStatement statement) throws SQLServerException {
void sendByRPC(TDSWriter tdsWriter, SQLServerStatement statement) throws SQLServerException {
assert null != inputDTV : "Parameter was neither set nor registered";
SQLServerConnection conn = statement.connection;

try {
inputDTV.isNonPLP = isNonPLP;
inputDTV.sendCryptoMetaData(this.cryptoMeta, tdsWriter);
inputDTV.setJdbcTypeSetByUser(getJdbcTypeSetByUser(), getValueLength());
inputDTV.sendByRPC(callRPCDirectly ? name : null, null, conn.getDatabaseCollation(), valueLength,
isOutput() ? outScale : scale, isOutput(), tdsWriter, statement);
inputDTV.sendByRPC(name, null, conn.getDatabaseCollation(), valueLength, isOutput() ? outScale : scale,
isOutput(), tdsWriter, statement);
} finally {
// reset the cryptoMeta in IOBuffer
inputDTV.sendCryptoMetaData(null, tdsWriter);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2129,8 +2129,7 @@ private void writeNullToTdsWriter(TDSWriter tdsWriter, int srcJdbcType,

private void writeColumnToTdsWriter(TDSWriter tdsWriter, int bulkPrecision, int bulkScale, int bulkJdbcType,
boolean bulkNullable, // should it be destNullable instead?
int srcColOrdinal, int destColOrdinal, boolean isStreaming, Object colValue,
Calendar cal) throws SQLServerException {
int srcColOrdinal, int destColOrdinal, boolean isStreaming, Object colValue, Calendar cal) throws SQLServerException {
SSType destSSType = destColumnMetadata.get(destColOrdinal).ssType;

bulkPrecision = validateSourcePrecision(bulkPrecision, bulkJdbcType,
Expand Down Expand Up @@ -3047,8 +3046,8 @@ private Object readColumnFromResultSet(int srcColOrdinal, int srcJdbcType, boole
/**
* Reads the given column from the result set current row and writes the data to tdsWriter.
*/
private void writeColumn(TDSWriter tdsWriter, int srcColOrdinal, int destColOrdinal, Object colValue,
Calendar cal) throws SQLServerException {
private void writeColumn(TDSWriter tdsWriter, int srcColOrdinal, int destColOrdinal,
Object colValue, Calendar cal) throws SQLServerException {
String destName = destColumnMetadata.get(destColOrdinal).columnName;
int srcPrecision, srcScale, destPrecision, srcJdbcType;
SSType destSSType = null;
Expand Down Expand Up @@ -3700,8 +3699,8 @@ private boolean writeBatchData(TDSWriter tdsWriter, TDSCommand command,
// Loop for each destination column. The mappings is a many to one mapping
// where multiple source columns can be mapped to one destination column.
for (ColumnMapping columnMapping : columnMappings) {
writeColumn(tdsWriter, columnMapping.sourceColumnOrdinal, columnMapping.destinationColumnOrdinal,
null, null // cell
writeColumn(tdsWriter, columnMapping.sourceColumnOrdinal, columnMapping.destinationColumnOrdinal, null,
null // cell
// value is
// retrieved
// inside
Expand Down
Loading
Loading