如何在PreparedStatement中使用Oracle的JSON_VALUE函数
我正在尝试使用Oracle的json_值函数和PreparedStatement运行SQL查询 假设下表设置:如何在PreparedStatement中使用Oracle的JSON_VALUE函数,json,oracle,jdbc,prepared-statement,Json,Oracle,Jdbc,Prepared Statement,我正在尝试使用Oracle的json_值函数和PreparedStatement运行SQL查询 假设下表设置: drop table foo cascade constraints purge; create table foo ( id integer primary key, payload clob, constraint ensure_json check (payload IS JSON STRICT) ); insert into foo values (1, '{
drop table foo cascade constraints purge;
create table foo
(
id integer primary key,
payload clob,
constraint ensure_json check (payload IS JSON STRICT)
);
insert into foo values (1, '{"data": {"k1": 1, "k2": "foo"}}');
以下SQL查询工作正常:
select *
from foo
where json_value(payload, '$.data.k1') = '1'
并返回所需的行
但是,当我尝试使用以下代码段中的PreparedStatement运行此查询时:
字符串sql=
选择*\n+
来自foo\n+
其中json_valuepayload,?=?;
PreparedStatement pstmt=conction.prepareStatementsql;
pstmt.setString1,$.data.k1;
pstmt.setString2,1;
结果集rs=pstmt.executeQuery;
我从示例中删除了所有错误检查以保持简单
这导致:
java.sql.SQLException:ORA-40454:路径表达式不是文本
罪魁祸首是传递json路径值参数索引1,第二个参数没有问题
当我用字符串常量json_valuepayload,'$.data.k1'=仅替换第一个参数时?事先准备好的声明很有效
在一次绝望的尝试中,我还尝试在参数pstmt.setString1,'$.data.k1'中包含单引号,但毫不奇怪,Oracle也不会接受相同的错误消息
我还尝试使用json_valuepayload,concat'$?并且只传递data.k1作为参数-结果相同
因此,问题是:
如何使用PreparedStatement参数将JSON路径表达式传递给Oracle的JSON_值函数?
有什么想法吗?这是驱动程序中的错误还是Oracle中的错误?我在Oracle支持上找不到任何内容
或者这仅仅是一个没有实施的案例
环境:
我正在使用Oracle 18.0
我尝试了18.3和19.3版本的ojdbc10.jar驱动程序以及OpenJDK11 这不是驱动因素-你会得到同样的结果: 它并不是一个真正的bug,它的重点是: JSON_基本路径_表达式 使用此子句指定SQL/JSON路径表达式。该函数使用路径表达式计算expr并查找与路径表达式匹配或满足该表达式的标量JSON值。路径表达式必须是文本文本。有关JSON_basic_path_表达式的完整语义,请参阅 因此,不幸的是,您必须,而不是绑定它:
declare
result foo%rowtype;
begin
execute immediate 'select *
from foo
where json_value(payload, ''' || '$.data.k1' || ''') = :1'
into result using '1';
dbms_output.put_line(result.payload);
end;
/
1 rows affected
dbms_output:
{"data": {"k1": 1, "k2": "foo"}}
或者对于JDBC示例,将路径保留为单独的字符串,因为您可能希望它真正成为一个变量:
String sql =
"select *\n" +
"from foo\n" +
"where json_value(payload, '" + "$.data.k1" + "') = ?";
PreparedStatement pstmt = conection.prepareStatement(sql);
pstmt.setString(1, "1");
ResultSet rs = pstmt.executeQuery();
这显然不是你想要做的,但似乎没有其他选择。除了将查询转换为函数并将path变量传递给该函数之外,该函数还必须使用动态SQL,因此效果大致相同——但这样可能更容易处理SQL注入问题
*我知道你知道如何用嵌入的方式来实现这一点,并且知道你想使用绑定变量,因为这是正确的做法;我已经为其他访问者详细说明了这一点*8-感谢您确认我没有在手册中发现这一部分,这是Oracle JSON支持的另一个令人讨厌的限制
String sql =
"select *\n" +
"from foo\n" +
"where json_value(payload, '" + "$.data.k1" + "') = ?";
PreparedStatement pstmt = conection.prepareStatement(sql);
pstmt.setString(1, "1");
ResultSet rs = pstmt.executeQuery();