Native query not running in HsqlDb using Spring-Junit4 - java

I have a method in my DAO which is querying a Oracle database and it is working fine in the application. However for testing we are using an Hsqldb and using Spring-junit for the tests. The same method returns an error during the tests because as far I have seen HSQL does not support subqueries so I'm getting:
Caused by: org.hsqldb.HsqlException: unexpected token: START required: )
Could you help me about how to proceed in this case? Could be possible to mock this method using Spring to not really do the call but give me some predefined result by configuration?
Any advice will be very welcome!
Here is the method:
private Long getRootParent(Long id) {
StringBuilder sqlQuery = new StringBuilder();
sqlQuery.append("SELECT ID FROM ");
sqlQuery.append(" ( SELECT MAX(level) , ff.ID FROM FOREF_FUND ff ");
sqlQuery.append(" START WITH ff.ID = ? ");
sqlQuery.append(" CONNECT BY PRIOR ff.PARENT_FK = ff.ID ");
sqlQuery.append(" GROUP BY ff.ID ORDER BY MAX (level) DESC ) ");
sqlQuery.append(" where rownum = 1 ");
SQLQuery query = this.createSQLQuery(sqlQuery.toString());
query.setParameter(0, id);
List result = query.list();
if (result != null && !result.isEmpty()) {
return ((BigDecimal) result.get(0)).longValue();
}
return null;
}

Related

How to read CLOB type to Spring Boot? [duplicate]

I have a table in Database where datatype of a column(STATUS) is CLOB.I need to read that STATUS
create table STATUS_TABLE
(
STATE_ID number(20,0),
STATUS clob
)
I am trying to read CLOB column as below
String getStatus = "SELECT STATUS FROM STATUS_TABLE WHERE STATE_ID="+id;
Query statusResults = session.createSQLQuery(getStatus);
List statusRes = statusResults.list();
if ((statusRes != null) && (statusRes.size() > 0)) {
oracle.sql.CLOB clobValue = (oracle.sql.CLOB) statusRes.get(0);
status = clobValue.getSubString(1, (int) clobValue.length());
log.info("Status->:" + status.toString());
}
And getting the error as
java.lang.ClassCastException: $Proxy194 cannot be cast to oracle.sql.CLOB
How can i read clob data from DB and convert to String ?
Here is the corrected version, and an explanation appears below the code:
Query query = session.createSQLQuery("SELECT STATUS FROM STATUS_TABLE WHERE STATE_ID = :param1");
query.setInt("param1", id);
query.setResultTransformer(Criteria.ALIAS_TO_ENTITY_MAP);
List statusRes = query.list();
if (statusRes != null) {
for (Object object : statusRes) {
Map row = (Map)object;
java.sql.Clob clobValue = (java.sql.Clob) row.get("STATUS");
status = clobValue.getSubString(1, (int) clobValue.length());
log.info("Status->:" + status.toString());
}
}
Problems I saw with your code:
You were building a raw query string using concatenation. This leaves you vulnerable to SQL injection and other bad things.
For whatever reason you were trying to cast the CLOB to oracle.sql.CLOB. AFAIK JDBC will return a java.sql.Clob
You are performing a native Hibernate query, which will return a list result set whose type is not known at compile time. Therefore, each element in the list represents one record.

reduce prepared statement count in hibernate

i am struggling with hibernate prepared statement count.
I am using the following JPA criteria query:
int count = 30
EntityManager manager = ...
CriteriaBuilder builder = manager.getCriteriaBuilder();
CriteriaQuery<String> select = builder.createQuery(String.class);
Root<AdministrationParameter> root = select.from(AdministrationParameter.class);
select.select(root.get(AdministrationParameter_.value));
ParameterExpression<String> peF1 = builder.parameter(AdministrationParameter_.context.getBindableJavaType(), "f1");
ParameterExpression<String> peF2 = builder.parameter(AdministrationParameter_.parameter.getBindableJavaType(), "f2");
Predicate p1 = builder.equal(root.get(AdministrationParameter_.context), peF1);
Predicate p2 = builder.equal(root.get(AdministrationParameter_.parameter), peF2);
select.where(p1, p2);
List<String> results = Collections.emptyList();
TypedQuery<String> query = manager.createQuery(select);
for (int i = 0; i < count; i++) {
query.setParameter(peF1, administrationParameterTypeInterface.getContext());
query.setParameter(peF2, administrationParameterTypeInterface.getParameter());
query.getResultList();
}
The count variable is to execute the query n times, e.g. to run a db trace in background (the query is executed against a db2 database).
Assume count = 30
The db2 trace says, there are "30 prepares" and "30 describes", the "statement found count = 30".
Hibernate give me the same values:
EntityManagerFactory factory = ...;
SessionFactory sessionFactory = factory.unwrap(SessionFactory.class);
statistics = sessionFactory.getStatistics();
Statistics statistics = statistics.setStatisticsEnabled(true);
...running the query above...
System.out.println("prepared statement count: " + statistics.getPrepareStatementCount());//is 30
System.out.println("query cache hit count: " + statistics.getQueryCacheHitCount());//0
System.out.println("query cache miss count: " + statistics.getQueryCacheMissCount());//0
System.out.println("query execution count: " + statistics.getQueryExecutionCount());//30
According to the javadoc https://docs.jboss.org/hibernate/orm/3.2/api/org/hibernate/stat/Statistics.html the statistics.getPrepareStatementCount() is "The number of prepared statements that were acquired".
Shouldn't it be 1?
Which Hibernate version are you using? This might be a bug that has already been fixed in newer versions. If updating doesn't help please create an issue in the issue tracker(https://hibernate.atlassian.net) with a test case(https://github.com/hibernate/hibernate-test-case-templates/blob/master/orm/hibernate-orm-5/src/test/java/org/hibernate/bugs/JPAUnitTestCase.java) that reproduces the issue.

