मैं एक PreparedStatement का उपयोग करके Oracle के json_value() फ़ंक्शन का उपयोग करके 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, '{"data": {"k1": 1, "k2": "foo"}}');

निम्न SQL क्वेरी ठीक काम करती है:

select *
from foo
where json_value(payload, '$.data.k1') = '1'

और अपेक्षित पंक्ति लौटाता है।

हालांकि, जब मैं निम्नलिखित कोड में PreparedStatement का उपयोग करके इस क्वेरी को चलाने का प्रयास करता हूं:

String sql =
     "select *\n" +
     "from foo\n" +
     "where json_value(payload, ?) = ?";

PreparedStatement pstmt = conection.prepareStatement(sql);
pstmt.setString(1, "$.data.k1");
pstmt.setString(2, "1");
ResultSet rs = pstmt.executeQuery();

(मैंने इसे सरल रखने के लिए उदाहरण से सभी त्रुटि जाँच को हटा दिया है)

इसका परिणाम यह होगा:

java.sql.SQLException: ORA-40454: पथ अभिव्यक्ति शाब्दिक नहीं है

अपराधी जेसन पथ मान (पैरामीटर इंडेक्स 1) पास कर रहा है, दूसरा पैरामीटर कोई समस्या नहीं है।

जब मैं (केवल) पहले पैरामीटर को स्ट्रिंग स्थिरांक json_value(payload, '$.data.k1') = ? से प्रतिस्थापित करता हूं तो तैयार कथन ठीक काम करता है।

एक हताश प्रयास में, मैंने पैरामीटर में एकल उद्धरणों को शामिल करने का भी प्रयास किया: pstmt.setString(1, "'$.data.k1'") लेकिन आश्चर्य की बात नहीं, Oracle इसे स्वीकार नहीं करेगा (वही त्रुटि संदेश)।

मैंने json_value(payload, concat('$.', ?) ) का उपयोग करने और पैरामीटर के रूप में केवल "data.k1" पास करने का भी प्रयास किया - वही परिणाम।

तो, सवाल यह है:

  • मैं एक PreparedStatement पैरामीटर का उपयोग करके Oracle के json_value फ़ंक्शन में JSON पथ अभिव्यक्ति कैसे पास कर सकता हूं?

कोई विचार? क्या यह ड्राइवर में या Oracle में बग है? (मुझे माई ओरेकल सपोर्ट पर कुछ नहीं मिला)

या यह केवल "लागू नहीं" का मामला है?


वातावरण:

मैं Oracle 18.0 का उपयोग कर रहा हूं
मैंने ओपनजेडीके 11 के साथ मिलकर ojdbc10.jar ड्राइवर के 18.3 और 19.3 संस्करण की कोशिश की।

2
a_horse_with_no_name 9 जुलाई 2019, 11:05

1 उत्तर

सबसे बढ़िया उत्तर

यह ड्राइवर नहीं है - आपको वही चीज़ मिलती है डायनेमिक SQL के साथ:

declare
  result foo%rowtype;
begin
  execute immediate 'select *
    from foo
    where json_value(payload, :1) = :2'
  into result using '$.data.k1', '1';
  dbms_output.put_line(result.payload);
end;
/

ORA-40454: path expression not a literal
ORA-06512: at line 4

और यह वास्तव में कोई बग नहीं है, यह दस्तावेज (जोर दिया गया):

JSON_basic_path_expression

SQL/JSON पथ व्यंजक निर्दिष्ट करने के लिए इस खंड का उपयोग करें। फ़ंक्शन expr का मूल्यांकन करने के लिए पथ अभिव्यक्ति का उपयोग करता है और एक स्केलर JSON मान ढूंढता है जो पथ अभिव्यक्ति से मेल खाता है या संतुष्ट करता है। पथ व्यंजक एक टेक्स्ट शाब्दिक होना चाहिए। देखें Oracle Database JSON Developer's Guide

तो दुर्भाग्यवश, आपको पथ शाब्दिक एम्बेड करना होगा, इसे बाध्य करने के बजाय, दुर्भाग्य से:

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();

जो स्पष्ट रूप से वह नहीं है जो आप करना चाहते हैं*, लेकिन कोई विकल्प प्रतीत नहीं होता है। अपनी क्वेरी को किसी फ़ंक्शन में बदलने और उसमें पथ चर पास करने के अलावा, लेकिन फिर फ़ंक्शन को गतिशील एसक्यूएल का उपयोग करना होगा, इसलिए प्रभाव बहुत समान है - हालांकि एसक्यूएल इंजेक्शन चिंताओं को इस तरह से संभालना आसान हो सकता है।

* और मुझे पता है कि आप इसे एम्बेडेड तरीके से करना जानते हैं, और जानते हैं कि आप बाइंड वेरिएबल्स का उपयोग करना चाहते हैं क्योंकि यह सही काम है; मैंने इसे अन्य आगंतुकों के लिए आपको की आवश्यकता से अधिक लिखा है *8-)

2
Alex Poole 9 जुलाई 2019, 11:44