/**
  * {@inheritdoc}
  */
 public function alterColumn(AbstractTable $table, AbstractColumn $initial, AbstractColumn $column)
 {
     $query = "ALTER TABLE {table} CHANGE {column} {statement}";
     $query = \Spiral\interpolate($query, ['table' => $table->getName(true), 'column' => $initial->getName(true), 'statement' => $column->sqlStatement()]);
     $this->run($query);
     return $this;
 }
 /**
  * {@inheritdoc}
  */
 public function alterColumn(AbstractTable $table, AbstractColumn $initial, AbstractColumn $column)
 {
     if (!$initial instanceof ColumnSchema || !$column instanceof ColumnSchema) {
         throw new SchemaException("Postgres commander can work only with Postgres columns.");
     }
     //Rename is separate operation
     if ($column->getName() != $initial->getName()) {
         $this->renameColumn($table, $initial, $column);
         //This call is required to correctly built set of alter operations
         $initial->setName($column->getName());
     }
     //Postgres columns should be altered using set of operations
     if (!($operations = $column->alteringOperations($initial))) {
         return $this;
     }
     //Postgres columns should be altered using set of operations
     $query = \Spiral\interpolate('ALTER TABLE {table} {operations}', ['table' => $table->getName(true), 'operations' => trim(join(', ', $operations), ', ')]);
     $this->run($query);
     return $this;
 }
 /**
  * {@inheritdoc}
  */
 public function sqlStatement()
 {
     $statement = parent::sqlStatement();
     if ($this->abstractType() != 'enum') {
         return $statement;
     }
     $enumValues = [];
     foreach ($this->enumValues as $value) {
         $enumValues[] = $this->table->driver()->getPDO()->quote($value);
     }
     return "{$statement} CHECK ({$this->getName(true)} IN (" . join(', ', $enumValues) . "))";
 }
 /**
  * Cast default value based on column type. Required to prevent conflicts when not nullable
  * column added to existed table with data in.
  *
  * @param AbstractTable  $table
  * @param AbstractColumn $column
  * @return bool|float|int|mixed|string
  */
 private function castDefault(AbstractTable $table, AbstractColumn $column)
 {
     if ($column->abstractType() == 'timestamp' || $column->abstractType() == 'datetime') {
         $driver = $table->driver();
         return $driver::DEFAULT_DATETIME;
     }
     if ($column->abstractType() == 'enum') {
         //We can use first enum value as default
         return $column->getEnumValues()[0];
     }
     switch ($column->phpType()) {
         case 'int':
             return 0;
             break;
         case 'float':
             return 0.0;
             break;
         case 'bool':
             return false;
             break;
     }
     return '';
 }
Exemple #5
0
 /**
  * {@inheritdoc}
  */
 protected function doColumnChange(AbstractColumn $column, AbstractColumn $dbColumn)
 {
     /**
      * @var ColumnSchema $column
      * @var ColumnSchema $dbColumn
      */
     //Renaming is separate operation
     if ($column->getName() != $dbColumn->getName()) {
         $this->driver->statement("sp_rename ?, ?, 'COLUMN'", [$this->getName() . '.' . $dbColumn->getName(), $column->getName()]);
         $column->setName($dbColumn->getName());
     }
     //In SQLServer we have to drop ALL related indexes and foreign keys while
     //applying type change... yeah...
     $indexesBackup = [];
     $foreignBackup = [];
     foreach ($this->indexes as $index) {
         if (in_array($column->getName(), $index->getColumns())) {
             $indexesBackup[] = $index;
             $this->doIndexDrop($index);
         }
     }
     foreach ($this->references as $foreign) {
         if ($foreign->getColumn() == $column->getName()) {
             $foreignBackup[] = $foreign;
             $this->doForeignDrop($foreign);
         }
     }
     //Column will recreate needed constraints
     foreach ($column->getConstraints() as $constraint) {
         $this->doConstraintDrop($constraint);
     }
     foreach ($column->alterOperations($dbColumn) as $operation) {
         $query = \Spiral\interpolate('ALTER TABLE {table} {operation}', ['table' => $this->getName(true), 'operation' => $operation]);
         $this->driver->statement($query);
     }
     //Recreating indexes
     foreach ($indexesBackup as $index) {
         $this->doIndexAdd($index);
     }
     foreach ($foreignBackup as $foreign) {
         $this->doForeignAdd($foreign);
     }
 }
Exemple #6
0
 /**
  * {@inheritdoc}
  */
 protected function doColumnChange(AbstractColumn $column, AbstractColumn $dbColumn)
 {
     $query = \Spiral\interpolate("ALTER TABLE {table} CHANGE {column} {statement}", ['table' => $this->getName(true), 'column' => $dbColumn->getName(true), 'statement' => $column->sqlStatement()]);
     $this->driver->statement($query);
 }
Exemple #7
0
 /**
  * {@inheritdoc}
  */
 protected function doColumnChange(AbstractColumn $column, AbstractColumn $dbColumn)
 {
     /**
      * @var ColumnSchema $column
      */
     //Rename is separate operation
     if ($column->getName() != $dbColumn->getName()) {
         $this->driver->statement(\Spiral\interpolate('ALTER TABLE {table} RENAME COLUMN {original} TO {column}', ['table' => $this->getName(true), 'column' => $column->getName(true), 'original' => $dbColumn->getName(true)]));
         $column->setName($dbColumn->getName());
     }
     //Postgres columns should be altered using set of operations
     if (!($operations = $column->alterOperations($dbColumn))) {
         return;
     }
     //Postgres columns should be altered using set of operations
     $query = \Spiral\interpolate('ALTER TABLE {table} {operations}', ['table' => $this->getName(true), 'operations' => trim(join(', ', $operations), ', ')]);
     $this->driver->statement($query);
 }
