Unable to create or change a table without a primary key - Laravel DigitalOcean Managed Database
Asked Answered
R

14

44

I've just deployed my app to DigitalOcean using (Managed Database) and I'm getting the following error when calling php artisan migrate

SQLSTATE[HY000]: General error: 3750 Unable to create or change a 
table without a primary key, when the system variable 'sql_require_primary_key'
is set. Add a primary key to the table or unset this variable to avoid
this message. Note that tables without a primary key can cause performance
problems in row-based replication, so please consult your DBA before changing
this setting. (SQL: create table `sessions` (`id` varchar(255) not null,
`user_id` bigint unsigned null, `ip_address` varchar(45) null,
`user_agent` text null, `payload` text not null, `last_activity` int not null)
default character set utf8mb4 collate 'utf8mb4_unicode_ci')

It appears that Laravel Migrations doesn't work when mysql var sql_require_primary_key is set to true.

Do you have any solutions for that?

Ruddock answered 16/6, 2020 at 21:47 Comment(0)
F
6

According to the MySQL documentation purpose of this system variable is

to avoid replication performance issues: "Enabling this variable helps avoid performance problems in row-based replication that can occur when tables have no primary key."

IMHO, there are two possible options to consider for your problem;

  • Add primary key to this and every table in your migration, including temporary tables. This one is better and i think more convenient way to do it since there is no drawback to have primary key for each table.

Whether statements that create new tables or alter the structure of existing tables enforce the requirement that tables have a primary key.

  • Change your provider because according to here "We support only MySQL v8."

Also here is the bug report

Francesco answered 16/6, 2020 at 22:22 Comment(0)
P
93

From March 2022, you can now configure your MYSQL and other database by making a request to digital ocean APIs. Here's the reference: https://docs.digitalocean.com/products/databases/mysql/#4-march-2022

STEPS TO FIX THE ISSUE:

Step - 1: Create AUTH token to access digital ocean APIs. https://cloud.digitalocean.com/account/api/tokens

STEP - 2: Get the database cluster id by hitting the GET request to the below URL with bearer token that you have just generated above.

URL: https://api.digitalocean.com/v2/databases

Step - 3: Hit the below URL with PATCH request along with the bearer token and payload.

URL: https://api.digitalocean.com/v2/databases/{YOUR_DATABASE_CLUSER_ID}/config

payload: {"config": { "sql_require_primary_key": false }}

That's all. It worked flawlessly.

For more information, please refer to API DOCS: https://docs.digitalocean.com/products/databases/mysql/#latest-updates

Preset answered 30/5, 2022 at 17:23 Comment(10)
Worked for me! Use this online post req maker reqbin.com if you dont have postman installedNonexistence
I aways get: Method not allowedExemplar
Which tool are you using to send the request to the API? Which request method are you using? @ExemplarPreset
It needs PATCH method not PUT, maybe they changed itLowell
@hamza ajaz personally am using my terminal and sending the requests as curl but I believe you can use tools like postman or insomnia to send those request easilyRiven
You're a life savior, I've been struggling with this since this morning. Done it with thunderclient extension in Visual Studio Code and worked flawlesslyPeccable
when sending the patch request via postman, it's easiest if you send in the body/payload via "raw" option. thks @hamzaajaz, saved hours ;) !Sawyere
Was trying to run the migrations to setup Pterodactyl and was running into this exact issue. Your solution still works in 2023!Facer
In my opinion this is a work-around, not a fix. The sql_require_primary_key config is used by DO for a (performance) reason, so if possible somehow I think it's better to work with it instead of against it.Dialectical
doctl databases config update <db-id> -e mysql --config-json '{ "sql_require_primary_key": false }' worked for mePanic
D
41

I was trying to fix this problem with an import to DO Managed MySQL using a mysqldump file from a WordPress installation. I found adding this to the top of the file did work for my import.

SET @ORIG_SQL_REQUIRE_PRIMARY_KEY = @@SQL_REQUIRE_PRIMARY_KEY;
SET SQL_REQUIRE_PRIMARY_KEY = 0;

I then imported using JetBrains DataGrip and it worked without error.

Dishtowel answered 7/4, 2021 at 18:46 Comment(4)
Why not just add a primary key to the tables that were missing them before importing them?Depreciatory
Note that according to DigitalOcean "MySQL databases containing tables without a primary key and which contain more than 5000 rows may experience replication issues."Overrule
If you're seeing this in 2022 or later, this answer is what you're looking for as it doesn't require a manipulation of your mysqldump file.Beira
I would still prefer this solution over selected answer. @Depreciatory sometimes, it may not be required. Some men just want to watch the world burn.Bik
T
21

Add in your first migration:

\Illuminate\Support\Facades\DB::statement('SET SESSION sql_require_primary_key=0');

Inside: Schema::create() function.

Tulley answered 24/6, 2021 at 14:32 Comment(3)
This solves the issue for session specific cases.Lacerated
You mentioned inside Schema::create(), however that function requires two arguments. I think you meant to put this line before Schema::Create() yeah?Chauvinism
Yes lsimonetti you're right.Tulley
T
17

Just add set sql_require_primary_key = off Like this

Click to view image

to your SQL file.

Tieratierce answered 12/8, 2020 at 4:51 Comment(3)
set sql_require_primary_key =off;Oshiro
This sis not allowed in DigitalOcean ManagedDatabases.Inquiline
Just FYI, you can set sql_require_primary_key off (set it to 0) on Digital Ocean managed databases. The default will always be on, but you can reset it for any session. Including a primary key on your table will always be easiest, otherwise the raw SQL to set this variable can be added to your laravel migration scripts for the tables that need it.Disenthrone
V
12

