Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[jdbc] Add support for case sensitive table names reflecting item names 1:1 #13544

Merged
merged 20 commits into from
Nov 5, 2022

Conversation

jlaur
Copy link
Contributor

@jlaur jlaur commented Oct 13, 2022

Add support for case sensitive tables named 1:1 by corresponding items, eliminating the need for an items management/mapping table.

Additionally:

  • Fix migration for MySQL when Multiple Statement Execution Support is not configured/supported. See below.
  • Fix migration when tableNamePrefix is changed. All migration paths are supported now.
  • Fix migration stopping on first unknown item.
  • Minor refactoring for readability (in context of changes) which also happened to remove some checkstyle warnings.

Fixes #11906

MySQL and Multiple Statement Execution Support

When Multiple Statement Execution Support is not configured/supported, the following exception would be thrown when migrating tables:

2022-10-16 14:56:32.114 [DEBUG] [nhab.persistence.jdbc.db.JdbcBaseDAO] - JDBC::query queryString = ALTER TABLE Item1 RENAME TO newitem;ALTER TABLE Item2 RENAME TO another_item;
2022-10-16 14:56:32.115 [ERROR] [org.knowm.yank.Yank                 ] - Error in SQL query!!!
java.sql.SQLException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'ALTER TABLE Item2 RENAME TO another_item' at line 1 Query: ALTER TABLE Item1 RENAME TO newitem;ALTER TABLE Item2 RENAME TO another_item; Parameters: []
	at org.apache.commons.dbutils.AbstractQueryRunner.rethrow(AbstractQueryRunner.java:392) ~[bundleFile:?]
	at org.apache.commons.dbutils.QueryRunner.update(QueryRunner.java:491) ~[bundleFile:?]
	at org.apache.commons.dbutils.QueryRunner.update(QueryRunner.java:457) ~[bundleFile:?]
	at org.knowm.yank.Yank.execute(Yank.java:194) [bundleFile:?]
	at org.knowm.yank.Yank.execute(Yank.java:177) [bundleFile:?]
	at org.openhab.persistence.jdbc.db.JdbcBaseDAO.doUpdateItemTableNames(JdbcBaseDAO.java:311) [bundleFile:?]
	at org.openhab.persistence.jdbc.internal.JdbcMapper.updateItemTableNames(JdbcMapper.java:148) [bundleFile:?]
	at org.openhab.persistence.jdbc.internal.JdbcMapper.formatTableNames(JdbcMapper.java:343) [bundleFile:?]
	at org.openhab.persistence.jdbc.internal.JdbcMapper.checkDBSchema(JdbcMapper.java:257) [bundleFile:?]
	at org.openhab.persistence.jdbc.internal.JdbcPersistenceService.updateConfig(JdbcPersistenceService.java:235) [bundleFile:?]
	at org.openhab.persistence.jdbc.internal.JdbcPersistenceService.activate(JdbcPersistenceService.java:89) [bundleFile:?]

References

Testing

I have manually tested most combinations of migration paths:

S = Source, T = Target
Prefix = tableNamePrefix, Real = tableUseRealItemNames, Case = tableCaseSensitiveItemNames, Digit = tableIdDigitCount

S:Prefix S:Real S:Case S:Digit S:Example T:Prefix T:Real T:Case T:Digit T:Result
Item false false 4 Item0001 item false false 4 item0001
Item false false 4 Item0001 Item false false 3 Item001
Item false false 4 Item0001 Item true false 4 myitem_0001
Item false false 4 Item0001 Item true true 4 MyItem
Item true false 4 myitem_0001 Item true true 4 MyItem
Item true false 4 myitem_0001 Item false false 4 Item0001
Item true true 4 MyItem Item false false 4 Item0001
Item true true 4 MyItem Item true false 4 myitem_0001

All of the above on a test database both with a copy of my production schema consisting of more than 200 tables, as well as small dedicated test scenarios with tricky naming etc.

Additionally I have performed tests of creating new items and tables with different configurations.

All tests have been performed only in MySQL. A forum user has tested with MariaDB.

JAR for testing: https://drive.google.com/file/d/1_CmJtYa2pwrN_LlrWu1H75muOW6seam7/view?usp=sharing

Note: Place the corresponding database driver into the addons directory. For example, download the MySQL connector and rename it to mysql-connector-java.jar.