query inside query to 1 query postgresql

i have a query like this
UPDATE FOLLOWUP F SET CUSTOMER=(SELECT NAME FROM CUSTOMERS C WHERE F.CUST_ID=C.ID), PHONE=(SELECT SEARCHKEY FROM CUSTOMERS C WHERE F.CUST_ID=C.ID);
this is succesfully working in my postgresql, but not running in java
and my java function
for (final TicketLineInfo l : ticket.getLines())
if(l.getConsumption()!= 0.0 && l.getMultiply()!=l.getConsumption()) {
new PreparedSentence(s
, "UPDATE FOLLOWUP F SET CUSTOMER=(SELECT NAME FROM CUSTOMERS C WHERE F.CUST_ID=?), PHONE=(SELECT SEARCHKEY FROM CUSTOMERS C WHERE F.CUST_ID=?);"
, SerializerWriteParams.INSTANCE
).exec(new DataParams() { public void writeValues() throws BasicException {
setString(1, ticket.getCustomerId());
setString(2, ticket.getCustomerId());
}});
}
when i run this
i get error like this:
com.openbravo.basic.BasicException:
org.postgresql.util.PSQLException: ERROR: more than one row returned by a subquery used as an expression
org.postgresql.util.PSQLException:
ERROR: more than one row returned by a subquery used as an expression
my question is how do i convert the above query into one single query without a subquery.. so that i can avoid this exception and proceed with my execution OR is there any other serializer which supports this
Looks like you don't need subqueries in your query:
update FOLLOWUP as F set
Name = c.Name,
Phone = c.SearchKey
from CUSTOMERS as c
where
F.Cust_ID = C.ID and
F.Cust_ID = ?

Retrieving a value from Stored Procedure using Native SQL Hibernate

Below is the stored procedure:
create or replace procedure
proc_emp_name(v_emp out emp.emp_name%TYPE, v_empid in emp.emp_id%TYPE)
is
begin
select emp_name into v_emp from emp where emp_id = v_empid;
dbms_output.put_line('Emp Name: ' || v_emp);
dbms_output.put_line('Procedure created successfully!!!');
end;
I want to invoke this using Native SQL, followed this link but not sure how to retrieve the OUT parameter from the Procedure.
http://www.mkyong.com/hibernate/how-to-call-store-procedure-in-hibernate/
Kindly let me know the simplest way to invoke the procedure and get the results out of it.
EDIT
As suggested, checking the docs, I modified the Proc having first parameter as a SYS_REFCURSOR as follows:
create or replace procedure
proc_empname_refcursor(v_empname OUT SYS_REFCURSOR, v_deptid in emp.emp_id%type)
is
begin
open v_empname for select * from dept where dept_id = v_deptid;
end;
I am able to invoke it using NamedQuery but I don't want to add anything in the mapping files because of some other restrictions. I tried the below code for invoking the proc without using NamedQuery but it did not worked out:
Query query = session.createSQLQuery(
"CALL proc_empname_refcursor(?, :deptId)")
.addEntity(Dept.class)
.setParameter("deptId", new Integer(2));
List<Dept> departments = query.list();
for(int i=0; i<departments.size(); i++){
Dept department = (Dept)departments.get(i);
System.out.println("Dept Id: " + department.getDeptId());
System.out.println("Dept Name: " + department.getDeptName());
}
I am getting the exception:
org.hibernate.QueryException: Expected positional parameter count: 1, actual parameters: [] [CALL proc_empname_refcursor(?, :deptId)]
at org.hibernate.impl.AbstractQueryImpl.verifyParameters(AbstractQueryImpl.java:319)
at org.hibernate.impl.SQLQueryImpl.verifyParameters(SQLQueryImpl.java:201)
at org.hibernate.impl.SQLQueryImpl.list(SQLQueryImpl.java:145)
at com.jdbc.HibernateStartup.main(HibernateStartup.java:70)
Kindly let me know how to resolve this.
I've managed to get an out parameter from a stored procedure using the following code in Hibernate and MS SQL Server:
#Override
public Serializable generate(SessionImplementor session, Object object) throws HibernateException {
Connection connection = session.connection();
CallableStatement callable = null;
try {
callable = connection.prepareCall("execute [procedure] ?");
callable.registerOutParameter(1, Types.INTEGER);
callable.execute();
int id = callable.getInt(1);
return id;
} catch (SQLException e) {
(...)
} finally {
(...)
}
}
From Hibernate Docs:
You cannot use stored procedures with Hibernate unless you follow some procedure/function rules.
For Oracle, A function must return a result set. The first parameter of a procedure must be an OUT that returns a result set.

