Closed chytonpide closed 2 years ago
@chytonpide Thanks for the very complete issue report. Can you clarify with a code snippet what you mean by this?
include the database name in the tables name for the Dispatcher
I think this is the more correct way. I am concerned about breaking changes, however.
@VaughnVernon I mean that adding database name on dispatchableTableName()
to every concrete class of JDBCStorageDelegate
like this.
@Override
protected String dispatchableTableName() {
return MessageFormat.format(TBL_VLINGO_SYMBIO_DISPATCHABLES, configuration.databaseName);
}
String TBL_VLINGO_SYMBIO_DISPATCHABLES = "{0}_tbl_xoom_symbio_dispatchables";
For Mysql and Postgres it would be also working that passing the database name as catalog parameter to DatabaseMetaData.getTables()
on JDBCStorageDelegate
like this.
private boolean tableExists(final String tableName) throws Exception {
final DatabaseMetaData metadata = connection.getMetaData();
try (final ResultSet resultSet = metadata.getTables(connectionProvider.databaseName, null, tableName, null)) {
return resultSet.next();
}
}
But It is not working on HSQLDB. On HSQLDB catalog means not the database or namespace.
DatabaseMetaData
seems to have a slightly different meaning and scope for each database.
So What about changing the tableExists
method into a protected abstract method on JDBCStorageDelegate
?
protected abstract boolean tableExists(final String tableName) throws Exception;
@chytonpide Wouldn't the database name be required for all tables used by XOOM, or only for Dispatchables
because it is the only table with a common name across databases?
@VaughnVernon You are right. I'm sorry. Yes, the database name is required for all tables used by XOOM with the storage type as the state store.
I would like to talk in more detail about the alternative that moves the private method tableExists
on JDBCStorageDelegate
to its child classes.
The responsibility to implement tableExists
is moved to its child classes.
public abstract class JDBCStorageDelegate<T> implements StorageDelegate,
DispatcherControl.DispatcherControlDelegate<Entry<?>, State<?>> {
...
protected abstract boolean tableExists(final String tableName) throws Exception
...
}
The implementation of tableExists
is exactly the same as the current private method tableExists
on JDBCStorageDelegate
.
I think there are no any other side effects because only the location of the implementation is changed.
public class PostgresStorageDelegate extends JDBCStorageDelegate<Object> implements StorageDelegate, PostgresQueries {
...
@Override
protected boolean tableExists(final String tableName) throws Exception {
final DatabaseMetaData metadata = connection.getMetaData();
try (final ResultSet resultSet = metadata.getTables(null, null, tableName, null)) {
return resultSet.next();
}
...
}
Same as PostgresStorageDelegate case.
public class YugaByteStorageDelegate extends PostgresStorageDelegate {
...
...
}
Same as PostgresStorageDelegate case.
public class HSQLDBStorageDelegate extends JDBCStorageDelegate<Blob> implements StorageDelegate, HSQLDBQueries {
...
@Override
protected boolean tableExists(final String tableName) throws Exception {
final DatabaseMetaData metadata = connection.getMetaData();
try (final ResultSet resultSet = metadata.getTables(null, null, tableName, null)) {
return resultSet.next();
}
...
}
The implementation of tableExists
is changed.
connectionProvider.databasename
is passed as argument to the DatabaseMetaData.getTables
.
DatabaseMetaData.getTables
's scope is limited to the currently connected database.
public class MySQLStorageDelegate extends JDBCStorageDelegate<Object> implements StateStore.StorageDelegate, MySQLQueries{
...
@Override
protected boolean tableExists(final String tableName) throws Exception {
final DatabaseMetaData metadata = connection.getMetaData();
try (final ResultSet resultSet = metadata.getTables(connectionProvider.databaseName, null, tableName, null)) {
return resultSet.next();
}
...
}
@chytonpide Good idea, thanks.
Would using the database (catalog) scope work for all database types?
metadata.getTables(connectionProvider.databaseName, null, tableName, null)
If so, that is the logical change for all database types.
We could still make tableExists()
a protected method in case a specific database type implementation must override it.
@VaughnVernon No it didn't work on Hsqldb. But, others work well with the catalog parameter. This is the test result and the test code.
We could still make tableExists() a protected method in case a specific database type implementation must override it.
I agree with this. It seems more common for the catalog to mean DB. I will test the other relational DB as well.
@VaughnVernon I have tested MariaDB, MsSqlServer, and OracleDB additionally.
These JDBC driver's getTable
work with the catalog parameter. (passing database name)
This JDBC dirver's getTable
didn't work with the catalog parameter. (passing database name)
@chytonpide I have increased tableExists()
visibility to protected
and also added protected String catalogName()
to JDBCStorageDelegate
. Now tableExists()
calls catalogName()
so that in most cases only catalogName()
would have to be overridden. Still, either or both methods can be overridden.
Also the HSQLDBStorageDelegate
now overrides only catalogName()
to return null
rather than databaseName
.
Note: MariaDB is supported by using MySQL. The two database types are 100% compatible.
Do you have XOOM Symbio JDBC implementations for MS SQL Server and Oracle?
Thanks for your help!
Do you have XOOM Symbio JDBC implementations for MS SQL Server and Oracle?
No, I don't have XOOM Symbio JDBC implementations for MS SQL Server and Oracle.
I just tested DatabaseMetaData of JDBC drivers.
This is my test code for Oracle and MS SQL Server.
I am afraid I can't contribute to them as this is my first time using Oracle and MS SQL Server.
(Actually, even the installation of Oracle was quite difficult for me.)
Thanks for confirming, @chytonpide.
I understand now how you testes. I appreciate the trouble you went through to test SQL Server and Oracle.
BTW, in case I was not clear enough about MariaDB, you would use use xoom-symbio-jdbc for MySQL to support MariaDB. They are the same from a XOOM perspective.
Description
JDBCStorageDelegate.tableExists()
usesDatabaseMetaData.getTables()
its inside. However, JDBC DatabaseMetaData has a different scope depending on the database. So,JDBCStorageDelegate.tableExists()
returns different result depending on the database.For example, In Mysql, when you create
tableA
and ondatabaseA
and then createtableA
(the same name) ondatabaseB
,DatabaseMetaData.getTables(null, null, "tableA", null)
returns two results. Regardless of the currentconnection
,DatabaseMetaData
is about the scope of the entire database.On the other hand, In Postgresql,
DatabaseMetaData
is about the scope of the currently connected database. If you have theconnection
todatabaseA
,DatabaseMetaData.getTables(null, null, "tableA", null)
returns only one result.This is the test for
DatabaseMetaData
. It fails with the Mysql driver but success with the Postgresql driver.Influence
It causes a problem when query and command databases are placed in the same Mysql instance.
tableExists()
returns true even if tables are created in only one of the two databases in Mysql. It causes to skip creating tables for Dispatcher that has the same name on each database.I have encountered this problem with this
xoom-turbo.properties
when I created a project using xoom-designer.Suggestion
It may be a solution to include the database name in the tables name for the Dispatcher or Adding the constraint that the query database and command database should be placed in the different database instances.