Oracle XMLDB's XMLCAST and XMLQUERY incompatible with iBatis? - oracle

I've been trying to select a list of values from XMLs stored in an
XMLType column but I keep getting the errors which are listed at the
tail end of this post.
The select id is
getXMLFragment
, and the relevant subset of the
sqlmap.xml is as follows:
<select id="getXMLFragment" resultClass="list">
SELECT
XMLCAST(XMLQUERY('$CUSTOMER/CUSTOMER/DETAILS/
CUST_NAME/text()' PASSING CUSTOMER AS
"CUSTOMER" RETURNING CONTENT) AS VARCHAR2(20))
AS customers FROM SHOP.CLIENT_INFO
</select>
(CUSTOMER is an XMLType column in CLIENT_INFO)
and I call the statement using
List<String> custNames= (List<String>)
sqlMap.queryForList("getXMLFragment");
I am using ibatis-2.3.4.726.jar.
Is it because iBatis does not recognise XMLDB queries and hence,
tokenizes the string wrongly? On a sidenote, I have implemented
XMLTypeCallback.java to handle XMLType insertions successfully, and I
think it will work should I wish to retrieve the entire XML. However,
in this case, I need to extract only individual values due to
requirements. A workaround would be greatly appreciated.
Thanks in advance.
The exceptions generated are listed below:
--- The error occurred in sqlMap.xml.
--- The error occurred while preparing the mapped statement for
execution.
--- Check the getXMLFragment.
--- Check the SQL statement.
--- Cause: java.util.NoSuchElementException
at
com.ibatis.sqlmap.engine.mapping.statement.MappedStatement.executeQueryWithCallback(MappedStatement.java:
204)
at
com.ibatis.sqlmap.engine.mapping.statement.MappedStatement.executeQueryForList(MappedStatement.java:
139)
at
com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate.queryForList(SqlMapExecutorDelegate.java:
567)
at
com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate.queryForList(SqlMapExecutorDelegate.java:
541)
at
com.ibatis.sqlmap.engine.impl.SqlMapSessionImpl.queryForList(SqlMapSessionImpl.java:
118)
at
com.ibatis.sqlmap.engine.impl.SqlMapSessionImpl.queryForList(SqlMapSessionImpl.java:
122)
at
com.ibatis.sqlmap.engine.impl.SqlMapClientImpl.queryForList(SqlMapClientImpl.java:
98)
at Main.main(Main.java:60)
Caused by: java.util.NoSuchElementException
at java.util.StringTokenizer.nextToken(StringTokenizer.java:332)
at
com.ibatis.sqlmap.engine.mapping.sql.simple.SimpleDynamicSql.processDynamicElements(SimpleDynamicSql.java:
90)
at
com.ibatis.sqlmap.engine.mapping.sql.simple.SimpleDynamicSql.getSql(SimpleDynamicSql.java:
45)
at
com.ibatis.sqlmap.engine.mapping.statement.MappedStatement.executeQueryWithCallback(MappedStatement.java:
184)
... 7 more

Update: We just need to repeat '$' once such that the sql is "....XMLQUERY('$$CUSTOMER....." The tokenization works fine after that and the query executes successfully.

Related

SimpleJdbcCall : No function exist error

I am getting Exception while executing store procedure. Exception is as below
org.springframework.jdbc.BadSqlGrammarException: CallableStatementCallback;badSQLgrammar [{call find_spot()}]; nestedexception is org.postgresql.util.PSQLException: ERROR: functionfind_spot()
does not exist Hint: No function matches the given name and argument types. You might need to add explicit type casts.Position:15
Its saying function find_spot() does not exist but I checked in database this procedure is there. I am using Postgresql [DBeaver]
Can anyone help me to solve this?
You should cast a json to make search or use the json access query, see the examples:
select * from table where cast(field_json as varchar(500)) !~ 'reg_ex' and id = 11
or
select field_json->>'key' from table where field_json->>'key' ilike 'value'

How to use Oracle query hint in Hibernate

I am trying to use Oracle hint in Hibernate to call force index, but didn't find any proper API in Hibernate 3.6.10.Final.
I somehow tried with projections in Hibernate criteria:
proList.add(Projections.sqlProjection("/*+ INDEX_DESC(CONTACT_USER_FK_I) */", new String[]{}, new Type[]{}));
proList.add(Projections.property("objectId"));
criteria.setProjection(proList);
return criteria.list();
But I am getting the exception below:
EXCEPTION
Caused by: 8 SQL Error (could not execute query; SQL [select /*+ INDEX_DESC(CONTACT_USER_FK_I) */, this_.CONTACT_ID as y0_ from R4GDEV01_MBW.CONTACT this_ w
here this_.USER_ID=? and this_.ADDRESS_BOOK_ID in (?) and this_.DELETION_DATE is null order by lower(this_.FIRSTNAME) asc]; nested exception is org.hibernate
.exception.SQLGrammarException: could not execute query)
at com.fusionone.pml.dao.hibernate.AbstractDao.executeCallback(AbstractDao.java:391)
at com.fusionone.pml.dao.hibernate.AbstractContactDao.searchContacts(AbstractContactDao.java:1019)
at com.fusionone.nab.core.service.impl.MergeServiceImpl.getFilteredContactIds(MergeServiceImpl.java:154)
... 91 more
I found out that the projection is appending a , after query hint.
Is there any other way to use Oracle query hint in Hibernate 3.6.10 criteria or in HQL?
Thanks
You should try to search first. Here is a simple trick to solve this, just transform the hint into a column:
"/*+ INDEX_DESC(CONTACT_USER_FK_I) */ 1 as MYHINT"
Your problem is that there is nothing previous to ,. Due to you want to add a projection on objectIdattribute, you could transform your criteria to somenthing like this:
Projections.sqlProjection("/*+ INDEX_DESC(CONTACT_USER_FK_I) */ objectId", new String[]{}, new Type[]{}))

