/lib/Doctrine/DBAL/Platforms/SqlitePlatform.php
PHP | 1218 lines | 1080 code | 48 blank | 90 comment | 30 complexity | 423dd3acd86363dc6fae5813210ad9b1 MD5 | raw file
Possible License(s): Unlicense
- <?php
- namespace Doctrine\DBAL\Platforms;
- use Doctrine\DBAL\DBALException;
- use Doctrine\DBAL\Schema\Column;
- use Doctrine\DBAL\Schema\Constraint;
- use Doctrine\DBAL\Schema\ForeignKeyConstraint;
- use Doctrine\DBAL\Schema\Identifier;
- use Doctrine\DBAL\Schema\Index;
- use Doctrine\DBAL\Schema\Table;
- use Doctrine\DBAL\Schema\TableDiff;
- use Doctrine\DBAL\TransactionIsolationLevel;
- use Doctrine\DBAL\Types;
- use function array_merge;
- use function array_unique;
- use function array_values;
- use function implode;
- use function is_numeric;
- use function sprintf;
- use function sqrt;
- use function str_replace;
- use function strlen;
- use function strpos;
- use function strtolower;
- use function trim;
- /**
- * The SqlitePlatform class describes the specifics and dialects of the SQLite
- * database platform.
- *
- * @todo Rename: SQLitePlatform
- */
- class SqlitePlatform extends AbstractPlatform
- {
- /**
- * {@inheritDoc}
- */
- public function getRegexpExpression()
- {
- return 'REGEXP';
- }
- /**
- * {@inheritDoc}
- *
- * @deprecated Use application-generated UUIDs instead
- */
- public function getGuidExpression()
- {
- return "HEX(RANDOMBLOB(4)) || '-' || HEX(RANDOMBLOB(2)) || '-4' || "
- . "SUBSTR(HEX(RANDOMBLOB(2)), 2) || '-' || "
- . "SUBSTR('89AB', 1 + (ABS(RANDOM()) % 4), 1) || "
- . "SUBSTR(HEX(RANDOMBLOB(2)), 2) || '-' || HEX(RANDOMBLOB(6))";
- }
- /**
- * @param string $type
- *
- * @return string
- */
- public function getNowExpression($type = 'timestamp')
- {
- switch ($type) {
- case 'time':
- return 'time(\'now\')';
- case 'date':
- return 'date(\'now\')';
- case 'timestamp':
- default:
- return 'datetime(\'now\')';
- }
- }
- /**
- * {@inheritDoc}
- */
- public function getTrimExpression($str, $pos = TrimMode::UNSPECIFIED, $char = false)
- {
- $trimChar = $char !== false ? ', ' . $char : '';
- switch ($pos) {
- case TrimMode::LEADING:
- $trimFn = 'LTRIM';
- break;
- case TrimMode::TRAILING:
- $trimFn = 'RTRIM';
- break;
- default:
- $trimFn = 'TRIM';
- }
- return $trimFn . '(' . $str . $trimChar . ')';
- }
- /**
- * {@inheritDoc}
- *
- * SQLite only supports the 2 parameter variant of this function
- */
- public function getSubstringExpression($value, $position, $length = null)
- {
- if ($length !== null) {
- return 'SUBSTR(' . $value . ', ' . $position . ', ' . $length . ')';
- }
- return 'SUBSTR(' . $value . ', ' . $position . ', LENGTH(' . $value . '))';
- }
- /**
- * {@inheritDoc}
- */
- public function getLocateExpression($str, $substr, $startPos = false)
- {
- if ($startPos === false) {
- return 'LOCATE(' . $str . ', ' . $substr . ')';
- }
- return 'LOCATE(' . $str . ', ' . $substr . ', ' . $startPos . ')';
- }
- /**
- * {@inheritdoc}
- */
- protected function getDateArithmeticIntervalExpression($date, $operator, $interval, $unit)
- {
- switch ($unit) {
- case DateIntervalUnit::SECOND:
- case DateIntervalUnit::MINUTE:
- case DateIntervalUnit::HOUR:
- return 'DATETIME(' . $date . ",'" . $operator . $interval . ' ' . $unit . "')";
- }
- switch ($unit) {
- case DateIntervalUnit::WEEK:
- $interval *= 7;
- $unit = DateIntervalUnit::DAY;
- break;
- case DateIntervalUnit::QUARTER:
- $interval *= 3;
- $unit = DateIntervalUnit::MONTH;
- break;
- }
- if (! is_numeric($interval)) {
- $interval = "' || " . $interval . " || '";
- }
- return 'DATE(' . $date . ",'" . $operator . $interval . ' ' . $unit . "')";
- }
- /**
- * {@inheritDoc}
- */
- public function getDateDiffExpression($date1, $date2)
- {
- return sprintf("JULIANDAY(%s, 'start of day') - JULIANDAY(%s, 'start of day')", $date1, $date2);
- }
- /**
- * {@inheritDoc}
- */
- protected function _getTransactionIsolationLevelSQL($level)
- {
- switch ($level) {
- case TransactionIsolationLevel::READ_UNCOMMITTED:
- return '0';
- case TransactionIsolationLevel::READ_COMMITTED:
- case TransactionIsolationLevel::REPEATABLE_READ:
- case TransactionIsolationLevel::SERIALIZABLE:
- return '1';
- default:
- return parent::_getTransactionIsolationLevelSQL($level);
- }
- }
- /**
- * {@inheritDoc}
- */
- public function getSetTransactionIsolationSQL($level)
- {
- return 'PRAGMA read_uncommitted = ' . $this->_getTransactionIsolationLevelSQL($level);
- }
- /**
- * {@inheritDoc}
- */
- public function prefersIdentityColumns()
- {
- return true;
- }
- /**
- * {@inheritDoc}
- */
- public function getBooleanTypeDeclarationSQL(array $field)
- {
- return 'BOOLEAN';
- }
- /**
- * {@inheritDoc}
- */
- public function getIntegerTypeDeclarationSQL(array $field)
- {
- return 'INTEGER' . $this->_getCommonIntegerTypeDeclarationSQL($field);
- }
- /**
- * {@inheritDoc}
- */
- public function getBigIntTypeDeclarationSQL(array $field)
- {
- // SQLite autoincrement is implicit for INTEGER PKs, but not for BIGINT fields.
- if (! empty($field['autoincrement'])) {
- return $this->getIntegerTypeDeclarationSQL($field);
- }
- return 'BIGINT' . $this->_getCommonIntegerTypeDeclarationSQL($field);
- }
- /**
- * @param array<string, mixed> $field
- *
- * @return string
- */
- public function getTinyIntTypeDeclarationSql(array $field)
- {
- // SQLite autoincrement is implicit for INTEGER PKs, but not for TINYINT fields.
- if (! empty($field['autoincrement'])) {
- return $this->getIntegerTypeDeclarationSQL($field);
- }
- return 'TINYINT' . $this->_getCommonIntegerTypeDeclarationSQL($field);
- }
- /**
- * {@inheritDoc}
- */
- public function getSmallIntTypeDeclarationSQL(array $field)
- {
- // SQLite autoincrement is implicit for INTEGER PKs, but not for SMALLINT fields.
- if (! empty($field['autoincrement'])) {
- return $this->getIntegerTypeDeclarationSQL($field);
- }
- return 'SMALLINT' . $this->_getCommonIntegerTypeDeclarationSQL($field);
- }
- /**
- * @param array<string, mixed> $field
- *
- * @return string
- */
- public function getMediumIntTypeDeclarationSql(array $field)
- {
- // SQLite autoincrement is implicit for INTEGER PKs, but not for MEDIUMINT fields.
- if (! empty($field['autoincrement'])) {
- return $this->getIntegerTypeDeclarationSQL($field);
- }
- return 'MEDIUMINT' . $this->_getCommonIntegerTypeDeclarationSQL($field);
- }
- /**
- * {@inheritDoc}
- */
- public function getDateTimeTypeDeclarationSQL(array $fieldDeclaration)
- {
- return 'DATETIME';
- }
- /**
- * {@inheritDoc}
- */
- public function getDateTypeDeclarationSQL(array $fieldDeclaration)
- {
- return 'DATE';
- }
- /**
- * {@inheritDoc}
- */
- public function getTimeTypeDeclarationSQL(array $fieldDeclaration)
- {
- return 'TIME';
- }
- /**
- * {@inheritDoc}
- */
- protected function _getCommonIntegerTypeDeclarationSQL(array $columnDef)
- {
- // sqlite autoincrement is only possible for the primary key
- if (! empty($columnDef['autoincrement'])) {
- return ' PRIMARY KEY AUTOINCREMENT';
- }
- return ! empty($columnDef['unsigned']) ? ' UNSIGNED' : '';
- }
- /**
- * {@inheritDoc}
- */
- public function getForeignKeyDeclarationSQL(ForeignKeyConstraint $foreignKey)
- {
- return parent::getForeignKeyDeclarationSQL(new ForeignKeyConstraint(
- $foreignKey->getQuotedLocalColumns($this),
- str_replace('.', '__', $foreignKey->getQuotedForeignTableName($this)),
- $foreignKey->getQuotedForeignColumns($this),
- $foreignKey->getName(),
- $foreignKey->getOptions()
- ));
- }
- /**
- * {@inheritDoc}
- */
- protected function _getCreateTableSQL($name, array $columns, array $options = [])
- {
- $name = str_replace('.', '__', $name);
- $queryFields = $this->getColumnDeclarationListSQL($columns);
- if (isset($options['uniqueConstraints']) && ! empty($options['uniqueConstraints'])) {
- foreach ($options['uniqueConstraints'] as $name => $definition) {
- $queryFields .= ', ' . $this->getUniqueConstraintDeclarationSQL($name, $definition);
- }
- }
- $queryFields .= $this->getNonAutoincrementPrimaryKeyDefinition($columns, $options);
- if (isset($options['foreignKeys'])) {
- foreach ($options['foreignKeys'] as $foreignKey) {
- $queryFields .= ', ' . $this->getForeignKeyDeclarationSQL($foreignKey);
- }
- }
- $tableComment = '';
- if (isset($options['comment'])) {
- $comment = trim($options['comment'], " '");
- $tableComment = $this->getInlineTableCommentSQL($comment);
- }
- $query = ['CREATE TABLE ' . $name . ' ' . $tableComment . '(' . $queryFields . ')'];
- if (isset($options['alter']) && $options['alter'] === true) {
- return $query;
- }
- if (isset($options['indexes']) && ! empty($options['indexes'])) {
- foreach ($options['indexes'] as $indexDef) {
- $query[] = $this->getCreateIndexSQL($indexDef, $name);
- }
- }
- if (isset($options['unique']) && ! empty($options['unique'])) {
- foreach ($options['unique'] as $indexDef) {
- $query[] = $this->getCreateIndexSQL($indexDef, $name);
- }
- }
- return $query;
- }
- /**
- * Generate a PRIMARY KEY definition if no autoincrement value is used
- *
- * @param mixed[][] $columns
- * @param mixed[] $options
- */
- private function getNonAutoincrementPrimaryKeyDefinition(array $columns, array $options) : string
- {
- if (empty($options['primary'])) {
- return '';
- }
- $keyColumns = array_unique(array_values($options['primary']));
- foreach ($keyColumns as $keyColumn) {
- if (! empty($columns[$keyColumn]['autoincrement'])) {
- return '';
- }
- }
- return ', PRIMARY KEY(' . implode(', ', $keyColumns) . ')';
- }
- /**
- * {@inheritDoc}
- */
- protected function getVarcharTypeDeclarationSQLSnippet($length, $fixed)
- {
- return $fixed ? ($length ? 'CHAR(' . $length . ')' : 'CHAR(255)')
- : ($length ? 'VARCHAR(' . $length . ')' : 'TEXT');
- }
- /**
- * {@inheritdoc}
- */
- protected function getBinaryTypeDeclarationSQLSnippet($length, $fixed)
- {
- return 'BLOB';
- }
- /**
- * {@inheritdoc}
- */
- public function getBinaryMaxLength()
- {
- return 0;
- }
- /**
- * {@inheritdoc}
- */
- public function getBinaryDefaultLength()
- {
- return 0;
- }
- /**
- * {@inheritDoc}
- */
- public function getClobTypeDeclarationSQL(array $field)
- {
- return 'CLOB';
- }
- /**
- * {@inheritDoc}
- */
- public function getListTableConstraintsSQL($table)
- {
- $table = str_replace('.', '__', $table);
- return sprintf(
- "SELECT sql FROM sqlite_master WHERE type='index' AND tbl_name = %s AND sql NOT NULL ORDER BY name",
- $this->quoteStringLiteral($table)
- );
- }
- /**
- * {@inheritDoc}
- */
- public function getListTableColumnsSQL($table, $currentDatabase = null)
- {
- $table = str_replace('.', '__', $table);
- return sprintf('PRAGMA table_info(%s)', $this->quoteStringLiteral($table));
- }
- /**
- * {@inheritDoc}
- */
- public function getListTableIndexesSQL($table, $currentDatabase = null)
- {
- $table = str_replace('.', '__', $table);
- return sprintf('PRAGMA index_list(%s)', $this->quoteStringLiteral($table));
- }
- /**
- * {@inheritDoc}
- */
- public function getListTablesSQL()
- {
- return "SELECT name FROM sqlite_master WHERE type = 'table' AND name != 'sqlite_sequence' AND name != 'geometry_columns' AND name != 'spatial_ref_sys' "
- . 'UNION ALL SELECT name FROM sqlite_temp_master '
- . "WHERE type = 'table' ORDER BY name";
- }
- /**
- * {@inheritDoc}
- */
- public function getListViewsSQL($database)
- {
- return "SELECT name, sql FROM sqlite_master WHERE type='view' AND sql NOT NULL";
- }
- /**
- * {@inheritDoc}
- */
- public function getCreateViewSQL($name, $sql)
- {
- return 'CREATE VIEW ' . $name . ' AS ' . $sql;
- }
- /**
- * {@inheritDoc}
- */
- public function getDropViewSQL($name)
- {
- return 'DROP VIEW ' . $name;
- }
- /**
- * {@inheritDoc}
- */
- public function getAdvancedForeignKeyOptionsSQL(ForeignKeyConstraint $foreignKey)
- {
- $query = parent::getAdvancedForeignKeyOptionsSQL($foreignKey);
- $query .= ($foreignKey->hasOption('deferrable') && $foreignKey->getOption('deferrable') !== false ? ' ' : ' NOT ') . 'DEFERRABLE';
- $query .= ' INITIALLY ' . ($foreignKey->hasOption('deferred') && $foreignKey->getOption('deferred') !== false ? 'DEFERRED' : 'IMMEDIATE');
- return $query;
- }
- /**
- * {@inheritDoc}
- */
- public function supportsIdentityColumns()
- {
- return true;
- }
- /**
- * {@inheritDoc}
- */
- public function supportsColumnCollation()
- {
- return true;
- }
- /**
- * {@inheritDoc}
- */
- public function supportsInlineColumnComments()
- {
- return true;
- }
- /**
- * {@inheritDoc}
- */
- public function getName()
- {
- return 'sqlite';
- }
- /**
- * {@inheritDoc}
- */
- public function getTruncateTableSQL($tableName, $cascade = false)
- {
- $tableIdentifier = new Identifier($tableName);
- $tableName = str_replace('.', '__', $tableIdentifier->getQuotedName($this));
- return 'DELETE FROM ' . $tableName;
- }
- /**
- * User-defined function for Sqlite that is used with PDO::sqliteCreateFunction().
- *
- * @param int|float $value
- *
- * @return float
- */
- public static function udfSqrt($value)
- {
- return sqrt($value);
- }
- /**
- * User-defined function for Sqlite that implements MOD(a, b).
- *
- * @param int $a
- * @param int $b
- *
- * @return int
- */
- public static function udfMod($a, $b)
- {
- return $a % $b;
- }
- /**
- * @param string $str
- * @param string $substr
- * @param int $offset
- *
- * @return int
- */
- public static function udfLocate($str, $substr, $offset = 0)
- {
- // SQL's LOCATE function works on 1-based positions, while PHP's strpos works on 0-based positions.
- // So we have to make them compatible if an offset is given.
- if ($offset > 0) {
- $offset -= 1;
- }
- $pos = strpos($str, $substr, $offset);
- if ($pos !== false) {
- return $pos + 1;
- }
- return 0;
- }
- /**
- * {@inheritDoc}
- */
- public function getForUpdateSQL()
- {
- return '';
- }
- /**
- * {@inheritDoc}
- */
- public function getInlineColumnCommentSQL($comment)
- {
- return '--' . str_replace("\n", "\n--", $comment) . "\n";
- }
- private function getInlineTableCommentSQL(string $comment) : string
- {
- return $this->getInlineColumnCommentSQL($comment);
- }
- /**
- * {@inheritDoc}
- */
- protected function initializeDoctrineTypeMappings()
- {
- $this->doctrineTypeMapping = [
- 'boolean' => 'boolean',
- 'tinyint' => 'boolean',
- 'smallint' => 'smallint',
- 'mediumint' => 'integer',
- 'int' => 'integer',
- 'integer' => 'integer',
- 'serial' => 'integer',
- 'bigint' => 'bigint',
- 'bigserial' => 'bigint',
- 'clob' => 'text',
- 'tinytext' => 'text',
- 'mediumtext' => 'text',
- 'longtext' => 'text',
- 'text' => 'text',
- 'varchar' => 'string',
- 'longvarchar' => 'string',
- 'varchar2' => 'string',
- 'nvarchar' => 'string',
- 'image' => 'string',
- 'ntext' => 'string',
- 'char' => 'string',
- 'date' => 'date',
- 'datetime' => 'datetime',
- 'timestamp' => 'datetime',
- 'time' => 'time',
- 'float' => 'float',
- 'double' => 'float',
- 'double precision' => 'float',
- 'real' => 'float',
- 'decimal' => 'decimal',
- 'numeric' => 'decimal',
- 'blob' => 'blob',
- ];
- }
- /**
- * {@inheritDoc}
- */
- protected function getReservedKeywordsClass()
- {
- return Keywords\SQLiteKeywords::class;
- }
- /**
- * {@inheritDoc}
- */
- protected function getPreAlterTableIndexForeignKeySQL(TableDiff $diff)
- {
- if (! $diff->fromTable instanceof Table) {
- throw new DBALException('Sqlite platform requires for alter table the table diff with reference to original table schema');
- }
- $sql = [];
- foreach ($diff->fromTable->getIndexes() as $index) {
- if ($index->isPrimary()) {
- continue;
- }
- $sql[] = $this->getDropIndexSQL($index, $diff->name);
- }
- return $sql;
- }
- /**
- * {@inheritDoc}
- */
- protected function getPostAlterTableIndexForeignKeySQL(TableDiff $diff)
- {
- if (! $diff->fromTable instanceof Table) {
- throw new DBALException('Sqlite platform requires for alter table the table diff with reference to original table schema');
- }
- $sql = [];
- $tableName = $diff->getNewName();
- if ($tableName === false) {
- $tableName = $diff->getName($this);
- }
- foreach ($this->getIndexesInAlteredTable($diff) as $index) {
- if ($index->isPrimary()) {
- continue;
- }
- $sql[] = $this->getCreateIndexSQL($index, $tableName->getQuotedName($this));
- }
- return $sql;
- }
- /**
- * {@inheritDoc}
- */
- protected function doModifyLimitQuery($query, $limit, $offset)
- {
- if ($limit === null && $offset > 0) {
- return $query . ' LIMIT -1 OFFSET ' . $offset;
- }
- return parent::doModifyLimitQuery($query, $limit, $offset);
- }
- /**
- * {@inheritDoc}
- */
- public function getBlobTypeDeclarationSQL(array $field)
- {
- return 'BLOB';
- }
- /**
- * {@inheritDoc}
- */
- public function getTemporaryTableName($tableName)
- {
- $tableName = str_replace('.', '__', $tableName);
- return $tableName;
- }
- /**
- * {@inheritDoc}
- *
- * Sqlite Platform emulates schema by underscoring each dot and generating tables
- * into the default database.
- *
- * This hack is implemented to be able to use SQLite as testdriver when
- * using schema supporting databases.
- */
- public function canEmulateSchemas()
- {
- return true;
- }
- /**
- * {@inheritDoc}
- */
- public function supportsForeignKeyConstraints()
- {
- return true;
- }
- public function supportsCreateDropForeignKeyConstraints() : bool
- {
- return false;
- }
- /**
- * {@inheritDoc}
- */
- public function getCreatePrimaryKeySQL(Index $index, $table)
- {
- throw new DBALException('Sqlite platform does not support alter primary key.');
- }
- /**
- * {@inheritdoc}
- */
- public function getCreateForeignKeySQL(ForeignKeyConstraint $foreignKey, $table)
- {
- throw new DBALException('Sqlite platform does not support alter foreign key, the table must be fully recreated using getAlterTableSQL.');
- }
- /**
- * {@inheritdoc}
- */
- public function getDropForeignKeySQL($foreignKey, $table)
- {
- throw new DBALException('Sqlite platform does not support alter foreign key, the table must be fully recreated using getAlterTableSQL.');
- }
- /**
- * {@inheritDoc}
- */
- public function getCreateConstraintSQL(Constraint $constraint, $table)
- {
- throw new DBALException('Sqlite platform does not support alter constraint.');
- }
- /**
- * {@inheritDoc}
- *
- * @param int|null $createFlags
- */
- public function getCreateTableSQL(Table $table, $createFlags = null)
- {
- $createFlags = $createFlags ?? self::CREATE_INDEXES | self::CREATE_FOREIGNKEYS;
- return parent::getCreateTableSQL($table, $createFlags);
- }
- /**
- * @param string $table
- * @param string|null $database
- *
- * @return string
- */
- public function getListTableForeignKeysSQL($table, $database = null)
- {
- $table = str_replace('.', '__', $table);
- return sprintf('PRAGMA foreign_key_list(%s)', $this->quoteStringLiteral($table));
- }
- /**
- * {@inheritDoc}
- */
- public function getAlterTableSQL(TableDiff $diff)
- {
- $sql = $this->getSimpleAlterTableSQL($diff);
- if ($sql !== false) {
- return $sql;
- }
- $fromTable = $diff->fromTable;
- if (! $fromTable instanceof Table) {
- throw new DBALException('Sqlite platform requires for alter table the table diff with reference to original table schema');
- }
- $table = clone $fromTable;
- $columns = [];
- $oldColumnNames = [];
- $newColumnNames = [];
- $columnSql = [];
- foreach ($table->getColumns() as $columnName => $column) {
- $columnName = strtolower($columnName);
- $columns[$columnName] = $column;
- $oldColumnNames[$columnName] = $newColumnNames[$columnName] = $column->getQuotedName($this);
- }
- foreach ($diff->removedColumns as $columnName => $column) {
- if ($this->onSchemaAlterTableRemoveColumn($column, $diff, $columnSql)) {
- continue;
- }
- $columnName = strtolower($columnName);
- if (! isset($columns[$columnName])) {
- continue;
- }
- unset(
- $columns[$columnName],
- $oldColumnNames[$columnName],
- $newColumnNames[$columnName]
- );
- }
- foreach ($diff->renamedColumns as $oldColumnName => $column) {
- if ($this->onSchemaAlterTableRenameColumn($oldColumnName, $column, $diff, $columnSql)) {
- continue;
- }
- $oldColumnName = strtolower($oldColumnName);
- if (isset($columns[$oldColumnName])) {
- unset($columns[$oldColumnName]);
- }
- $columns[strtolower($column->getName())] = $column;
- if (! isset($newColumnNames[$oldColumnName])) {
- continue;
- }
- $newColumnNames[$oldColumnName] = $column->getQuotedName($this);
- }
- foreach ($diff->changedColumns as $oldColumnName => $columnDiff) {
- if ($this->onSchemaAlterTableChangeColumn($columnDiff, $diff, $columnSql)) {
- continue;
- }
- if (isset($columns[$oldColumnName])) {
- unset($columns[$oldColumnName]);
- }
- $columns[strtolower($columnDiff->column->getName())] = $columnDiff->column;
- if (! isset($newColumnNames[$oldColumnName])) {
- continue;
- }
- $newColumnNames[$oldColumnName] = $columnDiff->column->getQuotedName($this);
- }
- foreach ($diff->addedColumns as $columnName => $column) {
- if ($this->onSchemaAlterTableAddColumn($column, $diff, $columnSql)) {
- continue;
- }
- $columns[strtolower($columnName)] = $column;
- }
- $sql = [];
- $tableSql = [];
- if (! $this->onSchemaAlterTable($diff, $tableSql)) {
- $dataTable = new Table('__temp__' . $table->getName());
- $newTable = new Table($table->getQuotedName($this), $columns, $this->getPrimaryIndexInAlteredTable($diff), $this->getForeignKeysInAlteredTable($diff), 0, $table->getOptions());
- $newTable->addOption('alter', true);
- $sql = $this->getPreAlterTableIndexForeignKeySQL($diff);
- //$sql = array_merge($sql, $this->getCreateTableSQL($dataTable, 0));
- $sql[] = sprintf('CREATE TEMPORARY TABLE %s AS SELECT %s FROM %s', $dataTable->getQuotedName($this), implode(', ', $oldColumnNames), $table->getQuotedName($this));
- $sql[] = $this->getDropTableSQL($fromTable);
- $sql = array_merge($sql, $this->getCreateTableSQL($newTable));
- $sql[] = sprintf('INSERT INTO %s (%s) SELECT %s FROM %s', $newTable->getQuotedName($this), implode(', ', $newColumnNames), implode(', ', $oldColumnNames), $dataTable->getQuotedName($this));
- $sql[] = $this->getDropTableSQL($dataTable);
- $newName = $diff->getNewName();
- if ($newName !== false) {
- $sql[] = sprintf(
- 'ALTER TABLE %s RENAME TO %s',
- $newTable->getQuotedName($this),
- $newName->getQuotedName($this)
- );
- }
- $sql = array_merge($sql, $this->getPostAlterTableIndexForeignKeySQL($diff));
- }
- return array_merge($sql, $tableSql, $columnSql);
- }
- /**
- * @return string[]|false
- */
- private function getSimpleAlterTableSQL(TableDiff $diff)
- {
- // Suppress changes on integer type autoincrement columns.
- foreach ($diff->changedColumns as $oldColumnName => $columnDiff) {
- if (! $columnDiff->fromColumn instanceof Column ||
- ! $columnDiff->column instanceof Column ||
- ! $columnDiff->column->getAutoincrement() ||
- ! $columnDiff->column->getType() instanceof Types\IntegerType
- ) {
- continue;
- }
- if (! $columnDiff->hasChanged('type') && $columnDiff->hasChanged('unsigned')) {
- unset($diff->changedColumns[$oldColumnName]);
- continue;
- }
- $fromColumnType = $columnDiff->fromColumn->getType();
- if (! ($fromColumnType instanceof Types\SmallIntType) && ! ($fromColumnType instanceof Types\BigIntType)) {
- continue;
- }
- unset($diff->changedColumns[$oldColumnName]);
- }
- if (! empty($diff->renamedColumns) || ! empty($diff->addedForeignKeys) || ! empty($diff->addedIndexes)
- || ! empty($diff->changedColumns) || ! empty($diff->changedForeignKeys) || ! empty($diff->changedIndexes)
- || ! empty($diff->removedColumns) || ! empty($diff->removedForeignKeys) || ! empty($diff->removedIndexes)
- || ! empty($diff->renamedIndexes)
- ) {
- return false;
- }
- $table = new Table($diff->name);
- $sql = [];
- $tableSql = [];
- $columnSql = [];
- foreach ($diff->addedColumns as $column) {
- if ($this->onSchemaAlterTableAddColumn($column, $diff, $columnSql)) {
- continue;
- }
- $field = array_merge(['unique' => null, 'autoincrement' => null, 'default' => null], $column->toArray());
- $type = $field['type'];
- switch (true) {
- case isset($field['columnDefinition']) || $field['autoincrement'] || $field['unique']:
- case $type instanceof Types\DateTimeType && $field['default'] === $this->getCurrentTimestampSQL():
- case $type instanceof Types\DateType && $field['default'] === $this->getCurrentDateSQL():
- case $type instanceof Types\TimeType && $field['default'] === $this->getCurrentTimeSQL():
- return false;
- }
- $field['name'] = $column->getQuotedName($this);
- if ($type instanceof Types\StringType && $field['length'] === null) {
- $field['length'] = 255;
- }
- $sql[] = 'ALTER TABLE ' . $table->getQuotedName($this) . ' ADD COLUMN ' . $this->getColumnDeclarationSQL($field['name'], $field);
- }
- if (! $this->onSchemaAlterTable($diff, $tableSql)) {
- if ($diff->newName !== false) {
- $newTable = new Identifier($diff->newName);
- $sql[] = 'ALTER TABLE ' . $table->getQuotedName($this) . ' RENAME TO ' . $newTable->getQuotedName($this);
- }
- }
- return array_merge($sql, $tableSql, $columnSql);
- }
- /**
- * @return string[]
- */
- private function getColumnNamesInAlteredTable(TableDiff $diff)
- {
- $columns = [];
- foreach ($diff->fromTable->getColumns() as $columnName => $column) {
- $columns[strtolower($columnName)] = $column->getName();
- }
- foreach ($diff->removedColumns as $columnName => $column) {
- $columnName = strtolower($columnName);
- if (! isset($columns[$columnName])) {
- continue;
- }
- unset($columns[$columnName]);
- }
- foreach ($diff->renamedColumns as $oldColumnName => $column) {
- $columnName = $column->getName();
- $columns[strtolower($oldColumnName)] = $columnName;
- $columns[strtolower($columnName)] = $columnName;
- }
- foreach ($diff->changedColumns as $oldColumnName => $columnDiff) {
- $columnName = $columnDiff->column->getName();
- $columns[strtolower($oldColumnName)] = $columnName;
- $columns[strtolower($columnName)] = $columnName;
- }
- foreach ($diff->addedColumns as $column) {
- $columnName = $column->getName();
- $columns[strtolower($columnName)] = $columnName;
- }
- return $columns;
- }
- /**
- * @return Index[]
- */
- private function getIndexesInAlteredTable(TableDiff $diff)
- {
- $indexes = $diff->fromTable->getIndexes();
- $columnNames = $this->getColumnNamesInAlteredTable($diff);
- foreach ($indexes as $key => $index) {
- foreach ($diff->renamedIndexes as $oldIndexName => $renamedIndex) {
- if (strtolower($key) !== strtolower($oldIndexName)) {
- continue;
- }
- unset($indexes[$key]);
- }
- $changed = false;
- $indexColumns = [];
- foreach ($index->getColumns() as $columnName) {
- $normalizedColumnName = strtolower($columnName);
- if (! isset($columnNames[$normalizedColumnName])) {
- unset($indexes[$key]);
- continue 2;
- }
- $indexColumns[] = $columnNames[$normalizedColumnName];
- if ($columnName === $columnNames[$normalizedColumnName]) {
- continue;
- }
- $changed = true;
- }
- if (! $changed) {
- continue;
- }
- $indexes[$key] = new Index($index->getName(), $indexColumns, $index->isUnique(), $index->isPrimary(), $index->getFlags());
- }
- foreach ($diff->removedIndexes as $index) {
- $indexName = strtolower($index->getName());
- if (! strlen($indexName) || ! isset($indexes[$indexName])) {
- continue;
- }
- unset($indexes[$indexName]);
- }
- foreach (array_merge($diff->changedIndexes, $diff->addedIndexes, $diff->renamedIndexes) as $index) {
- $indexName = strtolower($index->getName());
- if (strlen($indexName)) {
- $indexes[$indexName] = $index;
- } else {
- $indexes[] = $index;
- }
- }
- return $indexes;
- }
- /**
- * @return ForeignKeyConstraint[]
- */
- private function getForeignKeysInAlteredTable(TableDiff $diff)
- {
- $foreignKeys = $diff->fromTable->getForeignKeys();
- $columnNames = $this->getColumnNamesInAlteredTable($diff);
- foreach ($foreignKeys as $key => $constraint) {
- $changed = false;
- $localColumns = [];
- foreach ($constraint->getLocalColumns() as $columnName) {
- $normalizedColumnName = strtolower($columnName);
- if (! isset($columnNames[$normalizedColumnName])) {
- unset($foreignKeys[$key]);
- continue 2;
- }
- $localColumns[] = $columnNames[$normalizedColumnName];
- if ($columnName === $columnNames[$normalizedColumnName]) {
- continue;
- }
- $changed = true;
- }
- if (! $changed) {
- continue;
- }
- $foreignKeys[$key] = new ForeignKeyConstraint($localColumns, $constraint->getForeignTableName(), $constraint->getForeignColumns(), $constraint->getName(), $constraint->getOptions());
- }
- foreach ($diff->removedForeignKeys as $constraint) {
- if (! $constraint instanceof ForeignKeyConstraint) {
- $constraint = new Identifier($constraint);
- }
- $constraintName = strtolower($constraint->getName());
- if (! strlen($constraintName) || ! isset($foreignKeys[$constraintName])) {
- continue;
- }
- unset($foreignKeys[$constraintName]);
- }
- foreach (array_merge($diff->changedForeignKeys, $diff->addedForeignKeys) as $constraint) {
- $constraintName = strtolower($constraint->getName());
- if (strlen($constraintName)) {
- $foreignKeys[$constraintName] = $constraint;
- } else {
- $foreignKeys[] = $constraint;
- }
- }
- return $foreignKeys;
- }
- /**
- * @return Index[]
- */
- private function getPrimaryIndexInAlteredTable(TableDiff $diff)
- {
- $primaryIndex = [];
- foreach ($this->getIndexesInAlteredTable($diff) as $index) {
- if (! $index->isPrimary()) {
- continue;
- }
- $primaryIndex = [$index->getName() => $index];
- }
- return $primaryIndex;
- }
- }