Skip to content

Commit

Permalink
Merge branch 'microsoft:main' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
Jeffery-Wasty authored May 24, 2024
2 parents aa82054 + c79befa commit d2aae9f
Show file tree
Hide file tree
Showing 27 changed files with 393 additions and 109 deletions.
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,15 +46,17 @@ To build the jar files, you must use minimum version of Java 11 with Maven. You
* Maven:
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.
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.
* Run `mvn install -Pjre21`. This creates JRE 21 compatible jar in `\target` directory which is JDBC 4.3 compliant (Build with JDK 21).
* Run `mvn install -Pjre22`. This creates JRE 22 compatible jar in `\target` directory which is JDBC 4.3 compliant (Build with JDK 22).
* Run `mvn install -Pjre21`. This creates JRE 21 compatible jar in `\target` directory which is JDBC 4.3 compliant (Build with JDK 21+).
* Run `mvn install -Pjre17`. This creates JRE 17 compatible jar in `\target` directory which is JDBC 4.3 compliant (Build with JDK 17+).
* Run `mvn install -Pjre11`. This creates JRE 11 compatible jar in `\target` directory which is JDBC 4.3 compliant (Build with JDK 11+).
* Run `mvn install -Pjre8`. This creates JRE 8 compatible jar in `\target` directory which is JDBC 4.2 compliant (Build with JDK 11+).

* Gradle:
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.
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.
* 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).
* 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).
* 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+).
* 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+).
* 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+).
* 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+).
Expand Down
13 changes: 13 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,19 @@ test {
}
}

if (!hasProperty('buildProfile') || (hasProperty('buildProfile') && buildProfile == "jre22")) {

jreVersion = "jre22"
excludedFile = 'com/microsoft/sqlserver/jdbc/SQLServerJdbc42.java'
jar {
manifest {
attributes 'Automatic-Module-Name': 'com.microsoft.sqlserver.jdbc'
}
}
sourceCompatibility = 22
targetCompatibility = 22
}

