Skip to main content

MY.L3.ALGORITHM_LOCK_UNEXPRESSIBLE — An operation MySQL will not run online, written the one way that cannot say so

  • Category: safety
  • Level: 3
  • Confidence: deterministic
  • Downtime class: none — this finding is about a missing clause, not about a cost
  • Stability: stable
  • Suites: lint
  • Applies to: MySQL 8.4
  • Not transferable to MariaDB: this page describes MySQL 8.4 behavior. MariaDB answers the same driver and does not share these semantics, so SQLens refuses it outright rather than reasoning about it — see drivers/unsupported.

Laravel's MySQL grammar has no way to emit ALGORITHM= or LOCK=. That was verified against the installed framework rather than assumed, and it is pinned by a characterization test so a future Laravel that gains the ability breaks the test instead of leaving this rule quietly wrong.

Those two clauses are exactly what would keep an InnoDB migration provably online. Without them, a migration written through the schema builder takes whatever algorithm the server picks — and you find out which one that was afterwards.

What an explicit ALGORITHM actually buys

It does not make a copying operation online. It makes the server refuse.

ALGORITHM=INPLACE on an operation MySQL can only perform by copying fails with an error instead of silently copying the table. The deploy therefore stops before it locks anything, rather than in the middle of it — and that is the whole value. A reader who believes the clause makes the operation cheap has been made more confident and no safer, which is why the finding says this in plain words.

Flagged

Schema::table('orders', fn (Blueprint $table) => $table->primary('id'));

Preferred

// Raw SQL on purpose: Laravel's MySQL grammar cannot emit ALGORITHM/LOCK, and naming them
// makes the server refuse rather than silently copy the table if it cannot do this in place.
DB::statement('ALTER TABLE orders ADD PRIMARY KEY (id), ALGORITHM=INPLACE, LOCK=NONE');

The comment is part of the fix, not decoration. Raw SQL in a migration is a deliberate exception here, and the next reader has to be able to tell a considered exception from a shortcut.

When this rule fires, and when it says nothing

The trigger comes from the online-DDL matrix, never from a list written into the rule: the operation's downtime class comes back as something other than online, and the statement carries neither clause. A matrix revision therefore moves the rule with it, and the rule cannot disagree with the rules that report those same operations.

It says nothing in three cases, and only one of them is about safety:

  • the statement already names an algorithm or a lock level — the work is done;
  • the operation is one MySQL runs online anyway — there is nothing to suggest, and a hint on every ordinary index build is how a rule gets switched off;
  • the matrix could not settle the class, because it does not classify the operation or because its entry depends on a table fact no static reader can see.

That last silence means "no suggestion", not "safe". The safety verdict for those statements belongs to the rules that own them, and they report it. This rule only ever offers an improvement it can justify.

Sources

The fix material this rule carries

A finding from this rule carries machine-readable fix material. Which sequence depends on the statement:

  • algorithm_lock_hint — Name the algorithm and lock level the engine would otherwise pick for you.
  • none — Looked at, and there is no safe standard sequence — a statement, not an absence.

The payload is material for you or an agent to apply. SQLens writes no migration and runs no DDL. See the remediation payload for every field, the placeholder semantics, and the version rules a consumer has to follow.