Qiang Xue
14 years ago
7 changed files with 1766 additions and 1 deletions
@ -0,0 +1,148 @@ |
|||||||
|
<?php |
||||||
|
/** |
||||||
|
* CDbColumnSchema class file. |
||||||
|
* |
||||||
|
* @author Qiang Xue <qiang.xue@gmail.com> |
||||||
|
* @link http://www.yiiframework.com/ |
||||||
|
* @copyright Copyright © 2008-2011 Yii Software LLC |
||||||
|
* @license http://www.yiiframework.com/license/ |
||||||
|
*/ |
||||||
|
|
||||||
|
/** |
||||||
|
* CDbColumnSchema class describes the column meta data of a database table. |
||||||
|
* |
||||||
|
* @author Qiang Xue <qiang.xue@gmail.com> |
||||||
|
* @version $Id: CDbColumnSchema.php 3099 2011-03-19 01:26:47Z qiang.xue $ |
||||||
|
* @package system.db.schema |
||||||
|
* @since 1.0 |
||||||
|
*/ |
||||||
|
class CDbColumnSchema extends CComponent |
||||||
|
{ |
||||||
|
/** |
||||||
|
* @var string name of this column (without quotes). |
||||||
|
*/ |
||||||
|
public $name; |
||||||
|
/** |
||||||
|
* @var string raw name of this column. This is the quoted name that can be used in SQL queries. |
||||||
|
*/ |
||||||
|
public $rawName; |
||||||
|
/** |
||||||
|
* @var boolean whether this column can be null. |
||||||
|
*/ |
||||||
|
public $allowNull; |
||||||
|
/** |
||||||
|
* @var string the DB type of this column. |
||||||
|
*/ |
||||||
|
public $dbType; |
||||||
|
/** |
||||||
|
* @var string the PHP type of this column. |
||||||
|
*/ |
||||||
|
public $type; |
||||||
|
/** |
||||||
|
* @var mixed default value of this column |
||||||
|
*/ |
||||||
|
public $defaultValue; |
||||||
|
/** |
||||||
|
* @var integer size of the column. |
||||||
|
*/ |
||||||
|
public $size; |
||||||
|
/** |
||||||
|
* @var integer precision of the column data, if it is numeric. |
||||||
|
*/ |
||||||
|
public $precision; |
||||||
|
/** |
||||||
|
* @var integer scale of the column data, if it is numeric. |
||||||
|
*/ |
||||||
|
public $scale; |
||||||
|
/** |
||||||
|
* @var boolean whether this column is a primary key |
||||||
|
*/ |
||||||
|
public $isPrimaryKey; |
||||||
|
/** |
||||||
|
* @var boolean whether this column is a foreign key |
||||||
|
*/ |
||||||
|
public $isForeignKey; |
||||||
|
/** |
||||||
|
* @var boolean whether this column is auto-incremental |
||||||
|
* @since 1.1.7 |
||||||
|
*/ |
||||||
|
public $autoIncrement = false; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Initializes the column with its DB type and default value. |
||||||
|
* This sets up the column's PHP type, size, precision, scale as well as default value. |
||||||
|
* @param string $dbType the column's DB type |
||||||
|
* @param mixed $defaultValue the default value |
||||||
|
*/ |
||||||
|
public function init($dbType, $defaultValue) |
||||||
|
{ |
||||||
|
$this->dbType = $dbType; |
||||||
|
$this->extractType($dbType); |
||||||
|
$this->extractLimit($dbType); |
||||||
|
if ($defaultValue !== null) |
||||||
|
$this->extractDefault($defaultValue); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Extracts the PHP type from DB type. |
||||||
|
* @param string $dbType DB type |
||||||
|
*/ |
||||||
|
protected function extractType($dbType) |
||||||
|
{ |
||||||
|
if (stripos($dbType, 'int') !== false && stripos($dbType, 'unsigned int') === false) |
||||||
|
$this->type = 'integer'; |
||||||
|
elseif (stripos($dbType, 'bool') !== false) |
||||||
|
$this->type = 'boolean'; |
||||||
|
elseif (preg_match('/(real|floa|doub)/i', $dbType)) |
||||||
|
$this->type = 'double'; |
||||||
|
else |
||||||
|
$this->type = 'string'; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Extracts size, precision and scale information from column's DB type. |
||||||
|
* @param string $dbType the column's DB type |
||||||
|
*/ |
||||||
|
protected function extractLimit($dbType) |
||||||
|
{ |
||||||
|
if (strpos($dbType, '(') && preg_match('/\((.*)\)/', $dbType, $matches)) |
||||||
|
{ |
||||||
|
$values = explode(',', $matches[1]); |
||||||
|
$this->size = $this->precision = (int)$values[0]; |
||||||
|
if (isset($values[1])) |
||||||
|
$this->scale = (int)$values[1]; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Extracts the default value for the column. |
||||||
|
* The value is typecasted to correct PHP type. |
||||||
|
* @param mixed $defaultValue the default value obtained from metadata |
||||||
|
*/ |
||||||
|
protected function extractDefault($defaultValue) |
||||||
|
{ |
||||||
|
$this->defaultValue = $this->typecast($defaultValue); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Converts the input value to the type that this column is of. |
||||||
|
* @param mixed $value input value |
||||||
|
* @return mixed converted value |
||||||
|
*/ |
||||||
|
public function typecast($value) |
||||||
|
{ |
||||||
|
if (gettype($value) === $this->type || $value === null || $value instanceof CDbExpression) |
||||||
|
return $value; |
||||||
|
if ($value === '') |
||||||
|
return $this->type === 'string' ? '' : null; |
||||||
|
switch ($this->type) |
||||||
|
{ |
||||||
|
case 'string': return (string)$value; |
||||||
|
case 'integer': return (integer)$value; |
||||||
|
case 'boolean': return (boolean)$value; |
||||||
|
case 'double': |
||||||
|
default: return $value; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,61 @@ |
|||||||
|
<?php |
||||||
|
/** |
||||||
|
* Expression class file. |
||||||
|
* |
||||||
|
* @author Qiang Xue <qiang.xue@gmail.com> |
||||||
|
* @link http://www.yiiframework.com/ |
||||||
|
* @copyright Copyright © 2008-2012 Yii Software LLC |
||||||
|
* @license http://www.yiiframework.com/license/ |
||||||
|
*/ |
||||||
|
|
||||||
|
namespace yii\db\dao; |
||||||
|
|
||||||
|
/** |
||||||
|
* Expression represents a DB expression that does not need escaping or quoting. |
||||||
|
* When an Expression object is embedded within a SQL statement or fragment, |
||||||
|
* it will be replaced with the [[expression]] property value without any |
||||||
|
* DB escaping or quoting. For example, |
||||||
|
* |
||||||
|
* ~~~ |
||||||
|
* $expression = new Expression('NOW()'); |
||||||
|
* $sql = 'SELECT ' . $expression; // SELECT NOW() |
||||||
|
* ~~~ |
||||||
|
* |
||||||
|
* An expression can also be bound with parameters specified via [[params]]. |
||||||
|
* |
||||||
|
* @author Qiang Xue <qiang.xue@gmail.com> |
||||||
|
* @since 2.0 |
||||||
|
*/ |
||||||
|
class Expression |
||||||
|
{ |
||||||
|
/** |
||||||
|
* @var string the DB expression |
||||||
|
*/ |
||||||
|
public $expression; |
||||||
|
/** |
||||||
|
* @var array list of parameters that should be bound for this expression. |
||||||
|
* The keys are placeholders appearing in [[expression]] and the values |
||||||
|
* are the corresponding parameter values. |
||||||
|
*/ |
||||||
|
public $params = array(); |
||||||
|
|
||||||
|
/** |
||||||
|
* Constructor. |
||||||
|
* @param string $expression the DB expression |
||||||
|
* @param array $params parameters |
||||||
|
*/ |
||||||
|
public function __construct($expression, $params = array()) |
||||||
|
{ |
||||||
|
$this->expression = $expression; |
||||||
|
$this->params = $params; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* String magic method |
||||||
|
* @return string the DB expression |
||||||
|
*/ |
||||||
|
public function __toString() |
||||||
|
{ |
||||||
|
return $this->expression; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,520 @@ |
|||||||
|
<?php |
||||||
|
/** |
||||||
|
* Query class file. |
||||||
|
* |
||||||
|
* @author Qiang Xue <qiang.xue@gmail.com> |
||||||
|
* @link http://www.yiiframework.com/ |
||||||
|
* @copyright Copyright © 2008-2012 Yii Software LLC |
||||||
|
* @license http://www.yiiframework.com/license/ |
||||||
|
*/ |
||||||
|
|
||||||
|
namespace yii\db\dao; |
||||||
|
|
||||||
|
/** |
||||||
|
* Query represents the components in a DB query. |
||||||
|
* |
||||||
|
* @author Qiang Xue <qiang.xue@gmail.com> |
||||||
|
* @since 2.0 |
||||||
|
*/ |
||||||
|
class Query extends CComponent |
||||||
|
{ |
||||||
|
/** |
||||||
|
* @var mixed the columns being selected. This refers to the SELECT clause in an SQL |
||||||
|
* statement. The property can be either a string (column names separated by commas) |
||||||
|
* or an array of column names. Defaults to '*', meaning all columns. |
||||||
|
*/ |
||||||
|
public $select; |
||||||
|
|
||||||
|
public $from; |
||||||
|
/** |
||||||
|
* @var boolean whether to select distinct rows of data only. If this is set true, |
||||||
|
* the SELECT clause would be changed to SELECT DISTINCT. |
||||||
|
*/ |
||||||
|
public $distinct; |
||||||
|
/** |
||||||
|
* @var string query condition. This refers to the WHERE clause in an SQL statement. |
||||||
|
* For example, <code>age>31 AND team=1</code>. |
||||||
|
*/ |
||||||
|
public $where; |
||||||
|
/** |
||||||
|
* @var integer maximum number of records to be returned. If less than 0, it means no limit. |
||||||
|
*/ |
||||||
|
public $limit; |
||||||
|
/** |
||||||
|
* @var integer zero-based offset from where the records are to be returned. If less than 0, it means starting from the beginning. |
||||||
|
*/ |
||||||
|
public $offset; |
||||||
|
/** |
||||||
|
* @var string how to sort the query results. This refers to the ORDER BY clause in an SQL statement. |
||||||
|
*/ |
||||||
|
public $orderBy; |
||||||
|
/** |
||||||
|
* @var string how to group the query results. This refers to the GROUP BY clause in an SQL statement. |
||||||
|
* For example, <code>'projectID, teamID'</code>. |
||||||
|
*/ |
||||||
|
public $groupBy; |
||||||
|
/** |
||||||
|
* @var string how to join with other tables. This refers to the JOIN clause in an SQL statement. |
||||||
|
* For example, <code>'LEFT JOIN users ON users.id=authorID'</code>. |
||||||
|
*/ |
||||||
|
public $join; |
||||||
|
/** |
||||||
|
* @var string the condition to be applied with GROUP-BY clause. |
||||||
|
* For example, <code>'SUM(revenue)<50000'</code>. |
||||||
|
*/ |
||||||
|
public $having; |
||||||
|
/** |
||||||
|
* @var array list of query parameter values indexed by parameter placeholders. |
||||||
|
* For example, <code>array(':name'=>'Dan', ':age'=>31)</code>. |
||||||
|
*/ |
||||||
|
public $params; |
||||||
|
|
||||||
|
public $union; |
||||||
|
|
||||||
|
|
||||||
|
public function getSql($connection) |
||||||
|
{ |
||||||
|
return $connection->getQueryBuilder()->build($this); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Appends a condition to the existing {@link condition}. |
||||||
|
* The new condition and the existing condition will be concatenated via the specified operator |
||||||
|
* which defaults to 'AND'. |
||||||
|
* The new condition can also be an array. In this case, all elements in the array |
||||||
|
* will be concatenated together via the operator. |
||||||
|
* This method handles the case when the existing condition is empty. |
||||||
|
* After calling this method, the {@link condition} property will be modified. |
||||||
|
* @param mixed $condition the new condition. It can be either a string or an array of strings. |
||||||
|
* @param string $operator the operator to join different conditions. Defaults to 'AND'. |
||||||
|
* @return Query the criteria object itself |
||||||
|
* @since 1.0.9 |
||||||
|
*/ |
||||||
|
public function addCondition($condition, $operator = 'AND') |
||||||
|
{ |
||||||
|
if (is_array($condition)) |
||||||
|
{ |
||||||
|
if ($condition === array()) |
||||||
|
return $this; |
||||||
|
$condition = '(' . implode(') ' . $operator . ' (', $condition) . ')'; |
||||||
|
} |
||||||
|
if ($this->condition === '') |
||||||
|
$this->condition = $condition; |
||||||
|
else |
||||||
|
$this->condition = '(' . $this->condition . ') ' . $operator . ' (' . $condition . ')'; |
||||||
|
return $this; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Appends a search condition to the existing {@link condition}. |
||||||
|
* The search condition and the existing condition will be concatenated via the specified operator |
||||||
|
* which defaults to 'AND'. |
||||||
|
* The search condition is generated using the SQL LIKE operator with the given column name and |
||||||
|
* search keyword. |
||||||
|
* @param string $column the column name (or a valid SQL expression) |
||||||
|
* @param string $keyword the search keyword. This interpretation of the keyword is affected by the next parameter. |
||||||
|
* @param boolean $escape whether the keyword should be escaped if it contains characters % or _. |
||||||
|
* When this parameter is true (default), the special characters % (matches 0 or more characters) |
||||||
|
* and _ (matches a single character) will be escaped, and the keyword will be surrounded with a % |
||||||
|
* character on both ends. When this parameter is false, the keyword will be directly used for |
||||||
|
* matching without any change. |
||||||
|
* @param string $operator the operator used to concatenate the new condition with the existing one. |
||||||
|
* Defaults to 'AND'. |
||||||
|
* @param string $like the LIKE operator. Defaults to 'LIKE'. You may also set this to be 'NOT LIKE'. |
||||||
|
* @return Query the criteria object itself |
||||||
|
* @since 1.0.10 |
||||||
|
*/ |
||||||
|
public function addSearchCondition($column, $keyword, $escape = true, $operator = 'AND', $like = 'LIKE') |
||||||
|
{ |
||||||
|
if ($keyword == '') |
||||||
|
return $this; |
||||||
|
if ($escape) |
||||||
|
$keyword = '%' . strtr($keyword, array('%' => '\%', '_' => '\_', '\\' => '\\\\')) . '%'; |
||||||
|
$condition = $column . " $like " . self::PARAM_PREFIX . self::$paramCount; |
||||||
|
$this->params[self::PARAM_PREFIX . self::$paramCount++] = $keyword; |
||||||
|
return $this->addCondition($condition, $operator); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Appends an IN condition to the existing {@link condition}. |
||||||
|
* The IN condition and the existing condition will be concatenated via the specified operator |
||||||
|
* which defaults to 'AND'. |
||||||
|
* The IN condition is generated by using the SQL IN operator which requires the specified |
||||||
|
* column value to be among the given list of values. |
||||||
|
* @param string $column the column name (or a valid SQL expression) |
||||||
|
* @param array $values list of values that the column value should be in |
||||||
|
* @param string $operator the operator used to concatenate the new condition with the existing one. |
||||||
|
* Defaults to 'AND'. |
||||||
|
* @return Query the criteria object itself |
||||||
|
* @since 1.0.10 |
||||||
|
*/ |
||||||
|
public function addInCondition($column, $values, $operator = 'AND') |
||||||
|
{ |
||||||
|
if (($n = count($values)) < 1) |
||||||
|
return $this->addCondition('0=1', $operator); // 0=1 is used because in MSSQL value alone can't be used in WHERE |
||||||
|
if ($n === 1) |
||||||
|
{ |
||||||
|
$value = reset($values); |
||||||
|
if ($value === null) |
||||||
|
return $this->addCondition($column . ' IS NULL'); |
||||||
|
$condition = $column . '=' . self::PARAM_PREFIX . self::$paramCount; |
||||||
|
$this->params[self::PARAM_PREFIX . self::$paramCount++] = $value; |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
$params = array(); |
||||||
|
foreach ($values as $value) |
||||||
|
{ |
||||||
|
$params[] = self::PARAM_PREFIX . self::$paramCount; |
||||||
|
$this->params[self::PARAM_PREFIX . self::$paramCount++] = $value; |
||||||
|
} |
||||||
|
$condition = $column . ' IN (' . implode(', ', $params) . ')'; |
||||||
|
} |
||||||
|
return $this->addCondition($condition, $operator); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Appends an NOT IN condition to the existing {@link condition}. |
||||||
|
* The NOT IN condition and the existing condition will be concatenated via the specified operator |
||||||
|
* which defaults to 'AND'. |
||||||
|
* The NOT IN condition is generated by using the SQL NOT IN operator which requires the specified |
||||||
|
* column value to be among the given list of values. |
||||||
|
* @param string $column the column name (or a valid SQL expression) |
||||||
|
* @param array $values list of values that the column value should not be in |
||||||
|
* @param string $operator the operator used to concatenate the new condition with the existing one. |
||||||
|
* Defaults to 'AND'. |
||||||
|
* @return Query the criteria object itself |
||||||
|
* @since 1.1.1 |
||||||
|
*/ |
||||||
|
public function addNotInCondition($column, $values, $operator = 'AND') |
||||||
|
{ |
||||||
|
if (($n = count($values)) < 1) |
||||||
|
return $this; |
||||||
|
if ($n === 1) |
||||||
|
{ |
||||||
|
$value = reset($values); |
||||||
|
if ($value === null) |
||||||
|
return $this->addCondition($column . ' IS NOT NULL'); |
||||||
|
$condition = $column . '!=' . self::PARAM_PREFIX . self::$paramCount; |
||||||
|
$this->params[self::PARAM_PREFIX . self::$paramCount++] = $value; |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
$params = array(); |
||||||
|
foreach ($values as $value) |
||||||
|
{ |
||||||
|
$params[] = self::PARAM_PREFIX . self::$paramCount; |
||||||
|
$this->params[self::PARAM_PREFIX . self::$paramCount++] = $value; |
||||||
|
} |
||||||
|
$condition = $column . ' NOT IN (' . implode(', ', $params) . ')'; |
||||||
|
} |
||||||
|
return $this->addCondition($condition, $operator); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Appends a condition for matching the given list of column values. |
||||||
|
* The generated condition will be concatenated to the existing {@link condition} |
||||||
|
* via the specified operator which defaults to 'AND'. |
||||||
|
* The condition is generated by matching each column and the corresponding value. |
||||||
|
* @param array $columns list of column names and values to be matched (name=>value) |
||||||
|
* @param string $columnOperator the operator to concatenate multiple column matching condition. Defaults to 'AND'. |
||||||
|
* @param string $operator the operator used to concatenate the new condition with the existing one. |
||||||
|
* Defaults to 'AND'. |
||||||
|
* @return Query the criteria object itself |
||||||
|
* @since 1.0.10 |
||||||
|
*/ |
||||||
|
public function addColumnCondition($columns, $columnOperator = 'AND', $operator = 'AND') |
||||||
|
{ |
||||||
|
$params = array(); |
||||||
|
foreach ($columns as $name => $value) |
||||||
|
{ |
||||||
|
if ($value === null) |
||||||
|
$params[] = $name . ' IS NULL'; |
||||||
|
else |
||||||
|
{ |
||||||
|
$params[] = $name . '=' . self::PARAM_PREFIX . self::$paramCount; |
||||||
|
$this->params[self::PARAM_PREFIX . self::$paramCount++] = $value; |
||||||
|
} |
||||||
|
} |
||||||
|
return $this->addCondition(implode(" $columnOperator ", $params), $operator); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Adds a comparison expression to the {@link condition} property. |
||||||
|
* |
||||||
|
* This method is a helper that appends to the {@link condition} property |
||||||
|
* with a new comparison expression. The comparison is done by comparing a column |
||||||
|
* with the given value using some comparison operator. |
||||||
|
* |
||||||
|
* The comparison operator is intelligently determined based on the first few |
||||||
|
* characters in the given value. In particular, it recognizes the following operators |
||||||
|
* if they appear as the leading characters in the given value: |
||||||
|
* <ul> |
||||||
|
* <li><code><</code>: the column must be less than the given value.</li> |
||||||
|
* <li><code>></code>: the column must be greater than the given value.</li> |
||||||
|
* <li><code><=</code>: the column must be less than or equal to the given value.</li> |
||||||
|
* <li><code>>=</code>: the column must be greater than or equal to the given value.</li> |
||||||
|
* <li><code><></code>: the column must not be the same as the given value. |
||||||
|
* Note that when $partialMatch is true, this would mean the value must not be a substring |
||||||
|
* of the column.</li> |
||||||
|
* <li><code>=</code>: the column must be equal to the given value.</li> |
||||||
|
* <li>none of the above: the column must be equal to the given value. Note that when $partialMatch |
||||||
|
* is true, this would mean the value must be the same as the given value or be a substring of it.</li> |
||||||
|
* </ul> |
||||||
|
* |
||||||
|
* Note that any surrounding white spaces will be removed from the value before comparison. |
||||||
|
* When the value is empty, no comparison expression will be added to the search condition. |
||||||
|
* |
||||||
|
* @param string $column the name of the column to be searched |
||||||
|
* @param mixed $value the column value to be compared with. If the value is a string, the aforementioned |
||||||
|
* intelligent comparison will be conducted. If the value is an array, the comparison is done |
||||||
|
* by exact match of any of the value in the array. If the string or the array is empty, |
||||||
|
* the existing search condition will not be modified. |
||||||
|
* @param boolean $partialMatch whether the value should consider partial text match (using LIKE and NOT LIKE operators). |
||||||
|
* Defaults to false, meaning exact comparison. |
||||||
|
* @param string $operator the operator used to concatenate the new condition with the existing one. |
||||||
|
* Defaults to 'AND'. |
||||||
|
* @param boolean $escape whether the value should be escaped if $partialMatch is true and |
||||||
|
* the value contains characters % or _. When this parameter is true (default), |
||||||
|
* the special characters % (matches 0 or more characters) |
||||||
|
* and _ (matches a single character) will be escaped, and the value will be surrounded with a % |
||||||
|
* character on both ends. When this parameter is false, the value will be directly used for |
||||||
|
* matching without any change. |
||||||
|
* @return Query the criteria object itself |
||||||
|
* @since 1.1.1 |
||||||
|
*/ |
||||||
|
public function compare($column, $value, $partialMatch = false, $operator = 'AND', $escape = true) |
||||||
|
{ |
||||||
|
if (is_array($value)) |
||||||
|
{ |
||||||
|
if ($value === array()) |
||||||
|
return $this; |
||||||
|
return $this->addInCondition($column, $value, $operator); |
||||||
|
} |
||||||
|
else |
||||||
|
$value = "$value"; |
||||||
|
|
||||||
|
if (preg_match('/^(?:\s*(<>|<=|>=|<|>|=))?(.*)$/', $value, $matches)) |
||||||
|
{ |
||||||
|
$value = $matches[2]; |
||||||
|
$op = $matches[1]; |
||||||
|
} |
||||||
|
else |
||||||
|
$op = ''; |
||||||
|
|
||||||
|
if ($value === '') |
||||||
|
return $this; |
||||||
|
|
||||||
|
if ($partialMatch) |
||||||
|
{ |
||||||
|
if ($op === '') |
||||||
|
return $this->addSearchCondition($column, $value, $escape, $operator); |
||||||
|
if ($op === '<>') |
||||||
|
return $this->addSearchCondition($column, $value, $escape, $operator, 'NOT LIKE'); |
||||||
|
} |
||||||
|
elseif ($op === '') |
||||||
|
$op = '='; |
||||||
|
|
||||||
|
$this->addCondition($column . $op . self::PARAM_PREFIX . self::$paramCount, $operator); |
||||||
|
$this->params[self::PARAM_PREFIX . self::$paramCount++] = $value; |
||||||
|
|
||||||
|
return $this; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Adds a between condition to the {@link condition} property. |
||||||
|
* |
||||||
|
* The new between condition and the existing condition will be concatenated via |
||||||
|
* the specified operator which defaults to 'AND'. |
||||||
|
* If one or both values are empty then the condition is not added to the existing condition. |
||||||
|
* This method handles the case when the existing condition is empty. |
||||||
|
* After calling this method, the {@link condition} property will be modified. |
||||||
|
* @param string $column the name of the column to search between. |
||||||
|
* @param string $valueStart the beginning value to start the between search. |
||||||
|
* @param string $valueEnd the ending value to end the between search. |
||||||
|
* @param string $operator the operator used to concatenate the new condition with the existing one. |
||||||
|
* Defaults to 'AND'. |
||||||
|
* @return Query the criteria object itself |
||||||
|
* @since 1.1.2 |
||||||
|
*/ |
||||||
|
public function addBetweenCondition($column, $valueStart, $valueEnd, $operator = 'AND') |
||||||
|
{ |
||||||
|
if ($valueStart === '' || $valueEnd === '') |
||||||
|
return $this; |
||||||
|
|
||||||
|
$paramStart = self::PARAM_PREFIX . self::$paramCount++; |
||||||
|
$paramEnd = self::PARAM_PREFIX . self::$paramCount++; |
||||||
|
$this->params[$paramStart] = $valueStart; |
||||||
|
$this->params[$paramEnd] = $valueEnd; |
||||||
|
$condition = "$column BETWEEN $paramStart AND $paramEnd"; |
||||||
|
|
||||||
|
if ($this->condition === '') |
||||||
|
$this->condition = $condition; |
||||||
|
else |
||||||
|
$this->condition = '(' . $this->condition . ') ' . $operator . ' (' . $condition . ')'; |
||||||
|
return $this; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Merges with another criteria. |
||||||
|
* In general, the merging makes the resulting criteria more restrictive. |
||||||
|
* For example, if both criterias have conditions, they will be 'AND' together. |
||||||
|
* Also, the criteria passed as the parameter takes precedence in case |
||||||
|
* two options cannot be merged (e.g. LIMIT, OFFSET). |
||||||
|
* @param Query $criteria the criteria to be merged with. |
||||||
|
* @param boolean $useAnd whether to use 'AND' to merge condition and having options. |
||||||
|
* If false, 'OR' will be used instead. Defaults to 'AND'. This parameter has been |
||||||
|
* available since version 1.0.6. |
||||||
|
* @since 1.0.5 |
||||||
|
*/ |
||||||
|
public function mergeWith($criteria, $useAnd = true) |
||||||
|
{ |
||||||
|
$and = $useAnd ? 'AND' : 'OR'; |
||||||
|
if (is_array($criteria)) |
||||||
|
$criteria = new self($criteria); |
||||||
|
if ($this->select !== $criteria->select) |
||||||
|
{ |
||||||
|
if ($this->select === '*') |
||||||
|
$this->select = $criteria->select; |
||||||
|
elseif ($criteria->select !== '*') |
||||||
|
{ |
||||||
|
$select1 = is_string($this->select) ? preg_split('/\s*,\s*/', trim($this->select), -1, PREG_SPLIT_NO_EMPTY) : $this->select; |
||||||
|
$select2 = is_string($criteria->select) ? preg_split('/\s*,\s*/', trim($criteria->select), -1, PREG_SPLIT_NO_EMPTY) : $criteria->select; |
||||||
|
$this->select = array_merge($select1, array_diff($select2, $select1)); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if ($this->condition !== $criteria->condition) |
||||||
|
{ |
||||||
|
if ($this->condition === '') |
||||||
|
$this->condition = $criteria->condition; |
||||||
|
elseif ($criteria->condition !== '') |
||||||
|
$this->condition = "( {$this->condition}) $and ( {$criteria->condition})"; |
||||||
|
} |
||||||
|
|
||||||
|
if ($this->params !== $criteria->params) |
||||||
|
$this->params = array_merge($this->params, $criteria->params); |
||||||
|
|
||||||
|
if ($criteria->limit > 0) |
||||||
|
$this->limit = $criteria->limit; |
||||||
|
|
||||||
|
if ($criteria->offset >= 0) |
||||||
|
$this->offset = $criteria->offset; |
||||||
|
|
||||||
|
if ($criteria->alias !== null) |
||||||
|
$this->alias = $criteria->alias; |
||||||
|
|
||||||
|
if ($this->order !== $criteria->order) |
||||||
|
{ |
||||||
|
if ($this->order === '') |
||||||
|
$this->order = $criteria->order; |
||||||
|
elseif ($criteria->order !== '') |
||||||
|
$this->order = $criteria->order . ', ' . $this->order; |
||||||
|
} |
||||||
|
|
||||||
|
if ($this->group !== $criteria->group) |
||||||
|
{ |
||||||
|
if ($this->group === '') |
||||||
|
$this->group = $criteria->group; |
||||||
|
elseif ($criteria->group !== '') |
||||||
|
$this->group .= ', ' . $criteria->group; |
||||||
|
} |
||||||
|
|
||||||
|
if ($this->join !== $criteria->join) |
||||||
|
{ |
||||||
|
if ($this->join === '') |
||||||
|
$this->join = $criteria->join; |
||||||
|
elseif ($criteria->join !== '') |
||||||
|
$this->join .= ' ' . $criteria->join; |
||||||
|
} |
||||||
|
|
||||||
|
if ($this->having !== $criteria->having) |
||||||
|
{ |
||||||
|
if ($this->having === '') |
||||||
|
$this->having = $criteria->having; |
||||||
|
elseif ($criteria->having !== '') |
||||||
|
$this->having = "( {$this->having}) $and ( {$criteria->having})"; |
||||||
|
} |
||||||
|
|
||||||
|
if ($criteria->distinct > 0) |
||||||
|
$this->distinct = $criteria->distinct; |
||||||
|
|
||||||
|
if ($criteria->together !== null) |
||||||
|
$this->together = $criteria->together; |
||||||
|
|
||||||
|
if ($criteria->index !== null) |
||||||
|
$this->index = $criteria->index; |
||||||
|
|
||||||
|
if (empty($this->scopes)) |
||||||
|
$this->scopes = $criteria->scopes; |
||||||
|
elseif (!empty($criteria->scopes)) |
||||||
|
{ |
||||||
|
$scopes1 = (array)$this->scopes; |
||||||
|
$scopes2 = (array)$criteria->scopes; |
||||||
|
foreach ($scopes1 as $k => $v) |
||||||
|
{ |
||||||
|
if (is_integer($k)) |
||||||
|
$scopes[] = $v; |
||||||
|
elseif (isset($scopes2[$k])) |
||||||
|
$scopes[] = array($k => $v); |
||||||
|
else |
||||||
|
$scopes[$k] = $v; |
||||||
|
} |
||||||
|
foreach ($scopes2 as $k => $v) |
||||||
|
{ |
||||||
|
if (is_integer($k)) |
||||||
|
$scopes[] = $v; |
||||||
|
elseif (isset($scopes1[$k])) |
||||||
|
$scopes[] = array($k => $v); |
||||||
|
else |
||||||
|
$scopes[$k] = $v; |
||||||
|
} |
||||||
|
$this->scopes = $scopes; |
||||||
|
} |
||||||
|
|
||||||
|
if (empty($this->with)) |
||||||
|
$this->with = $criteria->with; |
||||||
|
elseif (!empty($criteria->with)) |
||||||
|
{ |
||||||
|
$this->with = (array)$this->with; |
||||||
|
foreach ((array)$criteria->with as $k => $v) |
||||||
|
{ |
||||||
|
if (is_integer($k)) |
||||||
|
$this->with[] = $v; |
||||||
|
elseif (isset($this->with[$k])) |
||||||
|
{ |
||||||
|
$excludes = array(); |
||||||
|
foreach (array('joinType', 'on') as $opt) |
||||||
|
{ |
||||||
|
if (isset($this->with[$k][$opt])) |
||||||
|
$excludes[$opt] = $this->with[$k][$opt]; |
||||||
|
if (isset($v[$opt])) |
||||||
|
$excludes[$opt] = ($opt === 'on' && isset($excludes[$opt]) && $v[$opt] !== $excludes[$opt]) ? |
||||||
|
"($excludes[$opt]) AND $v[$opt]" : $v[$opt]; |
||||||
|
unset($this->with[$k][$opt]); |
||||||
|
unset($v[$opt]); |
||||||
|
} |
||||||
|
$this->with[$k] = new self($this->with[$k]); |
||||||
|
$this->with[$k]->mergeWith($v, $useAnd); |
||||||
|
$this->with[$k] = $this->with[$k]->toArray(); |
||||||
|
if (count($excludes) !== 0) |
||||||
|
$this->with[$k] = CMap::mergeArray($this->with[$k], $excludes); |
||||||
|
} |
||||||
|
else |
||||||
|
$this->with[$k] = $v; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @return array the array representation of the criteria |
||||||
|
* @since 1.0.6 |
||||||
|
*/ |
||||||
|
public function toArray() |
||||||
|
{ |
||||||
|
$result = array(); |
||||||
|
foreach (array('select', 'condition', 'params', 'limit', 'offset', 'order', 'group', 'join', 'having', 'distinct', 'scopes', 'with', 'alias', 'index', 'together') as $name) |
||||||
|
$result[$name] = $this->$name; |
||||||
|
return $result; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,402 @@ |
|||||||
|
<?php |
||||||
|
/** |
||||||
|
* This file contains the Command class. |
||||||
|
* |
||||||
|
* @author Qiang Xue <qiang.xue@gmail.com> |
||||||
|
* @link http://www.yiiframework.com/ |
||||||
|
* @copyright Copyright © 2008-2012 Yii Software LLC |
||||||
|
* @license http://www.yiiframework.com/license/ |
||||||
|
*/ |
||||||
|
|
||||||
|
namespace yii\db\dao; |
||||||
|
|
||||||
|
/** |
||||||
|
* QueryBuilder builds a SQL statement based on the specification given as a [[Query]] object. |
||||||
|
* |
||||||
|
* @author Qiang Xue <qiang.xue@gmail.com> |
||||||
|
* @since 2.0 |
||||||
|
*/ |
||||||
|
class QueryBuilder extends \yii\base\Component |
||||||
|
{ |
||||||
|
private $_connection; |
||||||
|
|
||||||
|
public function __construct(Connection $connection) |
||||||
|
{ |
||||||
|
$this->_connection = $connection; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @return CDbConnection the connection associated with this command |
||||||
|
*/ |
||||||
|
public function getConnection() |
||||||
|
{ |
||||||
|
return $this->_connection; |
||||||
|
} |
||||||
|
|
||||||
|
public function build($query) |
||||||
|
{ |
||||||
|
$clauses = array( |
||||||
|
$this->buildSelect($query->select, $query->distinct), |
||||||
|
$this->buildFrom($query->from), |
||||||
|
$this->buildJoin($query->join), |
||||||
|
$this->buildWhere($query->where), |
||||||
|
$this->buildGroupBy($query->groupBy), |
||||||
|
$this->buildHaving($query->having), |
||||||
|
$this->buildOrderBy($query->orderBy), |
||||||
|
$this->buildLimit($query->offset, $query->limit), |
||||||
|
$this->buildUnion($query->union), |
||||||
|
); |
||||||
|
|
||||||
|
return implode("\n", array_filter($clauses)); |
||||||
|
} |
||||||
|
|
||||||
|
protected function buildSelect($columns, $distinct) |
||||||
|
{ |
||||||
|
$select = $distinct ? 'SELECT DISTINCT' : 'SELECT'; |
||||||
|
|
||||||
|
if (empty($columns)) { |
||||||
|
return $select . ' *'; |
||||||
|
} |
||||||
|
|
||||||
|
if (is_string($columns)) { |
||||||
|
if (strpos($columns, '(') !== false) { |
||||||
|
return $select . ' ' . $columns; |
||||||
|
} |
||||||
|
$columns = preg_split('/\s*,\s*/', trim($columns), -1, PREG_SPLIT_NO_EMPTY); |
||||||
|
} |
||||||
|
|
||||||
|
foreach ($columns as $i => $column) { |
||||||
|
if (is_object($column)) { |
||||||
|
$columns[$i] = (string)$column; |
||||||
|
} |
||||||
|
elseif (strpos($column, '(') === false) { |
||||||
|
if (preg_match('/^(.*?)(?i:\s+as\s+|\s+)(.*)$/', $column, $matches)) { |
||||||
|
$columns[$i] = $this->_connection->quoteColumnName($matches[1]) . ' AS ' . $this->_connection->quoteColumnName($matches[2]); |
||||||
|
} |
||||||
|
else { |
||||||
|
$columns[$i] = $this->_connection->quoteColumnName($column); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return $select . ' ' . implode(', ', $columns); |
||||||
|
} |
||||||
|
|
||||||
|
protected function buildFrom($tables) |
||||||
|
{ |
||||||
|
if (is_string($tables) && strpos($tables, '(') !== false) { |
||||||
|
return $tables; |
||||||
|
} |
||||||
|
|
||||||
|
if (!is_array($tables)) { |
||||||
|
$tables = preg_split('/\s*,\s*/', trim($tables), -1, PREG_SPLIT_NO_EMPTY); |
||||||
|
} |
||||||
|
foreach ($tables as $i => $table) { |
||||||
|
if (strpos($table, '(') === false) { |
||||||
|
if (preg_match('/^(.*?)(?i:\s+as\s+|\s+)(.*)$/', $table, $matches)) { // with alias |
||||||
|
$tables[$i] = $this->_connection->quoteTableName($matches[1]) . ' ' . $this->_connection->quoteTableName($matches[2]); |
||||||
|
} |
||||||
|
else { |
||||||
|
$tables[$i] = $this->_connection->quoteTableName($table); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
return implode(', ', $tables); |
||||||
|
} |
||||||
|
|
||||||
|
$this->buildJoin($query->join), |
||||||
|
$this->buildWhere($query->where), |
||||||
|
$this->buildGroupBy($query->groupBy), |
||||||
|
$this->buildHaving($query->having), |
||||||
|
$this->buildOrderBy($query->orderBy), |
||||||
|
$this->buildLimit($query->offset, $query->limit), |
||||||
|
|
||||||
|
|
||||||
|
if (isset($query['union'])) |
||||||
|
$sql .= "\nUNION (\n" . (is_array($query['union']) ? implode("\n) UNION (\n", $query['union']) : $query['union']) . ')'; |
||||||
|
|
||||||
|
return $sql; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Sets the WHERE part of the query. |
||||||
|
* |
||||||
|
* The method requires a $conditions parameter, and optionally a $params parameter |
||||||
|
* specifying the values to be bound to the query. |
||||||
|
* |
||||||
|
* The $conditions parameter should be either a string (e.g. 'id=1') or an array. |
||||||
|
* If the latter, it must be of the format <code>array(operator, operand1, operand2, ...)</code>, |
||||||
|
* where the operator can be one of the followings, and the possible operands depend on the corresponding |
||||||
|
* operator: |
||||||
|
* <ul> |
||||||
|
* <li><code>and</code>: the operands should be concatenated together using AND. For example, |
||||||
|
* array('and', 'id=1', 'id=2') will generate 'id=1 AND id=2'. If an operand is an array, |
||||||
|
* it will be converted into a string using the same rules described here. For example, |
||||||
|
* array('and', 'type=1', array('or', 'id=1', 'id=2')) will generate 'type=1 AND (id=1 OR id=2)'. |
||||||
|
* The method will NOT do any quoting or escaping.</li> |
||||||
|
* <li><code>or</code>: similar as the <code>and</code> operator except that the operands are concatenated using OR.</li> |
||||||
|
* <li><code>in</code>: operand 1 should be a column or DB expression, and operand 2 be an array representing |
||||||
|
* the range of the values that the column or DB expression should be in. For example, |
||||||
|
* array('in', 'id', array(1,2,3)) will generate 'id IN (1,2,3)'. |
||||||
|
* The method will properly quote the column name and escape values in the range.</li> |
||||||
|
* <li><code>not in</code>: similar as the <code>in</code> operator except that IN is replaced with NOT IN in the generated condition.</li> |
||||||
|
* <li><code>like</code>: operand 1 should be a column or DB expression, and operand 2 be a string or an array representing |
||||||
|
* the values that the column or DB expression should be like. |
||||||
|
* For example, array('like', 'name', '%tester%') will generate "name LIKE '%tester%'". |
||||||
|
* When the value range is given as an array, multiple LIKE predicates will be generated and concatenated using AND. |
||||||
|
* For example, array('like', 'name', array('%test%', '%sample%')) will generate |
||||||
|
* "name LIKE '%test%' AND name LIKE '%sample%'". |
||||||
|
* The method will properly quote the column name and escape values in the range.</li> |
||||||
|
* <li><code>not like</code>: similar as the <code>like</code> operator except that LIKE is replaced with NOT LIKE in the generated condition.</li> |
||||||
|
* <li><code>or like</code>: similar as the <code>like</code> operator except that OR is used to concatenated the LIKE predicates.</li> |
||||||
|
* <li><code>or not like</code>: similar as the <code>not like</code> operator except that OR is used to concatenated the NOT LIKE predicates.</li> |
||||||
|
* </ul> |
||||||
|
* @param mixed $conditions the conditions that should be put in the WHERE part. |
||||||
|
* @param array $params the parameters (name=>value) to be bound to the query |
||||||
|
* @return Command the command object itself |
||||||
|
* @since 1.1.6 |
||||||
|
*/ |
||||||
|
public function where($conditions, $params = array()) |
||||||
|
{ |
||||||
|
$this->_query['where'] = $this->processConditions($conditions); |
||||||
|
foreach ($params as $name => $value) |
||||||
|
$this->params[$name] = $value; |
||||||
|
return $this; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Appends an INNER JOIN part to the query. |
||||||
|
* @param string $table the table to be joined. |
||||||
|
* Table name can contain schema prefix (e.g. 'public.tbl_user') and/or table alias (e.g. 'tbl_user u'). |
||||||
|
* The method will automatically quote the table name unless it contains some parenthesis |
||||||
|
* (which means the table is given as a sub-query or DB expression). |
||||||
|
* @param mixed $conditions the join condition that should appear in the ON part. |
||||||
|
* Please refer to {@link where} on how to specify conditions. |
||||||
|
* @param array $params the parameters (name=>value) to be bound to the query |
||||||
|
* @return Command the command object itself |
||||||
|
* @since 1.1.6 |
||||||
|
*/ |
||||||
|
public function join($table, $conditions, $params = array()) |
||||||
|
{ |
||||||
|
return $this->joinInternal('join', $table, $conditions, $params); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Sets the GROUP BY part of the query. |
||||||
|
* @param mixed $columns the columns to be grouped by. |
||||||
|
* Columns can be specified in either a string (e.g. "id, name") or an array (e.g. array('id', 'name')). |
||||||
|
* The method will automatically quote the column names unless a column contains some parenthesis |
||||||
|
* (which means the column contains a DB expression). |
||||||
|
* @return Command the command object itself |
||||||
|
* @since 1.1.6 |
||||||
|
*/ |
||||||
|
public function group($columns) |
||||||
|
{ |
||||||
|
if (is_string($columns) && strpos($columns, '(') !== false) |
||||||
|
$this->_query['group'] = $columns; |
||||||
|
else |
||||||
|
{ |
||||||
|
if (!is_array($columns)) |
||||||
|
$columns = preg_split('/\s*,\s*/', trim($columns), -1, PREG_SPLIT_NO_EMPTY); |
||||||
|
foreach ($columns as $i => $column) |
||||||
|
{ |
||||||
|
if (is_object($column)) |
||||||
|
$columns[$i] = (string)$column; |
||||||
|
elseif (strpos($column, '(') === false) |
||||||
|
$columns[$i] = $this->_connection->quoteColumnName($column); |
||||||
|
} |
||||||
|
$this->_query['group'] = implode(', ', $columns); |
||||||
|
} |
||||||
|
return $this; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Sets the HAVING part of the query. |
||||||
|
* @param mixed $conditions the conditions to be put after HAVING. |
||||||
|
* Please refer to {@link where} on how to specify conditions. |
||||||
|
* @param array $params the parameters (name=>value) to be bound to the query |
||||||
|
* @return Command the command object itself |
||||||
|
* @since 1.1.6 |
||||||
|
*/ |
||||||
|
public function having($conditions, $params = array()) |
||||||
|
{ |
||||||
|
$this->_query['having'] = $this->processConditions($conditions); |
||||||
|
foreach ($params as $name => $value) |
||||||
|
$this->params[$name] = $value; |
||||||
|
return $this; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Sets the ORDER BY part of the query. |
||||||
|
* @param mixed $columns the columns (and the directions) to be ordered by. |
||||||
|
* Columns can be specified in either a string (e.g. "id ASC, name DESC") or an array (e.g. array('id ASC', 'name DESC')). |
||||||
|
* The method will automatically quote the column names unless a column contains some parenthesis |
||||||
|
* (which means the column contains a DB expression). |
||||||
|
* @return Command the command object itself |
||||||
|
* @since 1.1.6 |
||||||
|
*/ |
||||||
|
public function order($columns) |
||||||
|
{ |
||||||
|
if (is_string($columns) && strpos($columns, '(') !== false) |
||||||
|
$this->_query['order'] = $columns; |
||||||
|
else |
||||||
|
{ |
||||||
|
if (!is_array($columns)) |
||||||
|
$columns = preg_split('/\s*,\s*/', trim($columns), -1, PREG_SPLIT_NO_EMPTY); |
||||||
|
foreach ($columns as $i => $column) |
||||||
|
{ |
||||||
|
if (is_object($column)) |
||||||
|
$columns[$i] = (string)$column; |
||||||
|
elseif (strpos($column, '(') === false) |
||||||
|
{ |
||||||
|
if (preg_match('/^(.*?)\s+(asc|desc)$/i', $column, $matches)) |
||||||
|
$columns[$i] = $this->_connection->quoteColumnName($matches[1]) . ' ' . strtoupper($matches[2]); |
||||||
|
else |
||||||
|
$columns[$i] = $this->_connection->quoteColumnName($column); |
||||||
|
} |
||||||
|
} |
||||||
|
$this->_query['order'] = implode(', ', $columns); |
||||||
|
} |
||||||
|
return $this; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Sets the LIMIT part of the query. |
||||||
|
* @param integer $limit the limit |
||||||
|
* @param integer $offset the offset |
||||||
|
* @return Command the command object itself |
||||||
|
* @since 1.1.6 |
||||||
|
*/ |
||||||
|
public function limit($limit, $offset = null) |
||||||
|
{ |
||||||
|
$this->_query['limit'] = (int)$limit; |
||||||
|
if ($offset !== null) |
||||||
|
$this->offset($offset); |
||||||
|
return $this; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Appends a SQL statement using UNION operator. |
||||||
|
* @param string $sql the SQL statement to be appended using UNION |
||||||
|
* @return Command the command object itself |
||||||
|
* @since 1.1.6 |
||||||
|
*/ |
||||||
|
public function union($sql) |
||||||
|
{ |
||||||
|
if (isset($this->_query['union']) && is_string($this->_query['union'])) |
||||||
|
$this->_query['union'] = array($this->_query['union']); |
||||||
|
|
||||||
|
$this->_query['union'][] = $sql; |
||||||
|
|
||||||
|
return $this; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Generates the condition string that will be put in the WHERE part |
||||||
|
* @param mixed $conditions the conditions that will be put in the WHERE part. |
||||||
|
* @return string the condition string to put in the WHERE part |
||||||
|
*/ |
||||||
|
private function buildConditions($conditions) |
||||||
|
{ |
||||||
|
if (!is_array($conditions)) |
||||||
|
return $conditions; |
||||||
|
elseif ($conditions === array()) |
||||||
|
return ''; |
||||||
|
$n = count($conditions); |
||||||
|
$operator = strtoupper($conditions[0]); |
||||||
|
if ($operator === 'OR' || $operator === 'AND') |
||||||
|
{ |
||||||
|
$parts = array(); |
||||||
|
for ($i = 1;$i < $n;++$i) |
||||||
|
{ |
||||||
|
$condition = $this->processConditions($conditions[$i]); |
||||||
|
if ($condition !== '') |
||||||
|
$parts[] = '(' . $condition . ')'; |
||||||
|
} |
||||||
|
return $parts === array() ? '' : implode(' ' . $operator . ' ', $parts); |
||||||
|
} |
||||||
|
|
||||||
|
if (!isset($conditions[1], $conditions[2])) |
||||||
|
return ''; |
||||||
|
|
||||||
|
$column = $conditions[1]; |
||||||
|
if (strpos($column, '(') === false) |
||||||
|
$column = $this->_connection->quoteColumnName($column); |
||||||
|
|
||||||
|
$values = $conditions[2]; |
||||||
|
if (!is_array($values)) |
||||||
|
$values = array($values); |
||||||
|
|
||||||
|
if ($operator === 'IN' || $operator === 'NOT IN') |
||||||
|
{ |
||||||
|
if ($values === array()) |
||||||
|
return $operator === 'IN' ? '0=1' : ''; |
||||||
|
foreach ($values as $i => $value) |
||||||
|
{ |
||||||
|
if (is_string($value)) |
||||||
|
$values[$i] = $this->_connection->quoteValue($value); |
||||||
|
else |
||||||
|
$values[$i] = (string)$value; |
||||||
|
} |
||||||
|
return $column . ' ' . $operator . ' (' . implode(', ', $values) . ')'; |
||||||
|
} |
||||||
|
|
||||||
|
if ($operator === 'LIKE' || $operator === 'NOT LIKE' || $operator === 'OR LIKE' || $operator === 'OR NOT LIKE') |
||||||
|
{ |
||||||
|
if ($values === array()) |
||||||
|
return $operator === 'LIKE' || $operator === 'OR LIKE' ? '0=1' : ''; |
||||||
|
|
||||||
|
if ($operator === 'LIKE' || $operator === 'NOT LIKE') |
||||||
|
$andor = ' AND '; |
||||||
|
else |
||||||
|
{ |
||||||
|
$andor = ' OR '; |
||||||
|
$operator = $operator === 'OR LIKE' ? 'LIKE' : 'NOT LIKE'; |
||||||
|
} |
||||||
|
$expressions = array(); |
||||||
|
foreach ($values as $value) |
||||||
|
$expressions[] = $column . ' ' . $operator . ' ' . $this->_connection->quoteValue($value); |
||||||
|
return implode($andor, $expressions); |
||||||
|
} |
||||||
|
|
||||||
|
throw new CDbException(Yii::t('yii', 'Unknown operator "{operator}".', array('{operator}' => $operator))); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Appends an JOIN part to the query. |
||||||
|
* @param string $type the join type ('join', 'left join', 'right join', 'cross join', 'natural join') |
||||||
|
* @param string $table the table to be joined. |
||||||
|
* Table name can contain schema prefix (e.g. 'public.tbl_user') and/or table alias (e.g. 'tbl_user u'). |
||||||
|
* The method will automatically quote the table name unless it contains some parenthesis |
||||||
|
* (which means the table is given as a sub-query or DB expression). |
||||||
|
* @param mixed $conditions the join condition that should appear in the ON part. |
||||||
|
* Please refer to {@link where} on how to specify conditions. |
||||||
|
* @param array $params the parameters (name=>value) to be bound to the query |
||||||
|
* @return Command the command object itself |
||||||
|
* @since 1.1.6 |
||||||
|
*/ |
||||||
|
private function joinInternal($type, $table, $conditions = '', $params = array()) |
||||||
|
{ |
||||||
|
if (strpos($table, '(') === false) |
||||||
|
{ |
||||||
|
if (preg_match('/^(.*?)(?i:\s+as\s+|\s+)(.*)$/', $table, $matches)) // with alias |
||||||
|
$table = $this->_connection->quoteTableName($matches[1]) . ' ' . $this->_connection->quoteTableName($matches[2]); |
||||||
|
else |
||||||
|
$table = $this->_connection->quoteTableName($table); |
||||||
|
} |
||||||
|
|
||||||
|
$conditions = $this->processConditions($conditions); |
||||||
|
if ($conditions != '') |
||||||
|
$conditions = ' ON ' . $conditions; |
||||||
|
|
||||||
|
if (isset($this->_query['join']) && is_string($this->_query['join'])) |
||||||
|
$this->_query['join'] = array($this->_query['join']); |
||||||
|
|
||||||
|
$this->_query['join'][] = strtoupper($type) . ' ' . $table . $conditions; |
||||||
|
|
||||||
|
foreach ($params as $name => $value) |
||||||
|
$this->params[$name] = $value; |
||||||
|
return $this; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,556 @@ |
|||||||
|
<?php |
||||||
|
/** |
||||||
|
* CDbSchema class file. |
||||||
|
* |
||||||
|
* @author Qiang Xue <qiang.xue@gmail.com> |
||||||
|
* @link http://www.yiiframework.com/ |
||||||
|
* @copyright Copyright © 2008-2011 Yii Software LLC |
||||||
|
* @license http://www.yiiframework.com/license/ |
||||||
|
*/ |
||||||
|
|
||||||
|
/** |
||||||
|
* CDbSchema is the base class for retrieving metadata information. |
||||||
|
* |
||||||
|
* @author Qiang Xue <qiang.xue@gmail.com> |
||||||
|
* @version $Id: CDbSchema.php 3359 2011-07-18 11:25:17Z qiang.xue $ |
||||||
|
* @package system.db.schema |
||||||
|
* @since 1.0 |
||||||
|
*/ |
||||||
|
abstract class CDbSchema extends CComponent |
||||||
|
{ |
||||||
|
/** |
||||||
|
* @var array the abstract column types mapped to physical column types. |
||||||
|
* @since 1.1.6 |
||||||
|
*/ |
||||||
|
public $columnTypes = array(); |
||||||
|
|
||||||
|
private $_tableNames = array(); |
||||||
|
private $_tables = array(); |
||||||
|
private $_connection; |
||||||
|
private $_builder; |
||||||
|
private $_cacheExclude = array(); |
||||||
|
|
||||||
|
/** |
||||||
|
* Loads the metadata for the specified table. |
||||||
|
* @param string $name table name |
||||||
|
* @return CDbTableSchema driver dependent table metadata, null if the table does not exist. |
||||||
|
*/ |
||||||
|
abstract protected function loadTable($name); |
||||||
|
|
||||||
|
/** |
||||||
|
* Constructor. |
||||||
|
* @param CDbConnection $conn database connection. |
||||||
|
*/ |
||||||
|
public function __construct($conn) |
||||||
|
{ |
||||||
|
$this->_connection = $conn; |
||||||
|
foreach ($conn->schemaCachingExclude as $name) |
||||||
|
$this->_cacheExclude[$name] = true; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @return CDbConnection database connection. The connection is active. |
||||||
|
*/ |
||||||
|
public function getDbConnection() |
||||||
|
{ |
||||||
|
return $this->_connection; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Obtains the metadata for the named table. |
||||||
|
* @param string $name table name |
||||||
|
* @return CDbTableSchema table metadata. Null if the named table does not exist. |
||||||
|
*/ |
||||||
|
public function getTable($name) |
||||||
|
{ |
||||||
|
if (isset($this->_tables[$name])) |
||||||
|
return $this->_tables[$name]; |
||||||
|
else |
||||||
|
{ |
||||||
|
if ($this->_connection->tablePrefix !== null && strpos($name, '{{') !== false) |
||||||
|
$realName = preg_replace('/\{\{(.*?)\}\}/', $this->_connection->tablePrefix . '$1', $name); |
||||||
|
else |
||||||
|
$realName = $name; |
||||||
|
|
||||||
|
// temporarily disable query caching |
||||||
|
if ($this->_connection->queryCachingDuration > 0) |
||||||
|
{ |
||||||
|
$qcDuration = $this->_connection->queryCachingDuration; |
||||||
|
$this->_connection->queryCachingDuration = 0; |
||||||
|
} |
||||||
|
|
||||||
|
if (!isset($this->_cacheExclude[$name]) && ($duration = $this->_connection->schemaCachingDuration) > 0 && $this->_connection->schemaCacheID !== false && ($cache = Yii::app()->getComponent($this->_connection->schemaCacheID)) !== null) |
||||||
|
{ |
||||||
|
$key = 'yii:dbschema' . $this->_connection->connectionString . ':' . $this->_connection->username . ':' . $name; |
||||||
|
if (($table = $cache->get($key)) === false) |
||||||
|
{ |
||||||
|
$table = $this->loadTable($realName); |
||||||
|
if ($table !== null) |
||||||
|
$cache->set($key, $table, $duration); |
||||||
|
} |
||||||
|
$this->_tables[$name] = $table; |
||||||
|
} |
||||||
|
else |
||||||
|
$this->_tables[$name] = $table = $this->loadTable($realName); |
||||||
|
|
||||||
|
if (isset($qcDuration)) // re-enable query caching |
||||||
|
$this->_connection->queryCachingDuration = $qcDuration; |
||||||
|
|
||||||
|
return $table; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the metadata for all tables in the database. |
||||||
|
* @param string $schema the schema of the tables. Defaults to empty string, meaning the current or default schema. |
||||||
|
* @return array the metadata for all tables in the database. |
||||||
|
* Each array element is an instance of {@link CDbTableSchema} (or its child class). |
||||||
|
* The array keys are table names. |
||||||
|
* @since 1.0.2 |
||||||
|
*/ |
||||||
|
public function getTables($schema = '') |
||||||
|
{ |
||||||
|
$tables = array(); |
||||||
|
foreach ($this->getTableNames($schema) as $name) |
||||||
|
{ |
||||||
|
if (($table = $this->getTable($name)) !== null) |
||||||
|
$tables[$name] = $table; |
||||||
|
} |
||||||
|
return $tables; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns all table names in the database. |
||||||
|
* @param string $schema the schema of the tables. Defaults to empty string, meaning the current or default schema. |
||||||
|
* If not empty, the returned table names will be prefixed with the schema name. |
||||||
|
* @return array all table names in the database. |
||||||
|
* @since 1.0.2 |
||||||
|
*/ |
||||||
|
public function getTableNames($schema = '') |
||||||
|
{ |
||||||
|
if (!isset($this->_tableNames[$schema])) |
||||||
|
$this->_tableNames[$schema] = $this->findTableNames($schema); |
||||||
|
return $this->_tableNames[$schema]; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @return CDbCommandBuilder the SQL command builder for this connection. |
||||||
|
*/ |
||||||
|
public function getCommandBuilder() |
||||||
|
{ |
||||||
|
if ($this->_builder !== null) |
||||||
|
return $this->_builder; |
||||||
|
else |
||||||
|
return $this->_builder = $this->createCommandBuilder(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Refreshes the schema. |
||||||
|
* This method resets the loaded table metadata and command builder |
||||||
|
* so that they can be recreated to reflect the change of schema. |
||||||
|
*/ |
||||||
|
public function refresh() |
||||||
|
{ |
||||||
|
if (($duration = $this->_connection->schemaCachingDuration) > 0 && $this->_connection->schemaCacheID !== false && ($cache = Yii::app()->getComponent($this->_connection->schemaCacheID)) !== null) |
||||||
|
{ |
||||||
|
foreach (array_keys($this->_tables) as $name) |
||||||
|
{ |
||||||
|
if (!isset($this->_cacheExclude[$name])) |
||||||
|
{ |
||||||
|
$key = 'yii:dbschema' . $this->_connection->connectionString . ':' . $this->_connection->username . ':' . $name; |
||||||
|
$cache->delete($key); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
$this->_tables = array(); |
||||||
|
$this->_tableNames = array(); |
||||||
|
$this->_builder = null; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Quotes a table name for use in a query. |
||||||
|
* If the table name contains schema prefix, the prefix will also be properly quoted. |
||||||
|
* @param string $name table name |
||||||
|
* @return string the properly quoted table name |
||||||
|
* @see quoteSimpleTableName |
||||||
|
*/ |
||||||
|
public function quoteTableName($name) |
||||||
|
{ |
||||||
|
if (strpos($name, '.') === false) |
||||||
|
return $this->quoteSimpleTableName($name); |
||||||
|
$parts = explode('.', $name); |
||||||
|
foreach ($parts as $i => $part) |
||||||
|
$parts[$i] = $this->quoteSimpleTableName($part); |
||||||
|
return implode('.', $parts); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Quotes a simple table name for use in a query. |
||||||
|
* A simple table name does not schema prefix. |
||||||
|
* @param string $name table name |
||||||
|
* @return string the properly quoted table name |
||||||
|
* @since 1.1.6 |
||||||
|
*/ |
||||||
|
public function quoteSimpleTableName($name) |
||||||
|
{ |
||||||
|
return "'" . $name . "'"; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Quotes a column name for use in a query. |
||||||
|
* If the column name contains prefix, the prefix will also be properly quoted. |
||||||
|
* @param string $name column name |
||||||
|
* @return string the properly quoted column name |
||||||
|
* @see quoteSimpleColumnName |
||||||
|
*/ |
||||||
|
public function quoteColumnName($name) |
||||||
|
{ |
||||||
|
if (($pos = strrpos($name, '.')) !== false) |
||||||
|
{ |
||||||
|
$prefix = $this->quoteTableName(substr($name, 0, $pos)) . '.'; |
||||||
|
$name = substr($name, $pos + 1); |
||||||
|
} |
||||||
|
else |
||||||
|
$prefix = ''; |
||||||
|
return $prefix . ($name === '*' ? $name : $this->quoteSimpleColumnName($name)); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Quotes a simple column name for use in a query. |
||||||
|
* A simple column name does not contain prefix. |
||||||
|
* @param string $name column name |
||||||
|
* @return string the properly quoted column name |
||||||
|
* @since 1.1.6 |
||||||
|
*/ |
||||||
|
public function quoteSimpleColumnName($name) |
||||||
|
{ |
||||||
|
return '"' . $name . '"'; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Compares two table names. |
||||||
|
* The table names can be either quoted or unquoted. This method |
||||||
|
* will consider both cases. |
||||||
|
* @param string $name1 table name 1 |
||||||
|
* @param string $name2 table name 2 |
||||||
|
* @return boolean whether the two table names refer to the same table. |
||||||
|
*/ |
||||||
|
public function compareTableNames($name1, $name2) |
||||||
|
{ |
||||||
|
$name1 = str_replace(array('"', '`', "'"), '', $name1); |
||||||
|
$name2 = str_replace(array('"', '`', "'"), '', $name2); |
||||||
|
if (($pos = strrpos($name1, '.')) !== false) |
||||||
|
$name1 = substr($name1, $pos + 1); |
||||||
|
if (($pos = strrpos($name2, '.')) !== false) |
||||||
|
$name2 = substr($name2, $pos + 1); |
||||||
|
if ($this->_connection->tablePrefix !== null) |
||||||
|
{ |
||||||
|
if (strpos($name1, '{') !== false) |
||||||
|
$name1 = $this->_connection->tablePrefix . str_replace(array('{', '}'), '', $name1); |
||||||
|
if (strpos($name2, '{') !== false) |
||||||
|
$name2 = $this->_connection->tablePrefix . str_replace(array('{', '}'), '', $name2); |
||||||
|
} |
||||||
|
return $name1 === $name2; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Resets the sequence value of a table's primary key. |
||||||
|
* The sequence will be reset such that the primary key of the next new row inserted |
||||||
|
* will have the specified value or 1. |
||||||
|
* @param CDbTableSchema $table the table schema whose primary key sequence will be reset |
||||||
|
* @param mixed $value the value for the primary key of the next new row inserted. If this is not set, |
||||||
|
* the next new row's primary key will have a value 1. |
||||||
|
* @since 1.1 |
||||||
|
*/ |
||||||
|
public function resetSequence($table, $value = null) |
||||||
|
{ |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Enables or disables integrity check. |
||||||
|
* @param boolean $check whether to turn on or off the integrity check. |
||||||
|
* @param string $schema the schema of the tables. Defaults to empty string, meaning the current or default schema. |
||||||
|
* @since 1.1 |
||||||
|
*/ |
||||||
|
public function checkIntegrity($check = true, $schema = '') |
||||||
|
{ |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Creates a command builder for the database. |
||||||
|
* This method may be overridden by child classes to create a DBMS-specific command builder. |
||||||
|
* @return CDbCommandBuilder command builder instance |
||||||
|
*/ |
||||||
|
protected function createCommandBuilder() |
||||||
|
{ |
||||||
|
return new CDbCommandBuilder($this); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns all table names in the database. |
||||||
|
* This method should be overridden by child classes in order to support this feature |
||||||
|
* because the default implementation simply throws an exception. |
||||||
|
* @param string $schema the schema of the tables. Defaults to empty string, meaning the current or default schema. |
||||||
|
* If not empty, the returned table names will be prefixed with the schema name. |
||||||
|
* @return array all table names in the database. |
||||||
|
* @since 1.0.2 |
||||||
|
*/ |
||||||
|
protected function findTableNames($schema = '') |
||||||
|
{ |
||||||
|
throw new CDbException(Yii::t('yii', '{class} does not support fetching all table names.', |
||||||
|
array('{class}' => get_class($this)))); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Converts an abstract column type into a physical column type. |
||||||
|
* The conversion is done using the type map specified in {@link columnTypes}. |
||||||
|
* These abstract column types are supported (using MySQL as example to explain the corresponding |
||||||
|
* physical types): |
||||||
|
* <ul> |
||||||
|
* <li>pk: an auto-incremental primary key type, will be converted into "int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY"</li> |
||||||
|
* <li>string: string type, will be converted into "varchar(255)"</li> |
||||||
|
* <li>text: a long string type, will be converted into "text"</li> |
||||||
|
* <li>integer: integer type, will be converted into "int(11)"</li> |
||||||
|
* <li>boolean: boolean type, will be converted into "tinyint(1)"</li> |
||||||
|
* <li>float: float number type, will be converted into "float"</li> |
||||||
|
* <li>decimal: decimal number type, will be converted into "decimal"</li> |
||||||
|
* <li>datetime: datetime type, will be converted into "datetime"</li> |
||||||
|
* <li>timestamp: timestamp type, will be converted into "timestamp"</li> |
||||||
|
* <li>time: time type, will be converted into "time"</li> |
||||||
|
* <li>date: date type, will be converted into "date"</li> |
||||||
|
* <li>binary: binary data type, will be converted into "blob"</li> |
||||||
|
* </ul> |
||||||
|
* |
||||||
|
* If the abstract type contains two or more parts separated by spaces (e.g. "string NOT NULL"), then only |
||||||
|
* the first part will be converted, and the rest of the parts will be appended to the conversion result. |
||||||
|
* For example, 'string NOT NULL' is converted to 'varchar(255) NOT NULL'. |
||||||
|
* @param string $type abstract column type |
||||||
|
* @return string physical column type. |
||||||
|
* @since 1.1.6 |
||||||
|
*/ |
||||||
|
public function getColumnType($type) |
||||||
|
{ |
||||||
|
if (isset($this->columnTypes[$type])) |
||||||
|
return $this->columnTypes[$type]; |
||||||
|
elseif (($pos = strpos($type, ' ')) !== false) |
||||||
|
{ |
||||||
|
$t = substr($type, 0, $pos); |
||||||
|
return (isset($this->columnTypes[$t]) ? $this->columnTypes[$t] : $t) . substr($type, $pos); |
||||||
|
} |
||||||
|
else |
||||||
|
return $type; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Builds a SQL statement for creating a new DB table. |
||||||
|
* |
||||||
|
* The columns in the new table should be specified as name-definition pairs (e.g. 'name'=>'string'), |
||||||
|
* where name stands for a column name which will be properly quoted by the method, and definition |
||||||
|
* stands for the column type which can contain an abstract DB type. |
||||||
|
* The {@link getColumnType} method will be invoked to convert any abstract type into a physical one. |
||||||
|
* |
||||||
|
* If a column is specified with definition only (e.g. 'PRIMARY KEY (name, type)'), it will be directly |
||||||
|
* inserted into the generated SQL. |
||||||
|
* |
||||||
|
* @param string $table the name of the table to be created. The name will be properly quoted by the method. |
||||||
|
* @param array $columns the columns (name=>definition) in the new table. |
||||||
|
* @param string $options additional SQL fragment that will be appended to the generated SQL. |
||||||
|
* @return string the SQL statement for creating a new DB table. |
||||||
|
* @since 1.1.6 |
||||||
|
*/ |
||||||
|
public function createTable($table, $columns, $options = null) |
||||||
|
{ |
||||||
|
$cols = array(); |
||||||
|
foreach ($columns as $name => $type) |
||||||
|
{ |
||||||
|
if (is_string($name)) |
||||||
|
$cols[] = "\t" . $this->quoteColumnName($name) . ' ' . $this->getColumnType($type); |
||||||
|
else |
||||||
|
$cols[] = "\t" . $type; |
||||||
|
} |
||||||
|
$sql = "CREATE TABLE " . $this->quoteTableName($table) . " (\n" . implode(",\n", $cols) . "\n)"; |
||||||
|
return $options === null ? $sql : $sql . ' ' . $options; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Builds a SQL statement for renaming a DB table. |
||||||
|
* @param string $table the table to be renamed. The name will be properly quoted by the method. |
||||||
|
* @param string $newName the new table name. The name will be properly quoted by the method. |
||||||
|
* @return string the SQL statement for renaming a DB table. |
||||||
|
* @since 1.1.6 |
||||||
|
*/ |
||||||
|
public function renameTable($table, $newName) |
||||||
|
{ |
||||||
|
return 'RENAME TABLE ' . $this->quoteTableName($table) . ' TO ' . $this->quoteTableName($newName); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Builds a SQL statement for dropping a DB table. |
||||||
|
* @param string $table the table to be dropped. The name will be properly quoted by the method. |
||||||
|
* @return string the SQL statement for dropping a DB table. |
||||||
|
* @since 1.1.6 |
||||||
|
*/ |
||||||
|
public function dropTable($table) |
||||||
|
{ |
||||||
|
return "DROP TABLE " . $this->quoteTableName($table); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Builds a SQL statement for truncating a DB table. |
||||||
|
* @param string $table the table to be truncated. The name will be properly quoted by the method. |
||||||
|
* @return string the SQL statement for truncating a DB table. |
||||||
|
* @since 1.1.6 |
||||||
|
*/ |
||||||
|
public function truncateTable($table) |
||||||
|
{ |
||||||
|
return "TRUNCATE TABLE " . $this->quoteTableName($table); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Builds a SQL statement for adding a new DB column. |
||||||
|
* @param string $table the table that the new column will be added to. The table name will be properly quoted by the method. |
||||||
|
* @param string $column the name of the new column. The name will be properly quoted by the method. |
||||||
|
* @param string $type the column type. The {@link getColumnType} method will be invoked to convert abstract column type (if any) |
||||||
|
* into the physical one. Anything that is not recognized as abstract type will be kept in the generated SQL. |
||||||
|
* For example, 'string' will be turned into 'varchar(255)', while 'string not null' will become 'varchar(255) not null'. |
||||||
|
* @return string the SQL statement for adding a new column. |
||||||
|
* @since 1.1.6 |
||||||
|
*/ |
||||||
|
public function addColumn($table, $column, $type) |
||||||
|
{ |
||||||
|
return 'ALTER TABLE ' . $this->quoteTableName($table) |
||||||
|
. ' ADD ' . $this->quoteColumnName($column) . ' ' |
||||||
|
. $this->getColumnType($type); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Builds a SQL statement for dropping a DB column. |
||||||
|
* @param string $table the table whose column is to be dropped. The name will be properly quoted by the method. |
||||||
|
* @param string $column the name of the column to be dropped. The name will be properly quoted by the method. |
||||||
|
* @return string the SQL statement for dropping a DB column. |
||||||
|
* @since 1.1.6 |
||||||
|
*/ |
||||||
|
public function dropColumn($table, $column) |
||||||
|
{ |
||||||
|
return "ALTER TABLE " . $this->quoteTableName($table) |
||||||
|
. " DROP COLUMN " . $this->quoteColumnName($column); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Builds a SQL statement for renaming a column. |
||||||
|
* @param string $table the table whose column is to be renamed. The name will be properly quoted by the method. |
||||||
|
* @param string $name the old name of the column. The name will be properly quoted by the method. |
||||||
|
* @param string $newName the new name of the column. The name will be properly quoted by the method. |
||||||
|
* @return string the SQL statement for renaming a DB column. |
||||||
|
* @since 1.1.6 |
||||||
|
*/ |
||||||
|
public function renameColumn($table, $name, $newName) |
||||||
|
{ |
||||||
|
return "ALTER TABLE " . $this->quoteTableName($table) |
||||||
|
. " RENAME COLUMN " . $this->quoteColumnName($name) |
||||||
|
. " TO " . $this->quoteColumnName($newName); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Builds a SQL statement for changing the definition of a column. |
||||||
|
* @param string $table the table whose column is to be changed. The table name will be properly quoted by the method. |
||||||
|
* @param string $column the name of the column to be changed. The name will be properly quoted by the method. |
||||||
|
* @param string $type the new column type. The {@link getColumnType} method will be invoked to convert abstract column type (if any) |
||||||
|
* into the physical one. Anything that is not recognized as abstract type will be kept in the generated SQL. |
||||||
|
* For example, 'string' will be turned into 'varchar(255)', while 'string not null' will become 'varchar(255) not null'. |
||||||
|
* @return string the SQL statement for changing the definition of a column. |
||||||
|
* @since 1.1.6 |
||||||
|
*/ |
||||||
|
public function alterColumn($table, $column, $type) |
||||||
|
{ |
||||||
|
return 'ALTER TABLE ' . $this->quoteTableName($table) . ' CHANGE ' |
||||||
|
. $this->quoteColumnName($column) . ' ' |
||||||
|
. $this->quoteColumnName($column) . ' ' |
||||||
|
. $this->getColumnType($type); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Builds a SQL statement for adding a foreign key constraint to an existing table. |
||||||
|
* The method will properly quote the table and column names. |
||||||
|
* @param string $name the name of the foreign key constraint. |
||||||
|
* @param string $table the table that the foreign key constraint will be added to. |
||||||
|
* @param string $columns the name of the column to that the constraint will be added on. If there are multiple columns, separate them with commas. |
||||||
|
* @param string $refTable the table that the foreign key references to. |
||||||
|
* @param string $refColumns the name of the column that the foreign key references to. If there are multiple columns, separate them with commas. |
||||||
|
* @param string $delete the ON DELETE option. Most DBMS support these options: RESTRICT, CASCADE, NO ACTION, SET DEFAULT, SET NULL |
||||||
|
* @param string $update the ON UPDATE option. Most DBMS support these options: RESTRICT, CASCADE, NO ACTION, SET DEFAULT, SET NULL |
||||||
|
* @return string the SQL statement for adding a foreign key constraint to an existing table. |
||||||
|
* @since 1.1.6 |
||||||
|
*/ |
||||||
|
public function addForeignKey($name, $table, $columns, $refTable, $refColumns, $delete = null, $update = null) |
||||||
|
{ |
||||||
|
$columns = preg_split('/\s*,\s*/', $columns, -1, PREG_SPLIT_NO_EMPTY); |
||||||
|
foreach ($columns as $i => $col) |
||||||
|
$columns[$i] = $this->quoteColumnName($col); |
||||||
|
$refColumns = preg_split('/\s*,\s*/', $refColumns, -1, PREG_SPLIT_NO_EMPTY); |
||||||
|
foreach ($refColumns as $i => $col) |
||||||
|
$refColumns[$i] = $this->quoteColumnName($col); |
||||||
|
$sql = 'ALTER TABLE ' . $this->quoteTableName($table) |
||||||
|
. ' ADD CONSTRAINT ' . $this->quoteColumnName($name) |
||||||
|
. ' FOREIGN KEY (' . implode(', ', $columns) . ')' |
||||||
|
. ' REFERENCES ' . $this->quoteTableName($refTable) |
||||||
|
. ' (' . implode(', ', $refColumns) . ')'; |
||||||
|
if ($delete !== null) |
||||||
|
$sql .= ' ON DELETE ' . $delete; |
||||||
|
if ($update !== null) |
||||||
|
$sql .= ' ON UPDATE ' . $update; |
||||||
|
return $sql; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Builds a SQL statement for dropping a foreign key constraint. |
||||||
|
* @param string $name the name of the foreign key constraint to be dropped. The name will be properly quoted by the method. |
||||||
|
* @param string $table the table whose foreign is to be dropped. The name will be properly quoted by the method. |
||||||
|
* @return string the SQL statement for dropping a foreign key constraint. |
||||||
|
* @since 1.1.6 |
||||||
|
*/ |
||||||
|
public function dropForeignKey($name, $table) |
||||||
|
{ |
||||||
|
return 'ALTER TABLE ' . $this->quoteTableName($table) |
||||||
|
. ' DROP CONSTRAINT ' . $this->quoteColumnName($name); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Builds a SQL statement for creating a new index. |
||||||
|
* @param string $name the name of the index. The name will be properly quoted by the method. |
||||||
|
* @param string $table the table that the new index will be created for. The table name will be properly quoted by the method. |
||||||
|
* @param string $column the column(s) that should be included in the index. If there are multiple columns, please separate them |
||||||
|
* by commas. Each column name will be properly quoted by the method, unless a parenthesis is found in the name. |
||||||
|
* @param boolean $unique whether to add UNIQUE constraint on the created index. |
||||||
|
* @return string the SQL statement for creating a new index. |
||||||
|
* @since 1.1.6 |
||||||
|
*/ |
||||||
|
public function createIndex($name, $table, $column, $unique = false) |
||||||
|
{ |
||||||
|
$cols = array(); |
||||||
|
$columns = preg_split('/\s*,\s*/', $column, -1, PREG_SPLIT_NO_EMPTY); |
||||||
|
foreach ($columns as $col) |
||||||
|
{ |
||||||
|
if (strpos($col, '(') !== false) |
||||||
|
$cols[] = $col; |
||||||
|
else |
||||||
|
$cols[] = $this->quoteColumnName($col); |
||||||
|
} |
||||||
|
return ($unique ? 'CREATE UNIQUE INDEX ' : 'CREATE INDEX ') |
||||||
|
. $this->quoteTableName($name) . ' ON ' |
||||||
|
. $this->quoteTableName($table) . ' (' . implode(', ', $cols) . ')'; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Builds a SQL statement for dropping an index. |
||||||
|
* @param string $name the name of the index to be dropped. The name will be properly quoted by the method. |
||||||
|
* @param string $table the table whose index is to be dropped. The name will be properly quoted by the method. |
||||||
|
* @return string the SQL statement for dropping an index. |
||||||
|
* @since 1.1.6 |
||||||
|
*/ |
||||||
|
public function dropIndex($name, $table) |
||||||
|
{ |
||||||
|
return 'DROP INDEX ' . $this->quoteTableName($name) . ' ON ' . $this->quoteTableName($table); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,76 @@ |
|||||||
|
<?php |
||||||
|
/** |
||||||
|
* CDbTableSchema class file. |
||||||
|
* |
||||||
|
* @author Qiang Xue <qiang.xue@gmail.com> |
||||||
|
* @link http://www.yiiframework.com/ |
||||||
|
* @copyright Copyright © 2008-2011 Yii Software LLC |
||||||
|
* @license http://www.yiiframework.com/license/ |
||||||
|
*/ |
||||||
|
|
||||||
|
/** |
||||||
|
* CDbTableSchema is the base class for representing the metadata of a database table. |
||||||
|
* |
||||||
|
* It may be extended by different DBMS driver to provide DBMS-specific table metadata. |
||||||
|
* |
||||||
|
* CDbTableSchema provides the following information about a table: |
||||||
|
* <ul> |
||||||
|
* <li>{@link name}</li> |
||||||
|
* <li>{@link rawName}</li> |
||||||
|
* <li>{@link columns}</li> |
||||||
|
* <li>{@link primaryKey}</li> |
||||||
|
* <li>{@link foreignKeys}</li> |
||||||
|
* <li>{@link sequenceName}</li> |
||||||
|
* </ul> |
||||||
|
* |
||||||
|
* @author Qiang Xue <qiang.xue@gmail.com> |
||||||
|
* @version $Id: CDbTableSchema.php 2799 2011-01-01 19:31:13Z qiang.xue $ |
||||||
|
* @package system.db.schema |
||||||
|
* @since 1.0 |
||||||
|
*/ |
||||||
|
class CDbTableSchema extends CComponent |
||||||
|
{ |
||||||
|
/** |
||||||
|
* @var string name of this table. |
||||||
|
*/ |
||||||
|
public $name; |
||||||
|
/** |
||||||
|
* @var string raw name of this table. This is the quoted version of table name with optional schema name. It can be directly used in SQLs. |
||||||
|
*/ |
||||||
|
public $rawName; |
||||||
|
/** |
||||||
|
* @var string|array primary key name of this table. If composite key, an array of key names is returned. |
||||||
|
*/ |
||||||
|
public $primaryKey; |
||||||
|
/** |
||||||
|
* @var string sequence name for the primary key. Null if no sequence. |
||||||
|
*/ |
||||||
|
public $sequenceName; |
||||||
|
/** |
||||||
|
* @var array foreign keys of this table. The array is indexed by column name. Each value is an array of foreign table name and foreign column name. |
||||||
|
*/ |
||||||
|
public $foreignKeys = array(); |
||||||
|
/** |
||||||
|
* @var array column metadata of this table. Each array element is a CDbColumnSchema object, indexed by column names. |
||||||
|
*/ |
||||||
|
public $columns = array(); |
||||||
|
|
||||||
|
/** |
||||||
|
* Gets the named column metadata. |
||||||
|
* This is a convenient method for retrieving a named column even if it does not exist. |
||||||
|
* @param string $name column name |
||||||
|
* @return CDbColumnSchema metadata of the named column. Null if the named column does not exist. |
||||||
|
*/ |
||||||
|
public function getColumn($name) |
||||||
|
{ |
||||||
|
return isset($this->columns[$name]) ? $this->columns[$name] : null; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @return array list of column names |
||||||
|
*/ |
||||||
|
public function getColumnNames() |
||||||
|
{ |
||||||
|
return array_keys($this->columns); |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue