Hi

While trying to debug an old and highly annoying issue where Base can only
use "Tools" -> "Relationships" and "User Administration" when you connect
to MySQL over ODBC, but not over JDBC, I found and fixed a large number of
other bugs:

-------------------------------------------------------------------------------
1. "Tools" -> "Relationships" and "User Administration" only work in MySQL
when connected over ODBC, not JDBC.
-------------------------------------------------------------------------------
DatabaseMetaData::supportsRelations()
in main/connectivity/source/commontools/dbmetadata.cxx wants the
DatabaseMetaData to either return true
for supportsIntegrityEnhancementFacility(), or getURL() to begin with
"sdbc:mysql". The MySQL JDBC driver unfortunately both returns false
for supportsIntegrityEnhancementFacility(), and returns a URL starting with
"jdbc:mysql" instead.

In the same file, DatabaseMetaData::supportsUserAdministration() looks up
the XDataDefinitionSupplier interface from the Driver, but to obtain the
driver, it uses the URL from the connection's metadata, which starts with
the wrong "jdbc:mysql" as above.

Why do these features work with the ODBC connector? Because our MySQL SDBC
driver (main/connectivity/source/drivers/mysql/YDriver.cxx),
in ODriverDelegator::connect(), after a successful connection, will call
"pMetaConnection->setURL(url)" with its own URL, and getURL() in the
metadata from that connection will return that URL instead.

However an enormous amount of work and complexity goes into achieving that.
The setURL() method is not in the UNO specification, so the code hacks
through UNO using XUnoTunnel to retrieve a raw C++ pointer to call the
method on. Only ODBC uses the OMetaConnection class which provides this
setURL() feature, neither the old SDBC/JDBC bridge nor my new one do. My
new one also can't provide it since it is all in Java, and XUnoTunnel
doesn't work outside C++.

But do we really need to change UNO definitions or use only C++ just to
return 1 custom string? (The Adabas driver only works over ODBC for this
very reason...)

Of course not, there are many ways to get the SDBC/JDBC bridge to return a
custom URL for getURL():
1. Get JavaSQLConnection to implement the XPropertySet interface,
queryInterface() for that interface, and if present, set the field there.
Get the JavaSQLConnection metadata to return that when getURL() is called.
2. Pass the URL in the arguments to
XMultiComponentFactory.createInstanceWithArgumentsAndContext() when
the JavaSQLConnection is created.
3. XDriver::connect() already gets passed an array of PropertyValue, so it
could be added into that array.

XPropertySet requires adding several methods and is mostly intended for
properties that can continuously change, so it's overkill, and the problem
with XMultiComponentFactory.createInstanceWithArgumentsAndContext() is that
the arguments are nameless and all callers would have to change, so option
3 is the smallest, most compatible, and least invasive.

With that change made, and the other errors below fixed, it works, both
"Relationships" and "User administration" fully work with JDBC :-).

-------------------------------------------------------------------------------
2. java.lang.StackOverflowError in Tools.toUnoException()
-------------------------------------------------------------------------------
Some form of infinite recursion takes place, because on some exceptions, an
exception's getCause() returns a pointer to itself. Instead of just
checking for this condition, I've gone further and limited the maximum
recursion to 8 steps, which also prevents other exception cause cycles from
causing infinite recursion.

-------------------------------------------------------------------------------
3. Our ODBC driver only supports unixODBC on Linux/FreeBSD, not iODBC
-------------------------------------------------------------------------------
This is regrettable as we are compatible with both. FreeBSD only has iODBC
in its package repository. This was a very easy fix, but we should discuss
things like the priority we load them in when both are present, and whether
it should be user configurable.

-------------------------------------------------------------------------------
4. MySQL >= 8.0.11 removed the PASSWORD() function.
-------------------------------------------------------------------------------
https://dev.mysql.com/doc/refman/8.0/en/upgrading-from-previous-series.html

I've removed that function from OMySQLUser::changePassword(), and it works
on MySQL 8.4, but I wonder about earlier versions.

---

What's also interesting about (1) is that if we use that mechanism to set
the URL on internal database connections, a lot of code can possibly be
simplified and deleted. For example we no longer need XUnoTunnel for that,
and could eventually even remove the whole OMetaConnection class.
XUnoTunnel is used far too damn much in main/connectivity, it needs to
disappear! (I don't know what drove past developers into such object
orientation extremism, to use XUnoTunnel so they can call a new method,
instead of passing a new setting to an existing method.)

It's been a hard but productive journey. I'll try to clean up these changes
and commit them soon.

Regards
Damjan

Reply via email to