diff --git a/pom.xml b/pom.xml index 98b46104..d90e3fd7 100644 --- a/pom.xml +++ b/pom.xml @@ -335,7 +335,7 @@ false https://sonarcloud.io spannm - + true true diff --git a/src/main/java/net/ucanaccess/commands/AutoNumberAction.java b/src/main/java/net/ucanaccess/commands/AutoNumberAction.java index b809b0bb..656e925a 100644 --- a/src/main/java/net/ucanaccess/commands/AutoNumberAction.java +++ b/src/main/java/net/ucanaccess/commands/AutoNumberAction.java @@ -33,9 +33,9 @@ public AutoNumberAction(Table _table, Object[] memento, Object[] byAccess) throw oldAutoValues.put(col.getName(), cnOld); newAutoValues.put(col.getName(), cnNew); conn.setFeedbackState(true); - String stmt = "UPDATE " + SQLConverter.escapeIdentifier(_table.getName(), connHsqldb) + " SET " + cn - + "=? WHERE " + cn + "=?"; - try (PreparedStatement ps = connHsqldb.prepareStatement(stmt)) { + String sql = String.format("UPDATE %s SET %s=? WHERE %s=?", + SQLConverter.escapeIdentifier(_table.getName(), connHsqldb), cn, cn); + try (PreparedStatement ps = connHsqldb.prepareStatement(sql)) { ps.setObject(1, cnNew); ps.setObject(2, cnOld); ps.executeUpdate(); diff --git a/src/main/java/net/ucanaccess/commands/BlobAction.java b/src/main/java/net/ucanaccess/commands/BlobAction.java index bd628990..119507df 100644 --- a/src/main/java/net/ucanaccess/commands/BlobAction.java +++ b/src/main/java/net/ucanaccess/commands/BlobAction.java @@ -12,6 +12,7 @@ import java.sql.PreparedStatement; import java.sql.SQLException; import java.util.*; +import java.util.stream.Collectors; public class BlobAction implements IFeedbackAction { private final Table table; @@ -55,26 +56,23 @@ public void doAction(ICommand toChange) throws SQLException { Connection connHsqldb = conn.getHSQLDBConnection(); for (BlobKey bkey : keys) { - String sql = "UPDATE " + SQLConverter.escapeIdentifier(table.getName(), connHsqldb) + " SET " - + SQLConverter.escapeIdentifier(bkey.getColumnName(), connHsqldb) + "=? WHERE "; - StringBuilder sb = new StringBuilder(); - String and = ""; - List values = new ArrayList<>(); - for (Map.Entry me : bkey.getKey().entrySet()) { - sb.append(and).append(SQLConverter.escapeIdentifier(me.getKey(), connHsqldb)).append(" = ?"); - values.add(me.getValue()); - and = " AND "; - } - sql += sb.toString(); + + List values = new ArrayList<>(bkey.getKey().values()); + + String sql = String.format("UPDATE %s SET %s=? WHERE %s", + SQLConverter.escapeIdentifier(table.getName(), connHsqldb), + SQLConverter.escapeIdentifier(bkey.getColumnName(), connHsqldb), + bkey.getKey().keySet().stream().map(k -> SQLConverter.escapeIdentifier(k, connHsqldb) + " = ?").collect(Collectors.joining(" AND "))); + conn.setFeedbackState(true); conn.setFeedbackState(true); try (PreparedStatement ps = connHsqldb.prepareStatement(sql)) { ps.setObject(1, bkey.getBytes()); - int j = 2; + int i = 2; for (Object value : values) { - ps.setObject(j, value); - ++j; + ps.setObject(i, value); + i++; } ps.executeUpdate(); conn.setFeedbackState(false); diff --git a/src/main/java/net/ucanaccess/commands/DDLCommandEnlist.java b/src/main/java/net/ucanaccess/commands/DDLCommandEnlist.java index 858ccd43..821ab989 100644 --- a/src/main/java/net/ucanaccess/commands/DDLCommandEnlist.java +++ b/src/main/java/net/ucanaccess/commands/DDLCommandEnlist.java @@ -217,8 +217,7 @@ private String[] checkEscaped(String _ll, String _rl, String[] _colDecls, String } private void parseColumnTypes(List _typeList, List _defaultList, List _notNullList, String _tknt) { - - String[] colDecls = _tknt.split("[\\s\n\r]+"); + String[] colDecls = _tknt.split("\\s+"); colDecls = checkEscaped("[", "]", colDecls, _tknt); colDecls = checkEscaped("`", "`", colDecls, _tknt); String escaped = SQLConverter.isListedAsKeyword(colDecls[0].toUpperCase()) ? colDecls[0].toUpperCase() @@ -226,10 +225,10 @@ private void parseColumnTypes(List _typeList, List _defaultList, columnMap.put(escaped, colDecls[0]); boolean reset = false; - if (_tknt.matches("[\\s\n\r]*\\d+[\\s\n\r]*\\).*")) { + if (_tknt.matches("\\s*\\d+\\s*\\).*")) { reset = true; _tknt = _tknt.substring(_tknt.indexOf(')') + 1).trim(); - colDecls = _tknt.split("[\\s\n\r]+"); + colDecls = _tknt.split("\\s+"); } if (!reset && colDecls.length < 2) { @@ -263,16 +262,16 @@ private void parseColumnTypes(List _typeList, List _defaultList, } // getting AUTOINCREMENT and GUID + @SuppressWarnings("java:S5852") private void parseTypesFromCreateStatement(String _sql) throws SQLException { - _sql = _sql.replaceAll("([\\s\n\r]+)((?i)DECIMAL)([\\s\n\r]*\\()", "$1NUMERIC(") - .replaceAll("([\\s\n\r]+)((?i)NUMERIC)([\\s\n\r]*\\()", "$1NUMERIC("); - int startDecl = _sql.indexOf('('); - int endDecl = _sql.lastIndexOf(')'); + String sql = _sql.replaceAll("(\\s+)(?:(?i)DECIMAL|(?i)NUMERIC)\\s*\\(", "$1NUMERIC("); + int startDecl = sql.indexOf('('); + int endDecl = sql.lastIndexOf(')'); if (startDecl >= endDecl) { - throw new InvalidCreateStatementException(_sql); + throw new InvalidCreateStatementException(sql); } - String decl = _sql.substring(startDecl + 1, endDecl); + String decl = sql.substring(startDecl + 1, endDecl); String[] tokens = decl.split(","); List typeList = new ArrayList<>(); diff --git a/src/main/java/net/ucanaccess/console/Main.java b/src/main/java/net/ucanaccess/console/Main.java index d9598092..fefd5a60 100644 --- a/src/main/java/net/ucanaccess/console/Main.java +++ b/src/main/java/net/ucanaccess/console/Main.java @@ -15,6 +15,7 @@ import java.util.*; import java.util.stream.Collectors; +@SuppressWarnings("java:S106") // suppress sonarcloud warning to not use System.out/err public class Main { private static final String EXPORT_USAGE = "export [--help] [--bom] [-d ] [-t ] " + "[--big_query_schema ] " + "[--newlines] "; @@ -277,7 +278,6 @@ private void executeExport(String cmd) throws SQLException, IOException { // Process the command line flags. int i = 1; // skip the first token which will always be "export" - label: for (; i < tokens.size(); i++) { String arg = tokens.get(i); if (!arg.startsWith("-")) { @@ -322,7 +322,7 @@ private void executeExport(String cmd) throws SQLException, IOException { return; case "--": ++i; - break label; + break; default: prompt("Unknown flag " + arg); prompt(EXPORT_PROMPT); @@ -429,7 +429,7 @@ static class TableFormat { static final List NUMERIC_JDBC_TYPES = List.of(Types.BIT, Types.TINYINT, Types.SMALLINT, Types.INTEGER, Types.BIGINT, Types.FLOAT, Types.REAL, Types.DOUBLE, Types.NUMERIC, Types.DECIMAL, Types.ROWID); - private final int maxColWidth = 50; + private static final int MAX_COL_WIDTH = 50; private final List colNames; private final List colWidths; private final List colTypes; @@ -449,7 +449,7 @@ static class TableFormat { for (int col = 1; col <= columnCount; ++col) { String colLabel = meta.getColumnLabel(col); colNames.add(colLabel); - colWidths.add(Math.min(colLabel.length(), maxColWidth)); + colWidths.add(Math.min(colLabel.length(), MAX_COL_WIDTH)); colTypes.add(meta.getColumnType(col)); } @@ -467,7 +467,7 @@ static class TableFormat { rec.add(s); int colWidth = colWidths.get(col - 1); - if (colWidth < s.length() && colWidth < maxColWidth) { + if (colWidth < s.length() && colWidth < MAX_COL_WIDTH) { colWidths.set(col - 1, s.length()); } } diff --git a/src/main/java/net/ucanaccess/converters/Functions.java b/src/main/java/net/ucanaccess/converters/Functions.java index b96b028a..384ed246 100644 --- a/src/main/java/net/ucanaccess/converters/Functions.java +++ b/src/main/java/net/ucanaccess/converters/Functions.java @@ -11,6 +11,8 @@ import net.ucanaccess.ext.FunctionType; import net.ucanaccess.util.Try; +import java.lang.System.Logger; +import java.lang.System.Logger.Level; import java.math.BigDecimal; import java.math.MathContext; import java.math.RoundingMode; @@ -27,7 +29,9 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; +@SuppressWarnings("java:S2447") public final class Functions { + private static final Logger LOGGER = System.getLogger(Functions.class.getName()); private static Double rnd; private static Double lastRnd; private static final double APPROX = 0.00000001; @@ -110,7 +114,7 @@ public static double sqr(double _number) { @FunctionType(functionName = "CBool", argumentTypes = {AccessType.NUMERIC}, returnType = AccessType.YESNO) public static boolean cbool(BigDecimal _value) { - return cbool((Object) _value); + return cboolImpl(_value); } /** @@ -121,15 +125,15 @@ public static boolean cbool(BigDecimal _value) { */ @FunctionType(functionName = "CBool", argumentTypes = {AccessType.YESNO}, returnType = AccessType.YESNO) public static boolean cbool(Boolean _value) { - return cbool((Object) _value); + return cboolImpl(_value); } @FunctionType(functionName = "CBool", argumentTypes = {AccessType.MEMO}, returnType = AccessType.YESNO) public static boolean cbool(String _value) { - return cbool((Object) _value); + return cboolImpl(_value); } - private static boolean cbool(Object _obj) { + private static boolean cboolImpl(Object _obj) { if (_obj == null) { return false; } else if (_obj instanceof Boolean) { @@ -214,7 +218,6 @@ public static Integer clong(boolean _value) { return _value ? -1 : 0; } - // TODO @FunctionType(functionName = "CSign", argumentTypes = {AccessType.DOUBLE}, returnType = AccessType.SINGLE) public static double csign(double _value) { MathContext mc = new MathContext(7); @@ -226,7 +229,7 @@ public static double csign(double _value) { */ @FunctionType(functionName = "CStr", argumentTypes = {AccessType.YESNO}, returnType = AccessType.MEMO) public static String cstr(Boolean _value) throws UcanaccessSQLException { - return cstr((Object) _value); + return cstrImpl(_value); } @FunctionType(functionName = "CStr", argumentTypes = {AccessType.TEXT}, returnType = AccessType.MEMO) @@ -236,12 +239,12 @@ public static String cstr(String _value) { @FunctionType(functionName = "CStr", argumentTypes = {AccessType.DOUBLE}, returnType = AccessType.MEMO) public static String cstr(double _value) throws UcanaccessSQLException { - return cstr((Object) _value); + return cstrImpl(_value); } @FunctionType(functionName = "CStr", argumentTypes = {AccessType.LONG}, returnType = AccessType.MEMO) public static String cstr(int _value) throws UcanaccessSQLException { - return cstr((Object) _value); + return cstrImpl(_value); } @FunctionType(functionName = "CStr", argumentTypes = {AccessType.DATETIME}, returnType = AccessType.MEMO) @@ -249,7 +252,7 @@ public static String cstr(Timestamp _value) throws UcanaccessSQLException { return _value == null ? null : format(_value, "general date"); } - private static String cstr(Object _value) throws UcanaccessSQLException { + private static String cstrImpl(Object _value) throws UcanaccessSQLException { return _value == null ? null : format(_value.toString(), "", true); } @@ -547,7 +550,9 @@ private static Timestamp dateValue(String _dt, boolean _onlyDate) { t = new Timestamp(cl.getTime().getTime()); } return t; - } catch (ParseException _ignored) {} + } catch (ParseException _ignored) { + LOGGER.log(Level.DEBUG, "Ignoring {0}", _ignored.toString()); + } } return null; } @@ -658,8 +663,8 @@ public static String format(Timestamp _t, String _par) throws UcanaccessSQLExcep return String.valueOf(datePart(_par, _t)); } return createSimpleDateFormat(_par - .replace("m", "M") - .replace("n", "m") + .replace('m', 'M') + .replace('n', 'm') .replace("(?i)AM/PM|A/P|AMPM", "a") .replace("dddd", "EEEE")).format(_t); } @@ -668,33 +673,32 @@ public static String format(Timestamp _t, String _par) throws UcanaccessSQLExcep * Returns one of two parts, depending on the evaluation of an expression. */ @FunctionType(functionName = "IIf", argumentTypes = {AccessType.YESNO, AccessType.MEMO, AccessType.MEMO}, returnType = AccessType.MEMO) - public static String iif(Boolean _b, String _o, String _o1) { - return (String) iif(_b, _o, (Object) _o1); + public static String iif(Boolean _b, String _o1, String _o2) { + return iifImpl(_b, _o1, _o2); } @FunctionType(functionName = "IIf", argumentTypes = {AccessType.YESNO, AccessType.LONG, AccessType.LONG}, returnType = AccessType.LONG) - public static Integer iif(Boolean b, Integer o, Integer o1) { - return (Integer) iif(b, o, (Object) o1); + public static Integer iif(Boolean _b, Integer _o1, Integer _o2) { + return iifImpl(_b, _o1, _o2); } @FunctionType(functionName = "IIf", argumentTypes = {AccessType.YESNO, AccessType.DOUBLE, AccessType.DOUBLE}, returnType = AccessType.DOUBLE) - public static Double iif(Boolean b, Double o, Double o1) { - return (Double) iif(b, o, (Object) o1); + public static Double iif(Boolean _b, Double _o1, Double _o2) { + return iifImpl(_b, _o1, _o2); } @FunctionType(functionName = "IIf", argumentTypes = {AccessType.YESNO, AccessType.YESNO, AccessType.YESNO}, returnType = AccessType.YESNO) - public static Boolean iif(Boolean b, Boolean o, Boolean o1) { - - return (Boolean) iif(b, o, (Object) o1); + public static Boolean iif(Boolean _b, Boolean _o1, Boolean _o2) { + return iifImpl(_b, _o1, _o2); } @FunctionType(functionName = "IIf", argumentTypes = {AccessType.YESNO, AccessType.DATETIME, AccessType.DATETIME}, returnType = AccessType.DATETIME) - public static Timestamp iif(Boolean b, Timestamp o, Timestamp o1) { - return (Timestamp) iif(b, o, (Object) o1); + public static Timestamp iif(Boolean b, Timestamp _o1, Timestamp _o2) { + return iifImpl(b, _o1, _o2); } - private static Object iif(Boolean _b, Object _o1, Object _o2) { - return Objects.requireNonNullElse(_b, Boolean.FALSE) ? _o1 : _o2; + private static T iifImpl(Boolean _b, T _o1, T _o2) { + return _b != null && _b ? _o1 : _o2; } /** @@ -1064,9 +1068,7 @@ public static String weekdayName(int _number, boolean _abbreviate) { public static String weekdayName(int _number, boolean _abbreviate, int _firstDayOfWeek) { // DayOfWeek starts with Monday, WeekdayName with Sunday (default) int firstDayOfWeek = Math.min(Math.max(1, _firstDayOfWeek), 7); - int offset = firstDayOfWeek == 1 ? -1 - : firstDayOfWeek == 1 ? -1 - : firstDayOfWeek - 2; + int offset = firstDayOfWeek == 1 ? -1 : firstDayOfWeek - 2; int number = _number; while (number > 7) { number -= 7; @@ -1075,10 +1077,6 @@ public static String weekdayName(int _number, boolean _abbreviate, int _firstDay .getDisplayName(_abbreviate ? TextStyle.SHORT : TextStyle.FULL, Locale.getDefault()); } - public static void main(String[] args) { - System.out.println("WeekDayName(3): " + weekdayName(3)); - } - /** * Returns a number representing the day of the week (a number from 1 to 7) given a date value. */ @@ -1485,16 +1483,12 @@ public static Boolean formulaToBoolean(Boolean res, String datatype) { @FunctionType(functionName = "formulaToBoolean", argumentTypes = {AccessType.DOUBLE, AccessType.MEMO}, returnType = AccessType.YESNO) public static Boolean formulaToBoolean(Double res, String datatype) { - if (res == null) { - return null; - } - return res != 0d; + return res == null ? null : res != 0d; } @FunctionType(functionName = "formulaToBoolean", argumentTypes = {AccessType.DATETIME, AccessType.MEMO}, returnType = AccessType.YESNO) public static Boolean formulaToBoolean(Timestamp res, String datatype) { return null; - } @FunctionType(functionName = "formulaToBoolean", argumentTypes = {AccessType.MEMO, AccessType.MEMO}, returnType = AccessType.YESNO) @@ -1507,7 +1501,6 @@ public static Boolean formulaToBoolean(String res, String datatype) { return false; } return null; - } @FunctionType(functionName = "formulaToText", argumentTypes = {AccessType.MEMO, AccessType.MEMO}, returnType = AccessType.MEMO) diff --git a/src/main/java/net/ucanaccess/converters/LoadJet.java b/src/main/java/net/ucanaccess/converters/LoadJet.java index 625e09ec..2b4cda24 100644 --- a/src/main/java/net/ucanaccess/converters/LoadJet.java +++ b/src/main/java/net/ucanaccess/converters/LoadJet.java @@ -40,6 +40,7 @@ import java.util.stream.IntStream; import java.util.stream.Stream; +@SuppressWarnings({"java:S1192", "java:S2692"}) // suppress sonarcloud warnings public class LoadJet { private static final AtomicInteger NAMING_COUNTER = new AtomicInteger(0); @@ -99,7 +100,7 @@ private static boolean hasAutoNumberColumn(Table t) { return false; } - public void addFunctions(Class _clazz) throws SQLException { + public void addFunctions(Class _clazz) { functionsLoader.addFunctions(_clazz, false); } @@ -181,7 +182,7 @@ public void synchronisationTriggers(String tableName, boolean hasAutoNumberColum public Object tryDefault(Object _default) { try (Statement st = conn.createStatement()) { - ResultSet rs = st.executeQuery("SELECT " + _default + " FROM DUAL"); + ResultSet rs = st.executeQuery(String.format("SELECT %s FROM DUAL", _default)); if (rs.next()) { return rs.getObject(1); } @@ -353,7 +354,7 @@ private String getAggregate(String _functionName, String _type) { + "EXTERNAL NAME 'CLASSPATH:net.ucanaccess.converters.FunctionsAggregate." + _functionName + "'"; } - private void loadMappedFunctions() throws SQLException { + private void loadMappedFunctions() { addFunctions(Functions.class, true); addAggregates(); createFunctions(); @@ -558,7 +559,7 @@ private void createSyncrTable(Table _t, boolean _systemTable, boolean _constrain PropertyMap pm = col.getProperties(); Object required = pm.getValue(PropertyMap.REQUIRED_PROP); - if (_constraints && required instanceof Boolean && (Boolean) required) { + if (_constraints && required instanceof Boolean && (boolean) required) { sbC.append(" NOT NULL "); } comma = ","; @@ -649,33 +650,33 @@ private String defaultValue4SQL(Object defaulT, DataType dt) { private void setDefaultValue(Column _col, String _ntn, List _arTrigger) throws IOException, SQLException { PropertyMap pm = _col.getProperties(); String ncn = procedureEscapingIdentifier(_col.getName()); - Object defaulT = pm.getValue(PropertyMap.DEFAULT_VALUE_PROP); - if (defaulT != null) { - String default4SQL = defaultValue4SQL(defaulT, _col.getType()); + Object defVal = pm.getValue(PropertyMap.DEFAULT_VALUE_PROP); + if (defVal != null) { + String default4SQL = defaultValue4SQL(defVal, _col.getType()); String guidExp = "GenGUID()"; - if (!guidExp.equals(defaulT)) { - boolean defaultIsFunction = - defaulT.toString().trim().endsWith(")") && defaulT.toString().indexOf('(') > 0; - if (defaultIsFunction) { - metadata.columnDef(_col.getTable().getName(), _col.getName(), defaulT.toString()); + if (!guidExp.equals(defVal)) { + boolean defIsFunction = + defVal.toString().trim().endsWith(")") && defVal.toString().indexOf('(') > 0; + if (defIsFunction) { + metadata.columnDef(_col.getTable().getName(), _col.getName(), defVal.toString()); } Object defFound = default4SQL; boolean isNull = (default4SQL + "").equalsIgnoreCase("null"); if (!isNull && (defFound = tryDefault(default4SQL)) == null) { - logger.log(Level.WARNING, "Unknown expression: {0} (default value of column {1} table {2})", "" + defaulT, _col.getName(), + logger.log(Level.WARNING, "Unknown expression: {0} (default value of column {1} table {2})", "" + defVal, _col.getName(), _col.getTable().getName()); } else { - if (defFound != null && !defaultIsFunction) { + if (defFound != null && !defIsFunction) { metadata.columnDef(_col.getTable().getName(), _col.getName(), defFound.toString()); } - if (_col.getType() == DataType.TEXT && defaulT.toString().startsWith("'") - && defaulT.toString().endsWith("'") - && defaulT.toString().length() > _col.getLengthInUnits()) { + if (_col.getType() == DataType.TEXT && defVal.toString().startsWith("'") + && defVal.toString().endsWith("'") + && defVal.toString().length() > _col.getLengthInUnits()) { logger.log(Level.WARNING, "Default values should start and end with a double quote, " + "the single quote is considered as part of the default value {0} " + "(column {1},table {2}). It may result in a data truncation error at run-time due to max column size {3}", - defaulT, _col.getName(), _col.getTable().getName(), _col.getLengthInUnits()); + defVal, _col.getName(), _col.getTable().getName(), _col.getLengthInUnits()); } _arTrigger.add("CREATE TRIGGER DEFAULT_TRIGGER" + NAMING_COUNTER.getAndIncrement() + " BEFORE INSERT ON " + _ntn + " REFERENCING NEW ROW AS NEW FOR EACH ROW IF NEW." + ncn + " IS NULL THEN " diff --git a/src/main/java/net/ucanaccess/converters/Metadata.java b/src/main/java/net/ucanaccess/converters/Metadata.java index ba250376..54b7a617 100644 --- a/src/main/java/net/ucanaccess/converters/Metadata.java +++ b/src/main/java/net/ucanaccess/converters/Metadata.java @@ -7,6 +7,8 @@ import net.ucanaccess.type.ObjectType; import net.ucanaccess.util.Try; +import java.lang.System.Logger; +import java.lang.System.Logger.Level; import java.sql.*; import java.util.ArrayList; import java.util.Arrays; @@ -15,6 +17,8 @@ public class Metadata { + private static final Logger LOGGER = System.getLogger(Metadata.class.getName()); + private static final String SCHEMA = "CREATE SCHEMA UCA_METADATA AUTHORIZATION DBA"; private static final String TABLES = @@ -33,6 +37,7 @@ public class Metadata { * @author Markus Spann * @since v5.1.0 */ + @SuppressWarnings("java:S115") // suppress sonarcloud warning regarding constant names public enum Property { user(String.class, null, 500), password(String.class, null, 500), @@ -232,7 +237,7 @@ public void newColumn(String _name, String _escaped, String _originalType, Integ ps.setInt(4, _idTable); ps.executeUpdate(); } catch (SQLException _ignored) { - + LOGGER.log(Level.DEBUG, "Ignoring {0}", _ignored.toString()); } } @@ -245,7 +250,7 @@ public List getColumnNames(String _tableName) throws SQLException { result.add(rs.getString(COLUMN_NAME)); } return !SYSTEM_SUBQUERY.equals(_tableName) ? result : null; - }).orThrow(); + }).orThrow(ex -> ex); } public String getColumnName(String _escapedTableName, String _escapedColumnName) throws SQLException { @@ -260,7 +265,7 @@ public String getColumnName(String _escapedTableName, String _escapedColumnName) } } return null; - }).orThrow(); + }).orThrow(ex -> ex); } public String getEscapedColumnName(String _tableName, String _columnName) throws SQLException { @@ -269,7 +274,7 @@ public String getEscapedColumnName(String _tableName, String _columnName) throws ps.setString(2, _columnName); ResultSet rs = ps.executeQuery(); return rs.next() ? rs.getString(ESCAPED_COLUMN_NAME) : null; - }).orThrow(); + }).orThrow(ex -> ex); } public String getEscapedTableName(String _tableName) throws SQLException { @@ -277,7 +282,7 @@ public String getEscapedTableName(String _tableName) throws SQLException { ps.setString(1, _tableName); ResultSet rs = ps.executeQuery(); return rs.next() ? rs.getString(ESCAPED_TABLE_NAME) : null; - }).orThrow(); + }).orThrow(ex -> ex); } public boolean isAutoIncrement(String _tableName, String _columnName) throws SQLException { @@ -286,7 +291,7 @@ public boolean isAutoIncrement(String _tableName, String _columnName) throws SQL ps.setString(2, _columnName); ResultSet rs = ps.executeQuery(); return rs.next() && rs.getBoolean(IS_AUTOINCREMENT); - }).orThrow(); + }).orThrow(ex -> ex); } public boolean isCurrency(String _tableName, String _columnName) throws SQLException { @@ -295,7 +300,7 @@ public boolean isCurrency(String _tableName, String _columnName) throws SQLExcep ps.setString(2, _columnName); ResultSet rs = ps.executeQuery(); return rs.next() && rs.getBoolean(IS_CURRENCY); - }).orThrow(); + }).orThrow(ex -> ex); } public Integer getTableId(String _escapedName) throws SQLException { @@ -303,7 +308,7 @@ public Integer getTableId(String _escapedName) throws SQLException { ps.setString(1, _escapedName); ResultSet rs = ps.executeQuery(); return rs.next() ? rs.getInt(TABLE_ID) : -1; - }).orThrow(); + }).orThrow(ex -> ex); } public String getTableName(String _escapedName) throws SQLException { @@ -311,14 +316,14 @@ public String getTableName(String _escapedName) throws SQLException { ps.setString(1, _escapedName); ResultSet rs = ps.executeQuery(); return rs.next() ? rs.getString(TABLE_NAME) : null; - }).orThrow(); + }).orThrow(ex -> ex); } public void dropTable(String _tableName) throws SQLException { Try.withResources(() -> conn.prepareStatement(DROP_TABLE), ps -> { ps.setString(1, _tableName); ps.execute(); - }).orThrow(); + }).orThrow(ex -> ex); } public void columnDef(String _tableName, String _columnName, String _def) throws SQLException { @@ -327,7 +332,7 @@ public void columnDef(String _tableName, String _columnName, String _def) throws ps.setString(2, _columnName); ps.setString(3, _tableName); ps.execute(); - }).orThrow(); + }).orThrow(ex -> ex); } public void calculatedField(String _tableName, String _columnName) throws SQLException { @@ -335,7 +340,7 @@ public void calculatedField(String _tableName, String _columnName) throws SQLExc ps.setString(1, _columnName); ps.setString(2, _tableName); ps.execute(); - }).orThrow(); + }).orThrow(ex -> ex); } public void rename(String _oldTableName, String _newTableName, String _newEscapedTableName) throws SQLException { @@ -344,7 +349,7 @@ public void rename(String _oldTableName, String _newTableName, String _newEscape ps.setString(2, _newEscapedTableName); ps.setString(3, _oldTableName); ps.executeUpdate(); - }).orThrow(); + }).orThrow(ex -> ex); } } diff --git a/src/main/java/net/ucanaccess/converters/ParametricQuery.java b/src/main/java/net/ucanaccess/converters/ParametricQuery.java index 8a25bf31..874d39f1 100644 --- a/src/main/java/net/ucanaccess/converters/ParametricQuery.java +++ b/src/main/java/net/ucanaccess/converters/ParametricQuery.java @@ -8,6 +8,7 @@ import java.util.*; import java.util.regex.Pattern; +@SuppressWarnings("java:S2692") // suppress sonarcloud warnings public class ParametricQuery { private final Connection hsqldb; private final QueryImpl qi; diff --git a/src/main/java/net/ucanaccess/converters/Persist2Jet.java b/src/main/java/net/ucanaccess/converters/Persist2Jet.java index 27728d8a..7fb4e675 100644 --- a/src/main/java/net/ucanaccess/converters/Persist2Jet.java +++ b/src/main/java/net/ucanaccess/converters/Persist2Jet.java @@ -426,7 +426,7 @@ public void createTable(String tableName, Map columnMap, String[ lj.loadDefaultValues(table); createForeignKeys(tableName); try (UcanaccessStatement st = conn.createStatement()) { - ResultSet rs = st.executeQuery("SELECT * FROM " + tableName); + ResultSet rs = st.executeQuery(String.format("SELECT * FROM %s", tableName)); List clns = getColumnNamesCreate(tn); while (rs.next()) { Object[] rec = new Object[clns.size()]; diff --git a/src/main/java/net/ucanaccess/converters/Pivot.java b/src/main/java/net/ucanaccess/converters/Pivot.java index 02e9d2fc..fdc5276b 100644 --- a/src/main/java/net/ucanaccess/converters/Pivot.java +++ b/src/main/java/net/ucanaccess/converters/Pivot.java @@ -16,11 +16,10 @@ import java.util.regex.Pattern; public class Pivot { - private static final Pattern PIVOT_PATT = - Pattern.compile("(?i)TRANSFORM(.*\\W)(?i)SELECT(.*\\W)(?i)FROM(.*\\W)(?i)PIVOT(.*)"); - private static final Pattern PIVOT_EXPR_PATT = Pattern.compile("(.*)(?i)IN\\s*\\((.*)\\)"); - private static final Pattern PIVOT_AGGR_PATT = - Pattern.compile("((?i)SUM|MAX|MIN|FIRST|LAST|AVG|COUNT|STDEV|VAR)\\s*\\((.*)\\)"); + @SuppressWarnings("java:S5852") + private static final Pattern PIVOT_PATT = Pattern.compile("TRANSFORM(.*\\W)SELECT(.*\\W)FROM(.*\\W)PIVOT(.*)", Pattern.CASE_INSENSITIVE); + private static final Pattern PIVOT_EXPR_PATT = Pattern.compile("(.*)IN\\s*\\((.*)\\)", Pattern.CASE_INSENSITIVE); + private static final Pattern PIVOT_AGGR_PATT = Pattern.compile("(SUM|MAX|MIN|FIRST|LAST|AVG|COUNT|STDEV|VAR)\\s*\\((.*)\\)", Pattern.CASE_INSENSITIVE); private static final Pattern PIVOT_CN_PATT = Pattern.compile("[\"'#](.*)[\"'#]"); private static final String PIVOT_GROUP_BY = "(?i)GROUP\\s*(?i)BY"; @@ -31,7 +30,7 @@ public class Pivot { private String select; private String from; private String expression; - private String pivot; + private String pivotStr; private List pivotIn; private String aggregateFun; private final Connection conn; @@ -135,15 +134,15 @@ public boolean parsePivot(String _originalQuery) { select = mtc.group(2); from = mtc.group(3); String pe = mtc.group(4); - Matcher mtcExpr = PIVOT_EXPR_PATT.matcher(pe); - if (mtcExpr.find()) { - if (mtcExpr.groupCount() < 2) { + Matcher matcher = PIVOT_EXPR_PATT.matcher(pe); + if (matcher.find()) { + if (matcher.groupCount() < 2) { return false; } - pivot = mtcExpr.group(1); - pivotIn = Arrays.asList(mtcExpr.group(2).split(",")); + pivotStr = matcher.group(1); + pivotIn = Arrays.asList(matcher.group(2).split(",")); } else { - pivot = pe; + pivotStr = pe; } return true; } else { @@ -159,8 +158,8 @@ private void appendCaseWhen(StringBuilder _sb, String _condition, String _cn) { public String verifySQL() { StringBuilder sb = new StringBuilder(); String[] fromS = from.split(PIVOT_GROUP_BY); - sb.append("SELECT DISTINCT ").append(pivot).append(" AS PIVOT ") - .append(" FROM ").append(fromS[0]).append(" GROUP BY ").append(pivot).append(",").append(fromS[1]); + sb.append("SELECT DISTINCT ").append(pivotStr).append(" AS PIVOT ") + .append(" FROM ").append(fromS[0]).append(" GROUP BY ").append(pivotStr).append(",").append(fromS[1]); return SQLConverter.convertSQL(sb.toString()).getSql(); } @@ -192,24 +191,24 @@ private String format(Object cln) { SimpleDateFormat sdf = new SimpleDateFormat("#MM/dd/yyyy HH:mm:ss#"); String clns = sdf.format((Date) cln); if (clns.endsWith(" 00:00:00#")) { - clns = clns.replaceAll(" 00:00:00", ""); + clns = clns.replace(" 00:00:00", ""); } return clns; } else if (cln instanceof String) { - return "'" + cln.toString().replaceAll("'", "''") + "'"; + return "'" + cln.toString().replace("'", "''") + "'"; } return cln.toString(); } private String replaceQuotation(String cn) { - cn = cn.replaceAll("\n", " ").replaceAll("\r", " "); + cn = cn.replaceAll("[\n\\r]", " "); Matcher dcm = PIVOT_CN_PATT.matcher(cn); if (dcm.matches()) { cn = dcm.group(1); } - cn = cn.replaceAll("'", "").replaceAll("\"", ""); + cn = cn.replace("'", "").replace("\"", ""); return "[" + cn + "]"; } @@ -230,7 +229,7 @@ public String toSQL(String name) { .append(select); for (String s : pivotIn) { sb.append(","); - appendCaseWhen(sb, pivot + "=" + s, replaceQuotation(s)); + appendCaseWhen(sb, pivotStr + "=" + s, replaceQuotation(s)); } sb.append(" FROM ").append(from); diff --git a/src/main/java/net/ucanaccess/converters/RegionalSettings.java b/src/main/java/net/ucanaccess/converters/RegionalSettings.java index cb529ad0..1c9f12ea 100644 --- a/src/main/java/net/ucanaccess/converters/RegionalSettings.java +++ b/src/main/java/net/ucanaccess/converters/RegionalSettings.java @@ -118,7 +118,7 @@ public Map getDateFormats() { void addDateP(String _pattern, boolean _heuristic, boolean _yearOverride) { if (_heuristic && !_pattern.contains("a") && _pattern.indexOf('H') > 0) { - String chg = _pattern.replaceAll("H", "h") + " a"; + String chg = _pattern.replace('H', 'h') + " a"; addDateP(chg, false, false); addTogglePattern(chg); } @@ -139,7 +139,7 @@ void addDateP(String _pattern, boolean _heuristic, boolean _yearOverride) { if (_heuristic) { addTogglePattern(_pattern); if (_pattern.endsWith(" a") && _pattern.indexOf('h') > 0) { - String chg = _pattern.substring(0, _pattern.length() - 2).trim().replaceAll("h", "H"); + String chg = _pattern.substring(0, _pattern.length() - 2).trim().replace('h', 'H'); addDateP(chg, false, false); addTogglePattern(chg); } @@ -150,9 +150,9 @@ void addDateP(String _pattern, boolean _heuristic, boolean _yearOverride) { void addTogglePattern(String _p) { if (_p.indexOf('/') > 0) { - addDateP(_p.replaceAll("/", "-"), false, false); + addDateP(_p.replace('/', '-'), false, false); if (isPointDateSeparator()) { - addDateP(_p.replaceAll("/", "."), false, false); + addDateP(_p.replace('/', '.'), false, false); } } else if (_p.indexOf('-') > 0) { addDateP(_p.replaceAll(Pattern.quote("-"), "/"), false, false); @@ -170,15 +170,8 @@ public static RegionalSettings getRegionalSettings() { } public static RegionalSettings getRegionalSettings(Locale _locale) { - if (_locale == null) { - _locale = Locale.getDefault(); - } - RegionalSettings rs = REG_MAP.get(_locale); - if (rs == null) { - rs = new RegionalSettings(_locale); - REG_MAP.put(_locale, rs); - } - return rs; + Locale locale = Objects.requireNonNullElseGet(_locale, Locale::getDefault); + return REG_MAP.computeIfAbsent(locale, RegionalSettings::new); } @Override diff --git a/src/main/java/net/ucanaccess/converters/SQLConverter.java b/src/main/java/net/ucanaccess/converters/SQLConverter.java index f12fc873..b7a49284 100644 --- a/src/main/java/net/ucanaccess/converters/SQLConverter.java +++ b/src/main/java/net/ucanaccess/converters/SQLConverter.java @@ -16,48 +16,47 @@ public final class SQLConverter { private static final Pattern QUOTE_S_PATTERN = Pattern.compile("(')+"); private static final Pattern DOUBLE_QUOTE_S_PATTERN = Pattern.compile("(\")+"); - private static final Pattern SELECT_FROM_PATTERN_START = Pattern.compile("[\\s\n\r]*(?i)SELECT[\\s\n\r]+"); - private static final Pattern SELECT_FROM_PATTERN_END = Pattern.compile("[\\s\n\r]*(?i)FROM[\\s\n\r\\[]+"); - private static final Pattern UNESCAPED_ALIAS = Pattern.compile("[\\s\n\r]*(?i)AS[\\s\n\r]*"); + private static final Pattern SELECT_FROM_PATTERN_START = Pattern.compile("\\s*SELECT\\s+", Pattern.CASE_INSENSITIVE); + private static final Pattern SELECT_FROM_PATTERN_END = Pattern.compile("\\s*FROM[\\s\\[]+", Pattern.CASE_INSENSITIVE); + private static final Pattern UNESCAPED_ALIAS = Pattern.compile("\\s*AS\\s*", Pattern.CASE_INSENSITIVE); private static final Pattern QUOTE_M_PATTERN = Pattern.compile("'(([^'])*)'"); private static final Pattern DOUBLE_QUOTE_M_PATTERN = Pattern.compile("\"(([^\"])*)\""); private static final Pattern FIND_LIKE_PATTERN = Pattern - .compile("[\\s\n\r\\(]*([\\w\\.]*)([\\s\n\r\\)]*)((?i)NOT[\\s\n\r]*)*(?i)LIKE[\\s\n\r]*'([^']*(?:'')*)'"); + .compile("[\\s\\(]*([\\w\\.]*)([\\s\\)]*)(NOT\\s*)*LIKE\\s*'([^']*(?:'')*)'", Pattern.CASE_INSENSITIVE); private static final Pattern ACCESS_LIKE_CHARINTERVAL_PATTERN = Pattern.compile("\\[(?:\\!*[a-zA-Z0-9]\\-[a-zA-Z0-9])+\\]"); private static final Pattern ACCESS_LIKE_ESCAPE_PATTERN = Pattern.compile("\\[[\\*|_|#]\\]"); private static final Pattern CHECK_DDL = - Pattern.compile("^([\n\r\\s]*(?i)(create|alter|drop|enable|disable))[\n\r\\s]+.*"); + Pattern.compile("^([\n\r\\s]*(create|alter|drop|enable|disable))[\n\r\\s]+.*", Pattern.CASE_INSENSITIVE); private static final Pattern KIND_OF_SUBQUERY = - Pattern.compile("(\\[)(((?i) FROM )*((?i)SELECT )*([^\\]])*)(\\]\\.[\\s\n\r])"); + Pattern.compile("(\\[)(( FROM )*(SELECT )*([^\\]])*)(\\]\\.\\s)", Pattern.CASE_INSENSITIVE); - private static final Pattern NO_DATA_PATTERN = Pattern.compile(" (?i)WITH[\\s\n\r]+(?i)NO[\\s\n\r]+(?i)DATA"); + private static final Pattern NO_DATA_PATTERN = Pattern.compile(" WITH\\s+NO\\s+DATA", Pattern.CASE_INSENSITIVE); private static final Pattern NO_ALFANUMERIC = Pattern.compile("\\W"); private static final String IDENTITY = "(\\W+)((?i)@@identity)(\\W*)"; - private static final Pattern SELECT_IDENTITY = Pattern.compile("(?i)select[\\s\n\r]+(?i)@@identity.*"); - private static final Pattern HAS_FROM = Pattern.compile("[\\s\n\r]+(?i)from[\\s\n\r]+"); + private static final Pattern SELECT_IDENTITY = Pattern.compile("select\\s+@@identity.*", Pattern.CASE_INSENSITIVE); + private static final Pattern HAS_FROM = Pattern.compile("\\s+from\\s+", Pattern.CASE_INSENSITIVE); private static final Pattern FORMULA_DEPENDENCIES = Pattern.compile("\\[([^\\]]*)\\]"); private static final String EXCLAMATION_POINT = "(\\!)([\n\r\\s]*)([^\\=])"; private static final String YES = "(\\W)((?i)YES)(\\W)"; private static final String NO = "(\\W)((?i)NO)(\\W)"; - private static final String WITH_OWNERACCESS_OPTION = - "(\\W)(?i)WITH[\\s\n\r]+(?i)OWNERACCESS[\\s\n\r]+(?i)OPTION(\\W)"; - private static final Pattern DIGIT_STARTING_IDENTIFIERS = - Pattern.compile("(\\W)(([0-9])+(([_a-zA-Z])+([0-9])*)+)(\\W)"); + private static final String WITH_OWNERACCESS_OPTION = "(\\W)(?i)WITH\\s+(?i)OWNERACCESS\\s+(?i)OPTION(\\W)"; + @SuppressWarnings({"java:S5852", "java:S5998"}) + private static final Pattern DIGIT_STARTING_IDENTIFIERS = Pattern.compile("(\\W)(([0-9])+(([_a-zA-Z])+([0-9])*)+)(\\W)"); private static final String UNDERSCORE_IDENTIFIERS = "(\\W)((_)+([_a-zA-Z0-9])+)(\\W)"; private static final String XESCAPED = "(\\W)((?i)X)((?i)_)(\\W)"; private static final String[] DEFAULT_CATCH = new String[] { - "([\\s\n\r]*(?i)DEFAULT[\\s\n\r]+)('(?:[^']*(?:'')*)*')([\\s\n\r\\)\\,])", - "([\\s\n\r]*(?i)DEFAULT[\\s\n\r]+)(\"(?:[^\"]*(?:\"\")*)*\")([\\s\n\r\\)\\,])", - "([\\s\n\r]*(?i)DEFAULT[\\s\n\r]+)([0-9\\.\\-\\+]+)([\\s\n\r\\)\\,])", - "([\\s\n\r]*(?i)DEFAULT[\\s\n\r]+)([_0-9a-zA-Z]*\\([^\\)]*\\))([\\s\n\r\\)\\,])"}; - private static final Pattern DEFAULT_CATCH_0 = Pattern.compile("([\\s\n\r]*(?i)DEFAULT[\\s\n\r]+)"); - public static final String NOT_NULL = "[\\s\n\r](?i)NOT[\\s\n\r](?i)NULL"; - - private static final Pattern QUOTED_ALIAS = - Pattern.compile("([\\s\n\r]+(?i)AS[\\s\n\r]*)(\\[[^\\]]*\\])(\\W)"); + "(\\s*(?i)DEFAULT\\s+)('(?:[^']*(?:'')*)*')([\\s\\)\\,])", + "(\\s*(?i)DEFAULT\\s+)(\"(?:[^\"]*(?:\"\")*)*\")([\\s\\)\\,])", + "(\\s*(?i)DEFAULT\\s+)([0-9\\.\\-\\+]+)([\\s\\)\\,])", + "(\\s*(?i)DEFAULT\\s+)([_0-9a-zA-Z]*\\([^\\)]*\\))([\\s\\)\\,])"}; + @SuppressWarnings("java:S5852") + private static final Pattern DEFAULT_CATCH_0 = Pattern.compile("(\\s*DEFAULT\\s+)", Pattern.CASE_INSENSITIVE); + public static final String NOT_NULL = "\\s(?i)NOT\\s(?i)NULL"; + + private static final Pattern QUOTED_ALIAS = Pattern.compile("(\\s+AS\\s*)(\\[[^\\]]*\\])(\\W)", Pattern.CASE_INSENSITIVE); private static final String TYPES_TRANSLATE = "(?i)_(\\W)"; public static final String DATE_ACCESS_FORMAT = "(0[1-9]|[1-9]|1[012])/(0[1-9]|[1-9]|[12][0-9]|3[01])/(\\d\\d\\d\\d)"; @@ -70,18 +69,17 @@ public final class SQLConverter { "([0-9]|0[0-9]|1[0-9]|2[0-4]):([0-9]|[0-5][0-9]):([0-5][0-9]|[0-9])"; private static final String NAME_PATTERN = "(([_a-zA-Z0-9])+|\\[([^\\]])*\\]|`([^`])*`)"; private static final int NAME_PATTERN_STEP = 4; - private static final String UNION = "(;)([\\s\n\r]*)((?i)UNION)([\\s\n\r]*)"; - private static final String DISTINCT_ROW = "[\\s\n\r]+(?i)DISTINCTROW[\\s\n\r]+"; - private static final String DEFAULT_VARCHAR = "(\\W)(?i)VARCHAR([\\s\n\r,\\)])"; - - private static final String DEFAULT_VARCHAR_0 = "(\\W)(?i)VARCHAR([^\\(])"; - private static final String BACKTRIK = "(`)([^`]*)(`)"; - private static final String DELETE_ALL = - "((?i)DELETE[\\s\n\r]+)(\\*)([\\s\n\r]+(?i)FROM[\\s\n\r]+)"; - private static final String PARAMETERS = "(?i)PARAMETERS([^;]*);"; - private static final Pattern ESPRESSION_DIGIT = Pattern.compile("([\\d]+)(?![\\.\\d])"); - private static final String BIG_BANG = "1899-12-30"; - private static final List KEYWORDLIST = List.of("ALL", "AND", "ANY", + private static final String UNION = "(;)(\\s*)((?i)UNION)(\\s*)"; + private static final String DISTINCT_ROW = "\\s+(?i)DISTINCTROW\\s+"; + private static final String DEFAULT_VARCHAR = "(\\W)(?i)VARCHAR([\\s,\\)])"; + + private static final String DEFAULT_VARCHAR_0 = "(\\W)(?i)VARCHAR([^\\(])"; + private static final String BACKTICK = "(`)([^`]*)(`)"; + private static final String DELETE_ALL = "((?i)DELETE\\s+)(\\*)(\\s+(?i)FROM\\s+)"; + private static final String PARAMETERS = "(?i)PARAMETERS([^;]*);"; + private static final Pattern ESPRESSION_DIGIT = Pattern.compile("([\\d]+)(?![\\.\\d])"); + private static final String BIG_BANG = "1899-12-30"; + private static final List KEYWORDLIST = List.of("ALL", "AND", "ANY", "ALTER", "AS", "AT", "AVG", "BETWEEN", "BOTH", "BY", "CALL", "CASE", "CAST", "CHECK", "COALESCE", "CORRESPONDING", "CONVERT", "COUNT", "CREATE", "CROSS", "DEFAULT", "DISTINCT", "DROP", "ELSE", "EVERY", "EXISTS", "EXCEPT", "FOR", "FOREIGN", "FROM", "FULL", "GRANT", "GROUP", "HAVING", "IN", "INNER", @@ -117,7 +115,7 @@ private static String createKeywordAliasRegex() { keywords.append(sep).append(s); sep = "|"; } - return "([\\s\\n\\r]+AS[\\s\\n\\r]+)(" + keywords + ")(\\W)"; + return "(\\s+AS\\s+)(" + keywords + ")(\\W)"; } private static void aliases(String sql, NormalizedSQL nsql) { @@ -228,43 +226,34 @@ private static int[] getDoubleQuoteGroup(String _s) { public enum DDLType { CREATE_TABLE_AS_SELECT(Pattern.compile( - "[\\s\n\r]*(?i)create[\\s\n\r]+(?i)table[\\s\n\r]+" + NAME_PATTERN - + "[\\s\n\r]*(?)AS[\\s\n\r]*\\(\\s*((?)SELECT)")), + "\\s*create\\s+table\\s+" + NAME_PATTERN + "\\s*(?)AS\\s*\\(\\s*((?)SELECT)", Pattern.CASE_INSENSITIVE)), CREATE_TABLE(Pattern.compile( - "[\\s\n\r]*(?i)create[\\s\n\r]+(?i)table[\\s\n\r]+" + NAME_PATTERN)), + "\\s*create\\s+table\\s+" + NAME_PATTERN, Pattern.CASE_INSENSITIVE)), DROP_TABLE_CASCADE(Pattern.compile( - "[\\s\n\r]*(?i)drop[\\s\n\r]+(?i)table[\\s\n\r]+" + NAME_PATTERN + "[\\s\n\r]+(?i)cascade")), + "\\s*drop\\s+table\\s+" + NAME_PATTERN + "\\s+cascade", Pattern.CASE_INSENSITIVE)), DROP_TABLE(Pattern.compile( - "[\\s\n\r]*(?i)drop[\\s\n\r]+(?i)table[\\s\n\r]+" + NAME_PATTERN)), + "\\s*drop\\s+table\\s+" + NAME_PATTERN, Pattern.CASE_INSENSITIVE)), ALTER_RENAME(Pattern.compile( - "[\\s\n\r]*(?i)alter[\\s\n\r]+(?i)table[\\s\n\r]+" + NAME_PATTERN - + "[\\s\n\r]+(?i)rename[\\s\n\r]+(?i)to[\\s\n\r]+" + NAME_PATTERN)), + "\\s*alter\\s+table\\s+" + NAME_PATTERN + "\\s+rename\\s+to\\s+" + NAME_PATTERN, Pattern.CASE_INSENSITIVE)), CREATE_PRIMARY_KEY(Pattern.compile( - "[\\s\n\r]*(?i)alter[\\s\n\r]+(?i)table[\\s\n\r]+" + NAME_PATTERN - + "[\\s\n\r]+(?i)add[\\s\n\r]+(?:(?i)constraint[\\s\n\r]+" + NAME_PATTERN - + "[\\s\n\r]+)?(?i)primary[\\s\n\r]+(?i)key(.*)")), + "\\s*alter\\s+table\\s+" + NAME_PATTERN + "\\s+add\\s+(?:constraint\\s+" + NAME_PATTERN + "\\s+)?primary\\s+key(.*)", Pattern.CASE_INSENSITIVE)), CREATE_FOREIGN_KEY(Pattern.compile( - "[\\s\n\r]*(?i)alter[\\s\n\r]+(?i)table[\\s\n\r]+" + NAME_PATTERN - + "[\\s\n\r]+(?i)add[\\s\n\r]+(?:(?i)constraint[\\s\n\r]+" + NAME_PATTERN - + "[\\s\n\r]+)?(?i)foreign[\\s\n\r]+(?i)key[\\s\n\r]+" - + "(?:\\(.*\\))[\\s\n\r]*(?i)references[\\s\n\r]+" + NAME_PATTERN + "(.*)")), + "\\s*alter\\s+table\\s+" + NAME_PATTERN + "\\s+add\\s+(?:constraint\\s+" + NAME_PATTERN + + "\\s+)?foreign\\s+key\\s+" + "(?:\\(.*\\))\\s*references\\s+" + NAME_PATTERN + "(.*)", Pattern.CASE_INSENSITIVE)), DROP_FOREIGN_KEY(Pattern.compile( - "[\\s\n\r]*(?i)alter[\\s\n\r]+(?i)table[\\s\n\r]+" + NAME_PATTERN - + "[\\s\n\r]+(?i)drop[\\s\n\r]+(?i)constraint[\\s\n\r]+" + NAME_PATTERN)), + "\\s*alter\\s+table\\s+" + NAME_PATTERN + "\\s+drop\\s+constraint\\s+" + NAME_PATTERN, Pattern.CASE_INSENSITIVE)), ADD_COLUMN(Pattern.compile( - "[\\s\n\r]*(?i)alter[\\s\n\r]+(?i)table[\\s\n\r]+" + NAME_PATTERN - + "[\\s\n\r]+(?i)add[\\s\n\r]+(?:(?i)column[\\s\n\r]+)?" + NAME_PATTERN + "(.*)")), + "\\s*alter\\s+table\\s+" + NAME_PATTERN + "\\s+add\\s+(?:column\\s+)?" + NAME_PATTERN + "(.*)", Pattern.CASE_INSENSITIVE)), CREATE_INDEX(Pattern.compile( - "(?i)CREATE[\\s\n\r]+(?:(?i)unique)?[\\s\n\r]*(?i)index[\\s\n\r]+" + NAME_PATTERN - + "[\\s\n\r]+(?i)ON[\\s\n\r]+" + NAME_PATTERN + "[\\s\n\r]+")), + "CREATE\\s+(?:unique)?\\s*index\\s+" + NAME_PATTERN + "\\s+ON\\s+" + NAME_PATTERN + "\\s+", Pattern.CASE_INSENSITIVE)), DISABLE_AUTOINCREMENT(Pattern.compile( - "[\\s\n\r]*(?i)disable[\\s\n\r]+(?i)autoincrement[\\s\n\r]+(?i)on[\\s\n\r]*" + NAME_PATTERN)), + "\\s*disable\\s+autoincrement\\s+on\\s*" + NAME_PATTERN, Pattern.CASE_INSENSITIVE)), ENABLE_AUTOINCREMENT(Pattern.compile( - "[\\s\n\r]*(?i)enable[\\s\n\r]+(?i)autoincrement[\\s\n\r]+(?i)on[\\s\n\r]*" + NAME_PATTERN)); + "\\s*enable\\s+autoincrement\\s+on\\s*" + NAME_PATTERN, Pattern.CASE_INSENSITIVE)); private final Pattern pattern; private String ddl; @@ -353,7 +342,6 @@ public static DDLType getDDLType(String s) { } private static String replaceWorkAroundFunctions(String sql) { - for (String waFun : WORKAROUND_FUNCTIONS) { sql = sql.replaceAll("(\\W)(?i)" + waFun + "\\s*\\(", "$1" + waFun + "WA("); } @@ -375,8 +363,8 @@ public static String restoreWorkAroundFunctions(String sql) { return sql.replaceAll("(\\W)(?i)user\\s*\\(", "$1currentUser("); } - private static String replaceBacktrik(String sql) { - return sql.replaceAll(BACKTRIK, "[$2]"); + private static String replaceBacktick(String sql) { + return sql.replaceAll(BACKTICK, "[$2]"); } private static String replaceAposNames(String sql) { @@ -395,7 +383,7 @@ public static NormalizedSQL convertSQL(String sql, UcanaccessConnection conn, bo NormalizedSQL nsql = new NormalizedSQL(); sql = sql + " "; aliases(sql, nsql); - sql = replaceBacktrik(sql); + sql = replaceBacktick(sql); sql = replaceAposNames(sql); sql = convertUnion(sql); sql = convertAccessDate(sql); @@ -503,24 +491,19 @@ public static NormalizedSQL convertSQL(String sql, UcanaccessConnection conn) { public static String convertAccessDate(String sql) { sql = sql.replaceAll("#" + DATE_ACCESS_FORMAT + "#", "Timestamp('$3-$1-$2 00:00:00')") // FORMAT MM/dd/yyyy - .replaceAll("#" + DATE_ACCESS_FORMAT + "\\s*(" + HHMMSS_ACCESS_FORMAT + ")#", - "Timestamp0('$3-$1-$2 $4')") + .replaceAll("#" + DATE_ACCESS_FORMAT + "\\s*(" + HHMMSS_ACCESS_FORMAT + ")#", "Timestamp0('$3-$1-$2 $4')") - .replaceAll("#" + DATE_ACCESS_FORMAT + "\\s*(" + HHMMSS_ACCESS_FORMAT + ")\\s*(?i)AM#", - "Timestamp0('$3-$1-$2 $4')") + .replaceAll("#" + DATE_ACCESS_FORMAT + "\\s*(" + HHMMSS_ACCESS_FORMAT + ")\\s*(?i)AM#", "Timestamp0('$3-$1-$2 $4')") - .replaceAll("#" + DATE_ACCESS_FORMAT + "\\s*(" + HHMMSS_ACCESS_FORMAT + ")\\s*(?i)PM#", - "(Timestamp0('$3-$1-$2 $4')+ 12 Hour) ") + .replaceAll("#" + DATE_ACCESS_FORMAT + "\\s*(" + HHMMSS_ACCESS_FORMAT + ")\\s*(?i)PM#", "(Timestamp0('$3-$1-$2 $4')+ 12 Hour) ") // FORMAT yyyy-MM-dd .replaceAll("#" + DATE_FORMAT + "#", "Timestamp0('$1-$2-$3 00:00:00')") .replaceAll("#" + DATE_FORMAT + "\\s*(" + HHMMSS_ACCESS_FORMAT + ")#", "Timestamp0('$1-$2-$3 $4')") - .replaceAll("#" + DATE_FORMAT + "\\s*(" + HHMMSS_ACCESS_FORMAT + ")\\s*(?i)AM#", - "Timestamp0('$1-$2-$3 $4')") + .replaceAll("#" + DATE_FORMAT + "\\s*(" + HHMMSS_ACCESS_FORMAT + ")\\s*(?i)AM#", "Timestamp0('$1-$2-$3 $4')") - .replaceAll("#" + DATE_FORMAT + "\\s*(" + HHMMSS_ACCESS_FORMAT + ")\\s*(?i)PM#", - "(Timestamp0('$1-$2-$3 $4')+ 12 Hour)") + .replaceAll("#" + DATE_FORMAT + "\\s*(" + HHMMSS_ACCESS_FORMAT + ")\\s*(?i)PM#", "(Timestamp0('$1-$2-$3 $4')+ 12 Hour)") .replaceAll("#(" + HHMMSS_ACCESS_FORMAT + ")#", "Timestamp'" + BIG_BANG + " $1'") .replaceAll("#(" + HHMMSS_ACCESS_FORMAT + ")\\s*(?i)AM#", "Timestamp'" + BIG_BANG + " $1'") @@ -619,12 +602,11 @@ private static String replaceDigitStartingIdentifiers(String sql) { Matcher mtc = DIGIT_STARTING_IDENTIFIERS.matcher(sql); if (mtc.find()) { - if (Character.isLetter(mtc.group(0).charAt(0))) { + String grp0 = mtc.group(0); + if (Character.isLetter(grp0.charAt(0))) { return sql; } - String prefix = - mtc.group(0).matches("\\.([0-9])+[Ee]([0-9])+\\s") || mtc.group(0).matches("\\.([0-9])+[Ee][-+]") - ? "" : "Z_"; + String prefix = grp0.matches("\\.([0-9])+[Ee]([0-9])+\\s") || grp0.matches("\\.([0-9])+[Ee][-+]") ? "" : "Z_"; String build = mtc.group(1) + prefix + mtc.group(2); sql = sql.substring(0, mtc.start()) + build + replaceDigitStartingIdentifiers(mtc.group(7) + sql.substring(mtc.end())); @@ -635,7 +617,7 @@ private static String replaceDigitStartingIdentifiers(String sql) { private static String convertXescaped(String sqlc) { for (String xidt : ESCAPED_IDENTIFIERS) { - sqlc = sqlc.replaceAll(XESCAPED.replaceAll("_", xidt), "$1$3$4"); + sqlc = sqlc.replaceAll(XESCAPED.replace("_", xidt), "$1$3$4"); } return sqlc; } @@ -735,7 +717,7 @@ public static String basicEscapingIdentifier(String name) { } - public static String escapeIdentifier(String name, Connection conn) throws SQLException { + public static String escapeIdentifier(String name, Connection conn) { return checkLang(escapeIdentifier(name), conn, true); } @@ -754,17 +736,17 @@ private static String hsqlEscape(String escaped, boolean quote) { return escaped; } - public static String checkLang(String _name, Connection _conn) throws SQLException { + public static String checkLang(String _name, Connection _conn) { return checkLang(_name, _conn, true); } - public static String checkLang(String _name, Connection _conn, boolean _quote) throws SQLException { + public static String checkLang(String _name, Connection _conn, boolean _quote) { String name = _name; if (!_quote) { name = _name.replace(Pattern.quote("["), "\"").replace(Pattern.quote("]"), "\""); } try (Statement st = _conn.createStatement()) { - st.execute("SELECT 1 AS " + name + " FROM dual"); + st.execute(String.format("SELECT 1 AS %s FROM dual", name)); return _name; } catch (SQLException _ex) { return _quote ? "\"" + _name + "\"" : "[" + _name + "]"; @@ -800,7 +782,7 @@ public static String convertAddColumn(String tableName, String columnName, Strin private static String convertTypeDeclaration(String typeDecl) { typeDecl = " " + typeDecl + " "; // padding for a generic RE use for (Map.Entry entry : TypesMap.getAccess2HsqlTypesMap().entrySet()) { - typeDecl = typeDecl.replaceAll("([\\s\n\r]+)((?i)" + entry.getKey() + ")([\\s\n\r\\(]+)", + typeDecl = typeDecl.replaceAll("(\\s+)((?i)" + entry.getKey() + ")([\\s\\(]+)", "$1" + entry.getValue() + "$3"); } return typeDecl.replaceAll(DEFAULT_VARCHAR_0, "$1VARCHAR(255)$2"); @@ -815,13 +797,9 @@ private static String convertCreateTable(String sql, Map _types2 String pre = sql.substring(0, sql.indexOf('(')); sql = sql.substring(sql.indexOf('(')); for (Map.Entry entry : _types2Convert.entrySet()) { - sql = sql - .replaceAll("([,\\(][\\s\n\r]*)" + TYPES_TRANSLATE.replaceAll("_", entry.getKey()), - "$1___" + entry.getKey() + "___$2") - .replaceAll("(\\W)" + TYPES_TRANSLATE.replaceAll("_", entry.getKey()), - "$1" + entry.getValue() + "$2") - .replaceAll("(\\W)" + TYPES_TRANSLATE.replaceAll("_", "___" + entry.getKey() + "___"), - "$1" + entry.getKey() + "$2"); + sql = sql.replaceAll("([,\\(]\\s*)" + TYPES_TRANSLATE.replace("_", entry.getKey()), "$1___" + entry.getKey() + "___$2") + .replaceAll("(\\W)" + TYPES_TRANSLATE.replace("_", entry.getKey()), "$1" + entry.getValue() + "$2") + .replaceAll("(\\W)" + TYPES_TRANSLATE.replace("_", "___" + entry.getKey() + "___"), "$1" + entry.getKey() + "$2"); } sql = sql.replaceAll(DEFAULT_VARCHAR, "$1VARCHAR(255)$2"); return clearDefaultsCreateStatement(pre + sql); @@ -883,7 +861,7 @@ private static String convert2RegexMatches(String likeContent) { return convert2RegexMatches(likeContent.substring(0, mtc.start(0))) + mtc.group(0).charAt(1) + convert2RegexMatches(likeContent.substring(mtc.end(0))); } - return likeContent.replaceAll("#", "\\\\d").replaceAll("\\*", ".*").replaceAll("_", ".") + return likeContent.replaceAll("#", "\\\\d").replaceAll("\\*", ".*").replace('_', '.') .replaceAll("(\\[)\\!(\\w\\-\\w\\])", "$1^$2"); } diff --git a/src/main/java/net/ucanaccess/exception/UcanaccessSQLException.java b/src/main/java/net/ucanaccess/exception/UcanaccessSQLException.java index e69557e6..5ea8d1ce 100644 --- a/src/main/java/net/ucanaccess/exception/UcanaccessSQLException.java +++ b/src/main/java/net/ucanaccess/exception/UcanaccessSQLException.java @@ -5,6 +5,7 @@ import java.sql.SQLException; import java.util.Optional; +import java.util.function.BooleanSupplier; import java.util.function.Supplier; /** @@ -100,13 +101,11 @@ public String getMessage() { * @return wrapped exception or parameter if can be cast to {@link UcanaccessSQLException} */ public static final UcanaccessSQLException wrap(T _t) { - return UcanaccessSQLException.class.isInstance(_t) - ? UcanaccessSQLException.class.cast(_t) - : new UcanaccessSQLException(_t); + return _t instanceof UcanaccessSQLException ? (UcanaccessSQLException) _t : new UcanaccessSQLException(_t); } - public static final void throwIf(Supplier _condition, Supplier _exceptionSupplier) throws T { - if (_condition.get()) { + public static final void throwIf(BooleanSupplier _condition, Supplier _exceptionSupplier) throws T { + if (_condition.getAsBoolean()) { throw _exceptionSupplier.get(); } } diff --git a/src/main/java/net/ucanaccess/jdbc/AbstractExecute.java b/src/main/java/net/ucanaccess/jdbc/AbstractExecute.java index a3e5d5c3..782c0475 100644 --- a/src/main/java/net/ucanaccess/jdbc/AbstractExecute.java +++ b/src/main/java/net/ucanaccess/jdbc/AbstractExecute.java @@ -79,7 +79,7 @@ private Object enableDisable(DDLType _ddlType) throws SQLException, IOException private int count(String tableName) throws SQLException { UcanaccessConnection conn = statement.getConnection(); try (UcanaccessStatement st = conn.createStatement(); - ResultSet rs = st.executeQuery("SELECT COUNT(*) FROM " + tableName)) { + ResultSet rs = st.executeQuery(String.format("SELECT COUNT(*) FROM %s", tableName))) { rs.next(); return rs.getInt(1); } diff --git a/src/main/java/net/ucanaccess/jdbc/DBReference.java b/src/main/java/net/ucanaccess/jdbc/DBReference.java index 95b678e1..116da2b1 100644 --- a/src/main/java/net/ucanaccess/jdbc/DBReference.java +++ b/src/main/java/net/ucanaccess/jdbc/DBReference.java @@ -17,6 +17,7 @@ import java.util.*; import java.util.Date; +@SuppressWarnings("java:S2077") // suppress sonarcloud warnings regarding dynamically formatted SQL public class DBReference { private static final String CIPHER_SPEC = "AES"; private static List onReloadListeners = new ArrayList<>(); @@ -148,7 +149,7 @@ Connection checkLastModified(Connection _conn, Session _session) throws Exceptio return _conn; } updateLastModified(); - closeHSQLDB(_session); + closeHsqlDb(_session); dbIO.flush(); dbIO.close(); dbIO = open(dbFile, pwd); @@ -226,7 +227,7 @@ private long getLastUpdateHSQLDB() { return lu; } - private void closeHSQLDB(Session session) throws IOException { + private void closeHsqlDb(Session session) throws IOException { closeHsqlDb(session, false); } @@ -293,11 +294,11 @@ private void setIgnoreCase(Connection _conn) { private void initHSQLDB(Connection _conn) { try (Statement st = _conn.createStatement()) { st.execute("SET DATABASE SQL SYNTAX ora TRUE"); - st.execute("SET DATABASE SQL CONCAT NULLS " + concatNulls); + st.execute(String.format("SET DATABASE SQL CONCAT NULLS %s", concatNulls)); if (lobScale == null && inMemory) { st.execute("SET FILES LOB SCALE 1"); } else if (lobScale != null) { - st.execute("SET FILES LOB SCALE " + lobScale); + st.execute(String.format("SET FILES LOB SCALE %s", lobScale)); } } catch (Exception _ex) { @@ -305,6 +306,7 @@ private void initHSQLDB(Connection _conn) { } } + @SuppressWarnings("java:S2095") // suppress sonarcloud warning regarding try-with-resources public Connection getHSQLDBConnection(Session _session) throws SQLException { boolean keptMirror = firstConnection && toKeepHsql != null && toKeepHsql.exists(); @@ -363,7 +365,7 @@ private String getHsqlUrl(Session _session) throws SQLException { if (!inMemory && tempHsql == null) { if (toKeepHsql != null) { if (!toKeepHsql.exists() && !toKeepHsql.createNewFile()) { - logger.log(Level.WARNING, "Could not create file " + toKeepHsql); + logger.log(Level.WARNING, "Could not create file {0}", toKeepHsql); } tempHsql = toKeepHsql; } else { @@ -373,13 +375,13 @@ private String getHsqlUrl(Session _session) throws SQLException { tempHsql = new File(hbase, id); if (!tempHsql.createNewFile()) { - logger.log(Level.WARNING, "Could not create file " + tempHsql); + logger.log(Level.WARNING, "Could not create file {0}", tempHsql); } } Runtime.getRuntime().addShutdownHook(new Thread(() -> { try { if (toKeepHsql == null) { - closeHSQLDB(_session); + closeHsqlDb(_session); } else { finalizeHsqlDb(_session); } @@ -439,7 +441,7 @@ private void lockMdbFile() throws UcanaccessSQLException { try { File flLock = fileLock(); if (!flLock.createNewFile()) { - logger.log(Level.WARNING, "Could not create file " + flLock); + logger.log(Level.WARNING, "Could not create file {0}", flLock); } // suppress Eclipse warning "Resource leak: 'raf' is never closed", because that is exactly how UCanAccess @@ -500,7 +502,7 @@ void shutdown(Session _session) throws Exception { memoryTimer.timer.cancel(); dbIO.flush(); dbIO.close(); - closeHSQLDB(_session); + closeHsqlDb(_session); } @@ -591,6 +593,7 @@ public void setConcatNulls(boolean _concatNulls) { private static class MemoryTimer { private static final long INACTIVITY_TIMEOUT_DEFAULT = 120000; + private final Logger logger = System.getLogger(getClass().getName()); private final DBReference dbReference; private final Timer timer; private int activeConnection; @@ -608,7 +611,7 @@ synchronized void decrementActiveConnection(final Session _session) { try { dbReference.shutdown(_session); } catch (Exception _ex) { - System.getLogger(MemoryTimer.class.getName()).log(Level.WARNING, "Error shutting down db " + dbReference + ": " + _ex); + logger.log(Level.WARNING, "Error shutting down db {0}: {1}", dbReference, _ex.toString()); } timer.cancel(); @@ -624,6 +627,7 @@ && getActiveConnection() == 0) { try { dbReference.shutdown(_session); } catch (Exception _ignored) { + logger.log(Level.DEBUG, "Ignore {0}", _ignored.toString()); } } } diff --git a/src/main/java/net/ucanaccess/jdbc/UcanaccessConnection.java b/src/main/java/net/ucanaccess/jdbc/UcanaccessConnection.java index fe9ddda0..1153a8e9 100644 --- a/src/main/java/net/ucanaccess/jdbc/UcanaccessConnection.java +++ b/src/main/java/net/ucanaccess/jdbc/UcanaccessConnection.java @@ -24,7 +24,7 @@ public class UcanaccessConnection implements Connection { private static final ThreadLocal CTX = new ThreadLocal<>(); - private final transient Logger logger = System.getLogger(getClass().getName()); + private final Logger logger = System.getLogger(getClass().getName()); private boolean feedbackState; private final LinkedList commands = new LinkedList<>(); private Connection hsqlDBConnection; @@ -299,10 +299,7 @@ private void flushIO() throws SQLException { } catch (IOException _ex2) { logger.log(Level.WARNING, _ex2.toString()); } - if (UcanaccessSQLException.class.isInstance(_ex)) { - throw UcanaccessSQLException.class.cast(_ex); - } - throw new UcanaccessSQLException(_ex); + throw _ex instanceof UcanaccessSQLException ? (UcanaccessSQLException) _ex : new UcanaccessSQLException(_ex); } try { diff --git a/src/main/java/net/ucanaccess/jdbc/UcanaccessDataSource.java b/src/main/java/net/ucanaccess/jdbc/UcanaccessDataSource.java index d65391f4..8a7ad078 100644 --- a/src/main/java/net/ucanaccess/jdbc/UcanaccessDataSource.java +++ b/src/main/java/net/ucanaccess/jdbc/UcanaccessDataSource.java @@ -27,7 +27,7 @@ public class UcanaccessDataSource implements Serializable, Referenceable, DataSo private String accessPath; private int loginTimeout = 0; private transient PrintWriter logWriter = new PrintWriter(System.out); - private final Map userPass = new HashMap<>(); + private final Map userPass = new EnumMap<>(Property.class); private final Map props = new EnumMap<>(Property.class); diff --git a/src/main/java/net/ucanaccess/jdbc/UcanaccessDriver.java b/src/main/java/net/ucanaccess/jdbc/UcanaccessDriver.java index 56706145..bacb0b6e 100644 --- a/src/main/java/net/ucanaccess/jdbc/UcanaccessDriver.java +++ b/src/main/java/net/ucanaccess/jdbc/UcanaccessDriver.java @@ -16,7 +16,6 @@ import java.io.IOException; import java.lang.System.Logger; import java.lang.System.Logger.Level; -import java.lang.reflect.InvocationTargetException; import java.sql.*; import java.util.*; import java.util.function.BiConsumer; @@ -26,7 +25,6 @@ public final class UcanaccessDriver implements Driver { public static final String URL_PREFIX = "jdbc:ucanaccess://"; private static final Logger LOGGER = System.getLogger(UcanaccessDriver.class.getName()); - private final Logger logger = System.getLogger(getClass().getName()); static { try { @@ -60,7 +58,7 @@ public Connection connect(String _url, Properties _props) throws SQLException { Map props = readProperties(_props, _url, (k, v) -> { unknownProps.put(k, v); - logger.log(Level.WARNING, "Unknown driver property {0} with value {1}", k, v); + LOGGER.log(Level.WARNING, "Unknown driver property {0} with value {1}", k, v); }); int idxSemicolon = _url.indexOf(';'); @@ -74,11 +72,8 @@ public Connection connect(String _url, Properties _props) throws SQLException { boolean alreadyLoaded = as.loaded(fileDb); FileFormat ff = null; - if (props.containsKey(newDatabaseVersion)) { - if (!fileDb.exists()) { - ff = FileFormat.parse(props.get(newDatabaseVersion)); - } - + if (props.containsKey(newDatabaseVersion) && !fileDb.exists()) { + ff = FileFormat.parse(props.get(newDatabaseVersion)); } boolean useCustomOpener = props.containsKey(jackcessOpener); @@ -108,7 +103,7 @@ public Connection connect(String _url, Properties _props) throws SQLException { if (props.containsKey(keepMirror)) { dbRef.setInMemory(false); if (dbRef.isEncryptHSQLDB()) { - logger.log(Level.WARNING, "{0} parameter cannot be combined with parameters {1} or {2}, {3} skipped", + LOGGER.log(Level.WARNING, "{0} parameter cannot be combined with parameters {1} or {2}, {3} skipped", keepMirror, jackcessOpener, encrypt, keepMirror); } else { File dbMirror = @@ -172,7 +167,7 @@ public Connection connect(String _url, Properties _props) throws SQLException { dbRef.getDbIO().setErrorHandler((cl, bt, location, ex) -> { if (cl.getType().isTextual()) { - logger.log(Level.WARNING, "Invalid textual value in table {0}, column {1}: it might look like {2}", + LOGGER.log(Level.WARNING, "Invalid textual value in table {0}, column {1}: it might look like {2}", cl.getTable().getName(), cl.getName(), new String(bt)); } throw new IOException(ex); @@ -248,7 +243,7 @@ private Integer validateLobScale(String _property) { } } catch (Exception _ignored) { } - logger.log(Level.WARNING, "Lobscale value must equal at least one of the following values: 1,2,4,8,16,32, skipping it"); + LOGGER.log(Level.WARNING, "Lobscale value must equal at least one of the following values: 1,2,4,8,16,32, skipping it"); return null; } @@ -290,14 +285,13 @@ public boolean jdbcCompliant() { return true; } - private IJackcessOpenerInterface newJackcessOpenerInstance(String className) - throws InstantiationException, IllegalAccessException, ClassNotFoundException, UcanaccessSQLException, InvocationTargetException, NoSuchMethodException, SecurityException { - Object newInstance = Class.forName(className).getConstructor().newInstance(); + private IJackcessOpenerInterface newJackcessOpenerInstance(String className) throws UcanaccessSQLException { + Object instance = Try.catching(() -> Class.forName(className).getConstructor().newInstance()).orThrow(ex -> new UcanaccessSQLException("Failed to instantiate " + className, ex)); - if (!IJackcessOpenerInterface.class.isInstance(newInstance)) { - throw new UcanaccessSQLException("Jackess Opener class must implement " + IJackcessOpenerInterface.class.getName()); + if (instance instanceof IJackcessOpenerInterface) { + return (IJackcessOpenerInterface) instance; } - return (IJackcessOpenerInterface) newInstance; + throw new UcanaccessSQLException("Jackess Opener class must implement " + IJackcessOpenerInterface.class.getName()); } /** diff --git a/src/main/java/net/ucanaccess/jdbc/UcanaccessPreparedStatement.java b/src/main/java/net/ucanaccess/jdbc/UcanaccessPreparedStatement.java index 56de8a47..8591f938 100644 --- a/src/main/java/net/ucanaccess/jdbc/UcanaccessPreparedStatement.java +++ b/src/main/java/net/ucanaccess/jdbc/UcanaccessPreparedStatement.java @@ -671,6 +671,9 @@ public void setTimestamp(int _parmIdx, Timestamp ts, Calendar cal) throws Ucanac }); } + /** + * @deprecated Use {@code setCharacterStream} + */ @Override @Deprecated public void setUnicodeStream(int _parmIdx, InputStream is, int length) throws UcanaccessSQLException { diff --git a/src/main/java/net/ucanaccess/triggers/TriggerAppendOnly.java b/src/main/java/net/ucanaccess/triggers/TriggerAppendOnly.java index 688e5ec7..65649029 100644 --- a/src/main/java/net/ucanaccess/triggers/TriggerAppendOnly.java +++ b/src/main/java/net/ucanaccess/triggers/TriggerAppendOnly.java @@ -38,7 +38,7 @@ public void fire(int type, String name, String tableName, Object[] oldR, Object[ Version[] oldV = (Version[]) ((JavaObjectData) oldR[verCol.getColumnNumber()]).getObject(); Version[] newV = new Version[oldV.length + 1]; - if (oldV.length >= 0) { + if (oldV.length > 0) { System.arraycopy(oldV, 0, newV, 1, oldV.length); } newV[0] = new Version(val, upTime); diff --git a/src/main/java/net/ucanaccess/util/Try.java b/src/main/java/net/ucanaccess/util/Try.java index 5e829668..e63a1d40 100644 --- a/src/main/java/net/ucanaccess/util/Try.java +++ b/src/main/java/net/ucanaccess/util/Try.java @@ -56,6 +56,7 @@ * @author Markus Spann * @since v5.1.0 */ +@SuppressWarnings("java:S119") public final class Try { /** The immutable value or {@code null} if an exception occurred during retrieval. */ @@ -258,7 +259,7 @@ public V orElseApply(IThrowingFunction _function) { */ public V orElseGet(IThrowingSupplier _supplier) { if (hasThrown()) { - return Try.catching(_supplier).orThrow(); + return Try.catching(_supplier::get).orThrow(); } return val; } @@ -296,7 +297,11 @@ public V orThrow(Function _function) throws T2 { Objects.requireNonNull(_function, "Function required"); if (hasThrown()) { Throwable t2 = _function.apply(t); - doThrow(Objects.requireNonNullElseGet(t2, () -> new IllegalStateException("Function must provide a throwable"))); + if (t2 == null) { + doThrow(new IllegalStateException("Function must provide a throwable")); + } else { + doThrow(t2); + } } return val; } diff --git a/src/test/java/net/ucanaccess/jdbc/FunctionsTest.java b/src/test/java/net/ucanaccess/jdbc/FunctionsTest.java index 7203f4b6..81483b60 100644 --- a/src/test/java/net/ucanaccess/jdbc/FunctionsTest.java +++ b/src/test/java/net/ucanaccess/jdbc/FunctionsTest.java @@ -611,10 +611,10 @@ void testDateValue(AccessVersion _accessVersion) throws Exception { @AccessVersionSource void testFormatString(AccessVersion _accessVersion) throws Exception { init(_accessVersion); - checkQuery("SELECT Format(text,'Long date') FROM t_format", singleRec("")); - checkQuery("SELECT Format('05/13/1994','Long date') FROM t_funcs", singleRec("Friday, May 13, 1994")); - checkQuery("SELECT Format(0.6,'percent') FROM t_funcs", singleRec("60.00%")); - checkQuery("SELECT Format('0,6','percent') FROM t_funcs", singleRec("600.00%")); + checkQuery("SELECT Format(text, 'Long date') FROM t_format", singleRec("")); + checkQuery("SELECT Format('05/13/1994', 'Long date') FROM t_funcs", singleRec("Friday, May 13, 1994")); + checkQuery("SELECT Format(0.6, 'percent') FROM t_funcs", singleRec("60.00%")); + checkQuery("SELECT Format('0,6', 'percent') FROM t_funcs", singleRec("600.00%")); // beware of bug http://bugs.java.com/view_bug.do?bug_id=7131459 ! checkQuery("SELECT Format(48.14251, '.###') FROM t_funcs", singleRec("48.143")); } diff --git a/src/test/java/net/ucanaccess/jdbc/NotNullDdlTest.java b/src/test/java/net/ucanaccess/jdbc/NotNullDdlTest.java index d78bdb52..3e1585b1 100644 --- a/src/test/java/net/ucanaccess/jdbc/NotNullDdlTest.java +++ b/src/test/java/net/ucanaccess/jdbc/NotNullDdlTest.java @@ -53,7 +53,7 @@ void confirmNotNullColumnUsingJet(AccessVersion _accessVersion) throws Exception Process proc = Runtime.getRuntime().exec(command); proc.waitFor(15, TimeUnit.SECONDS); - assertThat(proc.exitValue()).isEqualTo(0); + assertThat(proc.exitValue()).isZero(); try (BufferedReader output = new BufferedReader(new InputStreamReader(proc.getErrorStream()))) { String stderr = output.lines().collect(Collectors.joining(System.lineSeparator())); diff --git a/src/test/java/net/ucanaccess/jdbc/RegexTest.java b/src/test/java/net/ucanaccess/jdbc/RegexTest.java index acd7c628..d0811ba6 100644 --- a/src/test/java/net/ucanaccess/jdbc/RegexTest.java +++ b/src/test/java/net/ucanaccess/jdbc/RegexTest.java @@ -29,8 +29,8 @@ void testRegex(AccessVersion _accessVersion) throws SQLException { try (UcanaccessStatement st = ucanaccess.createStatement()) { for (String c : in) { executeStatements(st, - getStatement(c.replaceAll("'", "''"), "'"), - getStatement(c.replaceAll("\"", "\"\""), "\"")); + getStatement(c.replace("'", "''"), "'"), + getStatement(c.replace("\"", "\"\""), "\"")); } int len = in.length * 2; diff --git a/src/test/java/net/ucanaccess/jdbc/UnproperExecuteQueryTest.java b/src/test/java/net/ucanaccess/jdbc/UnproperExecuteQueryTest.java index e7c854b6..fcb4135d 100644 --- a/src/test/java/net/ucanaccess/jdbc/UnproperExecuteQueryTest.java +++ b/src/test/java/net/ucanaccess/jdbc/UnproperExecuteQueryTest.java @@ -21,8 +21,8 @@ protected String getAccessPath() { @AccessVersionSource void testExecute(AccessVersion _accessVersion) throws Exception { init(_accessVersion); - execute("INSERT INTO t_noroman ([end],[q3¹²³¼½¾ß€Ð×ÝÞðýþäüöß]) VALUES('the end', 'yeeep')"); - execute("UPDATE t_noroman SET [ENd]='BLeah'"); + execute("INSERT INTO t_noroman ([end], [q3¹²³¼½¾ß€Ð×ÝÞðýþäüöß]) VALUES('the end', 'yeeep')"); + execute("UPDATE t_noroman SET [ENd] = 'BLeah'"); execute("DELETE FROM t_noroman"); } diff --git a/src/test/java/net/ucanaccess/test/UcanaccessBaseTest.java b/src/test/java/net/ucanaccess/test/UcanaccessBaseTest.java index 51b23378..4a4cd1ef 100644 --- a/src/test/java/net/ucanaccess/test/UcanaccessBaseTest.java +++ b/src/test/java/net/ucanaccess/test/UcanaccessBaseTest.java @@ -356,7 +356,7 @@ protected File copyResourceToTempFile(String _resourcePath) { getLogger().log(Level.WARNING, "Resource {0} not found in classpath", _resourcePath); return null; } - File tempFile = createTempFile(resourceFile.getName().replace(".", "_")); + File tempFile = createTempFile(resourceFile.getName().replace('.', '_')); getLogger().log(Level.DEBUG, "Copying resource '{0}' to '{1}'", _resourcePath, tempFile.getAbsolutePath()); return copyFile(is, tempFile); } catch (IOException _ex) { @@ -415,7 +415,7 @@ protected UcanaccessConnectionBuilder buildConnection() { } protected void initVerifyConnection() throws SQLException { - File tempVerifyFile = createTempFile(fileAccDb.getName().replace(".", "_") + "_verify"); + File tempVerifyFile = createTempFile(fileAccDb.getName().replace('.', '_') + "_verify"); copyFile(fileAccDb.toPath(), tempVerifyFile); if (verifyConnection != null) {