<commit_before><?php

namespace Dbmover;

use PDO;
use PDOException;
use Dariuszp\CliProgressBar;

/**
 * The main Dbmover class. This represents a migration for a single unique DSN
 * from the `dbmover.json` config file.
 */
abstract class Dbmover
{
    const CATALOG_COLUMN = 'CATALOG';
    const REGEX_PROCEDURES = '@^CREATE (PROCEDURE|FUNCTION).*?^END;$@ms';
    const REGEX_TRIGGERS = '@^CREATE TRIGGER.*?^END;$@ms';
    const DROP_ROUTINE_SUFFIX = '()';
    const DROP_CONSTRAINT = 'CONSTRAINT';

    public $pdo;
    public $schemas = [];
    public $database;
    public $ignores = [];

    /**
     * Constructor.
     *
     * @param string $dsn The DSN string to connect with. Passed verbatim to
     *  PHP's `PDO` constructor.
     * @param array $settings Hash of settings read from `dbmover.json`. The
     *  `"user"` and `"pass"` keys are mostly relevant.
     */
    public function __construct($dsn, array $settings = [])
    {
        preg_match('@dbname=(\w+)@', $dsn, $database);
        $this->database = $database[1];
        $user = isset($settings['user']) ? $settings['user'] : null;
        $pass = isset($settings['pass']) ? $settings['pass'] : null;
        $options = isset($settings['options']) ? $settings['options'] : [];
        $options[PDO::ATTR_ERRMODE] = PDO::ERRMODE_EXCEPTION;
        $this->pdo = new PDO($dsn, $user, $pass, $options);
        if (isset($options['ignore']) && is_array($options['ignore'])) {
            $this->ignores = $options['ignore'];
        }
    }

    /**
     * Expose the name of the current database.
     *
     * @return string
     */
    public function getName()
    {
        return $this->database;
    }

    /**
     * Add schema data read from an SQL file.
     *
     * @param string $schema The complete schema.
     */
    public function addSchema($schema)
    {
        $this->schemas[] = $schema;
    }

