我无法使用 jdbc 调用该函数,但如果它是流水线的,那么一切正常
I can't call the function using jdbc, but if it is pipelined, then everything works
我使用 spring jdbc 和 oracle 12.
我无法从包函数中得到响应。但是,如果我使用完全相同的功能但使用管道一切正常。
创建了一个包并在其中声明了 2 个函数。它们都以一个数字作为输入,并输出 table 条 pl/sql 条记录。功能上的区别,一个是流水线,一个不是
声明为:
type o_client is record(subs_id NUMBER);
type t_client is table of o_client;
function piplined_func (p_subs_id in NUMBER) return t_client pipelined;
function no_piplined_func (p_subs_id in NUMBER) return t_client;
正文是:
function piplined_func(p_subs_id in NUMBER) return t_client PIPELINED AS
v_pipe o_client;
BEGIN
FOR ids IN 1..10 LOOP
v_pipe.subs_id := ids;
PIPE ROW(v_pipe);
END LOOP;
return ;
END;
function no_piplined_func (p_subs_id in number) return t_client AS
l_tab t_client;
v_pipe o_client;
BEGIN
l_tab := t_client();
FOR ids IN 1..10 LOOP
v_pipe.subs_id := ids;
l_tab.extend;
l_tab(l_tab.last) := v_pipe;
END LOOP;
return l_tab;
END;
第一个功能是正确的:
System.out.println("Pipelined");
Processor processor = new Processor(oracleDataSource);
final String query = "select * MY_CATALOG.piplined_func(:p_subs_id)";
SqlParameterSource inputParams = new MapSqlParameterSource().addValue("p_subs_id", 1);
List<Wrapper> result = namedParameterJdbcTemplate.query(query, inputParams, BeanPropertyRowMapper.newInstance(Wrapper.class));
for (Wrapper wrapper : result) {
System.out.println(wrapper.toString());
}
Out:
Wrapper{subs_id=1}
Wrapper{subs_id=2}
Wrapper{subs_id=3}
第二个功能不正确:
System.out.println("Not Pipelined");
Processor processor = new Processor(oracleDataSource);
final String query = "select * from MY_CATALOG.no_piplined_func(:p_subs_id)";
SqlParameterSource inputParams = new MapSqlParameterSource().addValue("p_subs_id", 1);
List<Wrapper> result = namedParameterJdbcTemplate.query(query, inputParams, BeanPropertyRowMapper.newInstance(Wrapper.class));
for (Wrapper wrapper : result) {
System.out.println(wrapper.toString());
}
org.springframework.jdbc.BadSqlGrammarException: PreparedStatementCallback; bad SQL grammar [select * from sa_db_test.no_piplined_func(?)]; nested exception is java.sql.SQLSyntaxErrorException: ORA-00902: invalid datatype
我试过用同样的方法使用SimpleJdbcCall,但也没有成功。
SimpleJdbcCall simpleJdbcCall = new SimpleJdbcCall(oracleDataSource)
.withSchemaName("MY_SCHEMA")
.withCatalogName("MY_CATALOG")
.withProcedureName("no_piplined_func")
.withoutProcedureColumnMetaDataAccess()
.declareParameters( new SqlParameter("p_subs_id", Types.NUMERIC),);
SqlParameterSource in = new MapSqlParameterSource().addValue("p_subs_id", 1);
Map<String, Object> out = simpleJdbcCall.execute(in);
Exception in thread "main" org.springframework.jdbc.BadSqlGrammarException: CallableStatementCallback; bad SQL grammar [{call MY_SCHEMA.MY_CATALOG.NO_PIPLINED_FUNC(?)}]; nested exception is java.sql.SQLException: ORA-06550: line 1, column 7:
PLS-00221: 'NO_PIPLINED_FUNC' is not a procedure or is undefined
A RECORD
是 PL/SQL ONLY data-type 不能在 SQL 语句中使用。
一个 PIPELINED
函数被设计用于 SQL 语句,尽管你声明它 returns 是 RECORD
数据类型的 table,它实际上并没有这样做,而是创建了等效的 SQL data-types(即 OBJECT
data-types),可以在 SQL 语句中使用。
如果你想让两者都起作用,那么在 SQL 范围内声明 o_client
和 t_client
使用:
CREATE TYPE o_client IS OBJECT (subs_id NUMBER);
CREATE TYPE t_o_client IS TABLE OF o_client;
那么你可以使用 SQL data-types 而不是 PL/SQL data-types:
CREATE PACKAGE pkg IS
type r_client is record(subs_id NUMBER);
type t_client is table of r_client;
function pipelined_func return t_client pipelined;
function no_pipelined_func return t_client;
function no_pipelined_func_obj return t_o_client;
END;
/
和正文:
CREATE PACKAGE BODY pkg IS
FUNCTION pipelined_func
RETURN t_client PIPELINED
AS
v_pipe r_client;
BEGIN
FOR ids IN 1..10 LOOP
v_pipe.subs_id := ids;
PIPE ROW(v_pipe);
END LOOP;
END;
FUNCTION no_pipelined_func
RETURN t_client
AS
l_tab t_client;
v_pipe r_client;
BEGIN
l_tab := t_client();
FOR ids IN 1..10 LOOP
v_pipe.subs_id := ids;
l_tab.extend;
l_tab(l_tab.last) := v_pipe;
END LOOP;
RETURN l_tab;
END;
FUNCTION no_pipelined_func_obj
RETURN t_o_client
AS
l_tab t_o_client := t_o_client();
BEGIN
FOR ids IN 1..10 LOOP
l_tab.extend;
l_tab(l_tab.last) := o_client(ids);
END LOOP;
RETURN l_tab;
END;
END;
/
然后:
SELECT * FROM pkg.no_pipelined_func();
失败:
ORA-00902: invalid datatype
但是:
SELECT * FROM pkg.pipelined_func();
和
SELECT * FROM pkg.no_pipelined_func_obj();
两者输出:
SUBS_ID
1
2
3
4
5
6
7
8
9
10
db<>fiddle here
我使用 spring jdbc 和 oracle 12.
我无法从包函数中得到响应。但是,如果我使用完全相同的功能但使用管道一切正常。
创建了一个包并在其中声明了 2 个函数。它们都以一个数字作为输入,并输出 table 条 pl/sql 条记录。功能上的区别,一个是流水线,一个不是
声明为:
type o_client is record(subs_id NUMBER);
type t_client is table of o_client;
function piplined_func (p_subs_id in NUMBER) return t_client pipelined;
function no_piplined_func (p_subs_id in NUMBER) return t_client;
正文是:
function piplined_func(p_subs_id in NUMBER) return t_client PIPELINED AS
v_pipe o_client;
BEGIN
FOR ids IN 1..10 LOOP
v_pipe.subs_id := ids;
PIPE ROW(v_pipe);
END LOOP;
return ;
END;
function no_piplined_func (p_subs_id in number) return t_client AS
l_tab t_client;
v_pipe o_client;
BEGIN
l_tab := t_client();
FOR ids IN 1..10 LOOP
v_pipe.subs_id := ids;
l_tab.extend;
l_tab(l_tab.last) := v_pipe;
END LOOP;
return l_tab;
END;
第一个功能是正确的:
System.out.println("Pipelined");
Processor processor = new Processor(oracleDataSource);
final String query = "select * MY_CATALOG.piplined_func(:p_subs_id)";
SqlParameterSource inputParams = new MapSqlParameterSource().addValue("p_subs_id", 1);
List<Wrapper> result = namedParameterJdbcTemplate.query(query, inputParams, BeanPropertyRowMapper.newInstance(Wrapper.class));
for (Wrapper wrapper : result) {
System.out.println(wrapper.toString());
}
Out:
Wrapper{subs_id=1}
Wrapper{subs_id=2}
Wrapper{subs_id=3}
第二个功能不正确:
System.out.println("Not Pipelined");
Processor processor = new Processor(oracleDataSource);
final String query = "select * from MY_CATALOG.no_piplined_func(:p_subs_id)";
SqlParameterSource inputParams = new MapSqlParameterSource().addValue("p_subs_id", 1);
List<Wrapper> result = namedParameterJdbcTemplate.query(query, inputParams, BeanPropertyRowMapper.newInstance(Wrapper.class));
for (Wrapper wrapper : result) {
System.out.println(wrapper.toString());
}
org.springframework.jdbc.BadSqlGrammarException: PreparedStatementCallback; bad SQL grammar [select * from sa_db_test.no_piplined_func(?)]; nested exception is java.sql.SQLSyntaxErrorException: ORA-00902: invalid datatype
我试过用同样的方法使用SimpleJdbcCall,但也没有成功。
SimpleJdbcCall simpleJdbcCall = new SimpleJdbcCall(oracleDataSource)
.withSchemaName("MY_SCHEMA")
.withCatalogName("MY_CATALOG")
.withProcedureName("no_piplined_func")
.withoutProcedureColumnMetaDataAccess()
.declareParameters( new SqlParameter("p_subs_id", Types.NUMERIC),);
SqlParameterSource in = new MapSqlParameterSource().addValue("p_subs_id", 1);
Map<String, Object> out = simpleJdbcCall.execute(in);
Exception in thread "main" org.springframework.jdbc.BadSqlGrammarException: CallableStatementCallback; bad SQL grammar [{call MY_SCHEMA.MY_CATALOG.NO_PIPLINED_FUNC(?)}]; nested exception is java.sql.SQLException: ORA-06550: line 1, column 7: PLS-00221: 'NO_PIPLINED_FUNC' is not a procedure or is undefined
A RECORD
是 PL/SQL ONLY data-type 不能在 SQL 语句中使用。
一个 PIPELINED
函数被设计用于 SQL 语句,尽管你声明它 returns 是 RECORD
数据类型的 table,它实际上并没有这样做,而是创建了等效的 SQL data-types(即 OBJECT
data-types),可以在 SQL 语句中使用。
如果你想让两者都起作用,那么在 SQL 范围内声明 o_client
和 t_client
使用:
CREATE TYPE o_client IS OBJECT (subs_id NUMBER);
CREATE TYPE t_o_client IS TABLE OF o_client;
那么你可以使用 SQL data-types 而不是 PL/SQL data-types:
CREATE PACKAGE pkg IS
type r_client is record(subs_id NUMBER);
type t_client is table of r_client;
function pipelined_func return t_client pipelined;
function no_pipelined_func return t_client;
function no_pipelined_func_obj return t_o_client;
END;
/
和正文:
CREATE PACKAGE BODY pkg IS
FUNCTION pipelined_func
RETURN t_client PIPELINED
AS
v_pipe r_client;
BEGIN
FOR ids IN 1..10 LOOP
v_pipe.subs_id := ids;
PIPE ROW(v_pipe);
END LOOP;
END;
FUNCTION no_pipelined_func
RETURN t_client
AS
l_tab t_client;
v_pipe r_client;
BEGIN
l_tab := t_client();
FOR ids IN 1..10 LOOP
v_pipe.subs_id := ids;
l_tab.extend;
l_tab(l_tab.last) := v_pipe;
END LOOP;
RETURN l_tab;
END;
FUNCTION no_pipelined_func_obj
RETURN t_o_client
AS
l_tab t_o_client := t_o_client();
BEGIN
FOR ids IN 1..10 LOOP
l_tab.extend;
l_tab(l_tab.last) := o_client(ids);
END LOOP;
RETURN l_tab;
END;
END;
/
然后:
SELECT * FROM pkg.no_pipelined_func();
失败:
ORA-00902: invalid datatype
但是:
SELECT * FROM pkg.pipelined_func();
和
SELECT * FROM pkg.no_pipelined_func_obj();
两者输出:
SUBS_ID 1 2 3 4 5 6 7 8 9 10
db<>fiddle here