Skip to content

NestedPdoTransactionWithoutSavepoint ​

warning native on by default

Group: Probable bugs

PDO does not start nested transactions by calling beginTransaction again. Finish the current transaction or use an appropriate savepoint abstraction.

Example ​

php
<?php
$pdo=new PDO("sqlite::memory:");$pdo->beginTransaction();$pdo->beginTransaction();

Reported:

  • line 2: Finish the transaction before beginning another one.

Detection ​

  • Same proven PDO receiver calls beginTransaction twice in straight-line scope with no commit/rollBack between. Highlight second call. Unknown intervening calls discard proof. The second call must be the first thing its statement evaluates, unconditionally: the expression of an expression statement, a returned value or an if condition, possibly under parentheses, unary operators (!, @), a plain = assignment to a variable ($ok = $pdo->beginTransaction();), or as the left operand of a binary operator or the condition of a ternary.
  • Resolve builtin functions, classes, constants and methods; user-defined lookalikes are excluded. Follow only bounded local proof in one lexical scope.
  • Emit one finding per violating operation, not per supporting evidence statement. When the proof is inconclusive, nothing is reported.

Exceptions (no report) ​

  • Do not report unresolved or shadowed builtin names, unknown values, or incomplete receiver/type provenance. Unknown calls, aliases escaping, and intervening writes invalidate local proof. Similar code outside the stated detection contract is not a finding.
  • Do not report a second call that sits deeper inside its statement: as the right operand of &&, ||, ?? or any other binary operator, in a ternary branch, as a call argument, under ??=, in an elseif or loop condition, or in a closure or arrow-function body. Operands evaluated earlier in that statement may commit or roll back first ($pdo->rollBack() && $pdo->beginTransaction()), or short-circuit the call away ($pdo->inTransaction() || $pdo->beginTransaction()).
  • Both standard suppression forms suppress this native ID.

Fix ​

None. Choosing a repair requires intent or additional runtime information.

PHP versions ​

Available throughout supported PHP 5.3–8.5 where the referenced builtin/extension is available. Respect syntax/version-specific receiver contracts; unavailable APIs are not this rule’s concern.

Configure ​

In custos.json:

json
{
  "rules": {
    "NestedPdoTransactionWithoutSavepoint": {
      "enabled": false
    }
  }
}

Suppress ​

Before the statement or declaration (or the first statement of the file):

php
// @custos-ignore NestedPdoTransactionWithoutSavepoint

Released under the MIT License. Native rules and rules modeled on Php Inspections (EA Extended); independent clean-room implementation.