JDBC CallableStatement PostgreSQL Stored Function
By:Roy.LiuLast updated:2019-08-11
A JDBC CallableStatement example to show you how to call a stored function from PostgreSQL database.
P.S Tested with PostgreSQL 11 and Java 8
pom.xml
<dependency> <groupId>org.postgresql</groupId> <artifactId>postgresql</artifactId> <version>42.2.5</version> </dependency>
1. Call Function
1.1 Create a stored function and calling it via JDBC.
FunctionReturnString.java
package com.mkyong.jdbc.callablestatement;
import java.sql.*;
public class FunctionReturnString {
public static void main(String[] args) {
String createFunction = "CREATE OR REPLACE FUNCTION hello(p1 TEXT) RETURNS TEXT "
+ " AS $$ "
+ " BEGIN "
+ " RETURN 'hello ' || p1; "
+ " END; "
+ " $$ "
+ " LANGUAGE plpgsql";
String runFunction = "{ ? = call hello( ? ) }";
try (Connection conn = DriverManager.getConnection(
"jdbc:postgresql://127.0.0.1:5432/test", "postgres", "password");
Statement statement = conn.createStatement();
CallableStatement callableStatement = conn.prepareCall(runFunction)) {
// create or replace stored function
statement.execute(createFunction);
//----------------------------------
// output
callableStatement.registerOutParameter(1, Types.VARCHAR);
// input
callableStatement.setString(2, "mkyong");
// Run hello() function
callableStatement.executeUpdate();
// Get result
String result = callableStatement.getString(1);
System.out.println(result);
} catch (SQLException e) {
System.err.format("SQL State: %s\n%s", e.getSQLState(), e.getMessage());
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
Output
hello mkyong
1.2 SQL version.
CREATE OR REPLACE FUNCTION hello(p1 TEXT) RETURNS TEXT
AS $$
BEGIN
RETURN 'hello ' || p1;
END;
$$
LANGUAGE plpgsql;
-- run it
select hello('mkyong');
-- output: hello mkyong
2. Function Returning SETOF
2.1 For Functions that return data as a SETOF, we should use the normal Statement or PreparedStatement, NOT CallableStatement
P.S The table pg_roles is a system table containing database roles
FunctionReturnResultSet.java
package com.mkyong.jdbc.callablestatement;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
public class FunctionReturnResultSet {
public static void main(String[] args) {
List<String> users = new ArrayList<>();
String createFunction = "CREATE OR REPLACE FUNCTION getRoles() RETURNS SETOF pg_roles "
+ " AS 'select * from pg_roles' LANGUAGE sql;";
String runFunction = "select * from getRoles();";
try (Connection conn = DriverManager.getConnection(
"jdbc:postgresql://127.0.0.1:5432/test", "postgres", "password");
Statement statement = conn.createStatement()) {
// create a function returns as SETOF
statement.execute(createFunction);
// run it
ResultSet resultSet = statement.executeQuery(runFunction);
while (resultSet.next()) {
users.add(resultSet.getString("rolname"));
System.out.println("Database roles...");
users.forEach(x -> System.out.println(x));
} catch (SQLException e) {
System.err.format("SQL State: %s\n%s", e.getSQLState(), e.getMessage());
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
Output
Database roles... pg_signal_backend pg_read_server_files postgres pg_write_server_files pg_execute_server_program pg_read_all_stats pg_monitor pg_read_all_settings pg_stat_scan_tables
2.2 SQL version.
CREATE OR REPLACE FUNCTION getRoles() RETURNS SETOF pg_roles AS 'select * from pg_roles' LANGUAGE sql; -- run it select * from getRoles();
3. Function Returning Cursor
3.1 JDBC + Ref Cursor example.
FunctionReturnRefCursor.java
package com.mkyong.jdbc.callablestatement;
import java.sql.*;
public class FunctionReturnRefCursor {
public static void main(String[] args) {
String createFunction = "CREATE OR REPLACE FUNCTION getUsers(mycurs OUT refcursor) "
+ " RETURNS refcursor "
+ " AS $$ "
+ " BEGIN "
+ " OPEN mycurs FOR select * from pg_user; "
+ " END; "
+ " $$ "
+ " LANGUAGE plpgsql";
String runFunction = "{? = call getUsers()}";
try (Connection conn = DriverManager.getConnection(
"jdbc:postgresql://127.0.0.1:5432/test", "postgres", "password");
Statement statement = conn.createStatement();
CallableStatement cs = conn.prepareCall(runFunction);
) {
// We must be inside a transaction for cursors to work.
conn.setAutoCommit(false);
// create function
statement.execute(createFunction);
// register output
cs.registerOutParameter(1, Types.REF_CURSOR);
// run function
cs.execute();
// get refcursor and convert it to ResultSet
ResultSet resultSet = (ResultSet) cs.getObject(1);
while (resultSet.next()) {
System.out.println(resultSet.getString("usename"));
System.out.println(resultSet.getString("passwd"));
} catch (SQLException e) {
System.err.format("SQL State: %s\n%s", e.getSQLState(), e.getMessage());
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
Output – This database contains a single user for testing :)
postgres ********
3.2 SQL version.
CREATE OR REPLACE FUNCTION getUsers(mycurs OUT refcursor) RETURNS refcursor AS $$ BEGIN OPEN mycurs FOR select * from pg_user; END; $$ LANGUAGE plpgsql;
From:一号门

COMMENTS