get_var( 'SELECT @@autocommit' ) && ! self::in_transaction(); $point = 'vizyt_tx_' . self::$depth; if ( false === ( $outer ? $wpdb->query( 'START TRANSACTION' ) : $wpdb->query( "SAVEPOINT {$point}" ) ) ) { // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter -- $point is 'vizyt_tx_' plus the nesting depth (an int), never input. return false; } self::$depth++; try { $result = $fn(); } catch ( \Throwable $e ) { self::$depth--; self::rollback( $outer, $point ); throw $e; } self::$depth--; if ( false === $result ) { self::rollback( $outer, $point ); return false; } if ( false === ( $outer ? $wpdb->query( 'COMMIT' ) : $wpdb->query( "RELEASE SAVEPOINT {$point}" ) ) ) { // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter -- $point is 'vizyt_tx_' plus the nesting depth (an int), never input. self::rollback( $outer, $point ); return false; } return $result; } private static function rollback( bool $outer, string $point ): void { global $wpdb; if ( false === ( $outer ? $wpdb->query( 'ROLLBACK' ) : $wpdb->query( "ROLLBACK TO SAVEPOINT {$point}" ) ) ) { // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter -- $point is 'vizyt_tx_' plus the nesting depth (an int), never input. error_log( 'Vizyt: rollback failed: ' . $wpdb->last_error ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- a failed rollback leaves data half-written; the site owner's log is the only place to report it. } } /** * MariaDB: is a transaction open on this connection? Always false where * the server has no @@in_transaction (MySQL). */ private static function in_transaction(): bool { global $wpdb; if ( false === self::$has_in_transaction ) { return false; } $suppress = $wpdb->suppress_errors( true ); $value = $wpdb->get_var( 'SELECT @@in_transaction' ); $wpdb->suppress_errors( $suppress ); self::$has_in_transaction = null !== $value; return '1' === (string) $value; } }