if (!hasProperty('buildProfile') || (hasProperty('buildProfile') && buildProfile == "jre21")) {

jreVersion = "jre21"
Expand Down
46 changes: 41 additions & 5 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,13 @@
<!-- Driver Dependencies -->
<org.osgi.core.version>6.0.0</org.osgi.core.version>
<azure-security-keyvault-keys.version>4.7.3</azure-security-keyvault-keys.version>
<azure-identity.version>1.11.1</azure-identity.version>
<msal.version>1.14.1</msal.version>
<azure-identity.version>1.12.1</azure-identity.version>
<msal.version>1.15.0</msal.version>
<osgi.jdbc.version>1.1.0</osgi.jdbc.version>
<antlr-runtime.version>4.9.3</antlr-runtime.version>
<com.google.code.gson.version>2.10.1</com.google.code.gson.version>
<bcprov-jdk18on.version>1.77</bcprov-jdk18on.version>
<bcpkix-jdk18on.version>1.77</bcpkix-jdk18on.version>
<bcprov-jdk18on.version>1.78</bcprov-jdk18on.version>
<bcpkix-jdk18on.version>1.78</bcpkix-jdk18on.version>
<!-- JUnit Test Dependencies -->
<junit.platform.version>[1.3.2, 1.9.0]</junit.platform.version>
<junit.jupiter.version>5.8.2</junit.jupiter.version>
Expand Down Expand Up @@ -381,6 +381,42 @@
</plugins>
</build>
</profile>
<profile>
<id>jre22</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<build>
<finalName>${project.artifactId}-${project.version}.jre22${releaseExt}</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<excludes>
<exclude>**/com/microsoft/sqlserver/jdbc/SQLServerJdbc42.java</exclude>
</excludes>
<source>22</source>
<target>22</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.1.1</version>
<configuration>
<archive>
<manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
<manifestEntries>
<Automatic-Module-Name>com.microsoft.sqlserver.jdbc</Automatic-Module-Name>
</manifestEntries>
</archive>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
<build>
<resources>
Expand Down Expand Up @@ -522,7 +558,7 @@
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.9</version>
<version>0.8.12</version>
<executions>
<execution>
<id>pre-test</id>
Expand Down
20 changes: 7 additions & 13 deletions src/main/java/com/microsoft/sqlserver/jdbc/SQLServerBulkCopy.java
Original file line number Diff line number Diff line change
Expand Up @@ -2596,7 +2596,7 @@ else if (4 >= bulkScale)
throw new SQLServerException(null, form.format(new Object[] {}), null, 0, false);
}
writeSqlVariant(tdsWriter, colValue, sourceResultSet, srcColOrdinal, destColOrdinal, bulkJdbcType,
bulkScale, isStreaming);
isStreaming);
break;
default:
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_BulkTypeNotSupported"));
Expand All @@ -2622,9 +2622,10 @@ else if (4 >= bulkScale)
* Writes sql_variant data based on the baseType for bulkcopy
*
* @throws SQLServerException
* an exception
*/
private void writeSqlVariant(TDSWriter tdsWriter, Object colValue, ResultSet sourceResultSet, int srcColOrdinal,
int destColOrdinal, int bulkJdbcType, int bulkScale, boolean isStreaming) throws SQLServerException {
int destColOrdinal, int bulkJdbcType, boolean isStreaming) throws SQLServerException {
if (null == colValue) {
writeNullToTdsWriter(tdsWriter, bulkJdbcType, isStreaming);
return;
Expand All @@ -2633,7 +2634,7 @@ private void writeSqlVariant(TDSWriter tdsWriter, Object colValue, ResultSet sou
int baseType = variantType.getBaseType();
byte[] srcBytes;
// for sql variant we normally should return the colvalue for time as time string. but for
// bulkcopy we need it to be timestamp. so we have to retrieve it again once we are in bulkcopy
// bulkcopy we need it to be a timestamp. so we have to retrieve it again once we are in bulkcopy
// and make sure that the base type is time.
if (TDSType.TIMEN == TDSType.valueOf(baseType)) {
variantType.setIsBaseTypeTimeValue(true);
Expand Down Expand Up @@ -2671,6 +2672,7 @@ private void writeSqlVariant(TDSWriter tdsWriter, Object colValue, ResultSet sou
tdsWriter.writeReal(Float.valueOf(colValue.toString()));
break;

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

case MONEY4:
writeBulkCopySqlVariantHeader(21, TDSType.DECIMALN.byteValue(), (byte) 2, tdsWriter);
tdsWriter.writeByte((byte) 38);
tdsWriter.writeByte((byte) 4);
tdsWriter.writeSqlVariantInternalBigDecimal((BigDecimal) colValue, bulkJdbcType);
break;

case BIT1:
writeBulkCopySqlVariantHeader(3, TDSType.BIT1.byteValue(), (byte) 0, tdsWriter);
tdsWriter.writeByte((byte) (((Boolean) colValue).booleanValue() ? 1 : 0));
Expand Down Expand Up @@ -2791,9 +2786,8 @@ private void writeSqlVariant(TDSWriter tdsWriter, Object colValue, ResultSet sou
case GUID:
length = colValue.toString().length();
writeBulkCopySqlVariantHeader(9 + length, TDSType.BIGCHAR.byteValue(), (byte) 7, tdsWriter);
// since while reading collation from sourceMetaData in guid we don't read collation, cause we are
// reading binary
// but in writing it we are using char, we need to get the collation.
// since while reading collation from sourceMetaData in GUID we don't read collation, because we are
// reading binary, but in writing it we are using char, so we need to get the collation.
SQLCollation collation = (null != destColumnMetadata.get(srcColOrdinal).collation) ? destColumnMetadata
.get(srcColOrdinal).collation : connection.getDatabaseCollation();
variantType.setCollation(collation);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ && callRPCDirectly(inOutParam)) {
}

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

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

if (bReturnValueSyntax && (nOutParamsAssigned == 0) && !isCursorable(executeMethod) && !isTVPType
&& callRPCDirectly(inOutParam) && returnValueStatus != userDefinedFunctionReturnStatus) {
&& callRPCDirectly(inOutParam) && returnValueStatus != USER_DEFINED_FUNCTION_RETURN_STATUS) {
nOutParamsAssigned++;
}

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

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

if ((outParamIndex < 0 || outParamIndex >= inOutParam.length)
|| (!inOutParam[outParamIndex].isOutput())) {

// For RPC calls with out parameters, the initial return value token will indicate
// it being a RPC. In such case, consume the token as it does not contain the out parameter
// value. The subsequent token will have the value.
if (outParamHandler.srv.getStatus() == USER_DEFINED_FUNCTION_RETURN_STATUS) {
continue;
}

if (getStatementLogger().isLoggable(java.util.logging.Level.INFO)) {
getStatementLogger().info(toString() + " Unexpected outParamIndex: " + outParamIndex
+ "; adjustment: " + outParamIndexAdjustment);
}

connection.throwInvalidTDS();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,6 @@ public class SQLServerPreparedStatement extends SQLServerStatement implements IS
// flag whether is call escape syntax
private boolean isCallEscapeSyntax;

// flag whether is four part syntax
private boolean isFourPartSyntax;

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

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

/**
* Regex for four part syntax
*/
private static final Pattern fourPartSyntaxPattern = Pattern.compile("(.+)\\.(.+)\\.(.+)\\.(.+)");

/** Returns the prepared statement SQL */
@Override
public String toString() {
Expand Down Expand Up @@ -290,7 +282,6 @@ private boolean resetPrepStmtHandle(boolean discardCurrentCacheItem) {
userSQL = parsedSQL.processedSQL;
isExecEscapeSyntax = isExecEscapeSyntax(sql);
isCallEscapeSyntax = isCallEscapeSyntax(sql);
isFourPartSyntax = isFourPartSyntax(sql);
userSQLParamPositions = parsedSQL.parameterPositions;
initParams(userSQLParamPositions.length);
useBulkCopyForBatchInsert = conn.getUseBulkCopyForBatchInsert();
Expand Down Expand Up @@ -1258,10 +1249,8 @@ boolean callRPCDirectly(Parameter[] params) throws SQLServerException {
// 4. Compliant CALL escape syntax
// If isExecEscapeSyntax is true, EXEC escape syntax is used then use prior behaviour of
// wrapping call to execute the procedure
// If isFourPartSyntax is true, sproc is being executed against linked server, then
// use prior behaviour of wrapping call to execute procedure
return (null != procedureName && paramCount != 0 && !isTVPType(params) && isCallEscapeSyntax
&& !isExecEscapeSyntax && !isFourPartSyntax);
&& !isExecEscapeSyntax);
}

/**
Expand Down Expand Up @@ -1289,10 +1278,6 @@ private boolean isCallEscapeSyntax(String sql) {
return callEscapePattern.matcher(sql).find();
}

private boolean isFourPartSyntax(String sql) {
return fourPartSyntaxPattern.matcher(sql).find();
}

/**
* Executes sp_prepare to prepare a parameterized statement and sets the prepared statement handle
*
Expand Down
Loading

0 comments on commit d2aae9f

Please # to comment.