Close

JPA - Calling HSQLDB Stored Procedure involving Cursor to get result set

[Updated: Sep 18, 2018, Created: Sep 12, 2018]

In the last example we saw how to call a stored procedure involving Oracle's REF_CUSOR. In following example we will use HSQLDB database. We will call HSQLDB's store procedure with cursor output.

HSQLDB cursor is used to return a result set from a procedure. As HSQLDB is written in Java, the getResultSet() method of JDBC CallableStatement is used to retrieve the JDBC ResultSet.

Example

src/main/resources/procedure.sql

CREATE TABLE PERSON_HISTORY AS (SELECT * FROM PERSON) WITH NO DATA
/;

CREATE PROCEDURE MOVE_TO_HISTORY(IN person_id_in INT, OUT status_out BOOLEAN)
 MODIFIES SQL DATA
 BEGIN ATOMIC

 DECLARE temp_count INTEGER;
 SET temp_count = -1;
 SET status_out = FALSE;

  select count(*) into temp_count from PERSON p where p.id = person_id_in;
  if temp_count > -1  THEN
      SET status_out = TRUE;
      insert into PERSON_HISTORY (select * from PERSON p where p.id = person_id_in);
      delete from PERSON p where p.id = person_id_in;
 end if;
 END
 /;


CREATE PROCEDURE FETCH_PERSON_HISTORY()
READS SQL DATA DYNAMIC RESULT SETS 1
 BEGIN ATOMIC
  DECLARE history_cursor CURSOR FOR SELECT * FROM PERSON_HISTORY;
  open history_cursor;
 END
 /;

Above procedure 'MOVE_TO_HISTORY' transfers a record from PERSON table to PERSON_HISTORY table. The procedure 'FETCH_PERSON_HISTORY' returns a cursor of rows fetched from PERSON_HISTORY table.

A custom implementation of ImportSqlCommandExtractor of Hibernate is used to load above sql script.

JPA Entity

@Entity
public class Person {
  @Id
  @GeneratedValue
  private long id;
  private String firstName;
  private String lastName;
  private String address;
    .............
}

Calling Store procedures

public class ExampleMain {
  private static EntityManagerFactory entityManagerFactory =
          Persistence.createEntityManagerFactory("example-unit");

  public static void main(String[] args) {
      try {
          persistPersons();
          findAllEmployeeEntities();
          movePersonToHistoryById(1);
          movePersonToHistoryById(2);
          fetchPersonHistory();
      } finally {
          entityManagerFactory.close();
      }
  }

  private static void fetchPersonHistory() {
      System.out.println("-- Fetching person History --");
      EntityManager entityManager = entityManagerFactory.createEntityManager();
      StoredProcedureQuery procedureQuery = entityManager
              .createStoredProcedureQuery("FETCH_PERSON_HISTORY", Person.class);
      boolean execute = procedureQuery.execute();
      while (!execute && procedureQuery.hasMoreResults()) {
          execute = procedureQuery.execute();
      }
      if (!execute) {
          System.err.println("Cannot find result set");
          return;
      }
      List resultList = procedureQuery.getResultList();
      resultList.forEach(System.out::println);
      entityManager.close();
  }

  private static void movePersonToHistoryById(long personId) {
      System.out.printf("-- Moving person to history table id: %s --%n", personId);
      EntityManager entityManager = entityManagerFactory.createEntityManager();
      StoredProcedureQuery procedureQuery = entityManager
              .createStoredProcedureQuery("MOVE_TO_HISTORY");
      procedureQuery.registerStoredProcedureParameter("person_id_in", Integer.class, ParameterMode.IN);
      procedureQuery.registerStoredProcedureParameter("status_out", Boolean.class, ParameterMode.OUT);
      entityManager.getTransaction().begin();
      procedureQuery.setParameter("person_id_in", (int) personId);
      procedureQuery.execute();
      Object status_out = procedureQuery.getOutputParameterValue("status_out");
      System.out.println("Out status: " + status_out);
      entityManager.getTransaction().commit();
      entityManager.close();
  }

  public static void persistPersons() {
      Person person1 = Person.create("Dana", "Whitley", "464 Gorsuch Drive");
      Person person2 = Person.create("Robin", "Cash", "64 Zella Park");
      Person person3 = Person.create("Chary", "Mess", "112 Yellow Hill");
      EntityManager em = entityManagerFactory.createEntityManager();
      em.getTransaction().begin();
      em.persist(person1);
      em.persist(person2);
      em.persist(person3);
      em.getTransaction().commit();
      em.close();
  }

  private static void findAllEmployeeEntities() {
      System.out.println("-- finding Person entities -  --");
      EntityManager em = entityManagerFactory.createEntityManager();
      TypedQuery<Person> query = em.createQuery("SELECT p from Person p", Person.class);
      List<Person> resultList = query.getResultList();
      resultList.forEach(System.out::println);
      em.close();
  }
}
-- finding Person entities -  --
Person{id=1, firstName='Dana', lastName='Whitley', address='464 Gorsuch Drive'}
Person{id=2, firstName='Robin', lastName='Cash', address='64 Zella Park'}
Person{id=3, firstName='Chary', lastName='Mess', address='112 Yellow Hill'}
-- Moving person to history table id: 1 --
Out status: true
-- Moving person to history table id: 2 --
Out status: true
-- Fetching person History --
Person{id=1, firstName='Dana', lastName='Whitley', address='464 Gorsuch Drive'}
Person{id=2, firstName='Robin', lastName='Cash', address='64 Zella Park'}

Example Project

Dependencies and Technologies Used:

  • hsqldb 2.4.1: HSQLDB - Lightweight 100% Java SQL Database Engine.
  • hibernate-core 5.3.6.Final: Hibernate's core ORM functionality.
    Implements javax.persistence:javax.persistence-api version 2.2
  • JDK 1.8
  • Maven 3.5.4

Getting result set from HSQLDB's cursor Select All Download
  • jpa-stored-procedure-cursor-with-result-set
    • src
      • main
        • java
          • com
            • logicbig
              • common
              • example
                • ExampleMain.java
          • resources
            • META-INF

    See Also