[jdbc] Add safety valve for suspicious migrations (#13797)
* Abort migration from real names when most tables have table name prefix * Add missing checks for database connection from console commands * Add additional documentation for check/fix schema Signed-off-by: Jacob Laursen <jacob-github@vindvejr.dk>pull/13800/head
parent
826fc9e8d7
commit
3912487305
|
@ -214,6 +214,12 @@ Use the command `jdbc schema check` to perform an integrity check of the schema.
|
||||||
|
|
||||||
Identified issues can be fixed automatically using the command `jdbc schema fix` (all items having issues) or `jdbc schema fix <itemName>` (single item).
|
Identified issues can be fixed automatically using the command `jdbc schema fix` (all items having issues) or `jdbc schema fix <itemName>` (single item).
|
||||||
|
|
||||||
|
Issues than can be identified and possibly fixed:
|
||||||
|
|
||||||
|
- Wrong column name case (`time` and `name`).
|
||||||
|
- Wrong column type. Before fixing this, make sure that time-zone is correctly configured.
|
||||||
|
- Unexpected column (identify only).
|
||||||
|
|
||||||
### For Developers
|
### For Developers
|
||||||
|
|
||||||
* Clearly separated source files for the database-specific part of openHAB logic.
|
* Clearly separated source files for the database-specific part of openHAB logic.
|
||||||
|
|
|
@ -49,8 +49,9 @@ import com.zaxxer.hikari.pool.HikariPool.PoolInitializationException;
|
||||||
*/
|
*/
|
||||||
@NonNullByDefault
|
@NonNullByDefault
|
||||||
public class JdbcMapper {
|
public class JdbcMapper {
|
||||||
private final Logger logger = LoggerFactory.getLogger(JdbcMapper.class);
|
private static final int MIGRATION_PERCENTAGE_THRESHOLD = 50;
|
||||||
|
|
||||||
|
private final Logger logger = LoggerFactory.getLogger(JdbcMapper.class);
|
||||||
private final TimeZoneProvider timeZoneProvider;
|
private final TimeZoneProvider timeZoneProvider;
|
||||||
|
|
||||||
// Error counter - used to reconnect to database on error
|
// Error counter - used to reconnect to database on error
|
||||||
|
@ -407,6 +408,25 @@ public class JdbcMapper {
|
||||||
initialized = tmpinit;
|
initialized = tmpinit;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// Safety valve to prevent accidental migrations.
|
||||||
|
int numberOfTables = itemTables.size();
|
||||||
|
if (numberOfTables > 0) {
|
||||||
|
String prefix = conf.getTableNamePrefix();
|
||||||
|
long numberOfItemsWithPrefix = itemTables.stream()
|
||||||
|
.filter(i -> i.startsWith(prefix) || i.toLowerCase().startsWith("item")).count();
|
||||||
|
long percentageWithPrefix = (numberOfItemsWithPrefix * 100) / itemTables.size();
|
||||||
|
if (!prefix.isBlank() && percentageWithPrefix >= MIGRATION_PERCENTAGE_THRESHOLD) {
|
||||||
|
logger.error(
|
||||||
|
"JDBC::formatTableNames: {}% of all tables start with table name prefix '{}' or 'item', but items manage table '{}' was not found or is empty. Check configuration parameter 'itemsManageTable'",
|
||||||
|
percentageWithPrefix, conf.getTableNamePrefix(), conf.getItemsManageTable());
|
||||||
|
if (ifTableExists("items")) {
|
||||||
|
logger.error(
|
||||||
|
"JDBC::formatTableNames: Table 'items' was found, consider updating configuration parameter 'itemsManageTable' accordingly");
|
||||||
|
}
|
||||||
|
initialized = tmpinit;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
oldNewTableNames = new ArrayList<>();
|
oldNewTableNames = new ArrayList<>();
|
||||||
for (String itemName : itemTables) {
|
for (String itemName : itemTables) {
|
||||||
ItemsVO isvo = new ItemsVO();
|
ItemsVO isvo = new ItemsVO();
|
||||||
|
|
|
@ -322,6 +322,12 @@ public class JdbcPersistenceService extends JdbcMapper implements ModifiablePers
|
||||||
*/
|
*/
|
||||||
public Collection<String> getSchemaIssues(String tableName, String itemName) throws JdbcSQLException {
|
public Collection<String> getSchemaIssues(String tableName, String itemName) throws JdbcSQLException {
|
||||||
List<String> issues = new ArrayList<>();
|
List<String> issues = new ArrayList<>();
|
||||||
|
|
||||||
|
if (!checkDBAccessability()) {
|
||||||
|
logger.warn("JDBC::getSchemaIssues: database not connected");
|
||||||
|
return issues;
|
||||||
|
}
|
||||||
|
|
||||||
Item item;
|
Item item;
|
||||||
try {
|
try {
|
||||||
item = itemRegistry.getItem(itemName);
|
item = itemRegistry.getItem(itemName);
|
||||||
|
@ -375,6 +381,11 @@ public class JdbcPersistenceService extends JdbcMapper implements ModifiablePers
|
||||||
* @throws JdbcSQLException on SQL errors
|
* @throws JdbcSQLException on SQL errors
|
||||||
*/
|
*/
|
||||||
public boolean fixSchemaIssues(String tableName, String itemName) throws JdbcSQLException {
|
public boolean fixSchemaIssues(String tableName, String itemName) throws JdbcSQLException {
|
||||||
|
if (!checkDBAccessability()) {
|
||||||
|
logger.warn("JDBC::fixSchemaIssues: database not connected");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
Item item;
|
Item item;
|
||||||
try {
|
try {
|
||||||
item = itemRegistry.getItem(itemName);
|
item = itemRegistry.getItem(itemName);
|
||||||
|
@ -469,6 +480,11 @@ public class JdbcPersistenceService extends JdbcMapper implements ModifiablePers
|
||||||
* @throws JdbcSQLException
|
* @throws JdbcSQLException
|
||||||
*/
|
*/
|
||||||
public boolean cleanupItem(String itemName, boolean force) throws JdbcSQLException {
|
public boolean cleanupItem(String itemName, boolean force) throws JdbcSQLException {
|
||||||
|
if (!checkDBAccessability()) {
|
||||||
|
logger.warn("JDBC::cleanupItem: database not connected");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
String tableName = itemNameToTableNameMap.get(itemName);
|
String tableName = itemNameToTableNameMap.get(itemName);
|
||||||
if (tableName == null) {
|
if (tableName == null) {
|
||||||
return false;
|
return false;
|
||||||
|
|
Loading…
Reference in New Issue