Ошибка DB2 SQL: SQLCODE = -302 при выполнении подготовленного оператора - PullRequest
0 голосов
/ 10 июня 2019

У меня есть SQL-запрос, который принимает пользовательские данные, следовательно, существует уязвимость.

Существующий запрос:

SELECT  BUS_NM, STR_ADDR_1, CITY_NM, STATE_CD, POSTAL_CD, COUNTRY_CD,
        BUS_PHONE_NB,PEG_ACCOUNT_ID, GDN_ALERT_ID, GBIN, GDN_MON_REF_NB,
        ALERT_DT, ALERT_TYPE, ALERT_DESC,ALERT_PRIORITY 
FROM ( SELECT A.BUS_NM, AE.STR_ADDR_1, A.CITY_NM, A.STATE_CD, A.POSTAL_CD,
              CC.COUNTRY_CD,  A.BUS_PHONE_NB, A.PEG_ACCOUNT_ID, 'I' || 
              LPAD(INTL_ALERT_DTL_ID, 9,'0') GDN_ALERT_ID, 
              LPAD(IA.GBIN, 9,'0') GBIN, IA.GDN_MON_REF_NB,
              DATE(IAD.ALERT_TS) ALERT_DT, 
              XMLCAST(XMLQUERY('$A/alertTypeConfig/biqCode/text()' passing  
                IAC.INTL_ALERT_TYPE_CONFIG as "A") AS CHAR(4)) ALERT_TYPE, 
              , ROW_NUMBER() OVER () AS "RN" 
       FROM ACCOUNT A, Other tables 
       WHERE IA.GDN_MON_REF_NB = '100'  
         AND A.PEG_ACCOUNT_ID = IAAR.PEG_ACCOUNT_ID  
         AND CC.COUNTRY_CD = A.COUNTRY_ISO3_CD 
       ORDER BY IA.INTL_ALERT_ID ASC )  
WHERE  ALERT_TYPE  IN (" +TriggerType+ ");

Я изменил его, чтобы принимать TriggerType из setString как:

SELECT BUS_NM, STR_ADDR_1, CITY_NM, STATE_CD, POSTAL_CD, COUNTRY_CD,
       BUS_PHONE_NB,PEG_ACCOUNT_ID, GDN_ALERT_ID, GBIN, GDN_MON_REF_NB,
       ALERT_DT, ALERT_TYPE, ALERT_DESC,ALERT_PRIORITY 
FROM ( SELECT A.BUS_NM, AE.STR_ADDR_1, A.CITY_NM, A.STATE_CD, A.POSTAL_CD, 
              CC.COUNTRY_CD,  A.BUS_PHONE_NB, A.PEG_ACCOUNT_ID, 
              'I' || LPAD(INTL_ALERT_DTL_ID, 9,'0') GDN_ALERT_ID,
              LPAD(IA.GBIN, 9,'0') GBIN, IA.GDN_MON_REF_NB, 
              DATE(IAD.ALERT_TS) ALERT_DT, 
              XMLCAST(XMLQUERY('$A/alertTypeConfig/biqCode/text()' passing  
                IAC.INTL_ALERT_TYPE_CONFIG as "A") AS CHAR(4)) ALERT_TYPE, 
              ROW_NUMBER() OVER () AS "RN" 
       FROM ACCOUNT A, other tables 
       WHERE IA.GDN_MON_REF_NB = '100'  
         AND A.PEG_ACCOUNT_ID = IAAR.PEG_ACCOUNT_ID   
         AND CC.COUNTRY_CD = A.COUNTRY_ISO3_CD 
       ORDER BY IA.INTL_ALERT_ID ASC )  
WHERE  ALERT_TYPE  IN (?);

Установка типа триггера, как показано ниже:

if (StringUtils.isNotBlank(request.getTriggerType())) {
   preparedStatement.setString(1, triggerType != null ? triggerType.toString() : "");
}

Получение ошибки как

Причина: com.ibm.db2.jcc.am.SqlDataException: DB2Ошибка SQL: SQLCODE = -302, SQLSTATE = 22001, SQLERRMC = ноль, DRIVER = 4.19.26

Ответы [ 2 ]

0 голосов
/ 11 июня 2019

Неправильно IN использование предиката с параметром.
Не ожидайте, что IN ('AAAA, M250, ABCD') (так как вы пытаетесь передать строку через запятую как один параметр) работает как IN ('AAAA', 'M250', 'ABCD') (как вам нужно). Эти предикаты не эквивалентны.
Вам нужен какой-нибудь "токенайзер строк", если вы хотите передать такую ​​строку через запятую, как показано ниже.

select t.*
from
(
select XMLCAST(XMLQUERY('$A/alertTypeConfig/biqCode/text()' passing IAC.INTL_ALERT_TYPE_CONFIG as "A") AS CHAR(4)) ALERT_TYPE
from table(values xmlparse(document '<alertTypeConfig><biqCode>M250, really big code</biqCode></alertTypeConfig>')) IAC(INTL_ALERT_TYPE_CONFIG)
) t
--WHERE  ALERT_TYPE IN ('AAAA, M250, ABCD')
join xmltable('for $id in tokenize($s, ",\s?") return <i>{string($id)}</i>' 
passing cast('AAA, M250 , ABCD' as varchar(200)) as "s" 
columns token varchar(200) path '.') x on x.token=t.ALERT_TYPE
;

Запустите оператор как есть. Затем вы можете раскомментировать строку с предложением WHERE и закомментировать остальные, чтобы увидеть, что вы пытаетесь сделать.

P.S:.
Вероятно, вы получаете ошибку, потому что вы не указываете тип данных параметра (вы не используете что-то вроде IN (cast(? as varchar(xxx))), а компилятор db2 предполагает, что его длина равна длине выражения ALERT_TYPE (4 байт).

0 голосов
/ 11 июня 2019

-302 SQLCODE указывает какую-то ошибку преобразования.

SQLSTATE 22001 немного сужает это, говоря нам, что вы пытаетесь заставить большую строку в маленькую переменную. Учитывая ограниченную информацию в вашем вопросе, я предполагаю, что виновником является XMLCAST.

DB2 не будет складывать 30 фунтов дерьма в 4-фунтовый пакет, так сказать, из-за ошибки. Возможно, предоставление XML дополнительного пространства в актерском составе может помочь. Если вам нужно убедиться, что длина его всего 4 символа, вы можете явно сделать LEFT(XMLCAST( ... AS VARCHAR(64)), 4). Таким образом, XMLCAST имеет место, которое ему нужно, но вы сокращаете его, чтобы подогнать переменную к выборке.

Другое дело, что переменная, передаваемая в маркер параметра, слишком длинная. DB2 будет угадывать тип и длину на основе длины ALERT_TYPE. Обратите внимание, что вы можете передать только одно значение через маркер параметра. Если вы передадите список через запятую, он не будет работать так, как ожидалось (если только вы не ожидаете, что ALERT_TYPE также будет содержать список, разделенный запятыми). Если вы получаете разделенный запятыми список из таблицы, вы можете использовать вместо этого дополнительный выбор.

...