Skip to content

Commit

Permalink
Merge branch 'main' into dev/machavan/ado#33039
Browse files Browse the repository at this point in the history
  • Loading branch information
machavan committed Jan 8, 2025
2 parents 6c4dca3 + 5bb3353 commit 1480215
Show file tree
Hide file tree
Showing 8 changed files with 199 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2446,7 +2446,7 @@ Connection connectInternal(Properties propsIn,
if (null != sPropValue)
validateMaxSQLLoginName(sPropKey, sPropValue);
else
activeConnectionProperties.setProperty(sPropKey, SQLServerDriver.DEFAULT_APP_NAME);
activeConnectionProperties.setProperty(sPropKey, SQLServerDriver.constructedAppName);

sPropKey = SQLServerDriverBooleanProperty.LAST_UPDATE_COUNT.toString();
sPropValue = activeConnectionProperties.getProperty(sPropKey);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ public void setApplicationName(String applicationName) {
@Override
public String getApplicationName() {
return getStringProperty(connectionProps, SQLServerDriverStringProperty.APPLICATION_NAME.toString(),
SQLServerDriverStringProperty.APPLICATION_NAME.getDefaultValue());
SQLServerDriver.constructedAppName);
}

/**
Expand Down
33 changes: 32 additions & 1 deletion src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDriver.java
Original file line number Diff line number Diff line change
Expand Up @@ -731,7 +731,32 @@ public final class SQLServerDriver implements java.sql.Driver {
static final String AUTH_DLL_NAME = "mssql-jdbc_auth-" + SQLJdbcVersion.MAJOR + "." + SQLJdbcVersion.MINOR + "."
+ SQLJdbcVersion.PATCH + "." + Util.getJVMArchOnWindows() + SQLJdbcVersion.RELEASE_EXT;
static final String DEFAULT_APP_NAME = "Microsoft JDBC Driver for SQL Server";
static final String APP_NAME_TEMPLATE = "Microsoft JDBC - %s, %s - %s";
static final String constructedAppName;
static {
constructedAppName = getAppName();
}

/**
* Constructs the application name using system properties for OS, platform, and architecture.
* If any of the properties cannot be fetched, it falls back to the default application name.
* Format -> Microsoft JDBC - {OS}, {Platform} - {architecture}
*
* @return the constructed application name or the default application name if properties are not available
*/
static String getAppName() {
String osName = System.getProperty("os.name", "");
String osArch = System.getProperty("os.arch", "");
String javaVmName = System.getProperty("java.vm.name", "");
String javaVmVersion = System.getProperty("java.vm.version", "");
String platform = javaVmName.isEmpty() || javaVmVersion.isEmpty() ? "" : javaVmName + " " + javaVmVersion;

if (osName.isEmpty() && platform.isEmpty() && osArch.isEmpty()) {
return DEFAULT_APP_NAME;
}
return String.format(APP_NAME_TEMPLATE, osName, platform, osArch);
}

private static final String[] TRUE_FALSE = {"true", "false"};

private static final SQLServerDriverPropertyInfo[] DRIVER_PROPERTIES = {
Expand All @@ -741,7 +766,7 @@ public final class SQLServerDriver implements java.sql.Driver {
SQLServerDriverStringProperty.APPLICATION_INTENT.getDefaultValue(), false,
new String[] {ApplicationIntent.READ_ONLY.toString(), ApplicationIntent.READ_WRITE.toString()}),
new SQLServerDriverPropertyInfo(SQLServerDriverStringProperty.APPLICATION_NAME.toString(),
SQLServerDriverStringProperty.APPLICATION_NAME.getDefaultValue(), false, null),
SQLServerDriverStringProperty.APPLICATION_NAME.getDefaultValue(), false, null),
new SQLServerDriverPropertyInfo(SQLServerDriverStringProperty.COLUMN_ENCRYPTION.toString(),
SQLServerDriverStringProperty.COLUMN_ENCRYPTION.getDefaultValue(), false,
new String[] {ColumnEncryptionSetting.DISABLED.toString(),
Expand Down Expand Up @@ -1028,6 +1053,9 @@ String getClassNameLogging() {
drLogger.finer("Error registering driver: " + e);
}
}
if (loggerExternal.isLoggable(Level.FINE)) {
loggerExternal.log(Level.FINE, "Application Name: " + SQLServerDriver.constructedAppName);
}
}

// Check for jdk.net.ExtendedSocketOptions to set TCP keep-alive options for idle connection resiliency
Expand Down Expand Up @@ -1266,6 +1294,9 @@ public java.sql.Connection connect(String url, Properties suppliedProperties) th
Properties connectProperties = parseAndMergeProperties(url, suppliedProperties);
if (connectProperties != null) {
result = DriverJDBCVersion.getSQLServerConnection(toString());
if (connectProperties.getProperty(SQLServerDriverStringProperty.APPLICATION_NAME.toString()) == null) {
connectProperties.setProperty(SQLServerDriverStringProperty.APPLICATION_NAME.toString(), SQLServerDriver.constructedAppName);
}
result.connect(connectProperties, null);
}
loggerExternal.exiting(getClassNameLogging(), "connect", result);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1246,16 +1246,25 @@ public final java.sql.ResultSetMetaData getMetaData() throws SQLServerException,
*/
private SQLServerResultSet buildExecuteMetaData() throws SQLServerException, SQLTimeoutException {
String fmtSQL = userSQL;

SQLServerResultSet emptyResultSet = null;
try {
fmtSQL = replaceMarkerWithNull(fmtSQL);
internalStmt = (SQLServerStatement) connection.createStatement();
emptyResultSet = internalStmt.executeQueryInternal("set fmtonly on " + fmtSQL + "\nset fmtonly off");
} catch (SQLServerException sqle) {
// Ignore empty result set errors, otherwise propagate the server error.
if (!sqle.getMessage().equals(SQLServerException.getErrString("R_noResultset"))) {
throw sqle;
//try by replacing ? characters in case that was an issue
try {
fmtSQL = replaceMarkerWithNull(fmtSQL);
internalStmt = (SQLServerStatement) connection.createStatement();
emptyResultSet = internalStmt.executeQueryInternal("set fmtonly on " + fmtSQL + "\nset fmtonly off");
} catch (SQLServerException ex) {
// Ignore empty result set errors, otherwise propagate the server error.
if (!ex.getMessage().equals(SQLServerException.getErrString("R_noResultset"))) {
throw ex;
}
}
}
}
return emptyResultSet;
Expand Down
33 changes: 27 additions & 6 deletions src/main/java/microsoft/sql/DateTimeOffset.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@

package microsoft.sql;

import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.util.Calendar;
import java.util.Locale;
import java.util.TimeZone;
Expand Down Expand Up @@ -190,7 +192,6 @@ public String toString() {
.substring(2), // -> "123456"
formattedOffset);
}

return result;
}

Expand Down Expand Up @@ -257,12 +258,32 @@ public java.sql.Timestamp getTimestamp() {
* @return OffsetDateTime equivalent to this DateTimeOffset object.
*/
public java.time.OffsetDateTime getOffsetDateTime() {
java.time.ZoneOffset zoneOffset = java.time.ZoneOffset.ofTotalSeconds(60 * minutesOffset);
java.time.LocalDateTime localDateTime = java.time.LocalDateTime.ofEpochSecond(utcMillis / 1000, nanos,
zoneOffset);
return java.time.OffsetDateTime.of(localDateTime, zoneOffset);
// Format the offset as +hh:mm or -hh:mm. Zero offset is formatted as +00:00.
String formattedOffset = (minutesOffset < 0) ?
String.format(Locale.US, "-%1$02d:%2$02d", -minutesOffset / 60, -minutesOffset % 60) :
String.format(Locale.US, "+%1$02d:%2$02d", minutesOffset / 60, minutesOffset % 60);

// Create a Calendar instance with the time zone set to GMT plus the formatted offset
Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("GMT" + formattedOffset), Locale.US);
// Initialize the calendar with the UTC milliseconds value
calendar.setTimeInMillis(utcMillis);

// Extract the date and time components from the calendar
int year = calendar.get(Calendar.YEAR);
int month = calendar.get(Calendar.MONTH) + 1; // Calendar.MONTH is zero-based
int day = calendar.get(Calendar.DAY_OF_MONTH);
int hour = calendar.get(Calendar.HOUR_OF_DAY);
int minute = calendar.get(Calendar.MINUTE);
int second = calendar.get(Calendar.SECOND);

// Create the ZoneOffset from the minutesOffset
ZoneOffset offset = ZoneOffset.ofTotalSeconds(minutesOffset * 60);

// Create and return the OffsetDateTime
return OffsetDateTime.of(year, month, day, hour, minute, second, nanos, offset);
}



/**
* Returns this DateTimeOffset object's offset value.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import static org.junit.Assert.fail;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.sql.Connection;
Expand Down Expand Up @@ -190,4 +192,78 @@ public void testConnectionDriver() throws SQLException {
}
}
}

/**
* test application name
*
* @throws SQLException
*/
@Test
public void testApplicationName() throws SQLException {
try (Connection conn = DriverManager.getConnection(connectionString);
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT program_name FROM sys.dm_exec_sessions WHERE session_id = @@SPID")) {
if (rs.next()) {
assertEquals(SQLServerDriver.constructedAppName, rs.getString("program_name"));
}
} catch (SQLException e) {
fail(e.getMessage());
}
}

