<commit_before><?php

class TipyDaoException extends Exception {}

// ---------------------------------------------------------
// ApplicationDAO
// DB wrapper and base DAO class. Provides interface to
// database base functions
// ---------------------------------------------------------
class TipyDAO {

    protected $dbLink;
    public static $openTransactionsCount = 0;
    public static $queryCount;

    // -----------------------------------------------------
    // Constructor
    // -----------------------------------------------------
    public function __construct() {
        $app = TipyApp::getInstance();
        // If not yet connected then connect.
        if (!$app->db) {
            // Get  connection string
            $config = $app->config;
            $dbHost = $config->get('db_host');
            if ($config->get('db_port')) {
                $dbHost .= $dbHost.':'.$config->get('db_port');
            }
            $dbName = $config->get('db_name');
            $dbUser = $config->get('db_user');
            $dbPassword = $config->get('db_password');

            $dbLink = new mysqli('p:'.$dbHost, $dbUser, $dbPassword, $dbName);
            if ($dbLink->connect_error) {
                throw new TipyDaoException('DB connection error (' . $dbLink->connect_errno . ') '
                    . $dbLink->connect_error);
            } else {
                if ($config->get('db_character_set')) {
                    $dbLink->query("set names '".$config->get('db_character_set')."'");
                }
                $app->db = $dbLink;
            }
        }
        $this->dbLink = $app->db;
    }

    // ----------------------------------------------------
    // query
    // Just db query wrapper with some error handler
    // ----------------------------------------------------
    public function query($sql, $params = null) {
        if ($params) {
            $sql = str_replace('%', '%%', $sql);
            $sql = str_replace('?', '"%s"', $sql);
            $link = $this->dbLink;
            array_walk($params, function (&$string) use ($link) {
                $string = $link->real_escape_string($string);
            });
            array_unshift($params, $sql);
            $query = call_user_func_array('sprintf', $params);
        } else {
            $query = $sql;
        }
        $result = $this->dbLink->query($query);
        self::$queryCount++;
        if (!$result) {
            throw new TipyDaoException($this->dbLink->error);
        } else {
            return $result;
        }
    }

    // ----------------------------------------------------
    // limitQuery
    // ----------------------------------------------------
    public function limitQuery($sql, $span, $step, $params = []) {
        $sql = $sql." limit ".$span.",".$step;
        return $this->query($sql, $params);
    }

    // -----------------------------------------------------
    // numRows
    // -----------------------------------------------------
    public function numRows(&$result) {
        return $result->num_rows;
    }

    // -----------------------------------------------------
    // fetchRow
    // Need this method to do some common operations before
    // returning fetchRow from query result
    // -----------------------------------------------------
    public function fetchRow(&$result) {
        $result->field_seek(0);
        return $result->fetch_array(MYSQLI_ASSOC);
    }

    // -----------------------------------------------------
    // fetchAllRows - return all rows of the DB_result object
    // -----------------------------------------------------
    public function fetchAllRows(&$result) {
        return $result->fetch_all(MYSQLI_ASSOC);
    }

    // ----------------------------------------------------
    // queryRow
    // query & fetch in one flakon
    // ----------------------------------------------------
    public function queryRow($sql, $params = []) {
        $result = $this->query($sql, $params);
        return $this->fetchRow($result);
    }

    // ----------------------------------------------------
    // queryRows
    // query and fetch all rows in one flakon
    // ----------------------------------------------------
    public function queryAllRows($sql, $params = []) {
        $result = $this->query($sql, $params);
        return $this->fetchAllRows($result);
    }

    // ----------------------------------------------------
    // limit query and fetch
    // ----------------------------------------------------
    public function limitQueryAllRows($sql, $span, $step, $params = []) {
        $result = $this->limitQuery($sql, $span, $step, $params);
        if ($result) {
            return $this->fetchAllRows($result);
        } else {
            return null;
        }
    }

    // ----------------------------------------------------
    // last insert id
    // ----------------------------------------------------
    public function lastInsertId() {
        return $this->dbLink->insert_id;
    }

    // ----------------------------------------------------
    // affected rows
    // ----------------------------------------------------
    public function affectedRows() {
        return $this->dbLink->affected_rows;
    }

    public function queryErrno($sql, $params = []) {
        $this->query($sql, $params, true);
        return $this->dbLink->errno;
    }

    protected static function savepointName($number) {
        return 'tipy_savepoint_'.$number;
    }

    // ----------------------------------------------------
    // Start transaction with fallback mechanics
    // ----------------------------------------------------
    public function startTransaction() {
        if (self::$openTransactionsCount == 0) {
            $result = $this->dbLink->query('BEGIN');
        } else {
            $newSavepoint = self::savepointName(self::$openTransactionsCount + 1);
            $result = $this->dbLink->query('SAVEPOINT '.$newSavepoint);
        }
        if ($result) {
            register_shutdown_function([$this, "shutdownCheck"]);
            self::$openTransactionsCount++;
        }
        return $result;
    }

