Skip to content

Commit c99dca7

Browse files
committed
Document workarounds for 1071 Specified key was too long; max key length is 1000 (or 767) bytes
Fixes spatie#2563 Ref spatie#1689
1 parent 84f3138 commit c99dca7

File tree

2 files changed

+23
-9
lines changed

2 files changed

+23
-9
lines changed

database/migrations/create_permission_tables.php.stub

+6-4
Original file line numberDiff line numberDiff line change
@@ -25,22 +25,24 @@ return new class extends Migration
2525
}
2626

2727
Schema::create($tableNames['permissions'], function (Blueprint $table) {
28+
//$table->engine('InnoDB');
2829
$table->bigIncrements('id'); // permission id
29-
$table->string('name'); // For MySQL 8.0 use string('name', 125);
30-
$table->string('guard_name'); // For MySQL 8.0 use string('guard_name', 125);
30+
$table->string('name'); // For MyISAM use string('name', 225); // (or 166 for InnoDB with Redundant/Compact row format)
31+
$table->string('guard_name'); // For MyISAM use string('guard_name', 25);
3132
$table->timestamps();
3233

3334
$table->unique(['name', 'guard_name']);
3435
});
3536

3637
Schema::create($tableNames['roles'], function (Blueprint $table) use ($teams, $columnNames) {
38+
//$table->engine('InnoDB');
3739
$table->bigIncrements('id'); // role id
3840
if ($teams || config('permission.testing')) { // permission.testing is a fix for sqlite testing
3941
$table->unsignedBigInteger($columnNames['team_foreign_key'])->nullable();
4042
$table->index($columnNames['team_foreign_key'], 'roles_team_foreign_key_index');
4143
}
42-
$table->string('name'); // For MySQL 8.0 use string('name', 125);
43-
$table->string('guard_name'); // For MySQL 8.0 use string('guard_name', 125);
44+
$table->string('name'); // For MyISAM use string('name', 225); // (or 166 for InnoDB with Redundant/Compact row format)
45+
$table->string('guard_name'); // For MyISAM use string('guard_name', 25);
4446
$table->timestamps();
4547
if ($teams || config('permission.testing')) {
4648
$table->unique([$columnNames['team_foreign_key'], 'name', 'guard_name']);

docs/prerequisites.md

+17-5
Original file line numberDiff line numberDiff line change
@@ -43,14 +43,26 @@ This package publishes a `config/permission.php` file. If you already have a fil
4343

4444
## Schema Limitation in MySQL
4545

46-
MySQL 8.0 limits index keys to 1000 characters. This package publishes a migration which combines multiple columns in single index. With `utf8mb4` the 4-bytes-per-character requirement of `mb4` means the max length of the columns in the hybrid index can only be `125` characters.
46+
Potential error message: "1071 Specified key was too long; max key length is 1000 bytes"
4747

48-
Thus in your AppServiceProvider you will need to set `Schema::defaultStringLength(125)`. [See the Laravel Docs for instructions](https://laravel.com/docs/migrations#index-lengths-mysql-mariadb).
48+
MySQL 8.0 limits index key lengths, which might be too short for some compound indexes used by this package.
49+
This package publishes a migration which combines multiple columns in a single index. With `utf8mb4` the 4-bytes-per-character requirement of `mb4` means the total length of the columns in the hybrid index can only be `25%` of that maximum index length.
4950

50-
You may be able to bypass setting `defaultStringLength(125)` by editing the migration and specifying the `125` in 4 fields. There are 2 instances of this code snippet where you can explicitly set the `125`:
51+
- MyISAM tables limit the index to 1000 characters (which is only 250 total chars in `utf8mb4`)
52+
- InnoDB tables using ROW_FORMAT of 'Redundant' or 'Compact' limit the index to 767 characters (which is only 191 total chars in `utf8mb4`)
53+
- InnoDB tables using ROW_FORMAT of 'Dynamic' or 'Compressed' have a 3072 character limit (which is 768 total chars in `utf8mb4`).
54+
55+
Depending on your MySQL or MariaDB configuration, you may implement one of the following approaches:
56+
57+
1. Ideally, configure the database to use InnoDB by default, and use ROW FORMAT of 'Dynamic' by default for all new tables. (See [MySQL](https://dev.mysql.com/doc/refman/8.0/en/innodb-limits.html) and [MariaDB](https://mariadb.com/kb/en/innodb-dynamic-row-format/) docs.)
58+
59+
2. OR if your app doesn't require a longer default, in your AppServiceProvider you can set `Schema::defaultStringLength(125)`. [See the Laravel Docs for instructions](https://laravel.com/docs/migrations#index-lengths-mysql-mariadb). This will have Laravel set all strings to 125 characters by default.
60+
61+
3. OR you could edit the migration and specify a shorter length for 4 fields. Then in your app be sure to manually impose validation limits on any form fields related to these fields.
62+
There are 2 instances of this code snippet where you can explicitly set the length.:
5163
```php
52-
$table->string('name'); // For MySQL 8.0 use string('name', 125);
53-
$table->string('guard_name'); // For MySQL 8.0 use string('guard_name', 125);
64+
$table->string('name'); // For MyISAM use string('name', 225); // (or 166 for InnoDB with Redundant/Compact row format)
65+
$table->string('guard_name'); // For MyISAM use string('guard_name', 25);
5466
```
5567

5668
## Note for apps using UUIDs/ULIDs/GUIDs

0 commit comments

Comments
 (0)