/**
* test application name by executing select app_name()
*
* @throws SQLException
*/
@Test
public void testApplicationNameUsingApp_Name() throws SQLException {
try (Connection conn = DriverManager.getConnection(connectionString);
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT app_name()")) {
if (rs.next()) {
assertEquals(SQLServerDriver.constructedAppName, rs.getString(1));
}
} catch (SQLException e) {
fail(e.getMessage());
}
}

/**
* test application name by executing select app_name()
*
* @throws SQLException
*/
@Test
public void testAppNameWithSpecifiedApplicationName() throws SQLException {
String url = connectionString + ";applicationName={0123456789012345678901234567890123456789012345678901234567890123456789012345678901234589012345678901234567890123456789012345678}";

try (Connection conn = DriverManager.getConnection(url);
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT app_name()")) {
if (rs.next()) {
assertEquals("0123456789012345678901234567890123456789012345678901234567890123456789012345678901234589012345678901234567890123456789012345678", rs.getString(1));
}
} catch (SQLException e) {
fail(e.getMessage());
}
}

/**
* test application name when system properties are empty
*
*/
@Test
public void testGetAppName() {
String appName = SQLServerDriver.getAppName();
assertNotNull(appName, "Application name should not be null");
assertFalse(appName.isEmpty(), "Application name should not be empty");

System.setProperty("os.name", "");
System.setProperty("os.arch", "");
System.setProperty("java.vm.name", "");
System.setProperty("java.vm.version", "");
String defaultAppName = SQLServerDriver.getAppName();
assertEquals(SQLServerDriver.DEFAULT_APP_NAME, defaultAppName, "Application name should be the default one");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1945,6 +1945,34 @@ public void testDateTimeOffsetValueOfOffsetDateTime() throws Exception {
assertEquals(expected, DateTimeOffset.valueOf(roundUp).getOffsetDateTime());
assertEquals(expected, DateTimeOffset.valueOf(roundDown).getOffsetDateTime());
}

@Test
public void testPreGregorianDateTime() throws Exception {
try (Connection conn = getConnection();
Statement stmt = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_UPDATABLE);) {

conn.setAutoCommit(false);
TestUtils.dropTableIfExists(escapedTableName, stmt);

stmt.executeUpdate("CREATE TABLE " + escapedTableName + " (dob datetimeoffset(7) null)");
stmt.executeUpdate("INSERT INTO " + escapedTableName + " VALUES ('1500-12-16 00:00:00.0000000+08:00')");
stmt.executeUpdate("INSERT INTO " + escapedTableName + " VALUES ('1400-09-27 09:30:00.0000000+08:00')");
stmt.executeUpdate("INSERT INTO " + escapedTableName + " VALUES ('2024-12-16 23:40:00.0000000+08:00')");

try (ResultSet rs = stmt.executeQuery("select dob from " + escapedTableName + " order by dob")) {
while (rs.next()) {
String strDateTimeOffset = rs.getString(1).substring(0, 10);
DateTimeOffset objDateTimeOffset = (DateTimeOffset) rs.getObject(1);
OffsetDateTime objOffsetDateTime = objDateTimeOffset.getOffsetDateTime();

String strOffsetDateTime = objOffsetDateTime.toString().substring(0, 10);
assertEquals(strDateTimeOffset, strOffsetDateTime, "Mismatch found in DateTimeOffset : "
+ objDateTimeOffset + " and OffsetDateTime : " + objOffsetDateTime);
}
}
TestUtils.dropTableIfExists(escapedTableName, stmt);
}
}

static LocalDateTime getUnstorableValue() throws Exception {
ZoneId systemTimezone = ZoneId.systemDefault();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@

import java.lang.reflect.Field;
import java.sql.BatchUpdateException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Types;
Expand Down Expand Up @@ -124,6 +126,25 @@ public void testPreparedStatementWithSpPrepare() throws SQLException {
}
}
}

@Test
void testDatabaseQueryMetaData() throws SQLException {
try (Connection connection = getConnection()) {
try (SQLServerPreparedStatement stmt = (SQLServerPreparedStatement) connection.prepareStatement(
"select 1 as \"any questions ???\"")) {
ResultSetMetaData metaData = stmt.getMetaData();
String actualLabel = metaData.getColumnLabel(1);
String actualName = metaData.getColumnName(1);

String expected = "any questions ???";
assertEquals(expected, actualLabel, "Column label should match the expected value");
assertEquals(expected, actualName, "Column name should match the expected value");
}
} catch (SQLException e) {
e.printStackTrace();
fail("SQLException occurred during test: " + e.getMessage());
}
}

@Test
public void testPreparedStatementParamNameSpacingWithMultipleParams() throws SQLException {
Expand Down Expand Up @@ -927,5 +948,5 @@ private static void dropTables() throws Exception {
TestUtils.dropTableIfExists(AbstractSQLGenerator.escapeIdentifier(tableName5), stmt);
}
}

}

0 comments on commit 1480215

Please sign in to comment.