3


ユーザーが入力したテーブルがあり、その VARCHAR2 レコードには、実行可能な PL/SQL コード "IN(user_input)" の一部が含まれています。これらのユーザー入力をサニタイズしたり、より効率的に書き直すにはどうすればよいでしょうか。これまでの私のアイデアはすべて失敗しました。例えば:

  • この場合、バインド変数は受け入れられません
  • DBMS_ASSERT.enquote_literal は常に例外などを発生させます。

助けてくれてありがとう。

/* A "MY_PARAMETER" column is part of SQL: ...WHERE MY_DATA IN(MY_PARAMETER)... */
CREATE TABLE my_parameter_table (
       "ID" INTEGER NOT NULL ENABLE,
       "MY_PARAMETER" VARCHAR(255) NOT NULL ENABLE   
)

INSERT INTO my_parameter_table ("ID","MY_PARAMETER") VALUES (1,'6,7,8');
INSERT INTO my_parameter_table ("ID","MY_PARAMETER") VALUES (2,'''b'',''g'',''k''');
INSERT INTO my_parameter_table ("ID","MY_PARAMETER") VALUES (3,'SELECT dummy FROM dual'); -- return "X"

/* Tested table with data */
CREATE TABLE my_data_table (
       "ID" INTEGER NOT NULL ENABLE,
       "MY_DATA" VARCHAR(255) NOT NULL ENABLE,
       "MY_RESULT" VARCHAR(255) NOT NULL ENABLE   
);

INSERT INTO my_data_table ("ID","MY_DATA","MY_RESULT") VALUES (1,'a','NOT');
INSERT INTO my_data_table ("ID","MY_DATA","MY_RESULT") VALUES (2,'b','THIS'); --WILL PASS
INSERT INTO my_data_table ("ID","MY_DATA","MY_RESULT") VALUES (3,'c','NOT');
INSERT INTO my_data_table ("ID","MY_DATA","MY_RESULT") VALUES (4,'X','IS'); --WILL PASS
INSERT INTO my_data_table ("ID","MY_DATA","MY_RESULT") VALUES (5,'Y','NOT');
INSERT INTO my_data_table ("ID","MY_DATA","MY_RESULT") VALUES (6,'Z','CORRECT'); --WILL PASS

/* Result table where results are inserted */
CREATE TABLE my_result_table (
       "MESSAGE" VARCHAR(255) NOT NULL ENABLE   
);

/* ------------------------------------------- */

DECLARE
    where_condition VARCHAR2(1000) := '';
    v_query VARCHAR2(1000) := '';
    insert_or VARCHAR2(5) := '';

    CURSOR test_parameter_cur IS
        (
          SELECT * FROM my_parameter_table            
        );
    test_parameter_rec test_parameter_cur%ROWTYPE;

BEGIN

    /* Read all parameters and build an WHERE condition */
    OPEN test_parameter_cur;
    LOOP 
        FETCH test_parameter_cur INTO test_parameter_rec; 
        EXIT WHEN test_parameter_cur%NOTFOUND;

        /* Condition check can be any type. Varchar, number, date or some subselect */
        IF test_parameter_rec.ID = 1 THEN where_condition := where_condition || insert_or || 'd.ID IN('|| test_parameter_rec.MY_PARAMETER ||')';
        ELSE where_condition := where_condition || insert_or || 'd.MY_DATA IN('|| test_parameter_rec.MY_PARAMETER ||')';
        END IF;
        insert_or := ' OR '; -- after first run the "OR" operator is inserted in front of each where condition 

    END LOOP; 
    CLOSE test_parameter_cur; 

v_query := 'INSERT INTO my_result_table(MESSAGE) 
           (SELECT d.MY_RESULT FROM my_data_table d
           WHERE '|| where_condition ||')';

EXECUTE IMMEDIATE v_query;
COMMIT; 
END;

/* Now the my_result_table contains 3 records: THIS, IS, CORRECT */
SELECT * FROM my_result_table;

DROP TABLE my_parameter_table; 
DROP TABLE my_data_table;
4

1 に答える 1

0

こちらをご覧ください: https://blogs.oracle.com/aramamoo/entry/how_to_split_comma_separated_string_and_pass_to_in_clause_of_select_statement

「,」で区切られたリストの魅力のように機能します。結果を TRIM() して、結果から末尾と先頭の空白を削除することをお勧めします。

select-statement を in-clause の副選択として使用できます。

于 2013-04-03T14:03:15.960 に答える