@jlaur jlaur added bug An unexpected problem or unintended behavior of an add-on additional testing preferred The change works for the pull request author. A test from someone else is preferred though. labels Oct 13, 2022
@openhab-bot
Copy link
Collaborator

This pull request has been mentioned on openHAB Community. There might be relevant details there:

https://community.openhab.org/t/jdbc-persistence-with-tableuserealitemnames-and-tableiddigitcount-0/40552/8

@cweitkamp
Copy link
Contributor

I am looking forward to this fix. Currently I have the slight feeling that it will break a lot of users persistence when they are already using the tableUseRealItemNames=true configuration but still having table names with number prefixes. The new implementation creates name without prefix and probably creates a new table with that name because it is not able to match it to the existing table. Do you think we can set up a cleaning script to rename existing tables and their associated entries in the items table?

Furthermore I would like to question if the mentioned items table is needed anymore when setting this configuration to true.

@jlaur
Copy link
Contributor Author

jlaur commented Oct 14, 2022

I am looking forward to this fix. Currently I have the slight feeling that it will break a lot of users persistence when they are already using the tableUseRealItemNames=true configuration but still having table names with number prefixes. The new implementation creates name without prefix and probably creates a new table with that name because it is not able to match it to the existing table.

Good point, this needs to be verified (I have not started any testing yet):

private void formatTableNames() {
boolean tmpinit = initialized;
if (tmpinit) {
initialized = false;
}
Map<Integer, String> tableIds = new HashMap<>();
//
for (ItemsVO vo : getItemIDTableNames()) {
String t = getTableName(vo.getItemid(), vo.getItemname());
sqlTables.put(vo.getItemname(), t);
tableIds.put(vo.getItemid(), t);
}
//
List<ItemsVO> al = getItemTables();
String oldName = "";
String newName = "";
List<ItemVO> oldNewTablenames = new ArrayList<>();
for (int i = 0; i < al.size(); i++) {
int id = -1;
oldName = al.get(i).getTable_name();
logger.info("JDBC::formatTableNames: found Table Name= {}", oldName);
if (oldName.startsWith(conf.getTableNamePrefix()) && !oldName.contains("_")) {
id = Integer.parseInt(oldName.substring(conf.getTableNamePrefix().length()));
logger.info("JDBC::formatTableNames: found Table with Prefix '{}' Name= {} id= {}",
conf.getTableNamePrefix(), oldName, (id));
} else if (oldName.contains("_")) {
id = Integer.parseInt(oldName.substring(oldName.lastIndexOf("_") + 1));
logger.info("JDBC::formatTableNames: found Table Name= {} id= {}", oldName, (id));
}
logger.info("JDBC::formatTableNames: found Table id= {}", id);
newName = tableIds.get(id);
logger.info("JDBC::formatTableNames: found Table newName= {}", newName);
if (newName != null) {
if (!oldName.equalsIgnoreCase(newName)) {
oldNewTablenames.add(new ItemVO(oldName, newName));
logger.info("JDBC::formatTableNames: Table '{}' will be renamed to '{}'", oldName, newName);
} else {
logger.info("JDBC::formatTableNames: Table oldName='{}' newName='{}' nothing to rename", oldName,
newName);
}
} else {
logger.error("JDBC::formatTableNames: Table '{}' could NOT be renamed to '{}'", oldName, newName);
break;
}
}
updateItemTableNames(oldNewTablenames);
logger.info("JDBC::formatTableNames: Finished updating {} item table names", oldNewTablenames.size());
initialized = tmpinit;
}

Do you think we can set up a cleaning script to rename existing tables and their associated entries in the items table?

This should be possible by using the existing configuration option rebuildTableNames:
https://www.openhab.org/addons/persistence/jdbc/#configuration

But now it needs to support also migration from old to new behavior.

Furthermore I would like to question if the mentioned items table is needed anymore when setting this configuration to true.

Agreed, by principle it shouldn't be needed, although it might require some additional effort to get rid of. Also, case sensitivity would need to be checked - I believe I saw some example in the forum thread with lower case table names while having camel case item names.

