/** * * Alter columns and indexes of a table based on DB_Table column and index * arrays. * * @static * * @access public * * @param object &$db A PEAR DB/MDB2 object. * * @param string $table The table name to connect to in the database. * * @param mixed $column_set A DB_Table $this->col array. * * @param mixed $index_set A DB_Table $this->idx array. * * @return bool|object True if altering was successful or a PEAR_Error on * failure. * */ function alter(&$db, $table, $column_set, $index_set) { $phptype = $db->phptype; if (is_subclass_of($db, 'db_common')) { $backend = 'db'; $reverse =& $db; // workaround for missing index and constraint information methods // in PEAR::DB ==> use adopted code from MDB2's driver classes require_once 'DB/Table/Manager/' . $phptype . '.php'; $classname = 'DB_Table_Manager_' . $phptype; $dbtm =& new $classname(); $dbtm->_db =& $db; // pass database instance to the 'workaround' class $manager =& $dbtm; $table_info_mode = DB_TABLEINFO_FULL; $ok_const = DB_OK; } elseif (is_subclass_of($db, 'mdb2_driver_common')) { $backend = 'mdb2'; $db->loadModule('Reverse'); $manager =& $db->manager; $reverse =& $db->reverse; $table_info_mode = MDB2_TABLEINFO_FULL; $ok_const = MDB2_OK; } // get table info $tableInfo = $reverse->tableInfo($table, $table_info_mode); if (PEAR::isError($tableInfo)) { return $tableInfo; } $tableInfoOrder = array_change_key_case($tableInfo['order'], CASE_LOWER); // emulate MDB2 Reverse extension for PEAR::DB as backend if (is_subclass_of($db, 'db_common')) { $reverse =& $dbtm; } // check (and alter) columns if (is_null($column_set)) { $column_set = array(); } foreach ($column_set as $colname => $val) { $colname = strtolower(trim($colname)); // check the column name $name_check = DB_Table_Manager::_validateColumnName($colname); if (PEAR::isError($name_check)) { return $name_check; } // check the column's existence $column_exists = DB_Table_Manager::_columnExists($colname, $tableInfoOrder, 'alter'); if (PEAR::isError($column_exists)) { return $column_exists; } if ($column_exists === false) { // add the column $definition = DB_Table_Manager::_getColumnDefinition($backend, $phptype, $val); if (PEAR::isError($definition)) { return $definition; } $changes = array('add' => array($colname => $definition)); if (array_key_exists('debug', $GLOBALS['_DB_TABLE'])) { echo "(alter) New table field will be added ({$colname}):\n"; var_dump($changes); echo "\n"; } $result = $manager->alterTable($table, $changes, false); if (PEAR::isError($result)) { return $result; } continue; } // check whether the column type is a known type $type_check = DB_Table_Manager::_validateColumnType($phptype, $val['type']); if (PEAR::isError($type_check)) { return $type_check; } // check whether the column has the right type $type_check = DB_Table_Manager::_checkColumnType($phptype, $colname, $val['type'], $tableInfoOrder, $tableInfo, 'alter'); if (PEAR::isError($type_check)) { return $type_check; } if ($type_check === false) { // change the column type $definition = DB_Table_Manager::_getColumnDefinition($backend, $phptype, $val); if (PEAR::isError($definition)) { return $definition; } $changes = array('change' => array($colname => array('type' => null, 'definition' => $definition))); if (array_key_exists('debug', $GLOBALS['_DB_TABLE'])) { echo "(alter) Table field's type will be changed ({$colname}):\n"; var_dump($changes); echo "\n"; } $result = $manager->alterTable($table, $changes, false); if (PEAR::isError($result)) { return $result; } continue; } } // get information about indexes / constraints $table_indexes = DB_Table_Manager::getIndexes($db, $table); if (PEAR::isError($table_indexes)) { return $table_indexes; } // check (and alter) indexes / constraints if (is_null($index_set)) { $index_set = array(); } foreach ($index_set as $idxname => $val) { list($type, $cols) = DB_Table_Manager::_getIndexTypeAndColumns($val, $idxname); $newIdxName = ''; // check the index definition $index_check = DB_Table_Manager::_validateIndexName($idxname, $table, $phptype, $type, $cols, $column_set, $newIdxName); if (PEAR::isError($index_check)) { return $index_check; } // check whether the index has the right type and has all // specified columns $index_check = DB_Table_Manager::_checkIndex($idxname, $newIdxName, $type, $cols, $table_indexes, 'alter'); if (PEAR::isError($index_check)) { return $index_check; } if ($index_check === false) { // (1) drop wrong index/constraint // (2) add right index/constraint if ($backend == 'mdb2') { // save user defined 'idxname_format' option $idxname_format = $db->getOption('idxname_format'); $db->setOption('idxname_format', '%s'); } // drop index/constraint only if it exists foreach (array('normal', 'unique', 'primary') as $idx_type) { if (array_key_exists(strtolower($newIdxName), $table_indexes[$idx_type])) { if (array_key_exists('debug', $GLOBALS['_DB_TABLE'])) { echo "(alter) Index/constraint will be deleted (name: '{$newIdxName}', type: '{$idx_type}').\n"; } if ($idx_type == 'normal') { $result = $manager->dropIndex($table, $newIdxName); } else { $result = $manager->dropConstraint($table, $newIdxName); } if (PEAR::isError($result)) { if ($backend == 'mdb2') { // restore user defined 'idxname_format' option $db->setOption('idxname_format', $idxname_format); } return $result; } break; } } // prepare index/constraint definition $indexes = array(); if ($backend == 'mdb2') { // array with column names as keys $idx_cols = array(); foreach ($cols as $col) { $idx_cols[$col] = array(); } switch ($type) { case 'primary': $indexes['primary'][$newIdxName] = array('fields' => $idx_cols, 'primary' => true); break; case 'unique': $indexes['unique'][$newIdxName] = array('fields' => $idx_cols, 'unique' => true); break; case 'normal': $indexes['normal'][$newIdxName] = array('fields' => $idx_cols); break; } } else { $indexes[] = DB_Table_Manager::getDeclareForIndex($phptype, $type, $newIdxName, $table, $cols); } // create index/constraint if (array_key_exists('debug', $GLOBALS['_DB_TABLE'])) { echo "(alter) New index/constraint will be created (name: '{$newIdxName}', type: '{$type}'):\n"; var_dump($indexes); echo "\n"; } $result = DB_Table_Manager::_createIndexesAndContraints($db, $backend, $table, $indexes); if ($backend == 'mdb2') { // restore user defined 'idxname_format' option $db->setOption('idxname_format', $idxname_format); } if (PEAR::isError($result)) { return $result; } continue; } } return true; }