jtds.jdbc.JtdsConnection.createBlob java.lang.AbstractMethodError - jdbc

mvn:net.sourceforge.jtds/jtds/1.3.1-patch-20190523/jar
to save to a Microsoft SQL Server database.
Actually this JDBC driver is provided by Talend. For various reasons, I have some Java JDBC code which saves blobs to the database. This works fine with an Oracle DB.
try (Connection con = DriverManager.getConnection(this.connectionString, this.user, this.pw)) {
insert(con, ags, snr, productVersion, nummer, inhalt, this.migrationsBenutzer, format, daten);
}
public long insert(Connection con, String ags, String snr, int productVersion ,int nummer,String inhalt, String benutzer, String format, byte[] daten) throws SQLException {
long result = 0;
String timestamp = now();
try {
Blob blob = con.createBlob();
blob.setBytes(1, daten);
PreparedStatement ps = con.prepareStatement(this.insert);
...
ps.setBlob(9, blob);
result = ps.executeUpdate();
However when I call the method with a connection string for jtds:
jdbc:jtds:sqlserver://:1433;databaseName=
I get this exception
Exception in thread "main" java.lang.AbstractMethodError
at net.sourceforge.jtds.jdbc.JtdsConnection.createBlob(JtdsConnection.java:2776)
at de.iteos.dao.BildspeichernDAO.insert(BildspeichernDAO.java:60)
What can I do? If feasible I want to keep the method a generic as possible. Do I have to switch to another JDBC driver? I have read somewhere that this could be solved with a validation query. For this I would have to implement two different DataSources for Oracle and SQL Server right?

The problem is that jTDS is - as far as I know - no longer maintained, and available versions are stuck on JDBC 3.0 (Java 1.4) support. The method Connection.createBlob you're trying to call was introduced in JDBC 4.0 (Java 6). Attempts to call this method on a driver that was compiled against the JDBC 3.0 API will result in AbstractMethodError as the method from JDBC 4.0 (or higher) is not implemented.
The simplest and best solution is probably to switch to the Microsoft SQL Server JDBC driver.
Alternatively, you need to switch to the JDBC 3.0 options for populating a blob, that is, using the PreparedStatement.setBinaryStream(int, InputStream, int) method (not to be confused with setBinaryStream(int, InputStream) or setBinaryStream(int, InputStream, long) introduced in JDBC 4.0!), or possibly setBytes(int, byte[]), or using driver specific methods for creating blobs.
The validation query solution you mention doesn't apply here, that solves a problem with Connection.isValid that the data source implementation in some Tomcat versions calls by default, unless you configure a validation query. It has the same underlying cause (the isValid method was also introduced in JDBC 4.0).
I'm not sure what you mean with "I would have to implement two different DataSources for Oracle and SQL Server right?", you cannot use one and the same data source for two different databases, so you would need to configure two different instances anyway.

Related

Neo4j Dynamic cql switching

I want to switch database based on a request header, which I have managed to do but in a rather clunky way.
I had to change my jdbc driver to neo native driver to get the "USE database" prefix to work.
I had to prefix my cql query with "USE database "
What I really want is to do this via AOP, such that I can annotate the method with my custom java annotation and this aspect will just call "USE DATABASE" in isolation before going on to the joinpoint and calling the actual query.
When I try this though I get this error
Query cannot conclude with USE GRAPH (must be RETURN or an update clause)
Is it possible ?
You can change the database on the session object.
try (Session session = driver.session(SessionConfig.forDatabase( "databaseName" ))) {
session.executeWrite((tx) -> tx.run(stmt, params));
}
You shouldn't use JDBC for apps, that's rather for tools.
https://neo4j.com/docs/java-manual/current/cypher-workflow/#java-database-selection

solr jdbc throws and exception as if something is wrong within implementation there

I am trying to check the solr jdbc driver.
It seems to be working only with DbVisualizer & squirrelSQL.
As it is totally undocumented (properties, etc.) I've no idea what is the issue, but I keep on getting some weird error :
java.sql.SQLException which results from java.io.IOException which
results from org.noggit.JSONParser$ParserException: JSON Parse Error
char=<
It seems like internally something is going wrong there, as the engine expects JSON and receives XML.
The code is super straight forward :
Class.forName("org.apache.solr.client.solrj.io.sql.DriverImpl");
Connection conn = DriverManager.getConnection("jdbc:solr://zootest01:2181/?collection=mycol");
Statement stat = conn.createStatement();
ResultSet rs = stat.executeQuery("select item_id from mycol limit 10");
The above is the most straightforward code for Java using JDBC.
The executeQuery will always throw an exception.
What is more weird is that tools like DBeaver has the same problem exactly.
I couldn't find any explanation to this behavior, unless something in the implementation is somehow hard-coded to the above 2 specific tools.

SQLException: Cannot submit statement in current context

I encountered this exception when calling a stored procedure through a prepared statement, however, it works for callable statement. I am wondering if it is a must to use callable statement for invoking a stored procedure in voltdb?
String sql = "{call get_city_by_country(?)}";
PreparedStatement stat = conn.prepareStatement(sql);
stat.setString(1, "china");
ResultSet results = stat.executeQuery();
Throws exception below:
Exception in thread "main" java.sql.SQLException: Cannot submit statement in current context: '{call get_city_by_country(?)};'.
at org.voltdb.jdbc.SQLError.get(SQLError.java:45)
at org.voltdb.jdbc.JDBC4PreparedStatement.executeQuery(JDBC4PreparedStatement.java:121)
This one works fine.
CallableStatement proc = conn.prepareCall(sql);
proc.setString(1, "china");
ResultSet results = proc.executeQuery();
It look like your driver only supports the CALL escape on CallableStatement. So you need to use CallableStatement instead.
Section 6.4 Java EE JDBC Compliance of the JDBC 4.2 specification however says (empasis mine):
Drivers must support stored procedures. The DatabaseMetaData method
supportsStoredProcedures must return true. The driver must also support
the full JDBC API escape syntax for calling stored procedures with the following methods on the Statement, PreparedStatement, and CallableStatement classes:
executeUpdate
executeQuery
execute
This means that your driver is not fully compliant with the Java EE JDBC Compliance requirements. You might want to consider filing a bug report with the driver vendor.

Hibernate search, convert byte[] to List<LuceneWork>

As of Hibernate Search 3.1.1, when one wanted to send an indexed entity to a JMS queue for further processing, in the onMessage() method of the processing MDB was enough to apply a cast to obtain the list of LuceneWork, e.g
List<LuceneWork> queue = (List<LuceneWork>) objectMessage.getObject();
But in version 4.2.0 this is no longer an option as objectMessage.getObject() returns a byte[].
How could I deserialize this byte[] into List<LuceneWork>?
I've inspected the message and saw that I have the value for JMSBackendQueueTask.INDEX_NAME_JMS_PROPERTY.
You could extend AbstractJMSHibernateSearchController and have it deal with these details, or have a look at its source which contains:
indexName = objectMessage.getStringProperty(JmsBackendQueueTask.INDEX_NAME_JMS_PROPERTY);
indexManager = factory.getAllIndexesManager().getIndexManager(indexName);
if (indexManager == null) {
log.messageReceivedForUndefinedIndex(indexName);
return;
}
queue = indexManager.getSerializer().toLuceneWorks((byte[]) objectMessage.getObject());
indexManager.performOperations(queue, null);
Compared to older versions 3.x there are two main design differences to keep in mind:
The Serializer service is pluggable so it needs to be looked up
Each index (identified by name) can have an independent backend
The serialization is now performed (by default) using Apache Avro as newer Lucene classes are not Serializable.

porting tigase from derby to hsqldb ... how to call stored Java procedure and throw away (ignore) the result?

Trying to configure tigase to use hsqldb (hsqldb-1.8.0.9-1jpp.2) instead of derby (don't ask why, that's not the point) and everything works fine, except for setting some properties in the end. In Derby I had
CREATE procedure TigAddUserPlainPw(userId varchar(2049), userPw varchar(255))
PARAMETER STYLE JAVA
LANGUAGE JAVA
MODIFIES SQL DATA
DYNAMIC RESULT SETS 1
EXTERNAL NAME 'tigase.db.derby.StoredProcedures.tigAddUserPlainPw';
and
call TigAddUserPlainPw('db-properties', NULL);
When I try to replices this with hsqldb by
CREATE ALIAS TigAddUserPlainPw
FOR "tigase.db.derby.StoredProcedures.tigAddUserPlainPw";
and
CALL TigAddUserPlainPw('db-properties', NULL);
I get this error message
[root#tikanga scripts]# ./hsqldb-db-create.sh /var/lib/tigase/db/tigase
SQL Error at '/etc/tigase/database/hsqldb-schema-4-props.sql' line 1:
"CALL TigAddUserPlainPw('db-properties', NULL)"
Wrong data type: [Ljava.sql.ResultSet; in statement [CALL TigAddUserPlainPw(]
Any idea, what I am doing wrong?
You cannot use the Java static methods as they are. The Result[] parameters are not acceptable to HSQLDB 1.8.x.
It would be easier to convert to HSQLDB 2.0, as its stored procedure support has improved over version 1.8.
Your example shows we need to make some more improvements to HSQLDB to support these procedure declarations.
As far as I know, HSQLDB supports Java functions that return a ResultSet (Fred will correct me if I'm wrong): http://hsqldb.org/doc/2.0/guide/sqlroutines-chapt.html#N12835
You would need a new method:
public static ResultSet tigAddUserPlainPw(
String userId, String userPw) throws SQLException;

Resources