Signed-off-by: Jacob Laursen <jacob-github@vindvejr.dk>
@jlaur jlaur force-pushed the 11906-jdbc-tableUseRealItemNames branch from a3579f9 to c843a1c Compare October 14, 2022 14:31
jlaur added 3 commits October 14, 2022 17:04
Signed-off-by: Jacob Laursen <jacob-github@vindvejr.dk>
Signed-off-by: Jacob Laursen <jacob-github@vindvejr.dk>
Signed-off-by: Jacob Laursen <jacob-github@vindvejr.dk>
@jlaur jlaur force-pushed the 11906-jdbc-tableUseRealItemNames branch from 234b19e to c62672a Compare October 14, 2022 22:32
Signed-off-by: Jacob Laursen <jacob-github@vindvejr.dk>
@jlaur jlaur force-pushed the 11906-jdbc-tableUseRealItemNames branch from 6ae8e54 to d896763 Compare October 16, 2022 09:09
Signed-off-by: Jacob Laursen <jacob-github@vindvejr.dk>
@jlaur jlaur force-pushed the 11906-jdbc-tableUseRealItemNames branch from bf4bbd2 to 151a43f Compare October 16, 2022 12:06
jlaur added 3 commits October 16, 2022 15:01
Signed-off-by: Jacob Laursen <jacob-github@vindvejr.dk>
Signed-off-by: Jacob Laursen <jacob-github@vindvejr.dk>
Signed-off-by: Jacob Laursen <jacob-github@vindvejr.dk>
@jlaur
Copy link
Contributor Author

jlaur commented Oct 17, 2022

@cweitkamp - as I've been working my way through this, getting more acquainted with the code and also started testing things, I have now realized a few things and could use some feedback.

Even though current implementation of tableUseRealItemNames is inconsistent with the documentation, you have a valid point that users might be using this, so we need backwards compatibility. Therefore I would suggest to fix the documentation and keep current behavior when using just tableUseRealItemNames. In the latest commit I introduced tablePreserveCase, but now I would suggest to change/simplify this so we don't have many strange combinations of options, but instead just this:

  • tableUseRealItemNames = true, tableCaseSensitiveDirectMapping = false: Backwards compatible behavior, e.g. myitem_0001.
  • tableUseRealItemNames = true, tableCaseSensitiveDirectMapping = true: Number suffix is omitted and item name is case sensitive, e.g. MyItem.

A better name for the new option would be needed. :-) The thinking is that without case sensitive naming of tables, we risk collisions since item names in openHAB are case sensitive, i.e. you can have both MyItem and myItem. So to really solve that, we would need a suffix of some sort anyway. Case sensitive table names can depend on database, OS, filesystem, database configuration and other things, but IMHO this would be required for this fix to make any sense. So either users can choose current behavior with number suffix, or if supported by their database, they can use direct mapping from item name to table name.

Now, the only problem left could be difference in rules between item naming and table naming. I didn't mange to find the regex for item names yet, but from the UI at least it seems to be quite restrictive, so I'm hoping this won't be a problem. If an item could be named my-item, for example, this would be stripped to myitem, and then we would again risk collisions.

I have provided unit tests documenting the issues and migration paths. Next, if we agree on some sensible approach, I would then adapt the code, tests and documentation accordingly, which shouldn't be much additional work at this point. I would also be prepared to drop the items table entirely when running in "new mode".

Remove real name in lower case without suffix mode

Signed-off-by: Jacob Laursen <jacob-github@vindvejr.dk>
@jlaur jlaur force-pushed the 11906-jdbc-tableUseRealItemNames branch from b8456df to 6da14c2 Compare October 21, 2022 14:53
@jlaur
Copy link
Contributor Author

jlaur commented Oct 21, 2022

Now found item name regex:
/~https://github.com/openhab/openhab-core/blob/792b7511bf9bb830ec48b8f81bb0437f1b7ce867/bundles/org.openhab.core/src/main/java/org/openhab/core/items/ItemUtil.java#L56-L58

As it is more restrictive than the current regex for table names, case sensitive table names will be safe from collisions.

