столбец = символ (1), а также = символ (0) - PullRequest
2 голосов
/ 23 мая 2019

У нас есть таблица, включающая столбец foo.

show create table показывает `foo` bit(1) DEFAULT b'0', поэтому столбец должен содержать двоичные строки : байты 0 и 1.

select ascii(foo),
ord(foo),
foo=char(1),
foo=char(0),
char(1)=char(0)
from table_name
group by 1,2,3,4,5

1011 * выходы *

ascii(foo)   ord(foo)   foo=char(1)   foo=char(0)   char(1)=char(0)
         0          0             1             1                 0
         1          1             0             0                 0

Я ожидаю, что это даст

ascii(foo)   ord(foo)   foo=char(1)   foo=char(0)   char(1)=char(0)
         0          0             0             1                 0
         1          1             1             0                 0

Может кто-нибудь объяснить, что происходит?


Также это не ограничено пунктом select. Это также происходит в предложении where: select distinct ascii(foo) from table_name where foo=char(0) и select distinct ascii(foo) from table_name where foo=char(1) оба возвращают только 0.


select @@version
5.7.21-20-57-log

1 Ответ

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

Вы жертва неявного преобразования типов

MySQL рассматривает значения из столбца битового поля как integer и выполняет неявное приведение типа к CHAR(1) для сравнения. Вот что на самом деле делает MySQL, шаг за шагом:

SELECT `foo` = CHAR(1)             -- Need to cast incompatible data types
SELECT 0 = CHAR(1)                 -- Bitfield is treated as integer
SELECT 0 = CAST(CHAR(1) AS INT)    -- char 0x01 gets cast to integer
SELECT 0 = 0                       -- result: 1 (boolean TRUE for MySQL)

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

SELECT `foo` = CHAR(49)            -- Need to cast incompatible data types
SELECT 0 = CHAR(49)                -- Bitfield is treated as integer
SELECT 0 = CAST(CHAR(49) AS INT)   -- char 0x31 gets cast to integer
SELECT 0 = CAST("1" AS INT)        -- but: char 0x31 equals "1"
SELECT 0 = 1                       -- result: 0 (boolean FALSE for MySQL)

Почему это происходит? Числовой тип - это единственный тип, который можно сравнивать как с битовым полем, так и с (двоичной) строкой с помощью оператора равенства. Таким образом, столбец битового поля получает приведение к integer:

В числовом контексте MySQL рассматривает битовый литерал как целое число.

Также персонажу необходимо привести к integer, следуя этим правилам . Удивительно, но для того, чтобы привести двоичный символ в целое число, MySQL, по-видимому, сначала преобразовал его в обычный символ, например:

SELECT CAST(CAST(CHAR(49) AS CHAR) AS INT)   -- result 1

MySQL должен дважды выполнять неявные типы типов, потому что:

SELECT CHAR(49)                              -- result 0x31

Здесь функция CHAR возвращает двоичный символ без какой-либо кодировки, однако приведение к integer может произойти, только если символ можно интерпретировать с использованием кодировки. Вероятно, результат, полученный с CHAR(49), искажен настройкой кодирования моего соединения с MySQL.

...