Skip to content

Potential infinite recursion when executing schema:dump #52436

@FeBe95

Description

@FeBe95

Laravel Version

11.20.0

PHP Version

8.2.12

Database Driver & Version

MariaDB 10.6.16

Description

I noticed that the execution of

php artisan schema:dump

can potentially run into two infinite recursive loop here:

if (Str::contains($e->getMessage(), ['column-statistics', 'column_statistics'])) {
return $this->executeDumpProcess(Process::fromShellCommandLine(
str_replace(' --column-statistics=0', '', $process->getCommandLine())
), $output, $variables);
}
if (str_contains($e->getMessage(), 'set-gtid-purged')) {
return $this->executeDumpProcess(Process::fromShellCommandLine(
str_replace(' --set-gtid-purged=OFF', '', $process->getCommandLine())
), $output, $variables);
}

There's even a comment on StackOverflow, where a user ran into exactly this issue:
https://stackoverflow.com/questions/59410746/getting-mysqldump-error-unknown-variable-column-statistics-0-when-exporting#comment136792230_59442494

I am fine with recursion in general, but there needs to be some kind of fail-safe to catch infinit loops here, e.g. a max retry count. We can't rely on consistent output of mysqldump here.

Steps To Reproduce

TLDR:

  1. Run composer create-project laravel/laravel column-statistics
  2. Setup MySQL/MariaDB database connection
  3. Set DB_USERNAME to a user that does not have the LOCK TABLES permission
  4. Run php artisan schema:dump

Output:

> php artisan schema:dump
mysqldump: unknown variable 'column-statistics=0'
mysqldump: Got error: 1044: "Access denied for user 'test'@'%' to database 'test_database'" when using LOCK TABLES
mysqldump: Got error: 1044: "Access denied for user 'test'@'%' to database 'test_database'" when using LOCK TABLES
mysqldump: Got error: 1044: "Access denied for user 'test'@'%' to database 'test_database'" when using LOCK TABLES
mysqldump: Got error: 1044: "Access denied for user 'test'@'%' to database 'test_database'" when using LOCK TABLES
mysqldump: Got error: 1044: "Access denied for user 'test'@'%' to database 'test_database'" when using LOCK TABLES
# ...

Detailed Explanation:

There are for sure multiple ways of triggering an infinite recursion here, but the simplest way, that I have found, is to have the word column-statistics somewhere in the path of your working directory. Now, if any error is reported by mysqldump, it will result in an infinite loop, since the working directory is part of the error output that is being parsed here:

if (Str::contains($e->getMessage(), ['column-statistics', 'column_statistics'])) {

In my case $e->getMessage() looked like this:

The command "mysqldump  --user="${:LARAVEL_LOAD_USER}" --password="${:LARAVEL_LOAD_PASSWORD}" --host="${:LARAVEL_LOAD_HOST}" --port="${:LARAVEL_LOAD_PORT}" --no-tablespaces --skip-add-locks --skip-comments --skip-set-charset --tz-utc "${:LARAVEL_LOAD_DATABASE}" --routines --result-file="${:LARAVEL_LOAD_PATH}" --no-data" failed.

Exit Code: 2(Misuse of shell builtins)

Working directory: C:\xampp\htdocs\column-statistics

Output:
================


Error Output:
================
mysqldump: Got error: 1044: "Access denied for user 'test'@'%' to database 'test_database'" when using LOCK TABLES

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions