PL / SQL: запрос с использованием переменных связывания - PullRequest
1 голос
/ 14 июля 2020

Не могли бы вы помочь понять, возможно ли выполнить эту работу с использованием переменных связывания.

ШАГ №1:

SELECT sql_query INTO d_sql_query FROM RPU WHERE track_id = v_track_id AND track_id_serv = v_track_id_serv; 

=> например, d_sql_query может выглядеть как ' CD_UNBIL.trans_dt> = TO_DATE ('20200702 12:11:03', 'YYYYMMDD HH24: MI: SS') 'или d_sql_query может иметь более крупное условие

Позже мы добавляем этот d_sql_query в более крупный запрос следующим образом : -

ШАГ # 2

query := 'SELECT CDDATA.msg_id, CDDATA.msg_id2, CDDATA.msg_id_serv,

           CDDATA.split_row_num, CDDATA.cdr_data_partition_key,….

………

                AND RPU_WORK.tracking_id = :tracking_id AND RPU_WORK.tracking_id_serv = :tracking_id_serv AND '|| NVL(d_sql_query, ' 1=1 ');

Как видите, добавлен d_sql_query, поэтому весь запрос выглядит как

...
AND RPU_WORK.tracking_id = :tracking_id AND RPU_WORK.tracking_id_serv = :tracking_id_serv AND '|| NVL(CD_UNBIL.trans_dt >= TO_DATE('20200702 12:11:03', 'YYYYMMDD HH24:MI:SS'), ' 1=1 ');

Я ищу, чтобы это сделать как (используя переменные связывания, как показано ниже).

AND RPU_WORK.tracking_id = :tracking_id AND RPU_WORK.tracking_id_serv = :tracking_id_serv AND '|| NVL(CD_UNBIL.trans_dt >= :b1, ' 1=1 ');

Я могу использовать «выполнить немедленно используя "как только я получу запрос, как указано выше.

Ответы [ 2 ]

1 голос
/ 16 июля 2020

Вы можете использовать мою программу с открытым исходным кодом PLSQL_Lexer для динамического поиска и замены литералов связанными переменными.

Например:

--Convert literals to bind variables.
declare
    v_sql_expression clob := q'[CD_UNBIL.trans_dt >= TO_DATE('20200702 12:11:03', 'YYYYMMDD HH24:MI:SS')]';
    v_new_sql_expression clob;
    v_tokens token_table := token_table();
    v_bind_number number := 0;
begin
    v_tokens := plsql_lexer.lex(v_sql_expression);

    for i in 1 .. v_tokens.count loop
        if v_tokens(i).type in ('text', 'numeric') then
            v_new_sql_expression := v_new_sql_expression || ':b'||v_bind_number;
            v_bind_number := v_bind_number + 1;
        else
            v_new_sql_expression := v_new_sql_expression || v_tokens(i).value;
        end if;
    end loop;

    dbms_output.put_line('New expression: '||v_new_sql_expression);
end;
/

Вывод:

New expression: CD_UNBIL.trans_dt >= TO_DATE(:b0, :b1)

Этот код будет иметь некоторые проблемы - TO_DATE имеет две переменные вместо одной, литералы даты, такие как date '2000-01-01', потребуют специальной обработки, потому что на самом деле это 3 токена вместо одного, это не помешает SQL инъекция (как указал pmdba), вам необходимо настроить приведенный выше код для чтения из правильных таблиц, а затем сохранить и применить литералы и т. д.

Это может помочь полностью объяснить, в какой проблеме вы пытаетесь решить - почему бы просто не применить выражения Dynami c как литералы вместо того, чтобы пытаться использовать переменные связывания?

1 голос
/ 15 июля 2020

Не могли бы вы построить конец вашего запроса примерно так?

...
AND RPU_WORK.tracking_id = :tracking_id 
AND RPU_WORK.tracking_id_serv = :tracking_id_serv 
AND case when :b1 is not null
    then
        case when CD_UNBIL.trans_dt >= TO_DATE(:b1, 'YYYYMMDD HH24:MI:SS')
        then 1
        else 0
        end
    else 1 
    end = 1
...