Конференция "Базы" » Очередные загадки Firebird 2
 
  • dik59 (27.03.10 21:01) [0]
    Уважаемые мастера!
    Кто-нибудь сталкивался с такой проблемой: запрос

    Select * from dn
    Where
    ((select val from READ_DSI(dn.doc,dn.num,99692)) not between 0 and 60)

    исполняется без ошибок, результат выдается правильный, а запрос

    Select * from dn
    Where
    ((select val from READ_DSI(dn.doc,dn.num,99692)) between 0 and 60)

    сообщает:

    Unsuccessful execution caused by an unavailable resource.
    Unsupported field type specified in BETWEEN predicate.

    Вся разница есть или нет "not" перед "between" !!!

    Что бы это могло значить и как с этим бороться? Писать отдельно сравнение на первую границу а топом на вторую как-то топорно выглядит.

    На всякий случай текст READ_DSI:

    CREATE PROCEDURE READ_DSI (
       doc integer,
       num integer,
       atr integer)
    returns (
       val integer)
    as
    begin
     select val from dsi
     where doc=:doc and num=:num and atr=:atr into :val;
     suspend;
    end
  • sniknik © (27.03.10 21:20) [1]
    > Unsuccessful execution caused by an unavailable resource.
    > Unsupported field type specified in BETWEEN predicate.
    вернуло значение не поддерживаемого  типа, null например, или наоборот рекордсет, а можно только одиночное значение.

    > Что бы это могло значить и как с этим бороться?
    не знаю как это в синтаксисе Firebird, но попробуй примерно так

    ....
    begin
     select first 1 val from dsi
     where doc=:doc and num=:num and atr=:atr into :val;
     if val is null
     begin
       set val = -1
     end
     suspend;
    end

  • dik59 (27.03.10 21:55) [2]
    Правильно ли я понял, что BETWEEN не работает со значениями null ?
  • dik59 (27.03.10 22:13) [3]
    Так я сделать не могу, поскольку процедура должна правильно возвращать null, если значения не будет найдено.
    Гипотеза о том, что between не работает с null не подтвердилась проверкой.
  • dik59 (27.03.10 22:44) [4]
    Кроме того, в DSI на DOC,NUM,ATR стоит Primary_Key, так что "first 1" тут лишний
  • dik59 (27.03.10 23:23) [5]
    Поднял все записи запросом

    Select
    (select val from READ_DSI(dn.doc,dn.num,99692)) "val"
    ,dn.*
    from dn
    Where
    ((select val from READ_DSI(dn.doc,dn.num,99692)) >= 0) and
    ((select val from READ_DSI(dn.doc,dn.num,99692)) <= 60)



    который является полным логическим аналогом неработающего запроса (см.первый пост) и убедился, что все
    VAL

    имеют значение не
    null

  • sniknik © (27.03.10 23:32) [6]
    > Правильно ли я понял, что BETWEEN не работает со значениями null ?
    кто ж его знает как там у вас в Firebird-е (в mssql работает), но ошибка именно о не поддерживаемом типе, а что еще может возвращать твоя процедура неверного?

    > Гипотеза о том, что between не работает с null не подтвердилась проверкой.
    явно заданное null (выражение с которым на этапе компиляции вычисляется) проверял или возвращаемое процедурой?

    > Кроме того, в DSI на DOC,NUM,ATR стоит Primary_Key, так что "first 1" тут лишний
    позновато про Primary_Key, это надо было в первом посте, тогда в ответе было бы только одно действие...

    а вообще довольно глупая реализация с процедурой в одно действие... легко обойтись без нее простым запросом на объединение.
  • sniknik © (27.03.10 23:36) [7]
    > который является полным логическим аналогом неработающего запроса (см.первый пост) и убедился, что все VAL имеют значение не null
    для проверки нужен не аналог, а те значения которые у тебя в нем отсеиваются условием.
    т.е. убери условие вообще, есть хоть один null?
  • sniknik © (28.03.10 00:02) [8]
    > легко обойтись без нее простым запросом на объединение.
    SELECT dn.* FROM dn
    INNER JOIN dsi ON dn.doc=dsi.doc AND dn.num=dsi.num
    WHERE dsi.atr=99692 AND dsi.val between 0 and 60


    делов то. и работать это будет быстрее чем с процедурой.
  • dik59 (28.03.10 12:56) [9]
    Запрос
    Select dn.* from dn
    Where dn.doc=350
     and exists (select val from READ_DSI(dn.doc,dn.num,353))



    выдал 16 записей. Во всех записях
    val <> null

    . Значения val в пределах от 1 до 23.

    Запрос
    Select dn.* from dn
    Where dn.doc=350
     and not exists (select val from READ_DSI(dn.doc,dn.num,353))



    не выдал ни одной записи.
    Т.е. данные корректны.

    Запрос
    Select dn.* from dn
    Where dn.doc=350
     and ((select val from READ_DSI(dn.doc,dn.num,353)) between 0 and 60)
    опять выдал глюк
    Unsuccessful execution caused by an unavailable resource.
    Unsupported field type specified in BETWEEN predicate


    а запрос
    Select dn.* from dn
    Where dn.doc=350
     and ((select val from READ_DSI(dn.doc,dn.num,353)) not between 0 and 60)


    проработал нормально, выдав пустую таблицу. Запрос
    Select dn.* from dn
    Where dn.doc=350
     and ((select val from READ_DSI(dn.doc,dn.num,353)) not between 0 and 2)


    проработал нормально, выдав таблицу из 10 записей.
    Если же заменить  
    between

    на условие по двум границам, все запросы проходят на ура и работают правильно.

    Таким образом, похоже, что это глюк FireBird, связанный с неправильной работой оператора  
    between



    Что касается очевидного упрощения кода, то тут не все так просто, поскольку это лишь кусочек большого проекта, в котором запросы динамически формируются, типы поднимаемых полей заранее не известны и призодится писать группу процедур с похожими именами для поднятия данных разных типов (в том числе и нестандартных) из разных таблиц с помощью специального конструктора запроса.
  • Виталий Панасенко(дом) (28.03.10 13:40) [10]
  • Виталий Панасенко(дом) (28.03.10 13:48) [11]
    Оттуда же
    View that uses select expressions from selectable stored procedure fails to execute with error:
    Unsuccessful execution caused by an unavailable resource.
    Unsupported field type specified in BETWEEN predicate.

    for select from view that uses BETWEEN predicate applied to select expression. See attached script for reproducible test case.
    It executes correctly when equivalent construct X >= val1 and X <= val2 is used.
  • sniknik © (28.03.10 13:57) [12]
    > Т.е. данные корректны.
    проверять нужно не итоговые данные, а те которые были в условии до получения этих корректных данных.
    непонятно?
    сравниваем "0" = 0 → неверный тип, 0 = 1 → правильное условие но не подходящее. тебе говорят что у тебя в условиях бывают с неверным типом, а ты проверив другим способом говоришь, вот у меня же значения 0 и оно корректно!
    и кучу примеров одного и того же условия разными способами приводишь, а просили тебя проверить вообще без условий....

    > т.е. убери условие вообще, есть хоть один null?
    вот этот запрос, без условий
    Select (select val from READ_DSI(dn.doc,dn.num,99692)) "val"
    from dn

  • sniknik © (28.03.10 14:00) [13]
    Виталий Панасенко(дом)   (28.03.10 13:48) [11]
    > It executes correctly when equivalent construct X >= val1 and X <= val2 is used.
    тогда ему придется вызывать процедуру 2 раза...

    тогда уж лучше проверить работоспособность такого
    Where not ((select val from READ_DSI(dn.doc,dn.num,99692)) not between 0 and 60)

  • sniknik © (28.03.10 14:04) [14]
    > а просили тебя проверить вообще без условий....
    чтобы получить все значения которые попадут на вход тому условию которое не справляется, и посмотреть есть ли среди них не валидные.
  • dik59 (28.03.10 15:44) [15]
    [13] тогда уж лучше проверить работоспособность такого
    Where not ((select val from READ_DSI(dn.doc,dn.num,99692)) not between 0 and 60)

    Пробовал, тот же глюк. Двойное отрицание, по-видимому, оптимизируется до отсутствия отрицаний.

     [14] а просили тебя проверить вообще без условий....
    чтобы получить все значения которые попадут на вход тому условию
    которое не справляется, и посмотреть есть ли среди них не валидные
    .

    запрос
    Select (select val from READ_DSI(dn.doc,dn.num,99692)) "val"
    from dn


    вернул 15802 пустых записей и 16 записей с правильными данными. Получается, что для
    between

    значение
    null

    недопустимо, а для
    not between

    допустимо. Что странно, но представимо.

    Однако сделал еще следующие проверки.
    Запрос
    Select
     (select val from READ_DSI(dn.doc,dn.num,353)) "val"
     ,dn.* from dn
    Where dn.doc=350


    вернул 16 записей, все значения
    val

    не
    null

    из перечня (0,1,3)
    Запрос
    Select
    (select val from READ_DSI(dn.doc,dn.num,353)) "val"
    ,dn.* from dn
    Where dn.doc=350
    and ((select val from READ_DSI(dn.doc,dn.num,353)) between 0 and 1)


    породил уже упомянутый глюк!
    Так что либо гипотеза о недопуастимости
    null

    должна быть отвергнута, либо среда FireBird второе условие исполняет раньше первого, что странно, поскольку на
    doc

    в
    dn

    имеется индекс.
  • sniknik © (28.03.10 16:08) [16]
    > породил уже упомянутый глюк!
    естественно, т.к. при and, проверяются все условия, должно совпадать и то и то. а если or, то достаточно первого при true и все одно "свалится" при false.
    > Так что либо гипотеза о недопуастимости null должна быть отвергнута
    остается в силе...
    вот так "сработает"
    ...
    Where dn.doc<>350
    and ((select val from READ_DSI(dn.doc,dn.num,353)) between 0 and 1)


    т.к. тут первое будет false и дальнейшая проверка необязательна при "неправильных" вторых значеняих, и true и обязательна при "правильных".

    p.s.
    единственное показательное было бы проверить изменив процедуру так как показано в [1]. но ты как то странно обходишь все правильные проверки, и делаешь выводы по ничего не значащим тестам (проверяющим "рядом").
  • sniknik © (28.03.10 16:17) [17]
    > вот так "сработает"
    хотя, может и не сработать. порядок выполнения условий определяется, насколько помню, самим сервером.
  • dik59 (28.03.10 16:28) [18]
    [16] p.s.
    единственное показательное было бы проверить изменив процедуру так как показано в [1]


    В
    dsi

    могут быть любые численные значения, в том числе и -1, поэтому и нельзя переделывать процедуру.

    Всем спасибо, помогли.
  • sniknik © (28.03.10 16:37) [19]
    > поэтому и нельзя переделывать процедуру.
    значит нельзя проверить... странно.
  • sniknik © (28.03.10 16:38) [20]
    а другую написать, и проверить с ней тоже нельзя? еще более странно.
  • dik59 (28.03.10 17:20) [21]
    [20] а другую написать, и проверить с ней тоже нельзя? еще более странно.

    Проверил, написал. Результат обхохочешься:
    ваш запрос
    Select (select val from READ_DSI(dn.doc,dn.num,99692)) "val"
    from dn


    вернул вернул 15802 записей со значением val = -1 и 16 записей с правильными данными.

    а запрос
    Select * from dn
    Where
    ((select val from READ_DSI(dn.doc,dn.num,99692)) between 0 and 60)


    ОПЯТЬ выдал тот же глюк, что и раньше (хотя "невалидного" null не получал).
    Отсюда вывод: все-таки глючит FireBird. Кроме того, в стандарте и реализациях SQL (по Кевину Клайну) вроде бы нет упоминания о невалидности значения
    null

     для between, там только говорится, что если хотя бы одна из границ
    null

    , то результат сравнения будет
    null

    , что, вообще говоря, не должно мешать исполнению запроса, как не мешает исполнению запроса значение
    null

    в простом сравнении (например
    val > 2

    )

    Еще раз всем спасибо.
  • Виталий Панасенко(дом) (28.03.10 17:52) [22]

    > Виталий Панасенко(дом)   (28.03.10 13:48) [11]
    >
    > Оттуда же
    > View that uses select expressions from selectable stored
    > procedure fails to execute with error:
    > Unsuccessful execution caused by an unavailable resource.
    >
    > Unsupported field type specified in BETWEEN predicate.
    >
    > for select from view that uses BETWEEN predicate applied
    > to select expression. See attached script for reproducible
    > test case.
    > It executes correctly when equivalent construct X >= val1
    > and X <= val2 is used.
    >

    Это известный баг оптимизатора.. см.
    > Виталий Панасенко(дом)   (28.03.10 13:40) [10]
    >
    > http://tracker.firebirdsql.org/browse/CORE-1095
  • dik59 (28.03.10 18:26) [23]
    [22] Это известный баг

    Да, спасибо, я понял. Жаль только что разработчикам FireBird этот баг неизвестен.
    Сейчас пытался выйти на форум их сайта, но понял, что без бутылки это не судьба. Слишком умные (для меня).
  • dik59 (28.03.10 18:36) [24]
    P.S. может быть кто-то сможет отправить им эту страничку для ознакомления?
  • Виталий Панасенко(дом) (28.03.10 19:43) [25]

    > dik59   (28.03.10 18:26) [23]
    >
    > [22] Это известный баг
    >
    > Да, спасибо, я понял. Жаль только что разработчикам FireBird
    > этот баг неизвестен.

    Баг известен, я ж на треккер ошибок FireBird ссылку дал
    > http://tracker.firebirdsql.org/browse/CORE-1095

    .. Но не исправлен, это другое дело...
 
Конференция "Базы" » Очередные загадки Firebird 2
Есть новые Нет новых   [134433   +22][b:0][p:0.003]