Можно ли связать переменную связывания с динамическим предложением SQL WHERE, чтобы добавить оператор AND?

Я пытаюсь добавить оператор AND в динамическое предложение WHERE, используя переменную связывания, и получаю следующую ошибку Oracle:

ORA-01830: Изображение формата даты заканчивается до преобразования всей переменной связывания входной строки

Вот код нарушения:

FUNCTION WhereClause RETURN VARCHAR2
IS
BEGIN
    where_sql := 'WHERE TRUNC( ' || parm_rec.SRC_DATE_COLUMN || ' ) < ADD_MONTHS( ' ||
                                  'ADD_MONTHS ( TRUNC (  NVL ( :SYS_OFFSET, SYSDATE ) - ( :DAY_OFFSET )), ' ||
                                  '( :MON_OFFSET * :kNEGATIVE ) ), ' ||
                                  '( :YR_OFFSET * ( :kANNUM * :kNEGATIVE ) ) ) ';

    RETURN where_sql;
END WhereClause;



PROCEDURE ArchiveSrcDateFilter
IS     
BEGIN
DBMS_OUTPUT.PUT_LINE('ArchiveDynamic - ENTER');
IF parm_rec.SRC_DATE_COLUMN IS NULL THEN parm_rec.SRC_DATE_COLUMN := 'NULL';
END IF;
    FOR i in tbl_cur
    LOOP
    where_sql := WhereClause; -- defines the WHERE clause (where_sql) via function, Spec will not return variable to body?
    /*** DYNAMIC SQL DECLARATIONS ***/
        arc_sql := 'DECLARE ' ||
                    /*** DYNAMIC %ROWTYPE SELECT ***/
                        'CURSOR arc_cur IS ' ||
                        'SELECT * '||
                        'FROM '  || i.ARC_TABLE_NAME || '; '||               --obtain ARCHIVE ARC_SCHEMA_NAME.ARC_TABLE_NAME
                        'TYPE arc_cur_type IS TABLE OF arc_cur%ROWTYPE; ' || -- dynamically set archive record cursor %ROWTYPE for BULK COLECT as table collection 
                        'arc_rec    arc_cur_type; ' ||                       -- define archive record as TABLE OF cursor.%ROWTYPE          

                    /*** ARCHIVE PARAMETERS CURSOR - SRC_CREATE_DATE IS NOT NULL***/
                        'CURSOR parm_cur IS '||
                        'SELECT :seq_val AS ARCHIVE_ID, '||
                        'A.*, ' ||
                        'SYSDATE AS ARCHIVE_DATE ' ||
                        'FROM ' || srcSchemaTable || ' A ' ||                -- archive SRC_SCHEMA_NAME.SRC_TABLE_NAME (source table not archive table)
                        where_sql || ' || :ADD_FILTER ' || ' ; ' ||

               /*** DYNAMIC SQL STATEMENT BODY ***/                   
                   'BEGIN '||
                        'IF parm_cur%ISOPEN THEN CLOSE parm_cur; ' ||
                        'END IF; ' ||
                        'OPEN parm_cur; ' ||
                        'LOOP ' ||
                            'FETCH parm_cur ' ||
                            'BULK COLLECT INTO arc_rec LIMIT 500; ' ||
                            'EXIT WHEN arc_rec.COUNT = 0; ' ||
                            'FORALL i IN 1..arc_rec.COUNT ' ||
                                'INSERT INTO ' || arcTable ||
                                ' VALUES arc_rec( i );' ||
                                'DBMS_OUTPUT.PUT_LINE( ''ARC_REC_COUNT: '' || arc_rec.COUNT ); ' ||
                        'END LOOP; ' ||
                        'CLOSE parm_cur; ' ||                                   
                        'DBMS_OUTPUT.PUT_LINE(''SUCCESS...''); '||
                    'END; ';
    DBMS_OUTPUT.PUT_LINE('ArchiveDynamic - INSIDE LOOP: ' || arc_sql );

        EXECUTE IMMEDIATE arc_sql
        USING seq_val, parm_rec.SYS_OFFSET, parm_rec.DAY_OFFSET, parm_rec.MON_OFFSET, kNEGATIVE, parm_rec.YR_OFFSET, kANNUM, parm_rec.ADD_FILTER;

    END LOOP;

