hsqldb Oracle mode select for update NOWAIT - oracle

It seems NOWAIT is not supported by HSQLDB in Oracle syntax.
HSQLDB version: 2.3.3
with
SET DATABASE SQL SYNTAX ORA TRUE;
Exception produced on the SQL
select a, b, c from sometable where id=1 for update NOWAIT
The exception
Caused by: org.hsqldb.HsqlException: unexpected token: NOWAIT
at org.hsqldb.error.Error.parseError(Unknown Source)
at org.hsqldb.ParserBase.unexpectedToken(Unknown Source)
at org.hsqldb.ParserCommand.compileStatement(Unknown Source)
at org.hsqldb.Session.compileStatement(Unknown Source)
at org.hsqldb.StatementManager.compile(Unknown Source)
at org.hsqldb.Session.execute(Unknown Source)
Does anyone know if HSQLDB does not supports this ?
Any ideas how to avoid this exception without modifying the original SQL. I can ignore the NOWAIT functionality in my unit tests but just cant modify the SQL. Additional info: we use spring-jbdc and JdbcTemplate and thinking about intercepting this to replace sqls with NOWAIT as an hack in the JUnit test setup.

Found answer to my own question finally after digging hsqldb source code on sourceforge.
Version 2.3.3 of HSQLDB does NOT support NOWAIT.
I have asked this question in their Discussion Forum and raised the issue however its not like GitHub where you can create an issue so no formal Issue/Request opened.
I am getting along with a bad hack for now modifying HSQLDB code myself org.hsqldb.ParserDQL class to just ignore the NOWAIT in the select-for-update SQL.
If anyone has better answer I will accept their answer.
UPDATE: (Aug-24-2015)
Received confirmation from HSQLDB forum that NOWAIT will be ignored. Meanwhile I am posting the code snippet to ignore NOWAIT that I received from the HSQLDB sourceforge forum. You may want to wait for the next version of HSQLDB than adding this to your code base (as a hack).
if (Tokens.T_NOWAIT.equals(token.tokenString)) {
read();
}
UPDATED to show the full context as to where to add the above snippet in the ParserDQL.java
/**
* Retrieves a SELECT or other query expression Statement from this parse context.
*/
StatementQuery compileCursorSpecification(RangeGroup[] rangeGroups,
int props, boolean isRoutine) {
OrderedHashSet colNames = null;
QueryExpression queryExpression = XreadQueryExpression();
if (token.tokenType == Tokens.FOR) {
read();
if (token.tokenType == Tokens.READ
|| token.tokenType == Tokens.FETCH) {
read();
readThis(Tokens.ONLY);
props = ResultProperties.addUpdatable(props, false);
} else {
readThis(Tokens.UPDATE);
props = ResultProperties.addUpdatable(props, true);
if (token.tokenType == Tokens.OF) {
readThis(Tokens.OF);
colNames = new OrderedHashSet();
readColumnNameList(colNames, null, false);
}
if (Tokens.T_NOWAIT.equalsIgnoreCase(token.tokenString)) {
readIfThis(Tokens.X_IDENTIFIER);
}
}
}

Related

How to add reserved keywords in liquibase OracleDatabase?

Trying to make my spring boot JPA application compliant with Oracle DB, already running with MySQL and H2.
The data generated by liquibase unfortunately uses some of Oracle's reserved keywords as table or column names.
The good news is that hibernate and liquibase implementations can detect these keywords and "quote" them when querying database (using objectQuotingStrategy="QUOTE_ONLY_RESERVED_KEYWORDS" for liquibase, and spring.jpa.properties.hibernate.auto_quote_keyword: true for hibernate).
The bad news is hibernate and liquibase do not share the same list of reserved keywords for Oracle.
For example, value is not recognized as a reserved keyword by liquibase, but is by hibernate (which uses ANSI SQL:2003 keywords).
One of my liquibase changeSets creates a table with a lower case value column, so Liquibase creates the table with an unquoted lowercase value column, and Oracle DB turns it automatically in an upper case VALUE column. Now when hibernate tries to fetch
that column, it recognizes value and quotes it (`SELECT "value" from ...), which makes it case-sensitive, so the column is not found (ORA-00904).
I thought I found a workaround for it by extending SpringLiquibase and adding my custom keywords, as described here : https://liquibase.jira.com/browse/CORE-3324. The problem is that this does not seem to work with OracleDatabase implementation, which overwrites SpringLiquibase's set of reserved keywords (and of course, the isReservedWord() method uses OracleDatabase's set).
For now, I'll use the QUOTE_ALL_OBJECTS quoting strategy for liquibase and hibernate.globally_quoted_identifiers.
But, just out of curiosity, I wanted to know if the set of reserved keywords used by liquibase for Oracle could be appended.
spring boot version: 2.3.9.RELEASE.
hibernate-core version (spring boot dependency): 5.4.28
liquibase-core version (spring boot dependency): 3.8.9
Hmm in case of Oracle you have keywords and reserved words.
reserved words can not be used as identifiers
keywords can be used as identifiers but it is not recommened.
You can get list of them directly from database:
select KEYWORD, RESERVED from v$reserved_words;
...
1864 rows selected
What about using uppercase names everywhere in the source code?
It looks like Liqubase depends on some JDBC driver functionally - which does not work.
OracleDatabase.java:
public void setConnection(DatabaseConnection conn) {
//noinspection HardCodedStringLiteral,HardCodedStringLiteral,HardCodedStringLiteral,HardCodedStringLiteral,
// HardCodedStringLiteral
reservedWords.addAll(Arrays.asList("GROUP", "USER", "SESSION", "PASSWORD", "RESOURCE", "START", "SIZE", "UID", "DESC", "ORDER")); //more reserved words not returned by driver
Connection sqlConn = null;
if (!(conn instanceof OfflineConnection)) {
try {
/*
* Don't try to call getWrappedConnection if the conn instance is
* is not a JdbcConnection. This happens for OfflineConnection.
* see https://liquibase.jira.com/browse/CORE-2192
*/
if (conn instanceof JdbcConnection) {
sqlConn = ((JdbcConnection) conn).getWrappedConnection();
}
} catch (Exception e) {
throw new UnexpectedLiquibaseException(e);
}
if (sqlConn != null) {
tryProxySession(conn.getURL(), sqlConn);
try {
//noinspection HardCodedStringLiteral
reservedWords.addAll(Arrays.asList(sqlConn.getMetaData().getSQLKeywords().toUpperCase().split(",\\s*")));
} catch (SQLException e) {
//noinspection HardCodedStringLiteral
Scope.getCurrentScope().getLog(getClass()).info("Could get sql keywords on OracleDatabase: " + e.getMessage());
//can not get keywords. Continue on
}
If Liquibase calls sqlConn.getMetaData().getSQLKeywords() and this does not return proper output, then your chances are limited. It might be a bug in JDBC drivers, or your application does not have SELECT_CATALOG_ROLE privilege and does not see v$reserved_words view (if JDBC queries this internally).

Alter session hangs or causes ORA-01013

I have the following code block and when the ALTER SESSION statement is executed, it either hangs or it throws an ORA-01013 depending on whether we're connecting to Oracle 12r2 or 19.3 and what version of the OJDBC8 driver is being used:
try(Connection connection = jdbcConnection.connect(false)) {
// We now have a java.sql.Connection open to the database at this point
try(PreparedStatement ps = connection.prepareStatement(someQuery)) {
// We not have a prepared statement based on query, the query is irrelevent
try (Statement s = connection.createStatement()) {
// The following statement fails with the ORA-01013 error
s.execute("ALTER SESSION SET CONTAINER=" + pdbName);
}
}
}
If I rework this code block to the following, the problem disappears.
try(Connection connection = jdbcConnection.connect(false)) {
// We now have a java.sql.Connection open to the database at this point
try (Statement s = connection.createStatement()) {
s.execute("ALTER SESSION SET CONTAINER=" + pdbName);
}
try(PreparedStatement ps = connection.prepareStatement(someQuery)) {
// We not have a prepared statement based on query, the query is irrelevent
}
// or put the alter session here
}
From what I can determine, using Oracle OJDBC8 12.2.0.1, the hang nor the ORA-01013 exception is thrown; however when I migrate to 19.x.0.0, this is where I'm seeing this problem occur.
Is this a bug in the JDBC driver or is there actually a problem with how the code is written that the 12.2.0.1 driver is more lenient with than the later versions?

DB2 SQL Error: SQLCODE=-270 exception thrown by jpa paging item reader

I have created a spring batch service with a item reader, item processor and item writer.I have extended the AbstractPagingItemReader and created my own implementation by the name of JpaPagingItemReader.Now when I ran the batch service the reader reads a fix set of records from db (default page size: 10),processes them and writes them.However on second read it throws me the below exception:
2015-06-25 16:33:00,712 ERROR [jobLauncherTaskExecutor-6][saeedh:120659] org.hibernate.util.JDBCExceptionReporter : DB2 SQL Error: SQLCODE=-270, SQLSTATE=42997, SQLERRMC=63, DRIVER=3.61.65
2015-06-25 16:33:00,712 ERROR [jobLauncherTaskExecutor-6][saeedh:120659] org.hibernate.util.JDBCExceptionReporter : DB2 SQL Error: SQLCODE=-727, SQLSTATE=56098, SQLERRMC=2;-270;42997;63, DRIVER=3.61.65
2015-06-25 16:33:00,712 ERROR [jobLauncherTaskExecutor-6][saeedh:120659] org.hibernate.util.JDBCExceptionReporter : DB2 SQL Error: SQLCODE=-727, SQLSTATE=56098, SQLERRMC=2;-270;42997;63, DRIVER=3.61.65
javax.persistence.PersistenceException: org.hibernate.exception.SQLGrammarException: could not execute query
com.ibm.db2.jcc.am.SqlSyntaxErrorException: DB2 SQL Error: SQLCODE=-270, SQLSTATE=42997, SQLERRMC=63, DRIVER=3.61.65
at com.ibm.db2.jcc.am.ed.a(ed.java:676)
at com.ibm.db2.jcc.am.ed.a(ed.java:60)
at com.ibm.db2.jcc.am.ed.a(ed.java:127)
at com.ibm.db2.jcc.am.gn.c(gn.java:2554)
at com.ibm.db2.jcc.am.gn.d(gn.java:2542)
at com.ibm.db2.jcc.am.gn.a(gn.java:2034)
at com.ibm.db2.jcc.am.hn.a(hn.java:6500)
at com.ibm.db2.jcc.t4.cb.g(cb.java:140)
at com.ibm.db2.jcc.t4.cb.a(cb.java:40)
at com.ibm.db2.jcc.t4.q.a(q.java:32)
at com.ibm.db2.jcc.t4.rb.i(rb.java:135)
I get that this error is probably because there is a CLOB column in the table from where I am reading records but the weird thing is it reads the first batch of 10 records fine,process them and write them but on second time read it throws the above exception.Any suggestions?Below is a snippet from JpaPagingItemReader that I wrote.The override doReadPage method from AbstractPagingItemReader.java.
protected void doReadPage ()
{
setPageSize (10);
// Flush we already have in entity manager
getEntityManager ().flush ();
// clear the entity manager: To read and detach
getEntityManager ().clear ();
Query query = createQuery ().setFirstResult (getPage () * getPageSize ()).setMaxResults (getPageSize ());
if (parameterValues != null)
{
for (Map.Entry<String, Object> me : parameterValues.entrySet ())
{
query.setParameter (me.getKey (), me.getValue ());
}
}
if (results == null)
{
results = new CopyOnWriteArrayList<T> ();
}
else
{
results.clear ();
}
results.addAll (query.getResultList ());
// Detach all objects that became part of persistence context
getEntityManager ().clear ();
}
Any help is highly appreciated as I already behind deadline due to this issue.Please if you think any thing is missing,do let me know and I will update the question.Thanks.
I figured it out.The issue was indeed that we are not allowed to have Clob data as a projection in a scrollable JPA cursor.The first 10 records are read just fine but as soon as It starts to read the second batch it has to move the cursor from 0 to the 11th record.That is when I was getting sql exception.
Simple fix was to remove the CLOB column from the select statement and get it in a separate query where its value is required.That fixed my problem.Thanks.

Hibernate persist failure with PostGIS Geometry

Related to previous question. I have a Spring Roo application using Hibernate to write a Geometry object to a PostGIS database using JTS. I believe I've fixed the problems I had in defining my Geometry object, and now Hibernate is executing its persist() method, but something is going wrong just before it hits the DB and I'm getting the exception below.
Here are some interesting lines. First from the Hibernate logs, the object to be persisted, and then an SQL query (presumably the ? are substituted):
...
DEBUG org.hibernate.pretty.Printer - com.test.LandUse{id=1, centerPoint=POINT (5 6), version=0}
...
DEBUG org.hibernate.SQL - insert into land_use (center_point, version, id) values (?, ?, ?)
...
Then some more things happen, though nothing obviously bad. However I don't see any 'final' SQL, and there is an attempt to roll back the transaction. Then:
org.springframework.transaction.TransactionSystemException: Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Error while committing the transaction
at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:521)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:754)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:723)
at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:393)
at org.springframework.transaction.aspectj.AbstractTransactionAspect.ajc$afterReturning$org_springframework_transaction_aspectj_AbstractTransactionAspect$3$2a73e96c(AbstractTransactionAspect.aj:78)
at com.test.LandUse_Roo_Jpa_ActiveRecord.ajc$interMethod$com_test_LandUse_Roo_Jpa_ActiveRecord$com_test_LandUse$persist(LandUse_Roo_Jpa_ActiveRecord.aj:44)
at com.test.LandUse.persist(LandUse.java:1)
at com.test.LandUse_Roo_Jpa_ActiveRecord.ajc$interMethodDispatch1$com_test_LandUse_Roo_Jpa_ActiveRecord$com_test_LandUse$persist(LandUse_Roo_Jpa_ActiveRecord.aj)
at com.test.LandUseController_Roo_Controller.ajc$interMethod$com_test_LandUseController_Roo_Controller$com_test_LandUseController$create(LandUseController_Roo_Controller.aj:29)
at com.test.LandUseController.create(LandUseController.java:1)
...
Caused by: javax.persistence.RollbackException: Error while committing the transaction
at org.hibernate.ejb.TransactionImpl.commit(TransactionImpl.java:93)
at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:512)
... 54 more
Caused by: java.lang.UnsupportedOperationException
at org.hibernate.spatial.GeometrySqlTypeDescriptor.getBinder(GeometrySqlTypeDescriptor.java:52)
at org.hibernate.type.AbstractStandardBasicType.nullSafeSet(AbstractStandardBasicType.java:283)
at org.hibernate.type.AbstractStandardBasicType.nullSafeSet(AbstractStandardBasicType.java:278)
at org.hibernate.type.AbstractSingleColumnStandardBasicType.nullSafeSet(AbstractSingleColumnStandardBasicType.java:89)
at org.hibernate.persister.entity.AbstractEntityPersister.dehydrate(AbstractEntityPersister.java:2184)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2430)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2874)
at org.hibernate.action.EntityInsertAction.execute(EntityInsertAction.java:79)
at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:273)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:265)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:184)
at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:51)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1216)
at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:383)
at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:133)
at org.hibernate.ejb.TransactionImpl.commit(TransactionImpl.java:76)
... 55 more
I've been trying to get this simple use case (an object with just a single Geometry property) working for over a week now, and am about at my wits' end. If I replace the Geometry object with a String it works just fine. Does anyone know what might be causing such an error?
EDIT: Thierry's answer below got me poking through the source, and I noticed the exception is thrown in GeometrySqlTypeDescriptor, which has some interesting contents:
/**
* A generic <code>SqlTypeDescriptor</code>, intended to be remapped
* by the spatial dialect.
*
* #author Karel Maesen, Geovise BVBA
* creation-date: 7/27/11
*/
public class GeometrySqlTypeDescriptor implements SqlTypeDescriptor {
public static final GeometrySqlTypeDescriptor INSTANCE = new GeometrySqlTypeDescriptor();
#Override
public int getSqlType() {
return 3000; //this value doesn't conflict with presently defined java.sql.Types values.
}
#Override
public boolean canBeRemapped() {
return true;
}
#Override
public <X> ValueBinder<X> getBinder(JavaTypeDescriptor<X> javaTypeDescriptor) {
throw new UnsupportedOperationException();
}
#Override
public <X> ValueExtractor<X> getExtractor(JavaTypeDescriptor<X> javaTypeDescriptor) {
throw new UnsupportedOperationException();
}
}
In particular, note the class comment suggesting something is clearly wrong with the Hibernate dialect mapping. Unfortunately I have no idea what that means, but I'm guessing due to some kind of version mismatch. (Note also the declaration of SQL type 3000, as per my previous error!)
My current dialect is org.hibernate.spatial.dialect.postgis.PostgisDialect, as per the Hibernate Spatial usage guide. I'm using Hibernate Spatial 4.0-M1, JTS 1.12, and PostGIS 2.0.1. I'll try with a couple of different versions of PostGIS perhaps, particularly since that's the one dependency that Hibernate Spatial is supposed to provide but doesn't seem to.
It seems the problem was that the PostgisDialect was not been picked up and integrated correctly, and hence the required operations were not supported. The solution was as simple as upgrading from Hibernate 3.6.9.Final to 4.1.6.Final!
See my thread on the mailing list for more information.
As per that thread, you should also be aware that as of Hibernate Spatial 4.0-M1, only the Geometry type is specified to Hibernate, and hence the #Column annotation must set columnDefinition="Geometry", and not Point or anything else. This may be fixed in the future.
With this anthology of modifications, I can finally write a Point to a database! The correct property specification is:
#Column(columnDefinition="Geometry")
#Type(type = "org.hibernate.spatial.GeometryType")
private Point centerPoint;
I got this exception when I forgot to add the Postgis Dialect in hibernate configuration file.
Add following line to hibernate.cfg.xml
<property name="dialect">org.hibernate.spatial.dialect.postgis.PostgisDialect</property>
Yes, the ? are substituted by the values you need to store.
Did you try to use the following type: GeometryUserType and not the GeometryType?
I suspect GeometryType is not directly supported by the API of Hibernate Spatial Project. It is maybe an abstract class which you could not instantiate directly to map your datas with annotations - it acts beyond the scene as we have experimented.
Caused by: java.lang.UnsupportedOperationException which has make me tell that.
And the last XML stuff inside the tutorial you have followed is clear:
...
<property name="geometry" type="org.hibernatespatial.GeometryUserType">
<column name="geom" />
</property>
...
Looking at the code inside the GeometryUserType I see only one place where these exception could be thrown.
public Object conv2DBGeometry(Geometry jtsGeom, Connection connection) {
org.postgis.Geometry geom = null;
jtsGeom = forceEmptyToGeometryCollection(jtsGeom);
if (jtsGeom instanceof com.vividsolutions.jts.geom.Point) {
geom = convertJTSPoint((com.vividsolutions.jts.geom.Point) jtsGeom);
} else if (jtsGeom instanceof com.vividsolutions.jts.geom.LineString) {
geom = convertJTSLineString((com.vividsolutions.jts.geom.LineString) jtsGeom);
} else if (jtsGeom instanceof com.vividsolutions.jts.geom.MultiLineString) {
geom = convertJTSMultiLineString((com.vividsolutions.jts.geom.MultiLineString) jtsGeom);
} else if (jtsGeom instanceof com.vividsolutions.jts.geom.Polygon) {
geom = convertJTSPolygon((com.vividsolutions.jts.geom.Polygon) jtsGeom);
} else if (jtsGeom instanceof com.vividsolutions.jts.geom.MultiPoint) {
geom = convertJTSMultiPoint((com.vividsolutions.jts.geom.MultiPoint) jtsGeom);
} else if (jtsGeom instanceof com.vividsolutions.jts.geom.MultiPolygon) {
geom = convertJTSMultiPolygon((com.vividsolutions.jts.geom.MultiPolygon) jtsGeom);
} else if (jtsGeom instanceof com.vividsolutions.jts.geom.GeometryCollection) {
geom = convertJTSGeometryCollection((com.vividsolutions.jts.geom.GeometryCollection) jtsGeom);
}
if (geom != null)
return new PGgeometry(geom);
else
throw new UnsupportedOperationException("Conversion of "
+ jtsGeom.getClass().getSimpleName()
+ " to PGgeometry not supported");
}
Where PGgeometry stands for PostGis Geometry I think (or maybe PostgreSQL).
I have found some topics where Karel Maesen and others speak about the InnoDB support is not very well, but they are maybe outdated (05-2011).
Good luck!

Can I configure LLBLGen to include generated SQL in exceptions?

I'm using LLBLGen and I have some code like so:
if (onlyRecentMessages)
{
messageBucket.PredicateExpression.Add(MessageFields.DateEffective >= DateTime.Today.AddDays(-30));
}
var messageEntities = new EntityCollection<MessageEntity>();
using (var myAdapter = PersistenceLayer.GetDataAccessAdapter())
{
myAdapter.FetchEntityCollection(messageEntities, messageBucket);
}
I'm currently getting a SqlException on the FetchEntityCollection line. The error is:
System.Data.SqlClient.SqlException: The incoming tabular data stream (TDS) remote procedure call (RPC) protocol stream is incorrect. Too many parameters were provided in this RPC request. The maximum is 2100.
but that's a side note. What I actually want to be able to do is include the generated SQL in a custom exception in my code. So for instance something like this:
using (var myAdapter = PersistenceLayer.GetDataAccessAdapter())
{
try
{
myAdapter.FetchEntityCollection(messageEntities, messageBucket);
}
catch (SqlException ex)
{
throw new CustomSqlException(ex, myAdapter.GeneratedSqlFromLastOperation);
}
}
Of course, there is no such property as GeneratedSqlFromLastOperation. I'm aware that I can configure logging, but I would prefer to have the information directly in my stack track / exception so that my existing exception logging infrastructure can provide me with more information when these kinds of errors occur.
Thanks!
Steve
You should get an ORMQueryExecutionException, which contains the full query in the description. The query's execute method wraps all exceptions in an ORMQueryExecutionException and stores the query in the description.
ps: please, if possible ask llblgen pro related questions on our forums, as we don't monitor stackoverflow frequently. Thanks. :)

Resources