One neat solution is defined here. The solution is to add listeners to migrate scripts and turn sql_require_primary_key on and off before and after executing a migration. This solution solve the problem where one is unable modify migrations script such as when they are from a library or a framework like Voyager.

<?php

namespace App\Providers;

    use Illuminate\Database\Events\MigrationsStarted;
    use Illuminate\Database\Events\MigrationsEnded;
    use Illuminate\Support\Facades\DB;
    use Illuminate\Support\Facades\Event;
    use Illuminate\Support\ServiceProvider;
    
    class AppServiceProvider extends ServiceProvider {
        /**
         * Register any application services.
         *
         * @return void
         */
        public function register() {
    
            // check this one here https://github.com/laravel/framework/issues/33238#issuecomment-897063577
            Event::listen(MigrationsStarted::class, function (){
                if (config('databases.allow_disabled_pk')) {
                    DB::statement('SET SESSION sql_require_primary_key=0');
                }
            });
    
            Event::listen(MigrationsEnded::class, function (){
                if (config('databases.allow_disabled_pk')) {
                    DB::statement('SET SESSION sql_require_primary_key=1');
                }
            });
        } 
// rest of the class 

}
Vasyuta answered 18/8, 2021 at 12:37 Comment(2)
worked like magic for meRiven
This works on Laravel 10 and DigitalOceanToddle
A
7

For bigger sql file, can with this command (nano editor can open in 1 week if your file size is <8GB, lol):

First :

sed  -i '1i SET SQL_REQUIRE_PRIMARY_KEY = 0;' db.sql

Second :

sed  -i '1i SET @ORIG_SQL_REQUIRE_PRIMARY_KEY = @@SQL_REQUIRE_PRIMARY_KEY;' db.sql
Aweless answered 19/10, 2021 at 13:48 Comment(0)
F
6

According to the MySQL documentation purpose of this system variable is

to avoid replication performance issues: "Enabling this variable helps avoid performance problems in row-based replication that can occur when tables have no primary key."

IMHO, there are two possible options to consider for your problem;

  • Add primary key to this and every table in your migration, including temporary tables. This one is better and i think more convenient way to do it since there is no drawback to have primary key for each table.

Whether statements that create new tables or alter the structure of existing tables enforce the requirement that tables have a primary key.

  • Change your provider because according to here "We support only MySQL v8."

Also here is the bug report

Francesco answered 16/6, 2020 at 22:22 Comment(0)
M
5

I contacted DigitalOcean via a ticket to ask if they want to disable the requirement and they did the next day :)

So you can just ask them

Thanks for getting in touch with us! I understand you will like to disable the primary requirement on your managed database. The primary requirement for your managed database ****** has been disabled

Monjo answered 11/8, 2021 at 14:21 Comment(1)
Yes but note that "MySQL databases containing tables without a primary key and which contain more than 5000 rows may experience replication issues."Overrule
J
3

Unfortunately, we can't change the sql_require_primary_key value in the digital ocean MySQL database. instead, you can set the id to the primary key just by adding primary()

Jefferyjeffie answered 11/2, 2021 at 1:57 Comment(1)
i added it to the sql file on digitalocean and it workedGynaecocracy
M
2

When enabled, sql_require_primary_key has these effects:

  1. Attempts to create a new table with no primary key fail with an error. This includes CREATE TABLE ... LIKE. It also includes CREATE TABLE ... SELECT, unless the CREATE TABLE part includes a primary key definition.
  2. Attempts to drop the primary key from an existing table fail with an error, with the exception that dropping the primary key and adding a primary key in the same ALTER TABLE statement is permitted.

Dropping the primary key fails even if the table also contains a UNIQUE NOT NULL index.

  1. Attempts to import a table with no primary key fail with an error.

Default value is OFF , but in your case you need to set OFF from ON

IMPORTANT LINK

HOW TO SET

Melissiamelita answered 16/6, 2020 at 22:17 Comment(1)
@Michal did you find this answer helpful,then please mark as answer or give a upvoteMelissiamelita
V
2

If you're importing in some SQL client, just run this query on that particular database before importing.

set sql_require_primary_key = off

Works all good for DO managed Mysql Database. Cheers!

Vertebral answered 10/12, 2022 at 1:5 Comment(0)
P
1

I found the solution at https://www.digitalocean.com/community/questions/mysql-managed-database-can-t-modify-database-without-setting-primary-key-but-i-can-t-set-primary-key-without-modifying-the-database. I added SET SESSION sql_require_primary_key = 0; to the beginning of my .sql file that I used to import the database, as shown in the screenshot below:

enter image description here

Patella answered 11/10, 2023 at 0:37 Comment(0)
I
-1

If you see this error while using laravel, it's most likely from the password_resets_table

Update the up() method in your migration to below:

  public function up()
  {
    DB::statement('SET SESSION sql_require_primary_key=0');
    Schema::create('password_resets', function (Blueprint $table) {
      ....
    });
    DB::statement('SET SESSION sql_require_primary_key=1');
  }

Note: Remember to import DB

use Illuminate\Support\Facades\DB;

Illusionist answered 2/3, 2023 at 23:6 Comment(0)
B
-3

add this line to your migration file. $table->increments('aid');

Bisulcate answered 17/11, 2020 at 22:1 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.