ДОБАВИТЬ СИСТЕМНУЮ ВЕРСИЮ Исключение в миграции Laravel

Я пытаюсь использовать функцию System Versioned Tables в MariaDB. 10.3 в Ларавеле. Однако я получаю следующее исключение всякий раз, когда пытаюсь запустить ремесленную миграцию, которая изменяет таблицу.

C:\htdocs\Computers>php artisan migrate:fresh
Dropped all tables successfully.
Migration table created successfully.

   PDOException  : SQLSTATE[42000]: Syntax error or access violation: 1067 Invalid default value for 'row_start'

  at C:\htdocs\Computers\database\migrations\2018_07_14_191112_add_system_version_to_computers.php:16
    12|      * @return void
    13|      */
    14|     public function up()
    15|     {
  > 16|         DB::connection()->getPdo()->exec("ALTER TABLE `COMPUTERS` ADD SYSTEM VERSIONING;");
    17|     }
    18|
    19|     /**
    20|      * Reverse the migrations.

  Exception trace:

  1   PDO::exec("ALTER TABLE `COMPUTERS` ADD SYSTEM VERSIONING;")
      C:\htdocs\Computers\database\migrations\2018_07_14_191112_add_system_version_to_computers.php:16

  2   AddSystemVersionToComputers::up()
      C:\htdocs\Computers\vendor\laravel\framework\src\Illuminate\Database\Migrations\Migrator.php:359

  Please use the argument -v to see more details.
  1. Я пробовал это на пустой таблице, а также на той, в которой уже есть данные

  2. Я пытался подавить исключения PDO следующим образом, но он действует так, как будто он работает, но система управления версиями не добавляется, когда я проверяю таблицу

    DB::connection()->getPdo()->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT);
    
  3. Я могу добавить системную версию в таблицу, если выполню тот же SQL в HeidiSQL.

  4. Я искал в документации и коде Laravel любые методы, которые позволили бы мне добавить эту опцию таблицы при создании, но ничего не нашел.

Я мог бы вручную обойти это, но я действительно хочу включить это в файлы миграции Laravel, чтобы оно было включено в репозиторий Git.


Результат выполнения команды

SHOW CREATE TABLE `computers`;

...

+-----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table     | Create Table                                                                                                                                                                                                                                                                                                                                                          |
+-----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| computers | CREATE TABLE `computers` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `Name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  `created_at` timestamp NULL DEFAULT NULL,
  `updated_at` timestamp NULL DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `computers_name_unique` (`Name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci |
+-----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.000 sec)

Ниже приведены результаты выполнения того же оператора SQL из командной строки MariaDB. Обратите внимание на добавление WITH SYSTEM VERSIONING в определение таблицы.

MariaDB [computers]> ALTER TABLE COMPUTERS ADD SYSTEM VERSIONING;
Query OK, 0 rows affected (0.025 sec)
Records: 0  Duplicates: 0  Warnings: 0

MariaDB [computers]> SHOW CREATE TABLE `computers`;
+-----------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table     | Create Table                                                                                                                                                                                                                                                                                                                                                                                 |
+-----------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| computers | CREATE TABLE `computers` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `Name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  `created_at` timestamp NULL DEFAULT NULL,
  `updated_at` timestamp NULL DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `computers_name_unique` (`Name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci WITH SYSTEM VERSIONING |
+-----------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.002 sec)

Запустил ту же команду alter table в Artisan Tinker и получил ту же ошибку:

    >>>             DB::connection()->getPdo()->exec("ALTER TABLE `COMPUTERS` ADD SYSTEM VERSIONING;");
PDOException with message 'SQLSTATE[42000]: Syntax error or access violation: 1067 Invalid default value for 'row_start''

Все еще получаю ту же ошибку, если я пытаюсь предоставить все для пользователя computers-lcl.

DROP USER IF EXISTS `computers-lcl`@`localhost`;
FLUSH PRIVILEGES;
GRANT ALL ON *.* TO `computers-lcl`@`localhost` IDENTIFIED BY 'qej8lOjoc81Ekub1d26uzerOv332Qa' WITH GRANT OPTION;

Заранее благодарим за любые рекомендации.


person Eric Medlin    schedule 15.07.2018    source источник
comment
Какая версия PHP?   -  person Rick James    schedule 15.07.2018
comment
Привет Рик! Извините, я забыл отметить это. Конкретно это 7.2.7.   -  person Eric Medlin    schedule 16.07.2018
comment
Недопустимое значение по умолчанию для 'row_start', какое значение по умолчанию для этого?   -  person flakerimi    schedule 16.07.2018
comment
это не связано с laravel, проверьте, можете ли вы сделать это из командной строки, а затем используйте это как laravel raw   -  person flakerimi    schedule 16.07.2018
comment
@flakerimi я никак не могу определить значение по умолчанию, потому что ALTER TABLE COMPUTERS ADD SYSTEM VERSIONING; оператор выдает исключение, и когда я пытаюсь посмотреть, что показывает таблица, ничего не изменилось. Я отредактирую исходный вопрос, включив в него определение таблицы.   -  person Eric Medlin    schedule 17.07.2018
comment
@flakerimi, запускающий оператор SQL из командной строки MariaDB, работает. Я отредактирую исходный вопрос, чтобы включить вывод консоли.   -  person Eric Medlin    schedule 17.07.2018
comment
Кстати, я попытался запустить следующее в tinker и получил такое же сообщение. См. последнее обновление, о котором идет речь.   -  person Eric Medlin    schedule 17.07.2018
comment
@flakerimi наконец-то немного продвинулся в этом вопросе. Когда я выполнил инструкцию ALTER, которая работала из командной строки, я вошел в систему как пользователь root. Laravel использовал пользователя, которому были предоставлены все привилегии для БД компьютеров. Если я создаю процедуру в миграции Laravel и вызываю ее в миграции, она дает ту же ошибку. Если я создаю процедуру от root, а затем вызываю ее из миграции Laravel с тем же пользователем для компьютеров, она работает нормально. Выделенный пользователь для базы данных компьютеров по-прежнему имеет ту же проблему, даже если я даю ему все глобальные привилегии. Кажется, работает только с пользователем root.   -  person Eric Medlin    schedule 19.07.2018
comment
Возможно, вам нужен serverfault.com/a/826374/76964 грант   -  person flakerimi    schedule 19.07.2018
comment
@flakerimi спасибо за предложение, но все еще получаю ту же ошибку. Пожалуйста, смотрите обновление моего вопроса.   -  person Eric Medlin    schedule 20.07.2018


Ответы (1)


TL;DR: проблема вызвана тем, что NO_ZERO_DATE установлен в вашем sql_mode, используемом laravel. Установите 'strict' => false в части 'mysql' => [] в config/database.php


Я сам столкнулся с проблемой, и я совершенно уверен, что мы имеем дело с одной и той же проблемой, и это вызвано тем, что в вашем sql_mode установлен NO_ZERO_DATE.

Поскольку оператор ALTER TABLE отлично работает, когда вы выполняете оператор через CLI-клиент или HeidiSQL (или любой другой графический интерфейс БД, если на то пошло), сравните sql_mode от этого клиента с sql_mode из сеанса вашей базы данных laravel.

Вот мой SQL_MODE, используемый CLI-клиентом:

mysql -u root -p    
MariaDB [(none)]> SELECT @@SQL_MODE;
+-----------------------------------------------------------------------+
| @@SQL_MODE                                                            |
+-----------------------------------------------------------------------+
| ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION |
+-----------------------------------------------------------------------+
1 row in set (0.000 sec)

А вот мой SQL_MODE, используемый laravel:

php artisan tinker
Psy Shell v0.9.9 (PHP 7.3.4-1+ubuntu18.10.1+deb.sury.org+3 — cli) by Justin Hileman
>>> DB::select( DB::raw("SELECT @@SQL_MODE") );
=> [
     {#3102
       +"@@SQL_MODE": "ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION",
     },
   ]

Как видите, laravel использует NO_ZERO_DATE, а мой клиент командной строки — нет. Это связано с режимом strict, который является настройкой по умолчанию в config/database.php для баз данных MySQL. Если 'strict' => true, то при настройке соединения с БД в laravel/framework/src/Illuminate/Database/Connectors/MySqlConnector.php срабатывает следующий код:

    /**
     * Get the query to enable strict mode.
     *
     * @param  \PDO  $connection
     * @return string
     */
    protected function strictMode(PDO $connection)
    {
        if (version_compare($connection->getAttribute(PDO::ATTR_SERVER_VERSION), '8.0.11') >= 0) {
            return "set session sql_mode='ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION'";
        }

        return "set session sql_mode='ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION'";
    }

И есть виновный NO_ZERO_DATE. Установите 'strict' => false в config/database.php, и laravel больше не будет возиться с вашим sql_mode. Если вы хотите удалить только часть NO_ZERO_DATE, сохранив остальную часть строгого режима, одним из решений может быть предоставление ваш собственный MySqlConnector ServiceProvider.

person morten.c    schedule 30.04.2019