JOOQ - query without quotes

I use JOOQ-3.1.0 to generate and execute dynamic queries for Oracle and Postgresql with Spring-4. In a scenario I have a partitioned table, which I need to query using JOOQ. I use DSL.tableByName(vblTablename); where vblTablename is the string received as a string in the query generation method, ex, vbl_default partition(p_04-Dec-14). (The vblTablename pattern differs for different databases, and is configured in the external property file). The JOOQ generates the sql, but with the double-quote around the tablename. The query and error shown below
Query
SELECT COUNT(ID) COUNT FROM "vbl_default partition(p_04-Dec-14)"
where (rts between timestamp '2014-12-04 00:00:00.0' and timestamp '2014-12-05 00:00:00.0' and userid in (2))
Error
ORA-00972: identifier is too long
00972. 00000 - "identifier is too long"
*Cause: An identifier with more than 30 characters was specified.
*Action: Specify at most 30 characters.
Error at Line: 4 Column: 29
Though I have set the below settings on the DefaultDSLContext
Settings settings = new Settings();
settings.setRenderNameStyle(RenderNameStyle.AS_IS);
How do I remove the quote around the table? Any other settings have I missed?
The idea behind DSL.tableByName(String...) is that you provide a table ... by name :-)
What you're looking for is a plain SQL table, via DSL.table(String).
You can write:
// Assuming this import
import static org.jooq.impl.DSL.*;
DSL.using(configuration)
.select(count(VBL_DEFAULT.ID))
.from(table("vbl_default partition(p_04-Dec-14)"))
.where(...);
Or by using the convenient overload SelectFromStep.from(String)
DSL.using(configuration)
.select(count(VBL_DEFAULT.ID))
.from("vbl_default partition(p_04-Dec-14)")
.where(...);
More information about plain SQL in jOOQ can be obtained from this manual page:
http://www.jooq.org/doc/latest/manual/sql-building/plain-sql/
Partition support
Note that support for Oracle partitions is on the roadmap: #2775. If in the mean time you wish to use partitioned tables more often, you could also write your own function for that:
// Beware of the risk of SQL injection, though!
public <R extends Record> Table<R> partition(Table<R> table, String partition) {
return DSL.table("{0} partition(" + partition + ")", table);
}
... and then:
DSL.using(configuration)
.select(count(VBL_DEFAULT.ID))
.from(partition(VBL_DEFAULT, "p_04-Dec-14"))
.where(...);

Why do I get "ORA-00932: inconsistent datatypes: expected - got -" when using COLLECT() in a prepared statement?

I am using this query with the Perl DBI:
SELECT c.change_id
, COLLECT(t.tag) AS the_tags
FROM changes c
LEFT JOIN tags t ON c.change_id = t.change_id
WHERE c.project = ?
GROUP BY c.change_id
The DBI uses OCI to prepare this statement, bind the value I pass, and get the results. But Oracle, for some reason, does not like it. The error output is:
ORA-00932: inconsistent datatypes: expected - got - (DBD ERROR: error possibly near <*> indicator at char 41 in '
SELECT c.change_id
, <*>COLLECT(t.tag) AS the_tags
FROM changes c
LEFT JOIN tags t ON c.change_id = t.change_id
WHERE c.project = :p1
GROUP BY c.change_id
'
Not very informative. However, I can make this error go away not only by changing the call to COLLECT() also by replacing the placeholder with the actual value:
SELECT c.change_id
, COLLECT(t.tag) AS the_tags
FROM changes c
LEFT JOIN tags t ON c.change_id = t.change_id
WHERE c.project = 'tryoracle'
GROUP BY c.change_id
That version works perfectly. Why doesn't Oracle like the prepared statement with the COLLECT()?
In case it's any help, here is a trace of the OCI-related calls extracted via ora_verbose = 6 (h/t #bohica).
Finally got a solution to this issue, thanks to some digging by a user. The problem was not with the placeholder; why it worked without the placeholder on the VirtualBox image I have no idea. No, the issue was with the COLLECT(). Seems that both the values being collected need to be cast to a specific type, and the resulting array also needs to be cast to a pre-defined array data type. Just so happens that my code has a custom array type:
CREATE TYPE sqitch_array AS varray(1024) OF VARCHAR2(512);
So I'm able to get the query to work by casting the COLLECT() like so:
CAST(COLLECT(CAST(t.tags as VARCHAR2(512))) AS sqitch_array)

Spring jdbcTemplate executing query

I have a strange problem ,
My Query looks like below.
String tokenQuery = "select id from table
where current_timestamp between
creation_time and (creation_time + interval '10' minute)
and token = '"+Token+"'";
But when I run, jdbcTemplate.queryForLong(tokenQuery) , no matter what , it always throws EmptyDataAccessException.
I am executing this in Oracle
Can we not append dynamic values to string and then pass it as a query and execute ?
What could be the issue ?
I assume that what you get is in fact an EmptyResultDataAccessException. The javadoc of this exception says:
Data access exception thrown when a result was expected to have at least one row (or element) but zero rows (or elements) were actually returned.
That simply means that the query is executed fine, and is supposed to return one row, but doesn't return any. So no row satisfies the criteria of your query.
If that is expected, then catch the exception, or use a method that returns a list rather then returning a single value. That way, you can test if the returned list is empty.
That said, you should use a parameterized query instead of concatenating the token like you're doing. This would prevent SQL injection attacks. It would also work even if the token contains a quote, for example.

Resources