pkrenn: Fixing database issues (wrong DB connections, logical errors) (merged from branches/gsoc)

git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/sapphire/trunk@41712 467b73ca-7a2a-4603-9d3b-597d59a354a9
This commit is contained in:
Ingo Schommer 2007-09-14 01:44:34 +00:00
parent b29cc1fbc7
commit f912a33b63
3 changed files with 74 additions and 51 deletions

View File

@ -74,7 +74,7 @@ abstract class Database extends Object {
/** /**
* Alter a table's schema. * Alter a table's schema.
*/ */
abstract function alterTable($table, $newFields, $newIndexes, $alteredFields, $alteredIndexes); abstract function alterTable($table, $newFields = null, $newIndexes = null, $alteredFields = null, $alteredIndexes = null);
/** /**
* Rename a table. * Rename a table.

View File

@ -78,6 +78,14 @@ class MySQLDatabase extends Database {
return $this->mysqlVersion; return $this->mysqlVersion;
} }
/**
* Get the database server, namely mysql.
* @return string
*/
public function getDatabaseServer() {
return "mysql";
}
public function query($sql, $errorLevel = E_USER_ERROR) { public function query($sql, $errorLevel = E_USER_ERROR) {
if(isset($_REQUEST['previewwrite']) && in_array(strtolower(substr($sql,0,strpos($sql,' '))), array('insert','update','delete','replace'))) { if(isset($_REQUEST['previewwrite']) && in_array(strtolower(substr($sql,0,strpos($sql,' '))), array('insert','update','delete','replace'))) {
echo "<p>Will execute: $sql</p>"; echo "<p>Will execute: $sql</p>";
@ -185,7 +193,7 @@ class MySQLDatabase extends Database {
* @param $alteredFields Updated fields, a map of field name => field schema * @param $alteredFields Updated fields, a map of field name => field schema
* @param $alteredIndexes Updated indexes, a map of index name => index type * @param $alteredIndexes Updated indexes, a map of index name => index type
*/ */
public function alterTable($tableName, $newFields, $newIndexes, $alteredFields, $alteredIndexes) { public function alterTable($tableName, $newFields = null, $newIndexes = null, $alteredFields = null, $alteredIndexes = null) {
$fieldSchemas = $indexSchemas = ""; $fieldSchemas = $indexSchemas = "";
if($newFields) foreach($newFields as $k => $v) $alterList[] .= "ADD `$k` $v"; if($newFields) foreach($newFields as $k => $v) $alterList[] .= "ADD `$k` $v";

View File

@ -47,13 +47,15 @@ class PDODatabase extends Database {
* <li>database: The database to connect to</li></ul> * <li>database: The database to connect to</li></ul>
*/ */
public function __construct($parameters) { public function __construct($parameters) {
$connect = PDODatabase::getConnect($parameters); $connect = self::getConnect($parameters);
$connectWithDB = $connect . ';dbname=' . $parameters['database']; $connectWithDB = $connect . ';dbname=' . $parameters['database'];
try { // Try connect to the database, if it does not exist, create it try { // Try connect to the database, if it does not exist, create it
$this->dbConn = new PDO($connectWithDB, $parameters['username'], $parameters['password']); $this->dbConn = new PDO($connectWithDB, $parameters['username'], $parameters['password']);
} catch (PDOException $e) { } catch (PDOException $e) {
if (!self::createDatabase($connect, $parameters['username'], $parameters['password'], $parameters['database'])) { if (!self::createDatabase($connect, $parameters['username'], $parameters['password'], $parameters['database'])) {
$this->databaseError("Could not connect to the database, make sure the server is available and user credentials are correct"); $this->databaseError("Could not connect to the database, make sure the server is available and user credentials are correct");
} else {
$this->dbConn = new PDO($connectWithDB, $parameters['username'], $parameters['password']); // After creating the database, connect to it
} }
} }
parent::__construct(); parent::__construct();
@ -100,13 +102,13 @@ class PDODatabase extends Database {
*/ */
public function supportsCollations() { public function supportsCollations() {
$collations = false; $collations = false;
switch (PDO::ATTR_DRIVER_NAME) { switch (self::getDatabaseServer()) {
case "pgsql": // Generally supported in PostgreSQL (supported versions) case "pgsql": // Generally supported in PostgreSQL (supported versions), but handled differently than in MySQL, so do not set
case "mssql": // Generally supported in MS SQL (supported versions) case "mssql": // Generally supported in MS SQL (supported versions), but handled differently than in MySQL, so do not set
$collations = true; $collations = false;
break; break;
case "mysql": case "mysql":
if ($this->getVersion() >= 4.1) { // Supported in MySQL since 4.1 if (self::getVersion() >= 4.1) { // Supported in MySQL since 4.1
$collations = true; $collations = true;
} }
break; break;
@ -119,7 +121,7 @@ class PDODatabase extends Database {
* @return float * @return float
*/ */
public function getVersion() { public function getVersion() {
switch (PDO::ATTR_DRIVER_NAME) { switch (self::getDatabaseServer()) {
case "mysql": case "mysql":
case "pgsql": case "pgsql":
$query = "SELECT VERSION()"; $query = "SELECT VERSION()";
@ -128,13 +130,21 @@ class PDODatabase extends Database {
$query = "SELECT @@VERSION"; $query = "SELECT @@VERSION";
break; break;
} }
$stmt = $dbConn->prepare($query); $stmt = $this->dbConn->prepare($query);
$stmt->execute(); $stmt->execute();
$dbVersion = $stmt->fetchColumn(); $dbVersion = $stmt->fetchColumn();
$version = ereg_replace("([A-Za-z-])", "", $dbVersion); $version = ereg_replace("([A-Za-z-])", "", $dbVersion);
return substr(trim($version), 0, 3); // Just get the major and minor version return substr(trim($version), 0, 3); // Just get the major and minor version
} }
/**
* Get the database server, namely mysql, pgsql, or mssql.
* @return string
*/
public function getDatabaseServer() {
return $this->dbConn->getAttribute(PDO::ATTR_DRIVER_NAME);
}
/** /**
* Query the database. * Query the database.
* @var string $sql The query to be issued to the database. * @var string $sql The query to be issued to the database.
@ -152,6 +162,8 @@ class PDODatabase extends Database {
} }
$stmt = $dbConn->prepare($sql); $stmt = $dbConn->prepare($sql);
$stmt = $this->dbConn->prepare($sql);
$handle = $stmt->execute(); // Execute and save the return value (true or false) $handle = $stmt->execute(); // Execute and save the return value (true or false)
if(isset($_REQUEST['showqueries'])) { if(isset($_REQUEST['showqueries'])) {
@ -163,7 +175,7 @@ class PDODatabase extends Database {
$error = $stmt->errorInfo(); $error = $stmt->errorInfo();
$this->databaseError("Couldn't run query: $sql | " . $error[2], $errorLevel); $this->databaseError("Couldn't run query: $sql | " . $error[2], $errorLevel);
} }
return new PDOQuery($stmt); return new PDOQuery($this, $stmt);
} }
/** /**
@ -173,7 +185,7 @@ class PDODatabase extends Database {
* @return int * @return int
*/ */
public function getGeneratedID($table) { public function getGeneratedID($table) {
$stmt = $dbConn->prepare("SELECT MAX(ID) FROM $table"); $stmt = $this->dbConn->prepare("SELECT MAX(ID) FROM $table");
$handle = $stmt->execute(); $handle = $stmt->execute();
$result = $stmt->fetchColumn(); $result = $stmt->fetchColumn();
return $handle ? $result : 0; return $handle ? $result : 0;
@ -187,7 +199,7 @@ class PDODatabase extends Database {
*/ */
public function getNextID($table) { public function getNextID($table) {
user_error('getNextID is OBSOLETE (and will no longer work properly)', E_USER_WARNING); user_error('getNextID is OBSOLETE (and will no longer work properly)', E_USER_WARNING);
$stmt = $dbConn->prepare("SELECT MAX(ID)+1 FROM $table"); $stmt = $this->dbConn->prepare("SELECT MAX(ID)+1 FROM $table");
$handle = $stmt->execute(); $handle = $stmt->execute();
$result = $stmt->fetchColumn(); $result = $stmt->fetchColumn();
return $handle ? $result : 1; return $handle ? $result : 1;
@ -213,8 +225,8 @@ class PDODatabase extends Database {
*/ */
public function createDatabase($connect, $username, $password, $database) { public function createDatabase($connect, $username, $password, $database) {
try { try {
$dbConn = new PDO($connect, $username, $password); $dbh = new PDO($connect, $username, $password);
$stmt = $dbConn->prepare("CREATE DATABASE $database"); $stmt = $dbh->prepare("CREATE DATABASE $database");
$stmt->execute(); $stmt->execute();
$this->active = true; $this->active = true;
} catch (PDOException $e) { } catch (PDOException $e) {
@ -236,15 +248,15 @@ class PDODatabase extends Database {
switch ($parameters['type']) { switch ($parameters['type']) {
switch (PDO::ATTR_DRIVER_NAME) { switch (self::getDatabaseServer()) {
case "mysql": case "mysql":
$stmt = $dbConn->prepare("CREATE TABLE $tableName (ID INT(11) NOT NULL AUTO_INCREMENT, $fieldSchemas PRIMARY KEY (ID)) TYPE=MyISAM"); $stmt = $this->dbConn->prepare("CREATE TABLE $tableName (ID INT(11) NOT NULL AUTO_INCREMENT, $fieldSchemas PRIMARY KEY (ID)) TYPE=MyISAM");
break; break;
case "pgsql": case "pgsql":
$stmt = $dbConn->prepare("CREATE TABLE $tableName (ID SERIAL, $fieldSchemas PRIMARY KEY (ID))"); $stmt = $this->dbConn->prepare("CREATE TABLE $tableName (ID SERIAL, $fieldSchemas PRIMARY KEY (ID))");
break; break;
case "mssql": case "mssql":
$stmt = $dbConn->prepare("CREATE TABLE $tableName (ID INT(11) IDENTITY(1,1), $fieldSchemas PRIMARY KEY (ID))"); $stmt = $this->dbConn->prepare("CREATE TABLE $tableName (ID INT(11) IDENTITY(1,1), $fieldSchemas PRIMARY KEY (ID))");
break; break;
default: default:
$this->databaseError("This database server is not available"); $this->databaseError("This database server is not available");
@ -252,7 +264,7 @@ class PDODatabase extends Database {
$stmt->execute(); $stmt->execute();
if ($indexes) { if ($indexes) {
alterTable($tableName, null, $indexes, null, null); self::alterTable($tableName, null, $indexes, null, null);
} }
} }
@ -265,32 +277,32 @@ class PDODatabase extends Database {
* @var string $alteredIndexes Indexes to change. * @var string $alteredIndexes Indexes to change.
* @return void. * @return void.
*/ */
public function alterTable($table, $newFields, $newIndexes, $alteredFields, $alteredIndexes) { public function alterTable($table, $newFields = null, $newIndexes = null, $alteredFields = null, $alteredIndexes = null) {
if ($newFields) { if ($newFields) {
foreach ($newFields as $field => $type) { foreach ($newFields as $field => $type) {
$stmt = $dbConn->prepare("ALTER TABLE $table ADD $field $type"); $stmt = $this->dbConn->prepare("ALTER TABLE $table ADD $field $type");
$stmt->execute(); $stmt->execute();
} }
} }
if ($newIndexes) { if ($newIndexes) {
foreach ($newIndexes as $name => $column) { foreach ($newIndexes as $name => $column) {
$stmt = $dbConn->prepare("CREATE INDEX $name ON $table $column"); $stmt = $this->dbConn->prepare("CREATE INDEX $name ON $table $column");
$stmt->execute(); $stmt->execute();
} }
} }
if ($alteredFields) { if ($alteredFields) {
foreach ($alteredFields as $field => $type) { foreach ($alteredFields as $field => $type) {
alterField($table, $field, $type) self::alterField($table, $field, $type);
} }
} }
if ($alteredIndexes) { if ($alteredIndexes) {
foreach ($newIndexes as $name => $column) { foreach ($newIndexes as $name => $column) {
$dbConn->query("DROP INDEX $name"); $this->dbConn->query("DROP INDEX $name");
$stmt = $dbConn->prepare("CREATE INDEX $name ON $table $column"); $stmt = $this->dbConn->prepare("CREATE INDEX $name ON $table $column");
$stmt->execute(); $stmt->execute();
} }
} }
@ -303,7 +315,7 @@ class PDODatabase extends Database {
* @return void. * @return void.
*/ */
public function renameTable($oldTableName, $newTableName) { public function renameTable($oldTableName, $newTableName) {
$stmt = $dbConn->prepare("ALTER TABLE $oldTableName RENAME TO $newTableName"); $stmt = $this->dbConn->prepare("ALTER TABLE $oldTableName RENAME TO $newTableName");
$stmt->execute(); $stmt->execute();
} }
@ -334,7 +346,7 @@ class PDODatabase extends Database {
* @return boolean Returns if the query returns a successful result. * @return boolean Returns if the query returns a successful result.
*/ */
protected function runTableCheckCommand($sql) { protected function runTableCheckCommand($sql) {
foreach($dbConn->query($sql) as $testRecord) { foreach($this->dbConn->query($sql) as $testRecord) {
if(strtolower($testRecord['Msg_text']) != 'ok') { if(strtolower($testRecord['Msg_text']) != 'ok') {
return false; return false;
} }
@ -350,7 +362,7 @@ class PDODatabase extends Database {
* @return void * @return void
*/ */
public function createField($tableName, $fieldName, $fieldSpec) { public function createField($tableName, $fieldName, $fieldSpec) {
$stmt = $dbConn->prepare("ALTER TABLE $tableName ADD $fieldName $fieldSpec"); $stmt = $this->dbConn->prepare("ALTER TABLE $tableName ADD $fieldName $fieldSpec");
$stmt->execute(); $stmt->execute();
} }
@ -362,12 +374,12 @@ class PDODatabase extends Database {
* @return void * @return void
*/ */
public function alterField($table, $field, $type) { public function alterField($table, $field, $type) {
switch (PDO::ATTR_DRIVER_NAME) { switch (self::getDatabaseServer()) {
case "mysql": case "mysql":
$stmt = $dbConn->prepare("ALTER TABLE $table CHANGE $field $field $type"); $stmt = $this->dbConn->prepare("ALTER TABLE $table CHANGE $field $field $type");
break; break;
case "pgsql": case "pgsql":
$stmt = $dbConn->prepare(" $stmt = $this->dbConn->prepare("
BEGIN; BEGIN;
ALTER TABLE $table RENAME $field TO oldfield; ALTER TABLE $table RENAME $field TO oldfield;
ALTER TABLE $table ADD COLUMN $field $type; ALTER TABLE $table ADD COLUMN $field $type;
@ -377,7 +389,7 @@ class PDODatabase extends Database {
"); ");
break; break;
case "mssql": case "mssql":
$stmt = $dbConn->prepare("ALTER TABLE $table ALTER COLUMN $field $type"); $stmt = $this->dbConn->prepare("ALTER TABLE $table ALTER COLUMN $field $type");
break; break;
default: default:
$this->databaseError("This database server is not available"); $this->databaseError("This database server is not available");
@ -393,7 +405,7 @@ class PDODatabase extends Database {
* @return void * @return void
*/ */
public function createIndex($tableName, $indexName, $indexSpec) { public function createIndex($tableName, $indexName, $indexSpec) {
$stmt = $dbConn->prepare("CREATE INDEX $indexName ON $tableName $indexSpec"); $stmt = $this->dbConn->prepare("CREATE INDEX $indexName ON $tableName $indexSpec");
$stmt->execute(); $stmt->execute();
} }
@ -405,8 +417,8 @@ class PDODatabase extends Database {
* @return void * @return void
*/ */
public function alterIndex($tableName, $indexName, $indexSpec) { public function alterIndex($tableName, $indexName, $indexSpec) {
$dbConn->query("DROP INDEX $indexName"); $this->dbConn->query("DROP INDEX $indexName");
$stmt = $dbConn->prepare("CREATE INDEX $indexName ON $tableName $indexSpec"); $stmt = $this->dbConn->prepare("CREATE INDEX $indexName ON $tableName $indexSpec");
$stmt->execute(); $stmt->execute();
} }
@ -418,15 +430,15 @@ class PDODatabase extends Database {
* Returns a map of field name => field spec. * Returns a map of field name => field spec.
*/ */
public function fieldList($table) { public function fieldList($table) {
switch (PDO::ATTR_DRIVER_NAME) { switch (self::getDatabaseServer()) {
case "mysql": case "mysql":
foreach ($dbConn->query("SHOW FULL FIELDS IN $table") as $field) { foreach ($this->dbConn->query("SHOW FULL FIELDS IN $table") as $field) {
$fieldSpec = $field['Type']; $fieldSpec = $field['Type'];
if(!$field['Null'] || $field['Null'] == 'NO') { if(!$field['Null'] || $field['Null'] == 'NO') {
$fieldSpec .= ' not null'; $fieldSpec .= ' not null';
} }
if($field['Collation'] && $field['Collation'] != 'NULL') { if($field['Collation'] && $field['Collation'] != 'NULL') {
$values = $dbh->prepare("SHOW COLLATION LIKE '$field[Collation]'"); $values = $this->dbConn->prepare("SHOW COLLATION LIKE '$field[Collation]'");
$values->execute(); $values->execute();
$collInfo = $values->fetchColumn(); $collInfo = $values->fetchColumn();
$fieldSpec .= " character set $collInfo[Charset] collate $field[Collation]"; $fieldSpec .= " character set $collInfo[Charset] collate $field[Collation]";
@ -439,7 +451,7 @@ class PDODatabase extends Database {
} }
break; break;
case "pgsql": case "pgsql":
foreach ($dbh->query(" foreach ($this->dbConn->query("
SELECT SELECT
column_name AS cname, column_name AS cname,
column_default AS cdefault, column_default AS cdefault,
@ -466,7 +478,7 @@ class PDODatabase extends Database {
} }
break; break;
case "mssql": case "mssql":
foreach ($dbh->query(" foreach ($this->dbConn->query("
SELECT SELECT
COLUMN_NAME AS 'cname', COLUMN_NAME AS 'cname',
COLUMN_DEFAULT AS 'cdefault', COLUMN_DEFAULT AS 'cdefault',
@ -513,9 +525,9 @@ class PDODatabase extends Database {
* Returns a map of indexes. * Returns a map of indexes.
*/ */
public function indexList($table) { public function indexList($table) {
switch (PDO::ATTR_DRIVER_NAME) { switch (self::getDatabaseServer()) {
case "mysql": case "mysql":
foreach($dbh->query("SHOW INDEXES IN '$table'") as $index) { foreach($this->dbConn->query("SHOW INDEXES IN '$table'") as $index) {
$groupedIndexes[$index['Key_name']]['fields'][$index['Seq_in_index']] = $index['Column_name']; $groupedIndexes[$index['Key_name']]['fields'][$index['Seq_in_index']] = $index['Column_name'];
if($index['Index_type'] == 'FULLTEXT') { if($index['Index_type'] == 'FULLTEXT') {
$groupedIndexes[$index['Key_name']]['type'] = 'fulltext '; $groupedIndexes[$index['Key_name']]['type'] = 'fulltext ';
@ -531,12 +543,12 @@ class PDODatabase extends Database {
} }
break; break;
case "pgsql": case "pgsql":
foreach($dbh->query("select indexname, indexdef from pg_indexes where tablename = '$table'") as $index) { foreach($this->dbConn->query("SELECT indexname, indexdef FROM pg_indexes WHERE tablename = '$table'") as $index) {
$indexList[$index['indexname']] = $index['indexdef']; $indexList[$index['indexname']] = $index['indexdef'];
} }
break; break;
case "mssql": case "mssql":
foreach($dbh->query(" foreach($this->dbConn->query("
SELECT SELECT
i.name AS 'iname', i.name AS 'iname',
i.type_desc AS 'itype', i.type_desc AS 'itype',
@ -569,7 +581,7 @@ class PDODatabase extends Database {
* Returns a map of a table. * Returns a map of a table.
*/ */
public function tableList() { public function tableList() {
switch (PDO::ATTR_DRIVER_NAME) { switch (self::getDatabaseServer()) {
case "mysql": case "mysql":
$sql = "SHOW TABLES"; $sql = "SHOW TABLES";
break; break;
@ -582,10 +594,12 @@ class PDODatabase extends Database {
default: default:
$this->databaseError("This database server is not available"); $this->databaseError("This database server is not available");
} }
foreach($dbConn->query($sql) as $record) { if (is_array($this->dbConn->query($sql))) {
foreach($this->dbConn->query($sql) as $record) {
$table = strtolower(reset($record)); $table = strtolower(reset($record));
$tables[$table] = $table; $tables[$table] = $table;
} }
}
return isset($tables) ? $tables : null; return isset($tables) ? $tables : null;
} }
@ -612,7 +626,8 @@ class PDOQuery extends Query {
* Hook the result-set given into a Query class, suitable for use by sapphire. * Hook the result-set given into a Query class, suitable for use by sapphire.
* @param PDO object $stmt The object of all returned values. * @param PDO object $stmt The object of all returned values.
*/ */
public function __construct(PDODatabase $stmt) { public function __construct(PDODatabase $database, $stmt) {
$this->database = $database;
$this->stmt = $stmt; $this->stmt = $stmt;
parent::__construct(); parent::__construct();
} }