jlaur added 7 commits October 21, 2022 21:59
Signed-off-by: Jacob Laursen <jacob-github@vindvejr.dk>
Signed-off-by: Jacob Laursen <jacob-github@vindvejr.dk>
Signed-off-by: Jacob Laursen <jacob-github@vindvejr.dk>
Signed-off-by: Jacob Laursen <jacob-github@vindvejr.dk>
Signed-off-by: Jacob Laursen <jacob-github@vindvejr.dk>
Signed-off-by: Jacob Laursen <jacob-github@vindvejr.dk>
Signed-off-by: Jacob Laursen <jacob-github@vindvejr.dk>
@jlaur jlaur force-pushed the 11906-jdbc-tableUseRealItemNames branch from 88da107 to 330aae2 Compare October 22, 2022 15:21
@jlaur jlaur marked this pull request as ready for review October 22, 2022 20:03
@jlaur jlaur requested a review from a team as a code owner October 22, 2022 20:03
@jlaur
Copy link
Contributor Author

jlaur commented Oct 22, 2022

@cweitkamp - done. Backwards compatibility ensured and all migration paths supported.

@openhab-bot
Copy link
Collaborator

This pull request has been mentioned on openHAB Community. There might be relevant details there:

https://community.openhab.org/t/jdbc-persistence-with-tableuserealitemnames-and-tableiddigitcount-0/40552/11

@jlaur jlaur removed the additional testing preferred The change works for the pull request author. A test from someone else is preferred though. label Oct 23, 2022
Signed-off-by: Jacob Laursen <jacob-github@vindvejr.dk>
@jlaur
Copy link
Contributor Author

jlaur commented Oct 27, 2022

@openhab/add-ons-maintainers - I'm not sure whether this should be labelled as "bug" or "enhancement". For sure the documentation was misleading. In either case, would anyone be up for reviewing this? It would be really nice to finalize for the next milestone, so there would still be time for user feedback before the release.

tableUseRealItemNames

When set to true, real item names are used for table names

True, they were used, but lowercased and with a number suffix added (MyItem -> myitem_0001).

and tableNamePrefix is ignored.

True.

When set to false, the tableNamePrefix is used to generate table names with sequential numbers.

True. However, without using tableNamePrefix, there would also be sequential numbers.

tableIdDigitCount

when tableUseRealItemNames is false and thus table names are generated sequentially,

(which was also the case when tableUseRealItemNames was true)

this controls how many zero-padded digits are used in the table name.

True. But there would still be sequential numbers with padding according to this setting with tableUseRealItemNames being true.

@jlaur jlaur added enhancement An enhancement or new feature for an existing add-on and removed bug An unexpected problem or unintended behavior of an add-on labels Oct 31, 2022
@jlaur
Copy link
Contributor Author

jlaur commented Oct 31, 2022

@cweitkamp - do you think you could find time to have a look at this?

@lolodomo
Copy link
Contributor

lolodomo commented Nov 1, 2022

@jlaur : having a look at the global result of the static code analysis (all bindings), I found that one. Maybe you could check,.
image

@jlaur
Copy link
Contributor Author

jlaur commented Nov 1, 2022

@jlaur : having a look at the global result of the static code analysis (all bindings), I found that one. Maybe you could check,. image

I already checked this in context of #13429, but I'm not sure what to do with it:

@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((itemname == null) ? 0 : itemname.hashCode());
result = prime * result + (itemid ^ (itemid >>> 32));
return result;
}

It looks like it was generated by Eclipse:
https://www.baeldung.com/java-hashcode

It will work according to implementation requirements, but of course it would be nice to get rid of this checkstyle warning.

@jlaur
Copy link
Contributor Author

jlaur commented Nov 2, 2022

@lolodomo - would you be able to find time for reviewing this PR before M4? I have time the next few evenings for making corrections during review.

@lolodomo
Copy link
Contributor

lolodomo commented Nov 2, 2022

would you be able to find time for reviewing this PR before M4?

Probably only a limited time until next weekend.

Copy link
Contributor

@lolodomo lolodomo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have not reviewed in details but looks good to me.
Just one question.

Copy link
Contributor

@lolodomo lolodomo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thank you

