public function alterColumn($name, $attrib, $value)
    {
        $this->requireColumn($name);

        // Derive new column specification from existing one
        $newColumns = $this->_columns;
        if ($attrib === null) {
            unset($newColumns[$name]);
        } else {
            $newColumn = $newColumns[$name]->toArray();
            $newColumn[$attrib] = $value;
            $newColumns[$name] = $this->_database->createColumnFromArray($newColumn);
        }

        // Preserve PK
        // TODO preserve other constraints
        $pkColumns = array();
        if ($this->_primaryKey) {
            foreach ($this->_primaryKey as $column) {
                if ($name == $column->getName()) {
                    if ($attrib === null) {
                        // Skip column about to be deleted
                        continue;
                    } elseif ($attrib == 'name') {
                        // Use new column name for PK
                        $pkColumns[] = $value;
                        continue;
                    }
                }
                $pkColumns[] = $column->getName();
            }
        }

        // Start exclusive operations
        $savepoint = uniqid(__FUNCTION__);
        $this->_database->exec('SAVEPOINT ' . $savepoint);
        $this->_database->exec('PRAGMA locking_mode = EXCLUSIVE');

        $tmpTableName = $this->_renameToTmp();

        // Create table with new column specifications
        $this->_database->clearCache($this->_name);
        $this->_database->createTable($this->_name, $newColumns, $pkColumns);

        // Copy data from old table
        $columnsOld = array();
        $columnsNew = array();
        foreach ($newColumns as $column) {
            if ($attrib == 'name' and $column->getName() == $value) {
                // Special treatment for renamed columns
                $columnsOld[] = $this->_database->prepareIdentifier($name);
                $columnsNew[] = $this->_database->prepareIdentifier($value);
            } else {
                $columnsOld[] = $this->_database->prepareIdentifier($column->getName());
                $columnsNew[] = $this->_database->prepareIdentifier($column->getName());
            }
        }
        $columnsOld = implode (', ', $columnsOld);
        $columnsNew = implode (', ', $columnsNew);
        $tableName = $this->_database->prepareIdentifier($this->_name);
        $this->_database->exec(
            "INSERT INTO $tableName ($columnsNew) SELECT $columnsOld FROM $tmpTableName"
        );

        // Clean up
        $this->_database->exec("DROP TABLE $tmpTableName");
        $this->_database->exec('PRAGMA locking_mode = NORMAL');
        $this->_database->exec('RELEASE ' . $savepoint);

        // Update column cache (update keys as well in case of renamed columns)
        $this->_columns = array();
        foreach ($newColumns as $column) {
            $this->_columns[$column->getName()] = $column;
        }
    }
public function alterColumn($name, $attrib, $value)
    {
        $this->requireColumn($name);

        // Derive new column specification from existing one
        $newColumns = $this->_columns;
        if ($attrib === null) {
            unset($newColumns[$name]);
        } else {
            $newColumn = $newColumns[$name]->toArray();
            $newColumn[$attrib] = $value;
            $newColumns[$name] = $this->_database->createColumnFromArray($newColumn);
        }

        // Preserve PK
        // TODO preserve other constraints
        $pkColumns = array();
        if ($this->_primaryKey) {
            foreach ($this->_primaryKey as $column) {
                if ($name == $column->getName()) {
                    if ($attrib === null) {
                        // Skip column about to be deleted
                        continue;
                    } elseif ($attrib == 'name') {
                        // Use new column name for PK
                        $pkColumns[] = $value;
                        continue;
                    }
                }
                $pkColumns[] = $column->getName();
            }
        }

        // Start exclusive operations
        $savepoint = uniqid(__FUNCTION__);
        $this->_database->exec('SAVEPOINT ' . $savepoint);
        $this->_database->exec('PRAGMA locking_mode = EXCLUSIVE');

        $tmpTableName = $this->_renameToTmp();

        // Create table with new column specifications
        $this->_database->clearCache($this->_name);
        $this->_database->createTable($this->_name, $newColumns, $pkColumns);

        // Copy data from old table
        $columnsOld = array();
        $columnsNew = array();
        foreach ($newColumns as $column) {
            if ($attrib == 'name' and $column->getName() == $value) {
                // Special treatment for renamed columns
                $columnsOld[] = $this->_database->prepareIdentifier($name);
                $columnsNew[] = $this->_database->prepareIdentifier($value);
            } else {
                $columnsOld[] = $this->_database->prepareIdentifier($column->getName());
                $columnsNew[] = $this->_database->prepareIdentifier($column->getName());
            }
        }
        $columnsOld = implode (', ', $columnsOld);
        $columnsNew = implode (', ', $columnsNew);
        $tableName = $this->_database->prepareIdentifier($this->_name);
        $this->_database->exec(
            "INSERT INTO $tableName ($columnsNew) SELECT $columnsOld FROM $tmpTableName"
        );

        // Clean up
        $this->_database->exec("DROP TABLE $tmpTableName");
        $this->_database->exec('PRAGMA locking_mode = NORMAL');
        $this->_database->exec('RELEASE ' . $savepoint);

        // Update column cache (update keys as well in case of renamed columns)
        $this->_columns = array();
        foreach ($newColumns as $column) {
            $this->_columns[$column->getName()] = $column;
        }
    }