Exemple #8
0
 /**
  * {@inheritdoc}
  */
 protected function prepareDefault()
 {
     $defaultValue = parent::prepareDefault();
     if ($this->abstractType() == 'boolean') {
         $defaultValue = (int) $this->defaultValue;
     }
     return $defaultValue;
 }
 /**
  * Must compare two instances of AbstractColumn.
  *
  * @param self $initial
  * @return bool
  */
 public function compare(self $initial)
 {
     $normalized = clone $initial;
     $normalized->declared = $this->declared;
     if ($this == $normalized) {
         return true;
     }
     $columnVars = get_object_vars($this);
     $dbColumnVars = get_object_vars($normalized);
     $difference = [];
     foreach ($columnVars as $name => $value) {
         if ($name == 'defaultValue') {
             //Default values has to compared using type-casted value
             if ($this->getDefaultValue() != $initial->getDefaultValue()) {
                 $difference[] = $name;
             }
             continue;
         }
         if ($value != $dbColumnVars[$name]) {
             $difference[] = $name;
         }
     }
     return empty($difference);
 }
 /**
  * Generate set of altering operations should be applied to column to change it's type, size,
  * default value or null flag.
  *
  * @param AbstractColumn $original
  * @return array
  */
 public function alteringOperations(AbstractColumn $original)
 {
     $operations = [];
     $typeDefinition = [$this->type, $this->size, $this->precision, $this->scale];
     $originalType = [$original->type, $original->size, $original->precision, $original->scale];
     if ($typeDefinition != $originalType) {
         if ($this->abstractType() == 'enum') {
             //Getting longest value
             $enumSize = $this->size;
             foreach ($this->enumValues as $value) {
                 $enumSize = max($enumSize, strlen($value));
             }
             $type = "ALTER COLUMN {$this->getName(true)} TYPE character({$enumSize})";
             $operations[] = $type;
         } else {
             $type = "ALTER COLUMN {$this->getName(true)} TYPE {$this->type}";
             if (!empty($this->size)) {
                 $type .= "({$this->size})";
             } elseif (!empty($this->precision)) {
                 $type .= "({$this->precision}, {$this->scale})";
             }
             //Required to perform cross conversion
             $operations[] = "{$type} USING {$this->getName(true)}::{$this->type}";
         }
     }
     if ($original->abstractType() == 'enum' && !empty($this->enumConstraint)) {
         $operations[] = 'DROP CONSTRAINT ' . $this->enumConstraint(true);
     }
     if ($original->defaultValue != $this->defaultValue) {
         if (is_null($this->defaultValue)) {
             $operations[] = "ALTER COLUMN {$this->getName(true)} DROP DEFAULT";
         } else {
             $operations[] = "ALTER COLUMN {$this->getName(true)} SET DEFAULT {$this->prepareDefault()}";
         }
     }
     if ($original->nullable != $this->nullable) {
         $operations[] = "ALTER COLUMN {$this->getName(true)} " . (!$this->nullable ? 'SET' : 'DROP') . " NOT NULL";
     }
     if ($this->abstractType() == 'enum') {
         $enumValues = [];
         foreach ($this->enumValues as $value) {
             $enumValues[] = $this->table->driver()->getPDO()->quote($value);
         }
         $operations[] = "ADD CONSTRAINT {$this->enumConstraint(true)} " . "CHECK ({$this->getName(true)} IN (" . join(', ', $enumValues) . "))";
     }
     return $operations;
 }
Exemple #11
0
 /**
  * Driver specific column remove (drop) command.
  *
  * @param AbstractColumn $column
  */
 protected function doColumnDrop(AbstractColumn $column)
 {
     //We have to erase all associated constraints
     foreach ($column->getConstraints() as $constraint) {
         $this->doConstraintDrop($constraint);
     }
     if ($this->hasForeign($column->getName())) {
         $this->doForeignDrop($this->foreign($column->getName()));
     }
     $this->driver->statement("ALTER TABLE {$this->getName(true)} DROP COLUMN {$column->getName(true)}");
 }
 /**
  * Driver specific column remove (drop) command.
  *
  * @param AbstractTable  $table
  * @param AbstractColumn $column
  * @return self
  */
 public function dropColumn(AbstractTable $table, AbstractColumn $column)
 {
     foreach ($column->getConstraints() as $constraint) {
         //We have to erase all associated constraints
         $this->dropConstrain($table, $constraint);
     }
     $this->run("ALTER TABLE {$table->getName(true)} DROP COLUMN {$column->getName(true)}");
     return $this;
 }
 /**
  * Resolve correct abstract type to represent inner or outer key. Primary types will be
  * converted to appropriate sized integers.
  *
  * @param AbstractColumn $column
  * @return string
  */
 protected function resolveAbstract(AbstractColumn $column)
 {
     switch ($column->abstractType()) {
         case 'bigPrimary':
             return 'bigInteger';
         case 'primary':
             return 'integer';
         default:
             //Not primary key
             return $column->abstractType();
     }
 }
 /**
  * {@inheritdoc}
  */
 protected function prepareDefault()
 {
     if ($this->abstractType() == 'timestamp' && is_scalar($this->defaultValue)) {
         if (is_numeric($this->defaultValue)) {
             //Nothing to do
             return (int) $this->defaultValue;
         }
         $datetime = new \DateTime($this->defaultValue, new \DateTimeZone(DatabaseManager::DEFAULT_TIMEZONE));
         return $datetime->getTimestamp();
     }
     return parent::prepareDefault();
 }
 /**
  * Register new column element.
  *
  * @param AbstractColumn $column
  * @return AbstractColumn
  */
 protected function registerColumn(AbstractColumn $column)
 {
     $this->columns[$column->getName()] = $column;
     return $column;
 }