Skip to content

Commit d2aae9f

Browse files
Merge branch 'microsoft:main' into main
2 parents aa82054 + c79befa commit d2aae9f

27 files changed

+393
-109
lines changed

README.md

+4-2
Original file line numberDiff line numberDiff line change
@@ -46,15 +46,17 @@ To build the jar files, you must use minimum version of Java 11 with Maven. You
4646
* Maven:
4747
1. If you have not already done so, add the environment variable `mssql_jdbc_test_connection_properties` in your system with the connection properties for your SQL Server or SQL DB instance.
4848
2. Run one of the commands below to build a JRE 11 and newer versions compatible jar or JRE 8 compatible jar in the `\target` directory.
49-
* Run `mvn install -Pjre21`. This creates JRE 21 compatible jar in `\target` directory which is JDBC 4.3 compliant (Build with JDK 21).
49+
* Run `mvn install -Pjre22`. This creates JRE 22 compatible jar in `\target` directory which is JDBC 4.3 compliant (Build with JDK 22).
50+
* Run `mvn install -Pjre21`. This creates JRE 21 compatible jar in `\target` directory which is JDBC 4.3 compliant (Build with JDK 21+).
5051
* Run `mvn install -Pjre17`. This creates JRE 17 compatible jar in `\target` directory which is JDBC 4.3 compliant (Build with JDK 17+).
5152
* Run `mvn install -Pjre11`. This creates JRE 11 compatible jar in `\target` directory which is JDBC 4.3 compliant (Build with JDK 11+).
5253
* Run `mvn install -Pjre8`. This creates JRE 8 compatible jar in `\target` directory which is JDBC 4.2 compliant (Build with JDK 11+).
5354

5455
* Gradle:
5556
1. If you have not already done so, add the environment variable `mssql_jdbc_test_connection_properties` in your system with the connection properties for your SQL Server or SQL DB instance.
5657
2. Run one of the commands below to build a JRE 11 and newer versions compatible jar or JRE 8 compatible jar in the `\build\libs` directory.
57-
* Run `gradle build -PbuildProfile=jre21`. This creates JRE 21 compatible jar in `\build\libs` directory which is JDBC 4.3 compliant (Build with JDK 21).
58+
* Run `gradle build -PbuildProfile=jre22`. This creates JRE 22 compatible jar in `\build\libs` directory which is JDBC 4.3 compliant (Build with JDK 22).
59+
* Run `gradle build -PbuildProfile=jre21`. This creates JRE 21 compatible jar in `\build\libs` directory which is JDBC 4.3 compliant (Build with JDK 21+).
5860
* Run `gradle build -PbuildProfile=jre17`. This creates JRE 17 compatible jar in `\build\libs` directory which is JDBC 4.3 compliant (Build with JDK 17+).
5961
* Run `gradle build -PbuildProfile=jre11`. This creates JRE 11 compatible jar in `\build\libs` directory which is JDBC 4.3 compliant (Build with JDK 11+).
6062
* Run `gradle build -PbuildProfile=jre8`. This creates JRE 8 compatible jar in `\build\libs` directory which is JDBC 4.2 compliant (Build with JDK 11+).

build.gradle

+13
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,19 @@ test {
3333
}
3434
}
3535

36+
if (!hasProperty('buildProfile') || (hasProperty('buildProfile') && buildProfile == "jre22")) {
37+
38+
jreVersion = "jre22"
39+
excludedFile = 'com/microsoft/sqlserver/jdbc/SQLServerJdbc42.java'
40+
jar {
41+
manifest {
42+
attributes 'Automatic-Module-Name': 'com.microsoft.sqlserver.jdbc'
43+
}
44+
}
45+
sourceCompatibility = 22
46+
targetCompatibility = 22
47+
}
48+
3649
if (!hasProperty('buildProfile') || (hasProperty('buildProfile') && buildProfile == "jre21")) {
3750

3851
jreVersion = "jre21"

pom.xml

+41-5
Original file line numberDiff line numberDiff line change
@@ -55,13 +55,13 @@
5555
<!-- Driver Dependencies -->
5656
<org.osgi.core.version>6.0.0</org.osgi.core.version>
5757
<azure-security-keyvault-keys.version>4.7.3</azure-security-keyvault-keys.version>
58-
<azure-identity.version>1.11.1</azure-identity.version>
59-
<msal.version>1.14.1</msal.version>
58+
<azure-identity.version>1.12.1</azure-identity.version>
59+
<msal.version>1.15.0</msal.version>
6060
<osgi.jdbc.version>1.1.0</osgi.jdbc.version>
6161
<antlr-runtime.version>4.9.3</antlr-runtime.version>
6262
<com.google.code.gson.version>2.10.1</com.google.code.gson.version>
63-
<bcprov-jdk18on.version>1.77</bcprov-jdk18on.version>
64-
<bcpkix-jdk18on.version>1.77</bcpkix-jdk18on.version>
63+
<bcprov-jdk18on.version>1.78</bcprov-jdk18on.version>
64+
<bcpkix-jdk18on.version>1.78</bcpkix-jdk18on.version>
6565
<!-- JUnit Test Dependencies -->
6666
<junit.platform.version>[1.3.2, 1.9.0]</junit.platform.version>
6767
<junit.jupiter.version>5.8.2</junit.jupiter.version>
@@ -381,6 +381,42 @@
381381
</plugins>
382382
</build>
383383
</profile>
384+
<profile>
385+
<id>jre22</id>
386+
<activation>
387+
<activeByDefault>true</activeByDefault>
388+
</activation>
389+
<build>
390+
<finalName>${project.artifactId}-${project.version}.jre22${releaseExt}</finalName>
391+
<plugins>
392+
<plugin>
393+
<groupId>org.apache.maven.plugins</groupId>
394+
<artifactId>maven-compiler-plugin</artifactId>
395+
<version>3.8.0</version>
396+
<configuration>
397+
<excludes>
398+
<exclude>**/com/microsoft/sqlserver/jdbc/SQLServerJdbc42.java</exclude>
399+
</excludes>
400+
<source>22</source>
401+
<target>22</target>
402+
</configuration>
403+
</plugin>
404+
<plugin>
405+
<groupId>org.apache.maven.plugins</groupId>
406+
<artifactId>maven-jar-plugin</artifactId>
407+
<version>3.1.1</version>
408+
<configuration>
409+
<archive>
410+
<manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
411+
<manifestEntries>
412+
<Automatic-Module-Name>com.microsoft.sqlserver.jdbc</Automatic-Module-Name>
413+
</manifestEntries>
414+
</archive>
415+
</configuration>
416+
</plugin>
417+
</plugins>
418+
</build>
419+
</profile>
384420
</profiles>
385421
<build>
386422
<resources>
@@ -522,7 +558,7 @@
522558
<plugin>
523559
<groupId>org.jacoco</groupId>
524560
<artifactId>jacoco-maven-plugin</artifactId>
525-
<version>0.8.9</version>
561+
<version>0.8.12</version>
526562
<executions>
527563
<execution>
528564
<id>pre-test</id>

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

+7-13
Original file line numberDiff line numberDiff line change
@@ -2596,7 +2596,7 @@ else if (4 >= bulkScale)
25962596
throw new SQLServerException(null, form.format(new Object[] {}), null, 0, false);
25972597
}
25982598
writeSqlVariant(tdsWriter, colValue, sourceResultSet, srcColOrdinal, destColOrdinal, bulkJdbcType,
2599-
bulkScale, isStreaming);
2599+
isStreaming);
26002600
break;
26012601
default:
26022602
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_BulkTypeNotSupported"));
@@ -2622,9 +2622,10 @@ else if (4 >= bulkScale)
26222622
* Writes sql_variant data based on the baseType for bulkcopy
26232623
*
26242624
* @throws SQLServerException
2625+
* an exception
26252626
*/
26262627
private void writeSqlVariant(TDSWriter tdsWriter, Object colValue, ResultSet sourceResultSet, int srcColOrdinal,
2627-
int destColOrdinal, int bulkJdbcType, int bulkScale, boolean isStreaming) throws SQLServerException {
2628+
int destColOrdinal, int bulkJdbcType, boolean isStreaming) throws SQLServerException {
26282629
if (null == colValue) {
26292630
writeNullToTdsWriter(tdsWriter, bulkJdbcType, isStreaming);
26302631
return;
@@ -2633,7 +2634,7 @@ private void writeSqlVariant(TDSWriter tdsWriter, Object colValue, ResultSet sou
26332634
int baseType = variantType.getBaseType();
26342635
byte[] srcBytes;
26352636
// for sql variant we normally should return the colvalue for time as time string. but for
2636-
// bulkcopy we need it to be timestamp. so we have to retrieve it again once we are in bulkcopy
2637+
// bulkcopy we need it to be a timestamp. so we have to retrieve it again once we are in bulkcopy
26372638
// and make sure that the base type is time.
26382639
if (TDSType.TIMEN == TDSType.valueOf(baseType)) {
26392640
variantType.setIsBaseTypeTimeValue(true);
@@ -2671,6 +2672,7 @@ private void writeSqlVariant(TDSWriter tdsWriter, Object colValue, ResultSet sou
26712672
tdsWriter.writeReal(Float.valueOf(colValue.toString()));
26722673
break;
26732674

2675+
case MONEY4:
26742676
case MONEY8:
26752677
// For decimalN we right TDSWriter.BIGDECIMAL_MAX_LENGTH as maximum length = 17
26762678
// 17 + 2 for basetype and probBytes + 2 for precision and length = 21 the length of data in header
@@ -2680,13 +2682,6 @@ private void writeSqlVariant(TDSWriter tdsWriter, Object colValue, ResultSet sou
26802682
tdsWriter.writeSqlVariantInternalBigDecimal((BigDecimal) colValue, bulkJdbcType);
26812683
break;
26822684

2683-
case MONEY4:
2684-
writeBulkCopySqlVariantHeader(21, TDSType.DECIMALN.byteValue(), (byte) 2, tdsWriter);
2685-
tdsWriter.writeByte((byte) 38);
2686-
tdsWriter.writeByte((byte) 4);
2687-
tdsWriter.writeSqlVariantInternalBigDecimal((BigDecimal) colValue, bulkJdbcType);
2688-
break;
2689-
26902685
case BIT1:
26912686
writeBulkCopySqlVariantHeader(3, TDSType.BIT1.byteValue(), (byte) 0, tdsWriter);
26922687
tdsWriter.writeByte((byte) (((Boolean) colValue).booleanValue() ? 1 : 0));
@@ -2791,9 +2786,8 @@ private void writeSqlVariant(TDSWriter tdsWriter, Object colValue, ResultSet sou
27912786
case GUID:
27922787
length = colValue.toString().length();
27932788
writeBulkCopySqlVariantHeader(9 + length, TDSType.BIGCHAR.byteValue(), (byte) 7, tdsWriter);
2794-
// since while reading collation from sourceMetaData in guid we don't read collation, cause we are
2795-
// reading binary
2796-
// but in writing it we are using char, we need to get the collation.
2789+
// since while reading collation from sourceMetaData in GUID we don't read collation, because we are
2790+
// reading binary, but in writing it we are using char, so we need to get the collation.
27972791
SQLCollation collation = (null != destColumnMetadata.get(srcColOrdinal).collation) ? destColumnMetadata
27982792
.get(srcColOrdinal).collation : connection.getDatabaseCollation();
27992793
variantType.setCollation(collation);

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

+12-4
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ && callRPCDirectly(inOutParam)) {
216216
}
217217

218218
if (inOutParam[i - 1].isReturnValue() && bReturnValueSyntax && !isCursorable(executeMethod) && !isTVPType
219-
&& returnValueStatus != userDefinedFunctionReturnStatus) {
219+
&& returnValueStatus != USER_DEFINED_FUNCTION_RETURN_STATUS) {
220220
return inOutParam[i - 1];
221221
}
222222

@@ -269,7 +269,6 @@ final void processOutParameters() throws SQLServerException {
269269
// the response stream.
270270
for (int index = 0; index < inOutParam.length; ++index) {
271271
if (index != outParamIndex && inOutParam[index].isValueGotten()) {
272-
assert inOutParam[index].isOutput();
273272
inOutParam[index].resetOutputValue();
274273
}
275274
}
@@ -365,7 +364,7 @@ boolean onRetValue(TDSReader tdsReader) throws SQLServerException {
365364
OutParamHandler outParamHandler = new OutParamHandler();
366365

367366
if (bReturnValueSyntax && (nOutParamsAssigned == 0) && !isCursorable(executeMethod) && !isTVPType
368-
&& callRPCDirectly(inOutParam) && returnValueStatus != userDefinedFunctionReturnStatus) {
367+
&& callRPCDirectly(inOutParam) && returnValueStatus != USER_DEFINED_FUNCTION_RETURN_STATUS) {
369368
nOutParamsAssigned++;
370369
}
371370

@@ -414,7 +413,7 @@ && callRPCDirectly(inOutParam) && returnValueStatus != userDefinedFunctionReturn
414413
outParamIndex = outParamHandler.srv.getOrdinalOrLength();
415414

416415
if (bReturnValueSyntax && !isCursorable(executeMethod) && !isTVPType && callRPCDirectly(inOutParam)
417-
&& returnValueStatus != userDefinedFunctionReturnStatus) {
416+
&& returnValueStatus != USER_DEFINED_FUNCTION_RETURN_STATUS) {
418417
outParamIndex++;
419418
} else {
420419
// Statements need to have their out param indices adjusted by the number
@@ -424,10 +423,19 @@ && callRPCDirectly(inOutParam) && returnValueStatus != userDefinedFunctionReturn
424423

425424
if ((outParamIndex < 0 || outParamIndex >= inOutParam.length)
426425
|| (!inOutParam[outParamIndex].isOutput())) {
426+
427+
// For RPC calls with out parameters, the initial return value token will indicate
428+
// it being a RPC. In such case, consume the token as it does not contain the out parameter
429+
// value. The subsequent token will have the value.
430+
if (outParamHandler.srv.getStatus() == USER_DEFINED_FUNCTION_RETURN_STATUS) {
431+
continue;
432+
}
433+
427434
if (getStatementLogger().isLoggable(java.util.logging.Level.INFO)) {
428435
getStatementLogger().info(toString() + " Unexpected outParamIndex: " + outParamIndex
429436
+ "; adjustment: " + outParamIndexAdjustment);
430437
}
438+
431439
connection.throwInvalidTDS();
432440
}
433441

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

+1-16
Original file line numberDiff line numberDiff line change
@@ -77,9 +77,6 @@ public class SQLServerPreparedStatement extends SQLServerStatement implements IS
7777
// flag whether is call escape syntax
7878
private boolean isCallEscapeSyntax;
7979

80-
// flag whether is four part syntax
81-
private boolean isFourPartSyntax;
82-
8380
/** Parameter positions in processed SQL statement text. */
8481
final int[] userSQLParamPositions;
8582

@@ -149,11 +146,6 @@ private void setPreparedStatementHandle(int handle) {
149146
*/
150147
private static final Pattern execEscapePattern = Pattern.compile("^\\s*(?i)(?:exec|execute)\\b");
151148

152-
/**
153-
* Regex for four part syntax
154-
*/
155-
private static final Pattern fourPartSyntaxPattern = Pattern.compile("(.+)\\.(.+)\\.(.+)\\.(.+)");
156-
157149
/** Returns the prepared statement SQL */
158150
@Override
159151
public String toString() {
@@ -290,7 +282,6 @@ private boolean resetPrepStmtHandle(boolean discardCurrentCacheItem) {
290282
userSQL = parsedSQL.processedSQL;
291283
isExecEscapeSyntax = isExecEscapeSyntax(sql);
292284
isCallEscapeSyntax = isCallEscapeSyntax(sql);
293-
isFourPartSyntax = isFourPartSyntax(sql);
294285
userSQLParamPositions = parsedSQL.parameterPositions;
295286
initParams(userSQLParamPositions.length);
296287
useBulkCopyForBatchInsert = conn.getUseBulkCopyForBatchInsert();
@@ -1258,10 +1249,8 @@ boolean callRPCDirectly(Parameter[] params) throws SQLServerException {
12581249
// 4. Compliant CALL escape syntax
12591250
// If isExecEscapeSyntax is true, EXEC escape syntax is used then use prior behaviour of
12601251
// wrapping call to execute the procedure
1261-
// If isFourPartSyntax is true, sproc is being executed against linked server, then
1262-
// use prior behaviour of wrapping call to execute procedure
12631252
return (null != procedureName && paramCount != 0 && !isTVPType(params) && isCallEscapeSyntax
1264-
&& !isExecEscapeSyntax && !isFourPartSyntax);
1253+
&& !isExecEscapeSyntax);
12651254
}
12661255

12671256
/**
@@ -1289,10 +1278,6 @@ private boolean isCallEscapeSyntax(String sql) {
12891278
return callEscapePattern.matcher(sql).find();
12901279
}
12911280

1292-
private boolean isFourPartSyntax(String sql) {
1293-
return fourPartSyntaxPattern.matcher(sql).find();
1294-
}
1295-
12961281
/**
12971282
* Executes sp_prepare to prepare a parameterized statement and sets the prepared statement handle
12981283
*

0 commit comments

Comments
 (0)