public function alterColumn ( $ name , $ attrib , $ value ) { $ this -> requireColumn ( $ name ) ; // Derive new column specification from existing one $ newColumns = $ this -> _columns ; if ( $ attrib === null ) { unset ( $ newColumns [ $ name ] ) ; } else { $ newColumn = $ newColumns [ $ name ] -> toArray ( ) ; $ newColumn [ $ attrib ] = $ value ; $ newColumns [ $ name ] = $ this -> _database -> createColumnFromArray ( $ newColumn ) ; } // Preserve PK // TODO preserve other constraints $ pkColumns = array ( ) ; if ( $ this -> _primaryKey ) { foreach ( $ this -> _primaryKey as $ column ) { if ( $ name == $ column -> getName ( ) ) { if ( $ attrib === null ) { // Skip column about to be deleted continue ; } elseif ( $ attrib == 'name' ) { // Use new column name for PK $ pkColumns [ ] = $ value ; continue ; } } $ pkColumns [ ] = $ column -> getName ( ) ; } } // Start exclusive operations $ savepoint = uniqid ( __FUNCTION__ ) ; $ this -> _database -> exec ( 'SAVEPOINT ' . $ savepoint ) ; $ this -> _database -> exec ( 'PRAGMA locking_mode = EXCLUSIVE' ) ; $ tmpTableName = $ this -> _renameToTmp ( ) ; // Create table with new column specifications $ this -> _database -> clearCache ( $ this -> _name ) ; $ this -> _database -> createTable ( $ this -> _name , $ newColumns , $ pkColumns ) ; // Copy data from old table $ columnsOld = array ( ) ; $ columnsNew = array ( ) ; foreach ( $ newColumns as $ column ) { if ( $ attrib == 'name' and $ column -> getName ( ) == $ value ) { // Special treatment for renamed columns $ columnsOld [ ] = $ this -> _database -> prepareIdentifier ( $ name ) ; $ columnsNew [ ] = $ this -> _database -> prepareIdentifier ( $ value ) ; } else { $ columnsOld [ ] = $ this -> _database -> prepareIdentifier ( $ column -> getName ( ) ) ; $ columnsNew [ ] = $ this -> _database -> prepareIdentifier ( $ column -> getName ( ) ) ; } } $ columnsOld = implode ( ', ' , $ columnsOld ) ; $ columnsNew = implode ( ', ' , $ columnsNew ) ; $ tableName = $ this -> _database -> prepareIdentifier ( $ this -> _name ) ; $ this -> _database -> exec ( "INSERT INTO $tableName ($columnsNew) SELECT $columnsOld FROM $tmpTableName" ) ; // Clean up $ this -> _database -> exec ( "DROP TABLE $tmpTableName" ) ; $ this -> _database -> exec ( 'PRAGMA locking_mode = NORMAL' ) ; $ this -> _database -> exec ( 'RELEASE ' . $ savepoint ) ; // Update column cache (update keys as well in case of renamed columns) $ this -> _columns = array ( ) ; foreach ( $ newColumns as $ column ) { $ this -> _columns [ $ column -> getName ( ) ] = $ column ; } }
Internal method to alter a column

Since SQLite's ALTER TABLE statement only supports renaming tables and
adding columns, this method does everything else:

1. The table is renamed to a unique temporary name.
2. A new table with the original name and altered columns is created.
3. Data is copied to the new table.
4. The old table is dropped.

NOTE: Primary keys are preserved, but all other contraints are lost for
every column in this table, not just for the altered one.

@param string $name Column to be altered
@param string $attrib Attribute to be altered or NULL for dropping the column
@param mixed $value New value for altered attibute
@internal
Internal method to alter a column