    /**
     * Process all added schemas.
     */
    public function processSchemas()
    {
        echo "\033[0;34m".str_pad(
            "Gathering operations for {$this->database}...",
            100,
            ' ',
            STR_PAD_RIGHT
        );
        $sql = implode("\n", $this->schemas);
        $operations = [];
        $alter = $this->hoist( '@^ALTER TABLE .*?;$@ms', $sql);

        // Gather all conditionals and optionally wrap them in a "lambda".
        $ifs = $this->hoist('@^IF.*?^END IF;$@ms', $sql);
        foreach ($ifs as &$if) {
            $if = $this->wrapInProcedure($if);
        }

        $operations = array_merge($operations, $ifs);
        $tables = $this->hoist('@^CREATE TABLE .*?;$@ms', $sql);

        // Hoist all other recreatable objects.
        $hoists = array_merge(
            $this->hoist(
                static::REGEX_PROCEDURES,
                $sql
            ),
            $this->hoist(
                static::REGEX_TRIGGERS,
                $sql
            )
        );
        $views = $this->hoist(
            '@^CREATE VIEW.*?;$@ms',
            $sql
        );

        $operations = array_merge($operations, $this->dropRecreatables());

        $tablenames = [];
        foreach ($tables as $table) {
            preg_match('@^CREATE TABLE (\w+) ?\(@', $table, $name);
            $name = $name[1];
            $tablenames[] = $name;

            // If the table doesn't exist yet, create it verbatim.
            if (!$this->tableExists($name)) {
                $operations[] = $table;
            } else {
                $existing = $this->getTableDefinition($name);
                $new = $this->parseTableDefinition($table);
                foreach ($existing as $col => $definition) {
                    if (!isset($new[$col])) {
                        $operations[] = sprintf(
                            "ALTER TABLE %s DROP COLUMN %s",
                            $name,
                            $col
                        );
                    }
                }
                foreach ($new as $col => $definition) {
                    if (!isset($existing[$col])) {
                        $operations[] = $this->addColumn($name, $definition);
                    } else {
                        $operations = array_merge(
                            $operations,
                            $this->alterColumn($name, $definition)
                        );
                    }
                    if (isset($definition['key'])
                        && $definition['key'] == 'PRI'
                    ) {
                        $operations[] = sprintf(
                            "ALTER TABLE %s ADD PRIMARY KEY(%s)",
                            $name,
                            $col
                        );
                    }
                }
            }
        }

        foreach ($hoists as $hoist) {
            preg_match('@^CREATE (\w+) (\w+)@', $hoist, $data);
            if ($data[1] == 'FUNCTION' && $this instanceof Pgsql) {
                $data[2] .= '()';
            }
            $operations[] = "DROP {$data[1]} IF EXISTS {$data[2]}";
            $operations[] = $hoist;
        }

        if (strlen(trim($sql))) {
            $operations[] = $sql;
        }

        // Rerun ifs and alters
        $operations = array_merge($operations, $alter, $ifs);

        // Cleanup: remove tables that are not in the schema (any more)
        foreach ($this->getTables('BASE TABLE') as $table) {
            if (!in_array($table, $tablenames)
                && !$this->shouldIgnore($table)
            ) {<commit_msg>recreate views<commit_after><?php

namespace Dbmover;

use PDO;
use PDOException;
use Dariuszp\CliProgressBar;

/**
 * The main Dbmover class. This represents a migration for a single unique DSN
 * from the `dbmover.json` config file.
 */
abstract class Dbmover
{
    const CATALOG_COLUMN = 'CATALOG';
    const REGEX_PROCEDURES = '@^CREATE (PROCEDURE|FUNCTION).*?^END;$@ms';
    const REGEX_TRIGGERS = '@^CREATE TRIGGER.*?^END;$@ms';
    const DROP_ROUTINE_SUFFIX = '()';
    const DROP_CONSTRAINT = 'CONSTRAINT';

    public $pdo;
    public $schemas = [];
    public $database;
    public $ignores = [];

    /**
     * Constructor.
     *
     * @param string $dsn The DSN string to connect with. Passed verbatim to
     *  PHP's `PDO` constructor.
     * @param array $settings Hash of settings read from `dbmover.json`. The
     *  `"user"` and `"pass"` keys are mostly relevant.
     */
    public function __construct($dsn, array $settings = [])
    {
        preg_match('@dbname=(\w+)@', $dsn, $database);
        $this->database = $database[1];
        $user = isset($settings['user']) ? $settings['user'] : null;
        $pass = isset($settings['pass']) ? $settings['pass'] : null;
        $options = isset($settings['options']) ? $settings['options'] : [];
        $options[PDO::ATTR_ERRMODE] = PDO::ERRMODE_EXCEPTION;
        $this->pdo = new PDO($dsn, $user, $pass, $options);
        if (isset($options['ignore']) && is_array($options['ignore'])) {
            $this->ignores = $options['ignore'];
        }
    }

    /**
     * Expose the name of the current database.
     *
     * @return string
     */
    public function getName()
    {
        return $this->database;
    }

    /**
     * Add schema data read from an SQL file.
     *
     * @param string $schema The complete schema.
     */
    public function addSchema($schema)
    {
        $this->schemas[] = $schema;
    }

    /**
     * Process all added schemas.
     */
    public function processSchemas()
    {
        echo "\033[0;34m".str_pad(
            "Gathering operations for {$this->database}...",
            100,
            ' ',
            STR_PAD_RIGHT
        );
        $sql = implode("\n", $this->schemas);
        $operations = [];
        $alter = $this->hoist( '@^ALTER TABLE .*?;$@ms', $sql);

        // Gather all conditionals and optionally wrap them in a "lambda".
        $ifs = $this->hoist('@^IF.*?^END IF;$@ms', $sql);
        foreach ($ifs as &$if) {
            $if = $this->wrapInProcedure($if);
        }

        $operations = array_merge($operations, $ifs);
        $tables = $this->hoist('@^CREATE TABLE .*?;$@ms', $sql);

        // Hoist all other recreatable objects.
        $hoists = array_merge(
            $this->hoist(
                static::REGEX_PROCEDURES,
                $sql
            ),
            $this->hoist(
                static::REGEX_TRIGGERS,
                $sql
            )
        );
        $views = $this->hoist(
            '@^CREATE VIEW.*?;$@ms',
            $sql
        );

        $operations = array_merge($operations, $this->dropRecreatables());

        $tablenames = [];
        foreach ($tables as $table) {
            preg_match('@^CREATE TABLE (\w+) ?\(@', $table, $name);
            $name = $name[1];
            $tablenames[] = $name;

            // If the table doesn't exist yet, create it verbatim.
            if (!$this->tableExists($name)) {
                $operations[] = $table;
            } else {
                $existing = $this->getTableDefinition($name);
                $new = $this->parseTableDefinition($table);
                foreach ($existing as $col => $definition) {
                    if (!isset($new[$col])) {
                        $operations[] = sprintf(
                            "ALTER TABLE %s DROP COLUMN %s",
                            $name,
                            $col
                        );
                    }
                }
                foreach ($new as $col => $definition) {
                    if (!isset($existing[$col])) {
                        $operations[] = $this->addColumn($name, $definition);
                    } else {
                        $operations = array_merge(
                            $operations,
                            $this->alterColumn($name, $definition)
                        );
                    }
                    if (isset($definition['key'])
                        && $definition['key'] == 'PRI'
                    ) {
                        $operations[] = sprintf(
                            "ALTER TABLE %s ADD PRIMARY KEY(%s)",
                            $name,
                            $col
                        );
                    }
                }
            }
        }

        foreach ($hoists as $hoist) {
            preg_match('@^CREATE (\w+) (\w+)@', $hoist, $data);
            if ($data[1] == 'FUNCTION' && $this instanceof Pgsql) {
                $data[2] .= '()';
            }
            $operations[] = "DROP {$data[1]} IF EXISTS {$data[2]}";
            $operations[] = $hoist;
        }

        if (strlen(trim($sql))) {
            $operations[] = $sql;
        }

        // Recrate views
        $operations = array_merge($operations, $views);

        // Rerun ifs and alters
        $operations = array_merge($operations, $alter, $ifs);

        // Cleanup: remove tables that are not in the schema (any more)
        foreach ($this->getTables('BASE TABLE') as $table) {
            if (!in_array($table, $tablenames)
                && !$this->shouldIgnore($table)
            ) {
{'fraction_non_alphanumeric': 0.15134941271406796, 'fraction_numerical': 0.00268985923070026, 'mean_word_length': 1.5110310670868978, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 51, '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': '58674', 'n_tokens_mistral': 3268, 'n_tokens_neox': 3156, 'n_words': 732}