Битрикс: архитектурная ошибка SQL

В схеме базы данных битрикса есть неочевидный баг. На первый взгляд, всё выглядит нормально, а по факту - не работает. Дело вот в чём. Есть таблица пользователей - b_user. Вполне логично ожидать от такой таблицы, что поле логина будет уникальным. Чтобы база данных не давала физически сохранить две учётные записи с одинаковым логином. Но в битриксе это не так!

Уникальный составной ключ

Яркий пример проблемы, которую привносит разработчик, выполняя работу архитектора баз данных. SQL-запросом

SHOW CREATE TABLE b_user;

Можно просмотреть схему таблицы, где видно, что есть некий уникальный составной ключ ix_login. На этот ключ возлагались напрасные надежды следить за уникальностью логинов. Вот как выглядит схема этой таблицы (из вывода запроса убрал ненужные в данном обзоре столбцы):

CREATE TABLE `b_user` (
`ID` int(18) NOT NULL AUTO_INCREMENT,
`TIMESTAMP_X` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`LOGIN` varchar(50) COLLATE utf8_unicode_ci NOT NULL,
`PASSWORD` varchar(50) COLLATE utf8_unicode_ci NOT NULL,
`EXTERNAL_AUTH_ID` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
PRIMARY KEY (`ID`),
UNIQUE KEY `ix_login` (`LOGIN`,`EXTERNAL_AUTH_ID`),
KEY `ix_b_user_email` (`EMAIL`),
)

В битриксе реализована регистрация через внешние социальные сервисы. Пользователь из какого-нибудь, ВКонтакте имеет в битрикс логин вида VKuser123456789 и также в столбце EXTERNAL_AUTH_ID находится значение socservices. Обычный пользователь имеет какое-то значение в колонке LOGIN и значение NULL в колонке EXTERNAL_AUTH_ID. Вот этот-то NULL и портит проверку уникальности. Дело в том, что, в MySQL NULL <> NULL. В составном ключе нельзя допускать колонок, где могут встречаться значения NULL. Например, тут обсуждалось. Если бы вместо

`EXTERNAL_AUTH_ID` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,

было

`EXTERNAL_AUTH_ID` varchar(255) COLLATE utf8_unicode_ci DEFAULT "",

то всё было бы хорошо.

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

INSERT INTO `b_user` (`LOGIN`, `PASSWORD`, `ACTIVE`, `DATE_REGISTER`)
VALUES
("test123@texample.com", "123456", "Y", "2020-09-09 20:30:00"),
("test123@texample.com", "123456", "Y", "2020-09-09 20:30:00");

Комментарии

Популярные сообщения из этого блога

Пропорциональное распределение суммы

Битрикс: своя геолокация

Bitrix24 API - разбор демо приложения третьего типа