Hibernate and Mysql results don't match

I 'm using Hibernate connecting to mysql as database layer, the weird thing is for some reason
the result sets executed from Hibernate api java code are different from those executed directly from mysql. They are not a part of each other, they just look like no relationship.
Here's the Java code at Dao layer:
int totalPage = 0;
int reminder = total % pagination.getPageSize();
if(total == 0){
totalPage = 1;
pagination.setTotalPage(totalPage);
}else{
totalPage = reminder == 0 ? total / pagination.getPageSize() : (total - reminder) / pagination.getPageSize() + 1;
pagination.setTotalPage(totalPage);
}
pagination.setTotalRows(total);
pagination.setBeginAndEndPage(total);
final StringBuilder queryString = new StringBuilder();
queryString.append(" select a.target_id as itemId, a.isFree as isFree, ");
queryString.append(" ni.fullName as item, nc.fullName as category, a.downloadCount as downloadCounts from( ");
queryString.append(" select dldc.current_category_id, dldc.target_id, dldc.isFree, ");
queryString.append(" sum(dldc.counts) as downloadCount from download_log_day_count dldc ");
queryString.append(" group by dldc.current_category_id, dldc.target_id) as a ");
queryString.append(" left join item i on a.target_id = i.objectId ");
queryString.append(" left join name ni on i.nameId = ni.objectId ");
queryString.append(" left join category c on a.current_category_id = c.objectId ");
queryString.append(" left join name nc on c.nameId = nc.objectId ");
queryString.append(" order by downloadCounts desc");
List<ItemReportVO> reportList = (List<ItemReportVO>)getJpaTemplate().execute(new JpaCallback(){
#Override
public Object doInJpa(EntityManager em)
throws PersistenceException {
SQLQuery query = ((Session)em.getDelegate()).createSQLQuery(queryString.toString());
query.addScalar("itemId", Hibernate.LONG);
query.addScalar("isFree", Hibernate.BOOLEAN);
query.addScalar("item", Hibernate.STRING);
query.addScalar("category", Hibernate.STRING);
query.addScalar("downloadCounts", Hibernate.LONG);
query.setResultTransformer(Transformers.aliasToBean(ItemReportVO.class));
int firstResult = (pagination.getCurrentPage()-1) * pagination.getPageSize();
query.setFirstResult(firstResult);
if(token != null && "all".equals(token)){
int maxResult = pagination.getPageSize();
query.setMaxResults( maxResult );
}else{
int maxResult = pagination.getPageSize() > Integer.valueOf(token) ? Integer.valueOf(token) : pagination.getPageSize();
query.setMaxResults( maxResult );
}
return query.list();
}
});
When I set show_sql=true in Hibernate's config file, Hibernate prints the sql query below when Java code runs "return query.list();":
select a.target_id as itemId, a.isFree as isFree, ni.fullName as item, nc.fullName as category, a.downloadCount as downloadCounts
from(
select dldc.current_category_id, dldc.target_id, dldc.isFree, sum(dldc.counts) as downloadCount
from download_log_day_count dldc
group by dldc.current_category_id, dldc.target_id) as a
left join item i on a.target_id = i.objectId
left join name ni on i.nameId = ni.objectId
left join category c on a.current_category_id = c.objectId
left join name nc on c.nameId = nc.objectId
order by downloadCounts desc
limit ?
I always consider they should be the same, but it seems they are not, anybody can help me to adjust the java codes?
Hibernate will alter your query to apply limit that you coded via API setMaxResults(). It should also add rownum> for setFirstResult() but, in your case, it may be very first query.
You don't have to change anything as Hibernate applies those in database specific and correct way.
Is there any other difference that concerns you?

Categories

Resources