API CHANGE: Updated DB::manipulate() to be more db-agnostic.

API CHANGE: Moved the meat of SQLQuery's SQL generation into Database::sqlQueryToString(), to be overloaded by different database implementations.
API CHANGE: Moved the implementation of ClassInfo::hasTable() and ClassInfo::getValidSubClasses() into Database::hasTable() and Database::enumValuesForField(), to be overloaded by different database implementations.

git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/sapphire/trunk@66422 467b73ca-7a2a-4603-9d3b-597d59a354a9
This commit is contained in:
Sam Minnee 2008-11-23 23:20:02 +00:00
parent c7330dd231
commit 5a98e83f7a
4 changed files with 106 additions and 59 deletions

View File

@ -29,8 +29,7 @@ class ClassInfo {
*/ */
static function hasTable($class) { static function hasTable($class) {
if(DB::isActive()) { if(DB::isActive()) {
$SQL_table = Convert::raw2sql($class); return DB::getConn()->hasTable($class);
return (bool)(DB::query("SHOW TABLES LIKE '$SQL_table'")->value());
} else { } else {
return false; return false;
} }
@ -40,14 +39,7 @@ class ClassInfo {
* Returns the manifest of all classes which are present in the database. * Returns the manifest of all classes which are present in the database.
*/ */
static function getValidSubClasses(){ static function getValidSubClasses(){
// Get the enum of all page types from the SiteTree table return DB::getConn()->enumValuesForField("SiteTree", "ClassName");
$classnameinfo = DB::query("DESCRIBE SiteTree ClassName")->first();
preg_match_all("/'[^,]+'/", $classnameinfo["Type"], $matches);
foreach($matches[0] as $value) {
$classes[] = trim($value, "'");
}
return $classes;
} }
/** /**

View File

@ -111,6 +111,22 @@ abstract class Database extends Object {
*/ */
protected abstract function tableList(); protected abstract function tableList();
/**
* Returns true if the given table exists in the database
*/
abstract function hasTable($tableName);
/**
* Returns the enum values available on the given field
*/
abstract function enumValuesForField($tableName, $fieldName);
/**
* Convert a SQLQuery object into a SQL statement
*/
abstract function sqlQueryToString(SQLQuery $sqlQuery);
/** /**
* The table list, generated by the tableList() function. * The table list, generated by the tableList() function.
* Used by the requireTable() function. * Used by the requireTable() function.
@ -297,6 +313,8 @@ abstract class Database extends Object {
Profiler::mark('requireField'); Profiler::mark('requireField');
// TODO: This is tempororary
$spec['parts']['name'] = $field;
//Convert the $spec array into a database-specific string //Convert the $spec array into a database-specific string
$spec=DB::getConn()->$spec['type']($spec['parts']); $spec=DB::getConn()->$spec['type']($spec['parts']);
@ -386,37 +404,37 @@ abstract class Database extends Object {
function manipulate($manipulation) { function manipulate($manipulation) {
foreach($manipulation as $table => $writeInfo) { foreach($manipulation as $table => $writeInfo) {
if(isset($writeInfo['fields']) && $writeInfo['fields']) { if(isset($writeInfo['fields']) && $writeInfo['fields']) {
$fieldList = array(); $fieldList = $columnList = $valueList = array();
foreach($writeInfo['fields'] as $fieldName => $fieldVal) { foreach($writeInfo['fields'] as $fieldName => $fieldVal) {
$fieldList[] = "\"$fieldName\" = $fieldVal"; $fieldList[] = "\"$fieldName\" = $fieldVal";
$columnList[] = "\"$fieldName\"";
// Empty strings inserted as null in INSERTs. Replacement of Database::replace_with_null().
if($fieldVal === "''") $valueList[] = "null";
else $valueList[] = $fieldVal;
} }
$fieldList = implode(", ", $fieldList);
if(!isset($writeInfo['where']) && isset($writeInfo['id'])) { if(!isset($writeInfo['where']) && isset($writeInfo['id'])) {
$writeInfo['where'] = "ID = $writeInfo[id]"; $writeInfo['where'] = "\"ID\" = " . (int)$writeInfo['id'];
} }
switch($writeInfo['command']) { switch($writeInfo['command']) {
case "update": case "update":
$fieldList = implode(", ", $fieldList);
$sql = "update \"$table\" SET $fieldList where $writeInfo[where]"; $sql = "update \"$table\" SET $fieldList where $writeInfo[where]";
$this->query($sql); $this->query($sql);
// If numAffectedRecord = 0, then we want to run instert instead // If affectedRows = 0, then don't break, meaning the insert query below gets called
if(!$this->affectedRows()) { if($this->affectedRows()) break;
if(!isset($writeInfo['fields']['ID']) && isset($writeInfo['id'])) {
$fieldList .= ", ID = $writeInfo[id]";
}
$sql = "insert into \"$table\" SET $fieldList";
$this->query($sql, null);
}
break;
case "insert": case "insert":
if(!isset($writeInfo['fields']['ID']) && isset($writeInfo['id'])) { if(!isset($writeInfo['fields']['ID']) && isset($writeInfo['id'])) {
$fieldList .= ", ID = $writeInfo[id]"; $columnList[] = "\"$ID\"";
$valueList[] = (int)$writeInfo['id'];
} }
$fieldList = Database::replace_with_null($fieldList); $columnList = implode(", ", $columnList);
$sql = "insert into \"$table\" SET $fieldList"; $valueList = implode(", ", $valueList);
$sql = "insert into \"$table\" ($columnList) VALUES ($valueList)";
$this->query($sql); $this->query($sql);
break; break;

View File

@ -539,6 +539,74 @@ class MySQLDatabase extends Database {
return 'varchar(' . $values['precision'] . ') character set utf8 collate utf8_general_ci'; return 'varchar(' . $values['precision'] . ') character set utf8 collate utf8_general_ci';
} }
/**
* Returns true if the given table is exists in the current database
* NOTE: Experimental; introduced for db-abstraction and may changed before 2.4 is released.
*/
public function hasTable($table) {
$SQL_table = Convert::raw2sql($table);
return (bool)($this->query("SHOW TABLES LIKE '$SQL_table'")->value());
}
/**
* Returns the values of the given enum field
* NOTE: Experimental; introduced for db-abstraction and may changed before 2.4 is released.
*/
public function enumValuesForField($tableName, $fieldName) {
// Get the enum of all page types from the SiteTree table
$classnameinfo = DB::query("DESCRIBE \"$tableName\" \"$fieldName\"")->first();
preg_match_all("/'[^,]+'/", $classnameinfo["Type"], $matches);
foreach($matches[0] as $value) {
$classes[] = trim($value, "'");
}
return $classes;
}
/**
* Convert a SQLQuery object into a SQL statement
*/
public function sqlQueryToString(SQLQuery $sqlQuery) {
if (!$sqlQuery->from) return '';
$distinct = $sqlQuery->distinct ? "DISTINCT " : "";
if($sqlQuery->delete) {
$text = "DELETE ";
} else if($sqlQuery->select) {
$text = "SELECT $distinct" . implode(", ", $sqlQuery->select);
}
$text .= " FROM " . implode(" ", $sqlQuery->from);
if($sqlQuery->where) $text .= " WHERE (" . $sqlQuery->getFilter(). ")";
if($sqlQuery->groupby) $text .= " GROUP BY " . implode(", ", $sqlQuery->groupby);
if($sqlQuery->having) $text .= " HAVING ( " . implode(" ) AND ( ", $sqlQuery->having) . " )";
if($sqlQuery->orderby) $text .= " ORDER BY " . $sqlQuery->orderby;
if($sqlQuery->limit) {
$limit = $sqlQuery->limit;
// Pass limit as array or SQL string value
if(is_array($limit)) {
if(!array_key_exists('limit',$limit)) user_error('SQLQuery::limit(): Wrong format for $limit', E_USER_ERROR);
if(isset($limit['start']) && is_numeric($limit['start']) && isset($limit['limit']) && is_numeric($limit['limit'])) {
// @todo MySQL specific LIMIT syntax
//$combinedLimit = (int)$limit['start'] . ',' . (int)$limit['limit'];
$combinedLimit = "$limit[limit] OFFSET $limit[start]";
} elseif(isset($limit['limit']) && is_numeric($limit['limit'])) {
$combinedLimit = (int)$limit['limit'];
} else {
$combinedLimit = false;
}
if(!empty($combinedLimit)) $this->limit = $combinedLimit;
} else {
$text .= " LIMIT " . $sqlQuery->limit;
}
}
return $text;
}
} }
/** /**

View File

@ -169,23 +169,7 @@ class SQLQuery extends Object {
* @return SQLQuery This instance * @return SQLQuery This instance
*/ */
public function limit($limit) { public function limit($limit) {
// Pass limit as array or SQL string value $this->limit = $limit;
if(is_array($limit)) {
if(!array_key_exists('limit',$limit)) user_error('SQLQuery::limit(): Wrong format for $limit', E_USER_ERROR);
if(isset($limit['start']) && is_numeric($limit['start']) && isset($limit['limit']) && is_numeric($limit['limit'])) {
// @todo MySQL specific LIMIT syntax
$combinedLimit = (int)$limit['start'] . ',' . (int)$limit['limit'];
} elseif(isset($limit['limit']) && is_numeric($limit['limit'])) {
$combinedLimit = (int)$limit['limit'];
} else {
$combinedLimit = false;
}
} else {
$combinedLimit = $limit;
}
if(!empty($combinedLimit)) $this->limit = $combinedLimit;
return $this; return $this;
} }
@ -392,22 +376,7 @@ class SQLQuery extends Object {
* @return string * @return string
*/ */
function sql() { function sql() {
if (!$this->from) return ''; return DB::getConn()->sqlQueryToString($this);
$distinct = $this->distinct ? "DISTINCT " : "";
if($this->delete) {
$text = "DELETE ";
} else if($this->select) {
$text = "SELECT $distinct" . implode(", ", $this->select);
}
$text .= " FROM " . implode(" ", $this->from);
if($this->where) $text .= " WHERE (" . $this->getFilter(). ")";
if($this->groupby) $text .= " GROUP BY " . implode(", ", $this->groupby);
if($this->having) $text .= " HAVING ( " . implode(" ) AND ( ", $this->having) . " )";
if($this->orderby) $text .= " ORDER BY " . $this->orderby;
if($this->limit) $text .= " LIMIT " . $this->limit;
return $text;
} }
/** /**