@lolodomo lolodomo merged commit 70abb5d into openhab:main Nov 5, 2022
@lolodomo lolodomo added this to the 3.4 milestone Nov 5, 2022
andan67 pushed a commit to andan67/openhab-addons that referenced this pull request Nov 6, 2022
…es 1:1 (openhab#13544)

* Do not append number when using real item names
* Extract getTableName to separate class
* Add initial test coverage
* Extract migration logic to separate class
* Support migration from real names back to numbered
* Simplify zero-padding
* Fix NullPointerException
* Fix MySQL compatibility when CLIENT_MULTI_STATEMENTS option is not set
* Add option for case sensitive table names
* Add real name with suffix mode for backwards compatibility
* Remove real name in lower case without suffix mode
* Map directly from item name to table name
* Fix ambiguous table name scenario
* Add additional testcase
* Add migration path for changed table prefix
* Drop items table when using direct mapping
* Add configuration note
* Fix table alignment
* Extend description as more migration paths are now supported
* Do not stop halfway through a migration
* For clarity, do not use abbreviation for operating system

Signed-off-by: Jacob Laursen <jacob-github@vindvejr.dk>
@jlaur
Copy link
Contributor Author

jlaur commented Nov 14, 2022

@jlaur : having a look at the global result of the static code analysis (all bindings), I found that one. Maybe you could check,. image

I already checked this in context of #13429, but I'm not sure what to do with it:

@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((itemname == null) ? 0 : itemname.hashCode());
result = prime * result + (itemid ^ (itemid >>> 32));
return result;
}

It looks like it was generated by Eclipse: https://www.baeldung.com/java-hashcode

It will work according to implementation requirements, but of course it would be nice to get rid of this checkstyle warning.

@lolodomo - this is now addressed by commit 18892b8 in #13719.

borazslo pushed a commit to borazslo/openhab-mideaac-addon that referenced this pull request Jan 8, 2023
…es 1:1 (openhab#13544)

* Do not append number when using real item names
* Extract getTableName to separate class
* Add initial test coverage
* Extract migration logic to separate class
* Support migration from real names back to numbered
* Simplify zero-padding
* Fix NullPointerException
* Fix MySQL compatibility when CLIENT_MULTI_STATEMENTS option is not set
* Add option for case sensitive table names
* Add real name with suffix mode for backwards compatibility
* Remove real name in lower case without suffix mode
* Map directly from item name to table name
* Fix ambiguous table name scenario
* Add additional testcase
* Add migration path for changed table prefix
* Drop items table when using direct mapping
* Add configuration note
* Fix table alignment
* Extend description as more migration paths are now supported
* Do not stop halfway through a migration
* For clarity, do not use abbreviation for operating system

Signed-off-by: Jacob Laursen <jacob-github@vindvejr.dk>
psmedley pushed a commit to psmedley/openhab-addons that referenced this pull request Feb 23, 2023
…es 1:1 (openhab#13544)

* Do not append number when using real item names
* Extract getTableName to separate class
* Add initial test coverage
* Extract migration logic to separate class
* Support migration from real names back to numbered
* Simplify zero-padding
* Fix NullPointerException
* Fix MySQL compatibility when CLIENT_MULTI_STATEMENTS option is not set
* Add option for case sensitive table names
* Add real name with suffix mode for backwards compatibility
* Remove real name in lower case without suffix mode
* Map directly from item name to table name
* Fix ambiguous table name scenario
* Add additional testcase
* Add migration path for changed table prefix
* Drop items table when using direct mapping
* Add configuration note
* Fix table alignment
* Extend description as more migration paths are now supported
* Do not stop halfway through a migration
* For clarity, do not use abbreviation for operating system

Signed-off-by: Jacob Laursen <jacob-github@vindvejr.dk>
nemerdaud pushed a commit to nemerdaud/openhab-addons that referenced this pull request Feb 28, 2023
…es 1:1 (openhab#13544)

* Do not append number when using real item names
* Extract getTableName to separate class
* Add initial test coverage
* Extract migration logic to separate class
* Support migration from real names back to numbered
* Simplify zero-padding
* Fix NullPointerException
* Fix MySQL compatibility when CLIENT_MULTI_STATEMENTS option is not set
* Add option for case sensitive table names
* Add real name with suffix mode for backwards compatibility
* Remove real name in lower case without suffix mode
* Map directly from item name to table name
* Fix ambiguous table name scenario
* Add additional testcase
* Add migration path for changed table prefix
* Drop items table when using direct mapping
* Add configuration note
* Fix table alignment
* Extend description as more migration paths are now supported
* Do not stop halfway through a migration
* For clarity, do not use abbreviation for operating system

Signed-off-by: Jacob Laursen <jacob-github@vindvejr.dk>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
community approved enhancement An enhancement or new feature for an existing add-on
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[jdbc] even with tableUseRealItemNames=true a table name suffix is created
4 participants