Skip to content

Commit 42dc48d

Browse files
committed
Exec cstmt directly
1 parent fe56e25 commit 42dc48d

21 files changed

+1984
-466
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
@@ -467,6 +467,7 @@ static final String getEncryptionLevel(int level) {
467467
final static int COLINFO_STATUS_DIFFERENT_NAME = 0x20;
468468

469469
final static int MAX_FRACTIONAL_SECONDS_SCALE = 7;
470+
final static int DEFAULT_FRACTIONAL_SECONDS_SCALE = 3;
470471

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

48594860
/**
@@ -4868,8 +4869,8 @@ void writeRPCStringUnicode(String sValue) throws SQLServerException {
48684869
* @param collation
48694870
* the collation of the data value
48704871
*/
4871-
void writeRPCStringUnicode(String sName, String sValue, boolean bOut,
4872-
SQLCollation collation) throws SQLServerException {
4872+
void writeRPCStringUnicode(String sName, String sValue, boolean bOut, SQLCollation collation,
4873+
boolean isNonPLP) throws SQLServerException {
48734874
boolean bValueNull = (sValue == null);
48744875
int nValueLen = bValueNull ? 0 : (2 * sValue.length());
48754876
// Textual RPC requires a collation. If none is provided, as is the case when
@@ -4881,7 +4882,7 @@ void writeRPCStringUnicode(String sName, String sValue, boolean bOut,
48814882
* Use PLP encoding if either OUT params were specified or if the user query exceeds
48824883
* DataTypes.SHORT_VARTYPE_MAX_BYTES
48834884
*/
4884-
if (nValueLen > DataTypes.SHORT_VARTYPE_MAX_BYTES || bOut) {
4885+
if ((nValueLen > DataTypes.SHORT_VARTYPE_MAX_BYTES || bOut) && !isNonPLP) {
48854886
writeRPCNameValType(sName, bOut, TDSType.NVARCHAR);
48864887

48874888
writeVMaxHeader(nValueLen, // Length
@@ -5632,8 +5633,8 @@ void writeCryptoMetaData() throws SQLServerException {
56325633
writeByte(cryptoMeta.normalizationRuleVersion);
56335634
}
56345635

5635-
void writeRPCByteArray(String sName, byte[] bValue, boolean bOut, JDBCType jdbcType,
5636-
SQLCollation collation) throws SQLServerException {
5636+
void writeRPCByteArray(String sName, byte[] bValue, boolean bOut, JDBCType jdbcType, SQLCollation collation,
5637+
boolean isNonPLP) throws SQLServerException {
56375638
boolean bValueNull = (bValue == null);
56385639
int nValueLen = bValueNull ? 0 : bValue.length;
56395640
boolean isShortValue = (nValueLen <= DataTypes.SHORT_VARTYPE_MAX_BYTES);
@@ -5679,7 +5680,7 @@ void writeRPCByteArray(String sName, byte[] bValue, boolean bOut, JDBCType jdbcT
56795680

56805681
writeRPCNameValType(sName, bOut, tdsType);
56815682

5682-
if (usePLP) {
5683+
if (usePLP && !isNonPLP) {
56835684
writeVMaxHeader(nValueLen, bValueNull, collation);
56845685

56855686
// Send the data.
@@ -7058,6 +7059,35 @@ final short peekStatusFlag() {
70587059
return 0;
70597060
}
70607061

7062+
final int peekReturnValueStatus() throws SQLServerException {
7063+
// Ensure that we have a packet to read from.
7064+
if (!ensurePayload()) {
7065+
throwInvalidTDS();
7066+
}
7067+
7068+
// In order to parse the 'status' value, we need to skip over the following properties in the TDS packet
7069+
// payload: TDS token type (1 byte value), ordinal/length (2 byte value), parameter name length value (1 byte value) and
7070+
// the number of bytes that make the parameter name (need to be calculated).
7071+
//
7072+
// 'offset' starts at 4 because tdsTokenType + ordinal/length + parameter name length value is 4 bytes. So, we
7073+
// skip 4 bytes immediateley.
7074+
int offset = 4;
7075+
int paramNameLength = currentPacket.payload[payloadOffset + 3];
7076+
7077+
// Check if parameter name is set. If it's set, it should be > 0. In which case, we add the
7078+
// additional bytes to skip.
7079+
if (paramNameLength > 0) {
7080+
// Each character in unicode is 2 bytes
7081+
offset += 2 * paramNameLength;
7082+
}
7083+
7084+
if (payloadOffset + offset <= currentPacket.payloadLength) {
7085+
return currentPacket.payload[payloadOffset + offset] & 0xFF;
7086+
}
7087+
7088+
return -1;
7089+
}
7090+
70617091
final int readUnsignedByte() throws SQLServerException {
70627092
// Ensure that we have a packet to read from.
70637093
if (!ensurePayload())

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

Lines changed: 19 additions & 23 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
*
@@ -1346,27 +1365,4 @@ public interface ISQLServerDataSource extends javax.sql.CommonDataSource {
13461365
* @return cacheBulkCopyMetadata boolean value
13471366
*/
13481367
boolean getcacheBulkCopyMetadata();
1349-
1350-
/**
1351-
* useFlexibleCallableStatements is temporarily removed. This is meant as a no-op.
1352-
*
1353-
* Sets whether or not sp_sproc_columns will be used for parameter name lookup.
1354-
*
1355-
* @param useFlexibleCallableStatements
1356-
* When set to false, sp_sproc_columns is not used for parameter name lookup
1357-
* in callable statements. This eliminates a round trip to the server but imposes limitations
1358-
* on how parameters are set. When set to false, applications must either reference
1359-
* parameters by name or by index, not both. Parameters must also be set in the same
1360-
* order as the stored procedure definition.
1361-
*/
1362-
void setUseFlexibleCallableStatements(boolean useFlexibleCallableStatements);
1363-
1364-
/**
1365-
* useFlexibleCallableStatements is temporarily removed. This is meant as a no-op.
1366-
*
1367-
* Returns whether or not sp_sproc_columns is being used for parameter name lookup.
1368-
*
1369-
* @return useFlexibleCallableStatements
1370-
*/
1371-
boolean getUseFlexibleCallableStatements();
13721368
}

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);
@@ -1220,15 +1272,17 @@ String getTypeDefinition(SQLServerConnection con, TDSReader tdsReader) throws SQ
12201272
return typeDefinition;
12211273
}
12221274

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

12271280
try {
1281+
inputDTV.isNonPLP = isNonPLP;
12281282
inputDTV.sendCryptoMetaData(this.cryptoMeta, tdsWriter);
12291283
inputDTV.setJdbcTypeSetByUser(getJdbcTypeSetByUser(), getValueLength());
1230-
inputDTV.sendByRPC(name, null, conn.getDatabaseCollation(), valueLength, isOutput() ? outScale : scale,
1231-
isOutput(), tdsWriter, statement);
1284+
inputDTV.sendByRPC(callRPCDirectly ? name : null, null, conn.getDatabaseCollation(), valueLength,
1285+
isOutput() ? outScale : scale, isOutput(), tdsWriter, statement);
12321286
} finally {
12331287
// reset the cryptoMeta in IOBuffer
12341288
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)