class Schema
{
- static $_single = null;
+ static $_static = null;
protected $conn = null;
/**
* Constructor. Only run once for singleton object.
*/
- protected function __construct()
+ protected function __construct($conn = null)
{
- // XXX: there should be an easier way to do this.
- $user = new User();
-
- $this->conn = $user->getDatabaseConnection();
-
- $user->free();
+ if (is_null($conn)) {
+ // XXX: there should be an easier way to do this.
+ $user = new User();
+ $conn = $user->getDatabaseConnection();
+ $user->free();
+ unset($user);
+ }
- unset($user);
+ $this->conn = $conn;
}
/**
* Main public entry point. Use this to get
- * the singleton object.
+ * the schema object.
*
- * @return Schema the (single) Schema object
+ * @return Schema the Schema object for the connection
*/
- static function get()
+ static function get($conn = null)
{
- if (empty(self::$_single)) {
- self::$_single = new Schema();
+ if (is_null($conn)) {
+ $key = 'default';
+ } else {
+ $key = md5(serialize($conn->dsn));
}
- return self::$_single;
- }
-
- /**
- * Returns a TableDef object for the table
- * in the schema with the given name.
- *
- * Throws an exception if the table is not found.
- *
- * @param string $name Name of the table to get
- *
- * @return TableDef tabledef for that table.
- */
-
- public function getTableDef($name)
- {
- $res =& $this->conn->query('DESCRIBE ' . $name);
-
- if (PEAR::isError($res)) {
- throw new Exception($res->getMessage());
+
+ $type = common_config('db', 'type');
+ if (empty(self::$_static[$key])) {
+ $schemaClass = ucfirst($type).'Schema';
+ self::$_static[$key] = new $schemaClass($conn);
}
-
- $td = new TableDef();
-
- $td->name = $name;
- $td->columns = array();
-
- $row = array();
-
- while ($res->fetchInto($row, DB_FETCHMODE_ASSOC)) {
-
- $cd = new ColumnDef();
-
- $cd->name = $row['Field'];
-
- $packed = $row['Type'];
-
- if (preg_match('/^(\w+)\((\d+)\)$/', $packed, $match)) {
- $cd->type = $match[1];
- $cd->size = $match[2];
- } else {
- $cd->type = $packed;
- }
-
- $cd->nullable = ($row['Null'] == 'YES') ? true : false;
- $cd->key = $row['Key'];
- $cd->default = $row['Default'];
- $cd->extra = $row['Extra'];
-
- $td->columns[] = $cd;
- }
-
- return $td;
+ return self::$_static[$key];
}
/**
$sql .= "); ";
- $res =& $this->conn->query($sql);
+ $res = $this->conn->query($sql);
if (PEAR::isError($res)) {
throw new Exception($res->getMessage());
public function dropTable($name)
{
- $res =& $this->conn->query("DROP TABLE $name");
+ $res = $this->conn->query("DROP TABLE $name");
if (PEAR::isError($res)) {
throw new Exception($res->getMessage());
$name = "$table_".implode("_", $columnNames)."_idx";
}
- $res =& $this->conn->query("ALTER TABLE $table ".
+ $res = $this->conn->query("ALTER TABLE $table ".
"ADD INDEX $name (".
implode(",", $columnNames).")");
public function dropIndex($table, $name)
{
- $res =& $this->conn->query("ALTER TABLE $table DROP INDEX $name");
+ $res = $this->conn->query("ALTER TABLE $table DROP INDEX $name");
if (PEAR::isError($res)) {
throw new Exception($res->getMessage());
{
$sql = "ALTER TABLE $table ADD COLUMN " . $this->_columnSql($columndef);
- $res =& $this->conn->query($sql);
+ $res = $this->conn->query($sql);
if (PEAR::isError($res)) {
throw new Exception($res->getMessage());
$sql = "ALTER TABLE $table MODIFY COLUMN " .
$this->_columnSql($columndef);
- $res =& $this->conn->query($sql);
+ $res = $this->conn->query($sql);
if (PEAR::isError($res)) {
throw new Exception($res->getMessage());
{
$sql = "ALTER TABLE $table DROP COLUMN $columnName";
- $res =& $this->conn->query($sql);
+ $res = $this->conn->query($sql);
if (PEAR::isError($res)) {
throw new Exception($res->getMessage());
$sql = 'ALTER TABLE ' . $tableName . ' ' . implode(', ', $phrase);
- $res =& $this->conn->query($sql);
+ $res = $this->conn->query($sql);
if (PEAR::isError($res)) {
throw new Exception($res->getMessage());
$sql .= ($cd->nullable) ? "null " : "not null ";
}
+ if (!empty($cd->auto_increment)) {
+ $sql .= " auto_increment ";
+ }
+
+ if (!empty($cd->extra)) {
+ $sql .= "{$cd->extra} ";
+ }
+
return $sql;
}
}
-/**
- * A class encapsulating the structure of a table.
- *
- * @category Database
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- */
-
-class TableDef
+class SchemaTableMissingException extends Exception
{
- /** name of the table */
- public $name;
- /** array of ColumnDef objects for the columns. */
- public $columns;
+ // no-op
}
-/**
- * A class encapsulating the structure of a column in a table.
- *
- * @category Database
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- */
-
-class ColumnDef
-{
- /** name of the column. */
- public $name;
- /** type of column, e.g. 'int', 'varchar' */
- public $type;
- /** size of the column. */
- public $size;
- /** boolean flag; can it be null? */
- public $nullable;
- /**
- * type of key: null = no key; 'PRI' => primary;
- * 'UNI' => unique key; 'MUL' => multiple values.
- */
- public $key;
- /** default value if any. */
- public $default;
- /** 'extra' stuff. Returned by MySQL, largely
- * unused. */
- public $extra;
-
- /**
- * Constructor.
- *
- * @param string $name name of the column
- * @param string $type type of the column
- * @param int $size size of the column
- * @param boolean $nullable can this be null?
- * @param string $key type of key
- * @param value $default default value
- * @param value $extra unused
- */
-
- function __construct($name=null, $type=null, $size=null,
- $nullable=true, $key=null, $default=null,
- $extra=null)
- {
- $this->name = strtolower($name);
- $this->type = strtolower($type);
- $this->size = $size+0;
- $this->nullable = $nullable;
- $this->key = $key;
- $this->default = $default;
- $this->extra = $extra;
- }
-
- /**
- * Compares this columndef with another to see
- * if they're functionally equivalent.
- *
- * @param ColumnDef $other column to compare
- *
- * @return boolean true if equivalent, otherwise false.
- */
-
- function equals($other)
- {
- return ($this->name == $other->name &&
- $this->_typeMatch($other) &&
- $this->_defaultMatch($other) &&
- $this->_nullMatch($other) &&
- $this->key == $other->key);
- }
-
- /**
- * Does the type of this column match the
- * type of the other column?
- *
- * Checks the type and size of a column. Tries
- * to ignore differences between synonymous
- * data types, like 'integer' and 'int'.
- *
- * @param ColumnDef $other other column to check
- *
- * @return boolean true if they're about equivalent
- */
-
- private function _typeMatch($other)
- {
- switch ($this->type) {
- case 'integer':
- case 'int':
- return ($other->type == 'integer' ||
- $other->type == 'int');
- break;
- default:
- return ($this->type == $other->type &&
- $this->size == $other->size);
- }
- }
-
- /**
- * Does the default behaviour of this column match
- * the other?
- *
- * @param ColumnDef $other other column to check
- *
- * @return boolean true if defaults are effectively the same.
- */
-
- private function _defaultMatch($other)
- {
- return ((is_null($this->default) && is_null($other->default)) ||
- ($this->default == $other->default));
- }
-
- /**
- * Does the null behaviour of this column match
- * the other?
- *
- * @param ColumnDef $other other column to check
- *
- * @return boolean true if these columns 'null' the same.
- */
-
- private function _nullMatch($other)
- {
- return ((!is_null($this->default) && !is_null($other->default) &&
- $this->default == $other->default) ||
- ($this->nullable == $other->nullable));
- }
-}