跳转至

调用保存的函数和过程

调用保存的函数和过程

SeaboxSQL™支持两种类型的存储对象,一种可以返回结果的函数,以及可以执行事务控制的过程(从v11开始)。两种类型的存储对象都使用CallableStatement和标准JDBC转义调用语法{call storedobject(?)}进行调用。escapeSyntaxCallMode连接属性控制驱动程序如何将语法转换为调用函数或过程。

默认模式下,select支持现有应用程序的向后兼容性,并且仅支持函数调用。这需要调用一个不返回结果的函数。对于新应用程序,请使用escapeSyntaxCallMode = callIfNoReturn来将带有返回值的CallableStatements映射到存储函数,而将没有返回值的CallableStatements映射到存储过程。

示例 调用内置的存储函数

本示例说明如何调用SeaboxSQL™内置函数upper,该函数将提供的字符串参数简单地转换为大写。

CallableStatement upperFunc = conn.prepareCall("{? = call upper(?)}");
upperFunc.registerOutParameter(1, Types.VARCHAR);
upperFunc.setString(2, "lowercase to uppercase");
upperFunc.execute();String upperCased = upperFunc.getString(1);upperFunc.close();

从存储的函数中获取一个ResultSet

SeaboxSQL的存储函数以两种不同的方式返回结果。 该函数可以返回refcursor值或SETOF一些数据类型。 根据使用哪种返回方法,确定应如何调用该函数。

从返回SETOF类型的函数

返回数据集合的函数不应通过CallableStatement接口调用,而应使用常规的Statement或PreparedStatement接口。

示例 从函数获取SETOF类型值

Statement stmt = conn.createStatement();
stmt.execute("CREATE OR REPLACE FUNCTION setoffunc() RETURNS SETOF int AS "
    + "' SELECT 1 UNION SELECT 2;' LANGUAGE sql");
ResultSet rs = stmt.executeQuery("SELECT * FROM setoffunc()");
while (rs.next())
{
    // do something
}
rs.close();
stmt.close();

从函数返回一个refcursor

调用返回refcursor的函数时,必须将getObject的返回类型强制转换为ResultSet

注意: 当前支持从反射器创建的ResultSet的一个显着限制是,即使它是游标支持的ResultSet,也将在客户端上检索并缓存所有数据。获取结果大小参数将被忽略。 这种限制是JDBC驱动程序而不是服务器的缺陷,从技术上讲可以解决,只是暂时没有时间。

示例 从函数获取引用值

// Setup function to call.
Statement stmt = conn.createStatement();
stmt.execute("CREATE OR REPLACE FUNCTION refcursorfunc() RETURNS refcursor AS '"
    + " DECLARE "
    + "    mycurs refcursor; "
    + " BEGIN "
    + "    OPEN mycurs FOR SELECT 1 UNION SELECT 2; "
    + "    RETURN mycurs; "
    + " END;' language plpgsql");
stmt.close();

// We must be inside a transaction for cursors to work.
conn.setAutoCommit(false);

// Function call.
CallableStatement func = conn.prepareCall("{? = call refcursorfunc() }");
func.registerOutParameter(1, Types.OTHER);
func.execute();
ResultSet results = (ResultSet) func.getObject(1);
while (results.next())
{
    // do something with the results.
}
results.close();
func.close();

还可以将refcursor返回值直接视为游标名称。 为此,请使用ResultSet的getString。 使用基础的游标名称,您可以直接在其上直接使用游标命令,例如FETCH和MOVE。

示例 将refcursor当作游标名称

conn.setAutoCommit(false);
CallableStatement func = conn.prepareCall("{? = call refcursorfunc() }");
func.registerOutParameter(1, Types.OTHER);
func.execute();
String cursorName = func.getString(1);
func.close();

实例 调用存储过程

本示例说明如何调用使用事务控制的SeaboxSQL™过程。

// set up a connection
String url = "jdbc:seaboxsql://localhost/test";
Properties props = new Properties();
... other properties ...
// Ensure EscapeSyntaxCallmode property set to support procedures if no return value
props.setProperty("escapeSyntaxCallMode", "callIfNoReturn");
Connection con = DriverManager.getConnection(url, props);

// Setup procedure to call.
Statement stmt = con.createStatement();
stmt.execute("CREATE TEMP TABLE temp_val ( some_val bigint )");
stmt.execute("CREATE OR REPLACE PROCEDURE commitproc(a INOUT bigint) AS '"
    + " BEGIN "
    + "    INSERT INTO temp_val values(a); "
    + "    COMMIT; "
    + " END;' LANGUAGE plpgsql");
stmt.close();

// As of v11, we must be outside a transaction for procedures with transactions to work.
con.setAutoCommit(true);

// Procedure call with transaction
CallableStatement proc = con.prepareCall("{call commitproc( ? )}");
proc.setInt(1, 100);
proc.execute();
proc.close();