Skip to content

Commit 2ca13e8

Browse files
author
Divang Sharma
committed
Merged #2499 to test useFlexibleCallableStatements witj json
2 parents 4858245 + 42dc48d commit 2ca13e8

21 files changed

+1982
-453
lines changed

src/main/java/com/microsoft/sqlserver/jdbc/IOBuffer.java

Lines changed: 37 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -475,6 +475,7 @@ static final String getEncryptionLevel(int level) {
475475
final static int COLINFO_STATUS_DIFFERENT_NAME = 0x20;
476476

477477
final static int MAX_FRACTIONAL_SECONDS_SCALE = 7;
478+
final static int DEFAULT_FRACTIONAL_SECONDS_SCALE = 3;
478479

479480
final static Timestamp MAX_TIMESTAMP = Timestamp.valueOf("2079-06-06 23:59:59");
480481
final static Timestamp MIN_TIMESTAMP = Timestamp.valueOf("1900-01-01 00:00:00");
@@ -4861,7 +4862,7 @@ void writeVMaxHeader(long headerLength, boolean isNull, SQLCollation collation)
48614862
* Utility for internal writeRPCString calls
48624863
*/
48634864
void writeRPCStringUnicode(String sValue) throws SQLServerException {
4864-
writeRPCStringUnicode(null, sValue, false, null);
4865+
writeRPCStringUnicode(null, sValue, false, null, false);
48654866
}
48664867

48674868
void writeRPCJSON(String sValue) throws SQLServerException {
@@ -4879,8 +4880,8 @@ void writeRPCJSON(String sValue) throws SQLServerException {
48794880
* @param collation
48804881
* the collation of the data value
48814882
*/
4882-
void writeRPCStringUnicode(String sName, String sValue, boolean bOut,
4883-
SQLCollation collation) throws SQLServerException {
4883+
void writeRPCStringUnicode(String sName, String sValue, boolean bOut, SQLCollation collation,
4884+
boolean isNonPLP) throws SQLServerException {
48844885
boolean bValueNull = (sValue == null);
48854886
int nValueLen = bValueNull ? 0 : (2 * sValue.length());
48864887
// Textual RPC requires a collation. If none is provided, as is the case when
@@ -4892,7 +4893,7 @@ void writeRPCStringUnicode(String sName, String sValue, boolean bOut,
48924893
* Use PLP encoding if either OUT params were specified or if the user query exceeds
48934894
* DataTypes.SHORT_VARTYPE_MAX_BYTES
48944895
*/
4895-
if (nValueLen > DataTypes.SHORT_VARTYPE_MAX_BYTES || bOut) {
4896+
if ((nValueLen > DataTypes.SHORT_VARTYPE_MAX_BYTES || bOut) && !isNonPLP) {
48964897
writeRPCNameValType(sName, bOut, TDSType.NVARCHAR);
48974898

48984899
writeVMaxHeader(nValueLen, // Length
@@ -5667,8 +5668,8 @@ void writeCryptoMetaData() throws SQLServerException {
56675668
writeByte(cryptoMeta.normalizationRuleVersion);
56685669
}
56695670

5670-
void writeRPCByteArray(String sName, byte[] bValue, boolean bOut, JDBCType jdbcType,
5671-
SQLCollation collation) throws SQLServerException {
5671+
void writeRPCByteArray(String sName, byte[] bValue, boolean bOut, JDBCType jdbcType, SQLCollation collation,
5672+
boolean isNonPLP) throws SQLServerException {
56725673
boolean bValueNull = (bValue == null);
56735674
int nValueLen = bValueNull ? 0 : bValue.length;
56745675
boolean isShortValue = (nValueLen <= DataTypes.SHORT_VARTYPE_MAX_BYTES);
@@ -5720,7 +5721,7 @@ void writeRPCByteArray(String sName, byte[] bValue, boolean bOut, JDBCType jdbcT
57205721

57215722
writeRPCNameValType(sName, bOut, tdsType);
57225723

5723-
if (usePLP) {
5724+
if (usePLP && !isNonPLP) {
57245725
writeVMaxHeader(nValueLen, bValueNull, collation);
57255726

57265727
// Send the data.
@@ -7124,6 +7125,35 @@ final short peekStatusFlag() {
71247125
return 0;
71257126
}
71267127

7128+
final int peekReturnValueStatus() throws SQLServerException {
7129+
// Ensure that we have a packet to read from.
7130+
if (!ensurePayload()) {
7131+
throwInvalidTDS();
7132+
}
7133+
7134+
// In order to parse the 'status' value, we need to skip over the following properties in the TDS packet
7135+
// payload: TDS token type (1 byte value), ordinal/length (2 byte value), parameter name length value (1 byte value) and
7136+
// the number of bytes that make the parameter name (need to be calculated).
7137+
//
7138+
// 'offset' starts at 4 because tdsTokenType + ordinal/length + parameter name length value is 4 bytes. So, we
7139+
// skip 4 bytes immediateley.
7140+
int offset = 4;
7141+
int paramNameLength = currentPacket.payload[payloadOffset + 3];
7142+
7143+
// Check if parameter name is set. If it's set, it should be > 0. In which case, we add the
7144+
// additional bytes to skip.
7145+
if (paramNameLength > 0) {
7146+
// Each character in unicode is 2 bytes
7147+
offset += 2 * paramNameLength;
7148+
}
7149+
7150+
if (payloadOffset + offset <= currentPacket.payloadLength) {
7151+
return currentPacket.payload[payloadOffset + offset] & 0xFF;
7152+
}
7153+
7154+
return -1;
7155+
}
7156+
71277157
final int readUnsignedByte() throws SQLServerException {
71287158
// Ensure that we have a packet to read from.
71297159
if (!ensurePayload())

src/main/java/com/microsoft/sqlserver/jdbc/ISQLServerDataSource.java

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -609,6 +609,25 @@ public interface ISQLServerDataSource extends javax.sql.CommonDataSource {
609609
*/
610610
boolean getUseDefaultGSSCredential();
611611

612+
/**
613+
* Sets whether or not sp_sproc_columns will be used for parameter name lookup.
614+
*
615+
* @param useFlexibleCallableStatements
616+
* When set to false, sp_sproc_columns is not used for parameter name lookup
617+
* in callable statements. This eliminates a round trip to the server but imposes limitations
618+
* on how parameters are set. When set to false, applications must either reference
619+
* parameters by name or by index, not both. Parameters must also be set in the same
620+
* order as the stored procedure definition.
621+
*/
622+
void setUseFlexibleCallableStatements(boolean useFlexibleCallableStatements);
623+
624+
/**
625+
* Returns whether or not sp_sproc_columns is being used for parameter name lookup.
626+
*
627+
* @return useFlexibleCallableStatements
628+
*/
629+
boolean getUseFlexibleCallableStatements();
630+
612631
/**
613632
* Sets the GSSCredential.
614633
*
@@ -1391,7 +1410,7 @@ public interface ISQLServerDataSource extends javax.sql.CommonDataSource {
13911410
* parameters by name or by index, not both. Parameters must also be set in the same
13921411
* order as the stored procedure definition.
13931412
*/
1394-
void setUseFlexibleCallableStatements(boolean useFlexibleCallableStatements);
1413+
// void setUseFlexibleCallableStatements(boolean useFlexibleCallableStatements);
13951414

13961415
/**
13971416
* useFlexibleCallableStatements is temporarily removed. This is meant as a no-op.
@@ -1400,5 +1419,5 @@ public interface ISQLServerDataSource extends javax.sql.CommonDataSource {
14001419
*
14011420
* @return useFlexibleCallableStatements
14021421
*/
1403-
boolean getUseFlexibleCallableStatements();
1422+
// boolean getUseFlexibleCallableStatements();
14041423
}

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

Lines changed: 65 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ final class Parameter {
3838
// For unencrypted parameters cryptometa will be null. For encrypted parameters it will hold encryption metadata.
3939
CryptoMetadata cryptoMeta = null;
4040

41+
boolean isNonPLP = false;
42+
4143
TypeInfo getTypeInfo() {
4244
return typeInfo;
4345
}
@@ -49,6 +51,7 @@ final CryptoMetadata getCryptoMetadata() {
4951
private boolean shouldHonorAEForParameter = false;
5052
private boolean userProvidesPrecision = false;
5153
private boolean userProvidesScale = false;
54+
private boolean isReturnValue = false;
5255

5356
// The parameter type definition
5457
private String typeDefinition = null;
@@ -71,11 +74,49 @@ boolean isOutput() {
7174
return null != registeredOutDTV;
7275
}
7376

74-
// Since a parameter can have only one type definition for both sending its value to the server (IN)
75-
// and getting its value from the server (OUT), we use the JDBC type of the IN parameter value if there
76-
// is one; otherwise we use the registered OUT param JDBC type.
77-
JDBCType getJdbcType() {
78-
return (null != inputDTV) ? inputDTV.getJdbcType() : JDBCType.UNKNOWN;
77+
/**
78+
* Returns true/false if the parameter is of return type
79+
*
80+
* @return isReturnValue
81+
*/
82+
boolean isReturnValue() {
83+
return isReturnValue;
84+
}
85+
86+
/**
87+
* Sets the parameter to be of return type
88+
*
89+
* @param isReturnValue
90+
*/
91+
void setReturnValue(boolean isReturnValue) {
92+
this.isReturnValue = isReturnValue;
93+
}
94+
95+
/**
96+
* Sets the name of the parameter
97+
*
98+
* @param name
99+
*/
100+
void setName(String name) {
101+
this.name = name;
102+
}
103+
104+
/**
105+
* Retrieve the name of the parameter
106+
*
107+
* @return
108+
*/
109+
String getName() {
110+
return this.name;
111+
}
112+
113+
/**
114+
* Returns the `registeredOutDTV` instance of the parameter
115+
*
116+
* @return registeredOutDTV
117+
*/
118+
DTV getRegisteredOutDTV() {
119+
return this.registeredOutDTV;
79120
}
80121

81122
/**
@@ -87,6 +128,13 @@ DTV getInputDTV() {
87128
return this.inputDTV;
88129
}
89130

131+
// Since a parameter can have only one type definition for both sending its value to the server (IN)
132+
// and getting its value from the server (OUT), we use the JDBC type of the IN parameter value if there
133+
// is one; otherwise we use the registered OUT param JDBC type.
134+
JDBCType getJdbcType() {
135+
return (null != inputDTV) ? inputDTV.getJdbcType() : JDBCType.UNKNOWN;
136+
}
137+
90138
/**
91139
* Used when sendStringParametersAsUnicode=true to derive the appropriate National Character Set JDBC type
92140
* corresponding to the specified JDBC type.
@@ -256,7 +304,7 @@ void setFromReturnStatus(int returnStatus, SQLServerConnection con) throws SQLSe
256304
if (null == getterDTV)
257305
getterDTV = new DTV();
258306

259-
getterDTV.setValue(null, JDBCType.INTEGER, returnStatus, JavaType.INTEGER, null, null, null, con,
307+
getterDTV.setValue(null, this.getJdbcType(), returnStatus, JavaType.INTEGER, null, null, null, con,
260308
getForceEncryption());
261309
}
262310

@@ -397,10 +445,14 @@ boolean isValueGotten() {
397445

398446
Object getValue(JDBCType jdbcType, InputStreamGetterArgs getterArgs, Calendar cal, TDSReader tdsReader,
399447
SQLServerStatement statement) throws SQLServerException {
400-
if (null == getterDTV)
448+
if (null == getterDTV) {
401449
getterDTV = new DTV();
450+
}
451+
452+
if (null != tdsReader) {
453+
deriveTypeInfo(tdsReader);
454+
}
402455

403-
deriveTypeInfo(tdsReader);
404456
// If the parameter is not encrypted or column encryption is turned off (either at connection or
405457
// statement level), cryptoMeta would be null.
406458
return getterDTV.getValue(jdbcType, outScale, getterArgs, cal, typeInfo, cryptoMeta, tdsReader, statement);
@@ -1225,15 +1277,17 @@ String getTypeDefinition(SQLServerConnection con, TDSReader tdsReader) throws SQ
12251277
return typeDefinition;
12261278
}
12271279

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

12321285
try {
1286+
inputDTV.isNonPLP = isNonPLP;
12331287
inputDTV.sendCryptoMetaData(this.cryptoMeta, tdsWriter);
12341288
inputDTV.setJdbcTypeSetByUser(getJdbcTypeSetByUser(), getValueLength());
1235-
inputDTV.sendByRPC(name, null, conn.getDatabaseCollation(), valueLength, isOutput() ? outScale : scale,
1236-
isOutput(), tdsWriter, statement);
1289+
inputDTV.sendByRPC(callRPCDirectly ? name : null, null, conn.getDatabaseCollation(), valueLength,
1290+
isOutput() ? outScale : scale, isOutput(), tdsWriter, statement);
12371291
} finally {
12381292
// reset the cryptoMeta in IOBuffer
12391293
inputDTV.sendCryptoMetaData(null, tdsWriter);

src/main/java/com/microsoft/sqlserver/jdbc/SQLServerBulkCopy.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2129,7 +2129,8 @@ private void writeNullToTdsWriter(TDSWriter tdsWriter, int srcJdbcType,
21292129

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

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

0 commit comments

Comments
 (0)