Skip to content

Commit

Permalink
Merge branch 'microsoft:main' into feature/1582_JavaTypeUUID
Browse files Browse the repository at this point in the history
  • Loading branch information
vxel authored Jun 8, 2024
2 parents ae94a1b + d90ba9a commit a0a661b
Show file tree
Hide file tree
Showing 30 changed files with 450 additions and 99 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
42 changes: 39 additions & 3 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@
<!-- 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>
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
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import java.time.OffsetDateTime;
import java.time.OffsetTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map.Entry;

Expand Down Expand Up @@ -61,10 +62,9 @@ public class SQLServerBulkCSVFileRecord extends SQLServerBulkRecord implements j
private boolean escapeDelimiters;

/**
* Regex to ignore delimiter when the field is enclosed in quotes.
*
* Double quote character to parse lines with
*/
private static final String ESCAPE_SPLIT_PATTERN = "(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)";
private static final char doubleQuoteChar = '\"';

/*
* Class names for logging.
Expand Down Expand Up @@ -206,8 +206,10 @@ private void initFileReader(InputStreamReader sr, String encoding, String demlim
if (firstLineIsColumnNames) {
currentLine = fileReader.readLine();
if (null != currentLine) {
columnNames = (escapeDelimiters && currentLine.contains("\"")) ? escapeQuotesRFC4180(
currentLine.split(delimiter + ESCAPE_SPLIT_PATTERN, -1)) : currentLine.split(delimiter, -1);
columnNames = (escapeDelimiters && currentLine.contains("\""))
? escapeQuotesRFC4180(parseString(
currentLine, delimiter))
: parseString(currentLine, delimiter);
}
}
}
Expand Down Expand Up @@ -292,8 +294,10 @@ public Object[] getRowData() throws SQLServerException {
* Binary data may be corrupted The limit in split() function should be a negative value, otherwise trailing
* empty strings are discarded. Empty string is returned if there is no value.
*/
String[] data = (escapeDelimiters && currentLine.contains("\"")) ? escapeQuotesRFC4180(
currentLine.split(delimiter + ESCAPE_SPLIT_PATTERN, -1)) : currentLine.split(delimiter, -1);
String[] data = (escapeDelimiters && currentLine.contains("\""))
? escapeQuotesRFC4180(parseString(
currentLine, delimiter))
: parseString(currentLine, delimiter);

// Cannot go directly from String[] to Object[] and expect it to act as an array.

Expand Down Expand Up @@ -632,4 +636,27 @@ private static String[] escapeQuotesRFC4180(String[] tokens) throws SQLServerExc
}
return tokens;
}

private static String[] parseString(String buffer, String delimiter) {
ArrayList<String> tokens = new ArrayList<>();
int position = 0;
boolean quoted = false;

for (int i = 0; i < buffer.length(); i++) {
if (buffer.charAt(i) == doubleQuoteChar) {
quoted = !quoted;
} else if (!quoted && i + delimiter.length() <= buffer.length()
&& buffer.substring(i, i + delimiter.length()).equals(delimiter)) {
// Add field to token list when delimiter is found
tokens.add(buffer.substring(position, i));

position = i + delimiter.length();
i = position - 1; // Adjust the index to start after the delimiter
}
}

// Add the last field
tokens.add(buffer.substring(position));
return tokens.toArray(new String[0]);
}
}
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 a0a661b

Please sign in to comment.