    // ----------------------------------------------------
    // Rollback all opened transaction on fatal errors or
    // script stop
    // ----------------------------------------------------
    public function shutdowncheck() {
        if (self::istransactioninprogress()) {
            $this->rollback('hard');
        }
    }

    // ----------------------------------------------------
    // Commit transaction
    // ----------------------------------------------------
    public function commit() {
        if (self::$openTransactionsCount == 0) {
            throw new TipyDaoException('No transaction in progress');
        } else if (self::$openTransactionsCount == 1) {
            $result = $this->dbLink->query('COMMIT');
            if ($result) {
                self::$openTransactionsCount = 0;
            }
            return $result;
        } else if (self::$openTransactionsCount > 1) {
            $currentSavepointName = self::savepointName(self::$openTransactionsCount);
            $result = $this->dbLink->query('RELEASE SAVEPOINT '.$currentSavepointName);
            if ($result) {
                self::$openTransactionsCount--;
            }
            return $result;
        } else {
            // Just to be sure
            throw new TipyDaoException('Negative open transactions counter. Please contact tipy maintainers');
        }
    }

    // ----------------------------------------------------
    // Rollback transaction
    // ----------------------------------------------------


    public function rollback($kind = 'soft') {
        if (self::$openTransactionsCount == 0) {
            throw new TipyDaoException('No transaction in progress');
        } else if ($kind == 'hard') {
            // rollback parent transaction with all nested savepoints
            $result = $this->dbLink->rollback();
            if ($result) {
                self::$openTransactionsCount = 0;
            }
        } else if (self::$openTransactionsCount == 1) {
            $result = $this->dbLink->rollback();
            if ($result) {
                self::$openTransactionsCount = 0;
            }
            return $result;
        } else if (self::$openTransactionsCount > 1) {
            $currentSavepointName = self::savepointName(self::$openTransactionsCount);
            $result = $this->dbLink->query('ROLLBACK TO SAVEPOINT '.$currentSavepointName);
            if ($result) {
                self::$openTransactionsCount--;
            }
            return $result;
        } else {
            // Just to be sure
            throw new TipyDaoException('Negative open transactions counter. Please contact tipy maintainers');
        }
        return $result;
    }

    // ----------------------------------------------------
    // Return true if any transaction in progress
    // ----------------------------------------------------
    public function isTransactionInProgress() {
        return self::$openTransactionsCount > 0;
    }
}
<commit_msg>Register shutdown function only after transaction start. No need to register it again on savepoint.<commit_after><?php

class TipyDaoException extends Exception {}

// ---------------------------------------------------------
// ApplicationDAO
// DB wrapper and base DAO class. Provides interface to
// database base functions
// ---------------------------------------------------------
class TipyDAO {

    protected $dbLink;
    public static $openTransactionsCount = 0;
    public static $queryCount;

    // -----------------------------------------------------
    // Constructor
    // -----------------------------------------------------
    public function __construct() {
        $app = TipyApp::getInstance();
        // If not yet connected then connect.
        if (!$app->db) {
            // Get  connection string
            $config = $app->config;
            $dbHost = $config->get('db_host');
            if ($config->get('db_port')) {
                $dbHost .= $dbHost.':'.$config->get('db_port');
            }
            $dbName = $config->get('db_name');
            $dbUser = $config->get('db_user');
            $dbPassword = $config->get('db_password');

            $dbLink = new mysqli('p:'.$dbHost, $dbUser, $dbPassword, $dbName);
            if ($dbLink->connect_error) {
                throw new TipyDaoException('DB connection error (' . $dbLink->connect_errno . ') '
                    . $dbLink->connect_error);
            } else {
                if ($config->get('db_character_set')) {
                    $dbLink->query("set names '".$config->get('db_character_set')."'");
                }
                $app->db = $dbLink;
            }
        }
        $this->dbLink = $app->db;
    }

    // ----------------------------------------------------
    // query
    // Just db query wrapper with some error handler
    // ----------------------------------------------------
    public function query($sql, $params = null) {
        if ($params) {
            $sql = str_replace('%', '%%', $sql);
            $sql = str_replace('?', '"%s"', $sql);
            $link = $this->dbLink;
            array_walk($params, function (&$string) use ($link) {
                $string = $link->real_escape_string($string);
            });
            array_unshift($params, $sql);
            $query = call_user_func_array('sprintf', $params);
        } else {
            $query = $sql;
        }
        $result = $this->dbLink->query($query);
        self::$queryCount++;
        if (!$result) {
            throw new TipyDaoException($this->dbLink->error);
        } else {
            return $result;
        }
    }

    // ----------------------------------------------------
    // limitQuery
    // ----------------------------------------------------
    public function limitQuery($sql, $span, $step, $params = []) {
        $sql = $sql." limit ".$span.",".$step;
        return $this->query($sql, $params);
    }

    // -----------------------------------------------------
    // numRows
    // -----------------------------------------------------
    public function numRows(&$result) {
        return $result->num_rows;
    }

    // -----------------------------------------------------
    // fetchRow
    // Need this method to do some common operations before
    // returning fetchRow from query result
    // -----------------------------------------------------
    public function fetchRow(&$result) {
        $result->field_seek(0);
        return $result->fetch_array(MYSQLI_ASSOC);
    }