END ArchiveSrcDateFilter;

Это конкретный фрагмент кода в процедуре ArchiveSrcFilter, где находится переменная связывания :ADD_FILTER (Примечание: я безуспешно пытался выполнить различные итерации конкатенации для переменной связывания, это была просто моя последняя попытка перед публикацией проблемы здесь) :

'CURSOR parm_cur IS '||
'SELECT :seq_val AS ARCHIVE_ID, '||
'A.*, ' ||
'SYSDATE AS ARCHIVE_DATE ' ||
'FROM ' || srcSchemaTable || ' A ' ||
where_sql || ' || :ADD_FILTER ' || ' ; ' ||

И ВЫПОЛНИТЬ НЕМЕДЛЕННОЕ ИСПОЛЬЗОВАНИЕ с последним параметром в качестве привязки:

EXECUTE IMMEDIATE arc_sql
USING seq_val, parm_rec.SYS_OFFSET, parm_rec.DAY_OFFSET, parm_rec.MON_OFFSET, kNEGATIVE, parm_rec.YR_OFFSET, kANNUM, parm_rec.ADD_FILTER;

parm_rec.ADD_FILTER = AND STATUS = 1062

Можно ли сделать то, что я пытаюсь сделать, объединив привязку с where?

Я не понимаю странное сообщение об ошибке, которое я получаю, учитывая, что код выполняется без исключения, если я объединяю объектную переменную parm_rec.ADD_FILTER или жестко кодирую AND STATUS = 1062.

Я могу объединить parm_rec.ADD_FILTER вместо переменной связывания, и код будет выполняться без исключения, но мои попытки заставить переменную связывания работать не увенчались успехом.

Я благодарен за любые предложения и / или понимание.

Спасибо!


person TheSchnitz    schedule 21.02.2018    source источник
comment
Эта часть -- where_sql || ' || :ADD_FILTER ' || '; ' || -- вообще не имеет смысла. Вы применяете конкатенацию строк || к логическому состоянию. Это не может работать. Тем не менее, ошибка, которую вы получаете, выглядит не связанной с этим.   -  person wolfrevokcats    schedule 22.02.2018
comment
Вы могли бы подумать, что это не связано, но это происходит только тогда, когда я пытаюсь использовать переменную связывания так, как я это делаю. Какой консенсус между вами и @Allen ниже до сих пор заявлял, что это неправильное использование и невозможное. Спасибо за ваш отзыв.   -  person TheSchnitz    schedule 22.02.2018


Ответы (1)


Нет. Имена столбцов (например, STATUS) и операторы (например, AND, =) никогда не могут быть разрешены из переменных связывания.

person Allan    schedule 21.02.2018
comment
Подвергается ли использование объектной переменной parm_rec.ADD_FILTER SQL-инъекции? Этот пакет, скорее всего, не будет взаимодействовать с внешней веб-страницей и не будет использоваться извне; однако мне любопытно, является ли SQL-инъекция потенциальной проблемой в этом случае? Спасибо за ваш отзыв. - person TheSchnitz; 22.02.2018
comment
Каждый раз, когда вы объединяете оператор SQL, вы подвергаетесь риску SQL-инъекции. Вам необходимо определить степень риска, исходя из того, откуда ваше приложение получает значения, которые используются для построения SQL. DBMS_ASSERT можно использовать для дальнейшего снижения риска для имен объектов и столбцов, но нет встроенной проверки для добавления сравнений. - person Allan; 23.02.2018
comment
Любая конкатенация? Где-нибудь есть двойные трубы? Меня не беспокоит SQL-инъекция в этой конкретной программе, она предназначена только для внутреннего использования и будет защищена несколькими уровнями безопасности без уровня представления, отличного от ИТ (например, инструмента разработки/управления БД). Я полагаю, что просто недостаточно знаю механику SQL-инъекций. Привет-хо, чтобы исследовать я иду! Спасибо за ваш отзыв. - person TheSchnitz; 23.02.2018
comment
@TheSchnitz Можно использовать конкатенацию в запросе (например, select 'x' || some_column from table). Использование его для построения запроса является потенциальной уязвимостью (т.е. execute immediate 'select ' || column_name || ' from table'). - person Allan; 23.03.2018