Skip to content

Commit

Permalink
Fixed #4489: SQL Anywhere incorrectly reports VARCHAR(n CHAR) as VARC…
Browse files Browse the repository at this point in the history
…HAR(n)

Cause: There is no way to detect the size unit in the JDBC standard.

Solution: Using a native query to detect the size unit.
  • Loading branch information
mkarg committed Jul 15, 2023
1 parent 664db3e commit 28f31bd
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -400,7 +400,7 @@ public List<CachedRow> fastFetchQuery() throws SQLException, DatabaseException {
SQL_FILTER_MATCH_ALL)
);
//
// IF MARIADB
// IF MARIADB OR SQL ANYWHERE
// Query to get actual data types and then map each column to its CachedRow
//
determineActualDataTypes(returnList, tableName);
Expand Down Expand Up @@ -431,7 +431,7 @@ public List<CachedRow> bulkFetchQuery() throws SQLException, DatabaseException {
escapeForLike(((AbstractJdbcDatabase) database).getJdbcSchemaName(catalogAndSchema), database),
SQL_FILTER_MATCH_ALL, SQL_FILTER_MATCH_ALL));
//
// IF MARIADB
// IF MARIADB OR SQL ANYWHERE
// Query to get actual data types and then map each column to its CachedRow
//
determineActualDataTypes(returnList, null);
Expand All @@ -449,11 +449,58 @@ public List<CachedRow> bulkFetchQuery() throws SQLException, DatabaseException {
// For MariaDB, query for the data type column so that we can correctly
// set the DATETIME(6) type if specified
//
// For SQL Anywhere, query for the scale column so we can correctly
// set the size unit
//
private void determineActualDataTypes(List<CachedRow> returnList, String tableName) {
//
// If not MariaDB then just return
// If not MariaDB / SQL Anywhere then just return
//
if (!(database instanceof MariaDBDatabase)) {
if (!(database instanceof MariaDBDatabase || database instanceof SybaseASADatabase)) {
return;
}

if (database instanceof SybaseASADatabase) {
//
// Query for actual data type for column. The actual SYSTABCOL.scale column value is
// not reported by the DatabaseMetadata.getColumns() query for CHAR-limited (in contrast
// to BYTE-limited) columns, and it is needed to capture the kind if limitation.
//
// See https://help.sap.com/docs/SAP_SQL_Anywhere/93079d4ba8e44920ae63ffb4def91f5b/3beaa3956c5f1014883cb0c3e3559cc9.html.
//
String selectStatement =
"SELECT table_name, column_name, scale FROM SYSTABCOL KEY JOIN SYSTAB KEY JOIN SYSUSER " +
"WHERE user_name = ? AND ? IS NULL OR table_name = ?";
Connection underlyingConnection = ((JdbcConnection) database.getConnection()).getUnderlyingConnection();
try (PreparedStatement stmt = underlyingConnection.prepareStatement(selectStatement)) {
stmt.setString(1, schemaName);
stmt.setString(2, tableName);
stmt.setString(3, tableName);
try (ResultSet columnSelectRS = stmt.executeQuery()) {
while (columnSelectRS.next()) {
String selectedTableName = columnSelectRS.getString("table_name");
String selectedColumnName = columnSelectRS.getString("column_name");
int selectedScale = columnSelectRS.getInt("scale");
for (CachedRow row : returnList) {
String rowTableName = row.getString("TABLE_NAME");
String rowColumnName = row.getString("COLUMN_NAME");
if (rowTableName.equalsIgnoreCase(selectedTableName) &&
rowColumnName.equalsIgnoreCase(selectedColumnName)) {
int rowDataType = row.getInt("DATA_TYPE");
if (rowDataType == Types.VARCHAR || rowDataType == Types.CHAR) {
row.set("scale", selectedScale);
}
break;
}
}
}
}
} catch (SQLException sqle) {
throw new RuntimeException(sqle);
//
// Do not stop
//
}
return;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,12 @@ protected DataType readDataType(CachedRow columnMetadataResultSet, Column column

DataType.ColumnSizeUnit columnSizeUnit = DataType.ColumnSizeUnit.BYTE;

if (database instanceof SybaseASADatabase &&
(columnMetadataResultSet.getInt("DATA_TYPE") == Types.VARCHAR || columnMetadataResultSet.getInt("DATA_TYPE") == Types.CHAR) &&
columnMetadataResultSet.getInt("scale") == 1) {
columnSizeUnit = DataType.ColumnSizeUnit.CHAR;
}

int dataType = columnMetadataResultSet.getInt("DATA_TYPE");
Integer columnSize = null;
Integer decimalDigits = null;
Expand Down

0 comments on commit 28f31bd

Please sign in to comment.