    // -----------------------------------------------------
    // fetchAllRows - return all rows of the DB_result object
    // -----------------------------------------------------
    public function fetchAllRows(&$result) {
        return $result->fetch_all(MYSQLI_ASSOC);
    }

    // ----------------------------------------------------
    // queryRow
    // query & fetch in one flakon
    // ----------------------------------------------------
    public function queryRow($sql, $params = []) {
        $result = $this->query($sql, $params);
        return $this->fetchRow($result);
    }

    // ----------------------------------------------------
    // queryRows
    // query and fetch all rows in one flakon
    // ----------------------------------------------------
    public function queryAllRows($sql, $params = []) {
        $result = $this->query($sql, $params);
        return $this->fetchAllRows($result);
    }

    // ----------------------------------------------------
    // limit query and fetch
    // ----------------------------------------------------
    public function limitQueryAllRows($sql, $span, $step, $params = []) {
        $result = $this->limitQuery($sql, $span, $step, $params);
        if ($result) {
            return $this->fetchAllRows($result);
        } else {
            return null;
        }
    }

    // ----------------------------------------------------
    // last insert id
    // ----------------------------------------------------
    public function lastInsertId() {
        return $this->dbLink->insert_id;
    }

    // ----------------------------------------------------
    // affected rows
    // ----------------------------------------------------
    public function affectedRows() {
        return $this->dbLink->affected_rows;
    }

    public function queryErrno($sql, $params = []) {
        $this->query($sql, $params, true);
        return $this->dbLink->errno;
    }

    protected static function savepointName($number) {
        return 'tipy_savepoint_'.$number;
    }

    // ----------------------------------------------------
    // Start transaction with fallback mechanics
    // ----------------------------------------------------
    public function startTransaction() {
        if (self::$openTransactionsCount == 0) {
            $result = $this->dbLink->query('BEGIN');
            if ($result) {
                register_shutdown_function([$this, "shutdownCheck"]);
            }
        } else {
            $newSavepoint = self::savepointName(self::$openTransactionsCount + 1);
            $result = $this->dbLink->query('SAVEPOINT '.$newSavepoint);
        }
        if ($result) {
            register_shutdown_function([$this, "shutdownCheck"]);
            self::$openTransactionsCount++;
        }
        return $result;
    }

    // ----------------------------------------------------
    // Rollback all opened transaction on fatal errors or
    // script stop
    // ----------------------------------------------------
    public function shutdowncheck() {
        if (self::istransactioninprogress()) {
            $this->rollback('hard');
        }
    }

    // ----------------------------------------------------
    // Commit transaction
    // ----------------------------------------------------
    public function commit() {
        if (self::$openTransactionsCount == 0) {
            throw new TipyDaoException('No transaction in progress');
        } else if (self::$openTransactionsCount == 1) {
            $result = $this->dbLink->query('COMMIT');
            if ($result) {
                self::$openTransactionsCount = 0;
            }
            return $result;
        } else if (self::$openTransactionsCount > 1) {
            $currentSavepointName = self::savepointName(self::$openTransactionsCount);
            $result = $this->dbLink->query('RELEASE SAVEPOINT '.$currentSavepointName);
            if ($result) {
                self::$openTransactionsCount--;
            }
            return $result;
        } else {
            // Just to be sure
            throw new TipyDaoException('Negative open transactions counter. Please contact tipy maintainers');
        }
    }

    // ----------------------------------------------------
    // Rollback transaction
    // ----------------------------------------------------


    public function rollback($kind = 'soft') {
        if (self::$openTransactionsCount == 0) {
            throw new TipyDaoException('No transaction in progress');
        } else if ($kind == 'hard') {
            // rollback parent transaction with all nested savepoints
            $result = $this->dbLink->rollback();
            if ($result) {
                self::$openTransactionsCount = 0;
            }
        } else if (self::$openTransactionsCount == 1) {
            $result = $this->dbLink->rollback();
            if ($result) {
                self::$openTransactionsCount = 0;
            }
            return $result;
        } else if (self::$openTransactionsCount > 1) {
            $currentSavepointName = self::savepointName(self::$openTransactionsCount);
            $result = $this->dbLink->query('ROLLBACK TO SAVEPOINT '.$currentSavepointName);
            if ($result) {
                self::$openTransactionsCount--;
            }
            return $result;
        } else {
            // Just to be sure
            throw new TipyDaoException('Negative open transactions counter. Please contact tipy maintainers');
        }
        return $result;
    }

    // ----------------------------------------------------
    // Return true if any transaction in progress
    // ----------------------------------------------------
    public function isTransactionInProgress() {
        return self::$openTransactionsCount > 0;
    }
}

{'fraction_non_alphanumeric': 0.30471987514127336, 'fraction_numerical': 0.0015069156665410903, 'mean_word_length': 1.0704178272980502, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 121, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1597218', 'n_tokens_mistral': 4277, 'n_tokens_neox': 4222, 'n_words': 946}