Browse Source
Implement retrieving DBMS constraints * db-constraints2: (21 commits) CHANGELOG for #14105 added missing abstract methods to ConstraintFinderTrait avoid dependency of SqlTokenizer on sqlite implementation Mention an usage magic in descriptions Fix an unknown variable usage bug updated phpdoc make schema cache version a constant Have I fixed these phpdocs? Let’s see… Fixed phpdoc [skip ci] Mark not supported constraint retrieving methods Add PHPDoc Fix typo [skip ci] Rename DefaultConstraint to DefaultValueConstraint Fix imports Fix merging issues & CS Add Command tests Fix constraint tests Disable column comment test on old CUBRID Fix dropping unique/indexes Fix schema caching on commands ...tags/2.0.13
Carsten Brandt
7 years ago
51 changed files with 5805 additions and 440 deletions
@ -0,0 +1,22 @@
|
||||
<?php |
||||
/** |
||||
* @link http://www.yiiframework.com/ |
||||
* @copyright Copyright (c) 2008 Yii Software LLC |
||||
* @license http://www.yiiframework.com/license/ |
||||
*/ |
||||
|
||||
namespace yii\db; |
||||
|
||||
/** |
||||
* CheckConstraint represents the metadata of a table `CHECK` constraint. |
||||
* |
||||
* @author Sergey Makinen <sergey@makinen.ru> |
||||
* @since 2.0.13 |
||||
*/ |
||||
class CheckConstraint extends Constraint |
||||
{ |
||||
/** |
||||
* @var string the SQL of the `CHECK` constraint. |
||||
*/ |
||||
public $expression; |
||||
} |
@ -0,0 +1,28 @@
|
||||
<?php |
||||
/** |
||||
* @link http://www.yiiframework.com/ |
||||
* @copyright Copyright (c) 2008 Yii Software LLC |
||||
* @license http://www.yiiframework.com/license/ |
||||
*/ |
||||
|
||||
namespace yii\db; |
||||
|
||||
use yii\base\Object; |
||||
|
||||
/** |
||||
* Constraint represents the metadata of a table constraint. |
||||
* |
||||
* @author Sergey Makinen <sergey@makinen.ru> |
||||
* @since 2.0.13 |
||||
*/ |
||||
class Constraint extends Object |
||||
{ |
||||
/** |
||||
* @var string[]|null list of column names the constraint belongs to. |
||||
*/ |
||||
public $columnNames; |
||||
/** |
||||
* @var string|null the constraint name. |
||||
*/ |
||||
public $name; |
||||
} |
@ -0,0 +1,236 @@
|
||||
<?php |
||||
/** |
||||
* @link http://www.yiiframework.com/ |
||||
* @copyright Copyright (c) 2008 Yii Software LLC |
||||
* @license http://www.yiiframework.com/license/ |
||||
*/ |
||||
|
||||
namespace yii\db; |
||||
|
||||
/** |
||||
* ConstraintFinderTrait provides methods for getting a table constraint information. |
||||
* |
||||
* @property CheckConstraint[][] $schemaChecks Check constraints for all tables in the database. |
||||
* Each array element is an array of [[CheckConstraint]] or its child classes. This property is read-only. |
||||
* @property DefaultValueConstraint[] $schemaDefaultValues Default value constraints for all tables in the database. |
||||
* Each array element is an array of [[DefaultValueConstraint]] or its child classes. This property is read-only. |
||||
* @property ForeignKeyConstraint[][] $schemaForeignKeys Foreign keys for all tables in the database. Each |
||||
* array element is an array of [[ForeignKeyConstraint]] or its child classes. This property is read-only. |
||||
* @property IndexConstraint[][] $schemaIndexes Indexes for all tables in the database. Each array element is |
||||
* an array of [[IndexConstraint]] or its child classes. This property is read-only. |
||||
* @property Constraint[] $schemaPrimaryKeys Primary keys for all tables in the database. Each array element |
||||
* is an instance of [[Constraint]] or its child class. This property is read-only. |
||||
* @property IndexConstraint[][] $schemaUniques Unique constraints for all tables in the database. |
||||
* Each array element is an array of [[IndexConstraint]] or its child classes. This property is read-only. |
||||
* |
||||
* @author Sergey Makinen <sergey@makinen.ru> |
||||
* @since 2.0.13 |
||||
*/ |
||||
trait ConstraintFinderTrait |
||||
{ |
||||
/** |
||||
* Returns the metadata of the given type for the given table. |
||||
* @param string $name table name. The table name may contain schema name if any. Do not quote the table name. |
||||
* @param string $type metadata type. |
||||
* @param bool $refresh whether to reload the table metadata even if it is found in the cache. |
||||
* @return mixed metadata. |
||||
*/ |
||||
abstract protected function getTableMetadata($name, $type, $refresh); |
||||
|
||||
/** |
||||
* Returns the metadata of the given type for all tables in the given schema. |
||||
* @param string $schema the schema of the metadata. Defaults to empty string, meaning the current or default schema name. |
||||
* @param string $type metadata type. |
||||
* @param bool $refresh whether to fetch the latest available table metadata. If this is `false`, |
||||
* cached data may be returned if available. |
||||
* @return array array of metadata. |
||||
*/ |
||||
abstract protected function getSchemaMetadata($schema, $type, $refresh); |
||||
|
||||
/** |
||||
* Loads a primary key for the given table. |
||||
* @param string $tableName table name. |
||||
* @return Constraint|null primary key for the given table, `null` if the table has no primary key. |
||||
*/ |
||||
abstract protected function loadTablePrimaryKey($tableName); |
||||
|
||||
/** |
||||
* Loads all foreign keys for the given table. |
||||
* @param string $tableName table name. |
||||
* @return ForeignKeyConstraint[] foreign keys for the given table. |
||||
*/ |
||||
abstract protected function loadTableForeignKeys($tableName); |
||||
|
||||
/** |
||||
* Loads all indexes for the given table. |
||||
* @param string $tableName table name. |
||||
* @return IndexConstraint[] indexes for the given table. |
||||
*/ |
||||
abstract protected function loadTableIndexes($tableName); |
||||
|
||||
/** |
||||
* Loads all unique constraints for the given table. |
||||
* @param string $tableName table name. |
||||
* @return Constraint[] unique constraints for the given table. |
||||
*/ |
||||
abstract protected function loadTableUniques($tableName); |
||||
|
||||
/** |
||||
* Loads all check constraints for the given table. |
||||
* @param string $tableName table name. |
||||
* @return CheckConstraint[] check constraints for the given table. |
||||
*/ |
||||
abstract protected function loadTableChecks($tableName); |
||||
|
||||
/** |
||||
* Loads all default value constraints for the given table. |
||||
* |
||||
* @param string $tableName table name. |
||||
* @return DefaultValueConstraint[] default value constraints for the given table. |
||||
*/ |
||||
abstract protected function loadTableDefaultValues($tableName); |
||||
|
||||
/** |
||||
* Obtains the primary key for the named table. |
||||
* @param string $name table name. The table name may contain schema name if any. Do not quote the table name. |
||||
* @param bool $refresh whether to reload the information even if it is found in the cache. |
||||
* @return Constraint|null table primary key, `null` if the table has no primary key. |
||||
*/ |
||||
public function getTablePrimaryKey($name, $refresh = false) |
||||
{ |
||||
return $this->getTableMetadata($name, 'primaryKey', $refresh); |
||||
} |
||||
|
||||
/** |
||||
* Returns primary keys for all tables in the database. |
||||
* @param string $schema the schema of the tables. Defaults to empty string, meaning the current or default schema name. |
||||
* @param bool $refresh whether to fetch the latest available table schemas. If this is `false`, |
||||
* cached data may be returned if available. |
||||
* @return Constraint[] primary keys for all tables in the database. |
||||
* Each array element is an instance of [[Constraint]] or its child class. |
||||
*/ |
||||
public function getSchemaPrimaryKeys($schema = '', $refresh = false) |
||||
{ |
||||
return $this->getSchemaMetadata($schema, 'primaryKey', $refresh); |
||||
} |
||||
|
||||
/** |
||||
* Obtains the foreign keys information for the named table. |
||||
* @param string $name table name. The table name may contain schema name if any. Do not quote the table name. |
||||
* @param bool $refresh whether to reload the information even if it is found in the cache. |
||||
* @return ForeignKeyConstraint[] table foreign keys. |
||||
*/ |
||||
public function getTableForeignKeys($name, $refresh = false) |
||||
{ |
||||
return $this->getTableMetadata($name, 'foreignKeys', $refresh); |
||||
} |
||||
|
||||
/** |
||||
* Returns foreign keys for all tables in the database. |
||||
* @param string $schema the schema of the tables. Defaults to empty string, meaning the current or default schema name. |
||||
* @param bool $refresh whether to fetch the latest available table schemas. If this is false, |
||||
* cached data may be returned if available. |
||||
* @return ForeignKeyConstraint[][] foreign keys for all tables in the database. |
||||
* Each array element is an array of [[ForeignKeyConstraint]] or its child classes. |
||||
*/ |
||||
public function getSchemaForeignKeys($schema = '', $refresh = false) |
||||
{ |
||||
return $this->getSchemaMetadata($schema, 'foreignKeys', $refresh); |
||||
} |
||||
|
||||
/** |
||||
* Obtains the indexes information for the named table. |
||||
* @param string $name table name. The table name may contain schema name if any. Do not quote the table name. |
||||
* @param bool $refresh whether to reload the information even if it is found in the cache. |
||||
* @return IndexConstraint[] table indexes. |
||||
*/ |
||||
public function getTableIndexes($name, $refresh = false) |
||||
{ |
||||
return $this->getTableMetadata($name, 'indexes', $refresh); |
||||
} |
||||
|
||||
/** |
||||
* Returns indexes for all tables in the database. |
||||
* @param string $schema the schema of the tables. Defaults to empty string, meaning the current or default schema name. |
||||
* @param bool $refresh whether to fetch the latest available table schemas. If this is false, |
||||
* cached data may be returned if available. |
||||
* @return IndexConstraint[][] indexes for all tables in the database. |
||||
* Each array element is an array of [[IndexConstraint]] or its child classes. |
||||
*/ |
||||
public function getSchemaIndexes($schema = '', $refresh = false) |
||||
{ |
||||
return $this->getSchemaMetadata($schema, 'indexes', $refresh); |
||||
} |
||||
|
||||
/** |
||||
* Obtains the unique constraints information for the named table. |
||||
* @param string $name table name. The table name may contain schema name if any. Do not quote the table name. |
||||
* @param bool $refresh whether to reload the information even if it is found in the cache. |
||||
* @return Constraint[] table unique constraints. |
||||
*/ |
||||
public function getTableUniques($name, $refresh = false) |
||||
{ |
||||
return $this->getTableMetadata($name, 'uniques', $refresh); |
||||
} |
||||
|
||||
/** |
||||
* Returns unique constraints for all tables in the database. |
||||
* @param string $schema the schema of the tables. Defaults to empty string, meaning the current or default schema name. |
||||
* @param bool $refresh whether to fetch the latest available table schemas. If this is false, |
||||
* cached data may be returned if available. |
||||
* @return Constraint[][] unique constraints for all tables in the database. |
||||
* Each array element is an array of [[Constraint]] or its child classes. |
||||
*/ |
||||
public function getSchemaUniques($schema = '', $refresh = false) |
||||
{ |
||||
return $this->getSchemaMetadata($schema, 'uniques', $refresh); |
||||
} |
||||
|
||||
/** |
||||
* Obtains the check constraints information for the named table. |
||||
* @param string $name table name. The table name may contain schema name if any. Do not quote the table name. |
||||
* @param bool $refresh whether to reload the information even if it is found in the cache. |
||||
* @return CheckConstraint[] table check constraints. |
||||
*/ |
||||
public function getTableChecks($name, $refresh = false) |
||||
{ |
||||
return $this->getTableMetadata($name, 'checks', $refresh); |
||||
} |
||||
|
||||
/** |
||||
* Returns check constraints for all tables in the database. |
||||
* @param string $schema the schema of the tables. Defaults to empty string, meaning the current or default schema name. |
||||
* @param bool $refresh whether to fetch the latest available table schemas. If this is false, |
||||
* cached data may be returned if available. |
||||
* @return CheckConstraint[][] check constraints for all tables in the database. |
||||
* Each array element is an array of [[CheckConstraint]] or its child classes. |
||||
*/ |
||||
public function getSchemaChecks($schema = '', $refresh = false) |
||||
{ |
||||
return $this->getSchemaMetadata($schema, 'checks', $refresh); |
||||
} |
||||
|
||||
/** |
||||
* Obtains the default value constraints information for the named table. |
||||
* @param string $name table name. The table name may contain schema name if any. Do not quote the table name. |
||||
* @param bool $refresh whether to reload the information even if it is found in the cache. |
||||
* @return DefaultValueConstraint[] table default value constraints. |
||||
*/ |
||||
public function getTableDefaultValues($name, $refresh = false) |
||||
{ |
||||
return $this->getTableMetadata($name, 'defaultValues', $refresh); |
||||
} |
||||
|
||||
/** |
||||
* Returns default value constraints for all tables in the database. |
||||
* @param string $schema the schema of the tables. Defaults to empty string, meaning the current or default schema name. |
||||
* @param bool $refresh whether to fetch the latest available table schemas. If this is false, |
||||
* cached data may be returned if available. |
||||
* @return DefaultValueConstraint[] default value constraints for all tables in the database. |
||||
* Each array element is an array of [[DefaultValueConstraint]] or its child classes. |
||||
*/ |
||||
public function getSchemaDefaultValues($schema = '', $refresh = false) |
||||
{ |
||||
return $this->getSchemaMetadata($schema, 'defaultValues', $refresh); |
||||
} |
||||
} |
@ -0,0 +1,22 @@
|
||||
<?php |
||||
/** |
||||
* @link http://www.yiiframework.com/ |
||||
* @copyright Copyright (c) 2008 Yii Software LLC |
||||
* @license http://www.yiiframework.com/license/ |
||||
*/ |
||||
|
||||
namespace yii\db; |
||||
|
||||
/** |
||||
* DefaultValueConstraint represents the metadata of a table `DEFAULT` constraint. |
||||
* |
||||
* @author Sergey Makinen <sergey@makinen.ru> |
||||
* @since 2.0.13 |
||||
*/ |
||||
class DefaultValueConstraint extends Constraint |
||||
{ |
||||
/** |
||||
* @var mixed default value as returned by the DBMS. |
||||
*/ |
||||
public $value; |
||||
} |
@ -0,0 +1,38 @@
|
||||
<?php |
||||
/** |
||||
* @link http://www.yiiframework.com/ |
||||
* @copyright Copyright (c) 2008 Yii Software LLC |
||||
* @license http://www.yiiframework.com/license/ |
||||
*/ |
||||
|
||||
namespace yii\db; |
||||
|
||||
/** |
||||
* ForeignKeyConstraint represents the metadata of a table `FOREIGN KEY` constraint. |
||||
* |
||||
* @author Sergey Makinen <sergey@makinen.ru> |
||||
* @since 2.0.13 |
||||
*/ |
||||
class ForeignKeyConstraint extends Constraint |
||||
{ |
||||
/** |
||||
* @var string|null referenced table schema name. |
||||
*/ |
||||
public $foreignSchemaName; |
||||
/** |
||||
* @var string referenced table name. |
||||
*/ |
||||
public $foreignTableName; |
||||
/** |
||||
* @var string[] list of referenced table column names. |
||||
*/ |
||||
public $foreignColumnNames; |
||||
/** |
||||
* @var string|null referential action if rows in a referenced table are to be updated. |
||||
*/ |
||||
public $onUpdate; |
||||
/** |
||||
* @var string|null referential action if rows in a referenced table are to be deleted. |
||||
*/ |
||||
public $onDelete; |
||||
} |
@ -0,0 +1,26 @@
|
||||
<?php |
||||
/** |
||||
* @link http://www.yiiframework.com/ |
||||
* @copyright Copyright (c) 2008 Yii Software LLC |
||||
* @license http://www.yiiframework.com/license/ |
||||
*/ |
||||
|
||||
namespace yii\db; |
||||
|
||||
/** |
||||
* IndexConstraint represents the metadata of a table `INDEX` constraint. |
||||
* |
||||
* @author Sergey Makinen <sergey@makinen.ru> |
||||
* @since 2.0.13 |
||||
*/ |
||||
class IndexConstraint extends Constraint |
||||
{ |
||||
/** |
||||
* @var bool whether the index is unique. |
||||
*/ |
||||
public $isUnique; |
||||
/** |
||||
* @var bool whether the index was created for a primary key. |
||||
*/ |
||||
public $isPrimary; |
||||
} |
@ -0,0 +1,309 @@
|
||||
<?php |
||||
/** |
||||
* @link http://www.yiiframework.com/ |
||||
* @copyright Copyright (c) 2008 Yii Software LLC |
||||
* @license http://www.yiiframework.com/license/ |
||||
*/ |
||||
|
||||
namespace yii\db; |
||||
|
||||
use yii\base\Object; |
||||
|
||||
/** |
||||
* SqlToken represents SQL tokens produced by [[SqlTokenizer]] or its child classes. |
||||
* |
||||
* @property SqlToken[] $children Child tokens. |
||||
* @property bool $hasChildren Whether the token has children. This property is read-only. |
||||
* @property bool $isCollection Whether the token represents a collection of tokens. This property is |
||||
* read-only. |
||||
* @property string $sql SQL code. This property is read-only. |
||||
* |
||||
* @author Sergey Makinen <sergey@makinen.ru> |
||||
* @since 2.0.13 |
||||
*/ |
||||
class SqlToken extends Object implements \ArrayAccess |
||||
{ |
||||
const TYPE_CODE = 0; |
||||
const TYPE_STATEMENT = 1; |
||||
const TYPE_TOKEN = 2; |
||||
const TYPE_PARENTHESIS = 3; |
||||
const TYPE_KEYWORD = 4; |
||||
const TYPE_OPERATOR = 5; |
||||
const TYPE_IDENTIFIER = 6; |
||||
const TYPE_STRING_LITERAL = 7; |
||||
|
||||
/** |
||||
* @var int token type. It has to be one of the following constants: |
||||
* |
||||
* - [[TYPE_CODE]] |
||||
* - [[TYPE_STATEMENT]] |
||||
* - [[TYPE_TOKEN]] |
||||
* - [[TYPE_PARENTHESIS]] |
||||
* - [[TYPE_KEYWORD]] |
||||
* - [[TYPE_OPERATOR]] |
||||
* - [[TYPE_IDENTIFIER]] |
||||
* - [[TYPE_STRING_LITERAL]] |
||||
*/ |
||||
public $type = self::TYPE_TOKEN; |
||||
/** |
||||
* @var string|null token content. |
||||
*/ |
||||
public $content; |
||||
/** |
||||
* @var int original SQL token start position. |
||||
*/ |
||||
public $startOffset; |
||||
/** |
||||
* @var int original SQL token end position. |
||||
*/ |
||||
public $endOffset; |
||||
/** |
||||
* @var SqlToken parent token. |
||||
*/ |
||||
public $parent; |
||||
|
||||
/** |
||||
* @var SqlToken[] token children. |
||||
*/ |
||||
private $_children = []; |
||||
|
||||
|
||||
/** |
||||
* Returns the SQL code representing the token. |
||||
* @return string SQL code. |
||||
*/ |
||||
public function __toString() |
||||
{ |
||||
return $this->getSql(); |
||||
} |
||||
|
||||
/** |
||||
* Returns whether there is a child token at the specified offset. |
||||
* This method is required by the SPL [[\ArrayAccess]] interface. |
||||
* It is implicitly called when you use something like `isset($token[$offset])`. |
||||
* @param int $offset child token offset. |
||||
* @return bool whether the token exists. |
||||
*/ |
||||
public function offsetExists($offset) |
||||
{ |
||||
return isset($this->_children[$this->calculateOffset($offset)]); |
||||
} |
||||
|
||||
/** |
||||
* Returns a child token at the specified offset. |
||||
* This method is required by the SPL [[\ArrayAccess]] interface. |
||||
* It is implicitly called when you use something like `$child = $token[$offset];`. |
||||
* @param int $offset child token offset. |
||||
* @return SqlToken|null the child token at the specified offset, `null` if there's no token. |
||||
*/ |
||||
public function offsetGet($offset) |
||||
{ |
||||
$offset = $this->calculateOffset($offset); |
||||
return isset($this->_children[$offset]) ? $this->_children[$offset] : null; |
||||
} |
||||
|
||||
/** |
||||
* Adds a child token to the token. |
||||
* This method is required by the SPL [[\ArrayAccess]] interface. |
||||
* It is implicitly called when you use something like `$token[$offset] = $child;`. |
||||
* @param int|null $offset child token offset. |
||||
* @param SqlToken $token token to be added. |
||||
*/ |
||||
public function offsetSet($offset, $token) |
||||
{ |
||||
$token->parent = $this; |
||||
if ($offset === null) { |
||||
$this->_children[] = $token; |
||||
} else { |
||||
$this->_children[$this->calculateOffset($offset)] = $token; |
||||
} |
||||
$this->updateCollectionOffsets(); |
||||
} |
||||
|
||||
/** |
||||
* Removes a child token at the specified offset. |
||||
* This method is required by the SPL [[\ArrayAccess]] interface. |
||||
* It is implicitly called when you use something like `unset($token[$offset])`. |
||||
* @param int $offset child token offset. |
||||
*/ |
||||
public function offsetUnset($offset) |
||||
{ |
||||
$offset = $this->calculateOffset($offset); |
||||
if (isset($this->_children[$offset])) { |
||||
array_splice($this->_children, $offset, 1); |
||||
} |
||||
$this->updateCollectionOffsets(); |
||||
} |
||||
|
||||
/** |
||||
* Returns child tokens. |
||||
* @return SqlToken[] child tokens. |
||||
*/ |
||||
public function getChildren() |
||||
{ |
||||
return $this->_children; |
||||
} |
||||
|
||||
/** |
||||
* Sets a list of child tokens. |
||||
* @param SqlToken[] $children child tokens. |
||||
*/ |
||||
public function setChildren($children) |
||||
{ |
||||
$this->_children = []; |
||||
foreach ($children as $child) { |
||||
$child->parent = $this; |
||||
$this->_children[] = $child; |
||||
} |
||||
$this->updateCollectionOffsets(); |
||||
} |
||||
|
||||
/** |
||||
* Returns whether the token represents a collection of tokens. |
||||
* @return bool whether the token represents a collection of tokens. |
||||
*/ |
||||
public function getIsCollection() |
||||
{ |
||||
return in_array($this->type, [ |
||||
self::TYPE_CODE, |
||||
self::TYPE_STATEMENT, |
||||
self::TYPE_PARENTHESIS, |
||||
], true); |
||||
} |
||||
|
||||
/** |
||||
* Returns whether the token represents a collection of tokens and has non-zero number of children. |
||||
* @return bool whether the token has children. |
||||
*/ |
||||
public function getHasChildren() |
||||
{ |
||||
return $this->getIsCollection() && !empty($this->_children); |
||||
} |
||||
|
||||
/** |
||||
* Returns the SQL code representing the token. |
||||
* @return string SQL code. |
||||
*/ |
||||
public function getSql() |
||||
{ |
||||
$code = $this; |
||||
while ($code->parent !== null) { |
||||
$code = $code->parent; |
||||
} |
||||
return mb_substr($code->content, $this->startOffset, $this->endOffset - $this->startOffset, 'UTF-8'); |
||||
} |
||||
|
||||
/** |
||||
* Returns whether this token (including its children) matches the specified "pattern" SQL code. |
||||
* |
||||
* Usage Example: |
||||
* |
||||
* ```php |
||||
* $patternToken = (new \yii\db\sqlite\SqlTokenizer('SELECT any FROM any'))->tokenize(); |
||||
* if ($sqlToken->matches($patternToken, 0, $firstMatchIndex, $lastMatchIndex)) { |
||||
* // ... |
||||
* } |
||||
* ``` |
||||
* |
||||
* @param SqlToken $patternToken tokenized SQL code to match against. In addition to normal SQL, the |
||||
* `any` keyword is supported which will match any number of keywords, identifiers, whitespaces. |
||||
* @param int $offset token children offset to start lookup with. |
||||
* @param int|null $firstMatchIndex token children offset where a successful match begins. |
||||
* @param int|null $lastMatchIndex token children offset where a successful match ends. |
||||
* @return bool whether this token matches the pattern SQL code. |
||||
*/ |
||||
public function matches(SqlToken $patternToken, $offset = 0, &$firstMatchIndex = null, &$lastMatchIndex = null) |
||||
{ |
||||
if (!$patternToken->getHasChildren()) { |
||||
return false; |
||||
} |
||||
|
||||
$patternToken = $patternToken[0]; |
||||
return $this->tokensMatch($patternToken, $this, $offset, $firstMatchIndex, $lastMatchIndex); |
||||
} |
||||
|
||||
/** |
||||
* Tests the given token to match the specified pattern token. |
||||
* @param SqlToken $patternToken |
||||
* @param SqlToken $token |
||||
* @param int $offset |
||||
* @param int|null $firstMatchIndex |
||||
* @param int|null $lastMatchIndex |
||||
* @return bool |
||||
*/ |
||||
private function tokensMatch(SqlToken $patternToken, SqlToken $token, $offset = 0, &$firstMatchIndex = null, &$lastMatchIndex = null) |
||||
{ |
||||
if ( |
||||
$patternToken->getIsCollection() !== $token->getIsCollection() |
||||
|| (!$patternToken->getIsCollection() && $patternToken->content !== $token->content) |
||||
) { |
||||
return false; |
||||
} |
||||
|
||||
if ($patternToken->children === $token->children) { |
||||
$firstMatchIndex = $lastMatchIndex = $offset; |
||||
return true; |
||||
} |
||||
|
||||
$firstMatchIndex = $lastMatchIndex = null; |
||||
$wildcard = false; |
||||
for ($index = 0, $count = count($patternToken->children); $index < $count; $index++) { |
||||
// Here we iterate token by token with an exception of "any" that toggles |
||||
// an iteration until we matched with a next pattern token or EOF. |
||||
if ($patternToken[$index]->content === 'any') { |
||||
$wildcard = true; |
||||
continue; |
||||
} |
||||
|
||||
for ($limit = $wildcard ? count($token->children) : $offset + 1; $offset < $limit; $offset++) { |
||||
if (!$wildcard && !isset($token[$offset])) { |
||||
break; |
||||
} |
||||
|
||||
if (!$this->tokensMatch($patternToken[$index], $token[$offset])) { |
||||
continue; |
||||
} |
||||
|
||||
if ($firstMatchIndex === null) { |
||||
$firstMatchIndex = $offset; |
||||
$lastMatchIndex = $offset; |
||||
} else { |
||||
$lastMatchIndex = $offset; |
||||
} |
||||
$wildcard = false; |
||||
$offset++; |
||||
continue 2; |
||||
} |
||||
return false; |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* Returns an absolute offset in the children array. |
||||
* @param int $offset |
||||
* @return int |
||||
*/ |
||||
private function calculateOffset($offset) |
||||
{ |
||||
if ($offset >= 0) { |
||||
return $offset; |
||||
} |
||||
|
||||
return count($this->_children) + $offset; |
||||
} |
||||
|
||||
/** |
||||
* Updates token SQL code start and end offsets based on its children. |
||||
*/ |
||||
private function updateCollectionOffsets() |
||||
{ |
||||
if (!empty($this->_children)) { |
||||
$this->startOffset = reset($this->_children)->startOffset; |
||||
$this->endOffset = end($this->_children)->endOffset; |
||||
} |
||||
if ($this->parent !== null) { |
||||
$this->parent->updateCollectionOffsets(); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,389 @@
|
||||
<?php |
||||
/** |
||||
* @link http://www.yiiframework.com/ |
||||
* @copyright Copyright (c) 2008 Yii Software LLC |
||||
* @license http://www.yiiframework.com/license/ |
||||
*/ |
||||
|
||||
namespace yii\db; |
||||
|
||||
use yii\base\Component; |
||||
use yii\base\InvalidParamException; |
||||
|
||||
/** |
||||
* SqlTokenizer splits an SQL query into individual SQL tokens. |
||||
* |
||||
* It can be used to obtain an addition information from an SQL code. |
||||
* |
||||
* Usage example: |
||||
* |
||||
* ```php |
||||
* $tokenizer = new SqlTokenizer("SELECT * FROM user WHERE id = 1"); |
||||
* $root = $tokeinzer->tokenize(); |
||||
* $sqlTokens = $root->getChildren(); |
||||
* ``` |
||||
* |
||||
* Tokens are instances of [[SqlToken]]. |
||||
* |
||||
* @author Sergey Makinen <sergey@makinen.ru> |
||||
* @since 2.0.13 |
||||
*/ |
||||
abstract class SqlTokenizer extends Component |
||||
{ |
||||
/** |
||||
* @var string SQL code. |
||||
*/ |
||||
public $sql; |
||||
|
||||
/** |
||||
* @var int SQL code string length. |
||||
*/ |
||||
protected $length; |
||||
/** |
||||
* @var int SQL code string current offset. |
||||
*/ |
||||
protected $offset; |
||||
|
||||
/** |
||||
* @var \SplStack stack of active tokens. |
||||
*/ |
||||
private $_tokenStack; |
||||
/** |
||||
* @var SqlToken active token. It's usually a top of the token stack. |
||||
*/ |
||||
private $_currentToken; |
||||
/** |
||||
* @var string[] cached substrings. |
||||
*/ |
||||
private $_substrings; |
||||
/** |
||||
* @var string current buffer value. |
||||
*/ |
||||
private $_buffer = ''; |
||||
/** |
||||
* @var SqlToken resulting token of a last [[tokenize()]] call. |
||||
*/ |
||||
private $_token; |
||||
|
||||
|
||||
/** |
||||
* Constructor. |
||||
* @param string $sql SQL code to be tokenized. |
||||
* @param array $config name-value pairs that will be used to initialize the object properties |
||||
*/ |
||||
public function __construct($sql, $config = []) |
||||
{ |
||||
$this->sql = $sql; |
||||
parent::__construct($config); |
||||
} |
||||
|
||||
/** |
||||
* Tokenizes and returns a code type token. |
||||
* @return SqlToken code type token. |
||||
*/ |
||||
public function tokenize() |
||||
{ |
||||
$this->length = mb_strlen($this->sql, 'UTF-8'); |
||||
$this->offset = 0; |
||||
$this->_substrings = []; |
||||
$this->_buffer = ''; |
||||
$this->_token = new SqlToken([ |
||||
'type' => SqlToken::TYPE_CODE, |
||||
'content' => $this->sql, |
||||
]); |
||||
$this->_tokenStack = new \SplStack(); |
||||
$this->_tokenStack->push($this->_token); |
||||
$this->_token[] = new SqlToken(['type' => SqlToken::TYPE_STATEMENT]); |
||||
$this->_tokenStack->push($this->_token[0]); |
||||
$this->_currentToken = $this->_tokenStack->top(); |
||||
while (!$this->isEof()) { |
||||
if ($this->isWhitespace($length) || $this->isComment($length)) { |
||||
$this->addTokenFromBuffer(); |
||||
$this->advance($length); |
||||
continue; |
||||
} |
||||
|
||||
if ($this->tokenizeOperator($length) || $this->tokenizeDelimitedString($length)) { |
||||
$this->advance($length); |
||||
continue; |
||||
} |
||||
|
||||
$this->_buffer .= $this->substring(1); |
||||
$this->advance(1); |
||||
} |
||||
$this->addTokenFromBuffer(); |
||||
if ($this->_token->getHasChildren() && !$this->_token[-1]->getHasChildren()) { |
||||
unset($this->_token[-1]); |
||||
} |
||||
return $this->_token; |
||||
} |
||||
|
||||
/** |
||||
* Returns whether there's a whitespace at the current offset. |
||||
* If this methos returns `true`, it has to set the `$length` parameter to the length of the matched string. |
||||
* @param int $length length of the matched string. |
||||
* @return bool whether there's a whitespace at the current offset. |
||||
*/ |
||||
abstract protected function isWhitespace(&$length); |
||||
|
||||
/** |
||||
* Returns whether there's a commentary at the current offset. |
||||
* If this methos returns `true`, it has to set the `$length` parameter to the length of the matched string. |
||||
* @param int $length length of the matched string. |
||||
* @return bool whether there's a commentary at the current offset. |
||||
*/ |
||||
abstract protected function isComment(&$length); |
||||
|
||||
/** |
||||
* Returns whether there's an operator at the current offset. |
||||
* If this methos returns `true`, it has to set the `$length` parameter to the length of the matched string. |
||||
* It may also set `$content` to a string that will be used as a token content. |
||||
* @param int $length length of the matched string. |
||||
* @param string $content optional content instead of the matched string. |
||||
* @return bool whether there's an operator at the current offset. |
||||
*/ |
||||
abstract protected function isOperator(&$length, &$content); |
||||
|
||||
/** |
||||
* Returns whether there's an identifier at the current offset. |
||||
* If this methos returns `true`, it has to set the `$length` parameter to the length of the matched string. |
||||
* It may also set `$content` to a string that will be used as a token content. |
||||
* @param int $length length of the matched string. |
||||
* @param string $content optional content instead of the matched string. |
||||
* @return bool whether there's an identifier at the current offset. |
||||
*/ |
||||
abstract protected function isIdentifier(&$length, &$content); |
||||
|
||||
/** |
||||
* Returns whether there's a string literal at the current offset. |
||||
* If this methos returns `true`, it has to set the `$length` parameter to the length of the matched string. |
||||
* It may also set `$content` to a string that will be used as a token content. |
||||
* @param int $length length of the matched string. |
||||
* @param string $content optional content instead of the matched string. |
||||
* @return bool whether there's a string literal at the current offset. |
||||
*/ |
||||
abstract protected function isStringLiteral(&$length, &$content); |
||||
|
||||
/** |
||||
* Returns whether the given string is a keyword. |
||||
* The method may set `$content` to a string that will be used as a token content. |
||||
* @param string $string string to be matched. |
||||
* @param string $content optional content instead of the matched string. |
||||
* @return bool whether the given string is a keyword. |
||||
*/ |
||||
abstract protected function isKeyword($string, &$content); |
||||
|
||||
/** |
||||
* Returns whether the longest common prefix equals to the SQL code of the same length at the current offset. |
||||
* @param string[] $with strings to be tested. |
||||
* The method **will** modify this parameter to speed up lookups. |
||||
* @param bool $caseSensitive whether to perform a case sensitive comparison. |
||||
* @param int|null $length length of the matched string. |
||||
* @param string|null $content matched string. |
||||
* @return bool whether a match is found. |
||||
*/ |
||||
protected function startsWithAnyLongest(array &$with, $caseSensitive, &$length = null, &$content = null) |
||||
{ |
||||
if (empty($with)) { |
||||
return false; |
||||
} |
||||
|
||||
if (!is_array(reset($with))) { |
||||
usort($with, function ($string1, $string2) { |
||||
return mb_strlen($string2, 'UTF-8') - mb_strlen($string1, 'UTF-8'); |
||||
}); |
||||
$map = []; |
||||
foreach ($with as $string) { |
||||
$map[mb_strlen($string, 'UTF-8')][$caseSensitive ? $string : mb_strtoupper($string, 'UTF-8')] = true; |
||||
} |
||||
$with = $map; |
||||
} |
||||
foreach ($with as $testLength => $testValues) { |
||||
$content = $this->substring($testLength, $caseSensitive); |
||||
if (isset($testValues[$content])) { |
||||
$length = $testLength; |
||||
return true; |
||||
} |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
/** |
||||
* Returns a string of the given length starting with the specified offset. |
||||
* @param int $length string length to be returned. |
||||
* @param bool $caseSensitive if it's `false`, the string will be uppercased. |
||||
* @param int|null $offset SQL code offset, defaults to current if `null` is passed. |
||||
* @return string result string, it may be empty if there's nothing to return. |
||||
*/ |
||||
protected function substring($length, $caseSensitive = true, $offset = null) |
||||
{ |
||||
if ($offset === null) { |
||||
$offset = $this->offset; |
||||
} |
||||
if ($offset + $length > $this->length) { |
||||
return ''; |
||||
} |
||||
|
||||
$cacheKey = $offset . ',' . $length; |
||||
if (!isset($this->_substrings[$cacheKey . ',1'])) { |
||||
$this->_substrings[$cacheKey . ',1'] = mb_substr($this->sql, $offset, $length, 'UTF-8'); |
||||
} |
||||
if (!$caseSensitive && !isset($this->_substrings[$cacheKey . ',0'])) { |
||||
$this->_substrings[$cacheKey . ',0'] = mb_strtoupper($this->_substrings[$cacheKey . ',1'], 'UTF-8'); |
||||
} |
||||
return $this->_substrings[$cacheKey . ',' . (int) $caseSensitive]; |
||||
} |
||||
|
||||
/** |
||||
* Returns an index after the given string in the SQL code starting with the specified offset. |
||||
* @param string $string string to be found. |
||||
* @param int|null $offset SQL code offset, defaults to current if `null` is passed. |
||||
* @return int index after the given string or end of string index. |
||||
*/ |
||||
protected function indexAfter($string, $offset = null) |
||||
{ |
||||
if ($offset === null) { |
||||
$offset = $this->offset; |
||||
} |
||||
if ($offset + mb_strlen($string, 'UTF-8') > $this->length) { |
||||
return $this->length; |
||||
} |
||||
|
||||
$afterIndexOf = mb_strpos($this->sql, $string, $offset, 'UTF-8'); |
||||
if ($afterIndexOf === false) { |
||||
$afterIndexOf = $this->length; |
||||
} else { |
||||
$afterIndexOf += mb_strlen($string, 'UTF-8'); |
||||
} |
||||
return $afterIndexOf; |
||||
} |
||||
|
||||
/** |
||||
* Determines whether there is a delimited string at the current offset and adds it to the token children. |
||||
* @param int $length |
||||
* @return bool |
||||
*/ |
||||
private function tokenizeDelimitedString(&$length) |
||||
{ |
||||
$isIdentifier = $this->isIdentifier($length, $content); |
||||
$isStringLiteral = !$isIdentifier && $this->isStringLiteral($length, $content); |
||||
if (!$isIdentifier && !$isStringLiteral) { |
||||
return false; |
||||
} |
||||
|
||||
$this->addTokenFromBuffer(); |
||||
$this->_currentToken[] = new SqlToken([ |
||||
'type' => $isIdentifier ? SqlToken::TYPE_IDENTIFIER : SqlToken::TYPE_STRING_LITERAL, |
||||
'content' => is_string($content) ? $content : $this->substring($length), |
||||
'startOffset' => $this->offset, |
||||
'endOffset' => $this->offset + $length, |
||||
]); |
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* Determines whether there is an operator at the current offset and adds it to the token children. |
||||
* @param int $length |
||||
* @return bool |
||||
*/ |
||||
private function tokenizeOperator(&$length) |
||||
{ |
||||
if (!$this->isOperator($length, $content)) { |
||||
return false; |
||||
} |
||||
|
||||
$this->addTokenFromBuffer(); |
||||
switch ($this->substring($length)) { |
||||
case '(': |
||||
$this->_currentToken[] = new SqlToken([ |
||||
'type' => SqlToken::TYPE_OPERATOR, |
||||
'content' => is_string($content) ? $content : $this->substring($length), |
||||
'startOffset' => $this->offset, |
||||
'endOffset' => $this->offset + $length, |
||||
]); |
||||
$this->_currentToken[] = new SqlToken(['type' => SqlToken::TYPE_PARENTHESIS]); |
||||
$this->_tokenStack->push($this->_currentToken[-1]); |
||||
$this->_currentToken = $this->_tokenStack->top(); |
||||
break; |
||||
case ')': |
||||
$this->_tokenStack->pop(); |
||||
$this->_currentToken = $this->_tokenStack->top(); |
||||
$this->_currentToken[] = new SqlToken([ |
||||
'type' => SqlToken::TYPE_OPERATOR, |
||||
'content' => ')', |
||||
'startOffset' => $this->offset, |
||||
'endOffset' => $this->offset + $length, |
||||
]); |
||||
break; |
||||
case ';': |
||||
if (!$this->_currentToken->getHasChildren()) { |
||||
break; |
||||
} |
||||
|
||||
$this->_currentToken[] = new SqlToken([ |
||||
'type' => SqlToken::TYPE_OPERATOR, |
||||
'content' => is_string($content) ? $content : $this->substring($length), |
||||
'startOffset' => $this->offset, |
||||
'endOffset' => $this->offset + $length, |
||||
]); |
||||
$this->_tokenStack->pop(); |
||||
$this->_currentToken = $this->_tokenStack->top(); |
||||
$this->_currentToken[] = new SqlToken(['type' => SqlToken::TYPE_STATEMENT]); |
||||
$this->_tokenStack->push($this->_currentToken[-1]); |
||||
$this->_currentToken = $this->_tokenStack->top(); |
||||
break; |
||||
default: |
||||
$this->_currentToken[] = new SqlToken([ |
||||
'type' => SqlToken::TYPE_OPERATOR, |
||||
'content' => is_string($content) ? $content : $this->substring($length), |
||||
'startOffset' => $this->offset, |
||||
'endOffset' => $this->offset + $length, |
||||
]); |
||||
break; |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* Determines a type of text in the buffer, tokenizes it and adds it to the token children. |
||||
*/ |
||||
private function addTokenFromBuffer() |
||||
{ |
||||
if ($this->_buffer === '') { |
||||
return; |
||||
} |
||||
|
||||
$isKeyword = $this->isKeyword($this->_buffer, $content); |
||||
$this->_currentToken[] = new SqlToken([ |
||||
'type' => $isKeyword ? SqlToken::TYPE_KEYWORD : SqlToken::TYPE_TOKEN, |
||||
'content' => is_string($content) ? $content : $this->_buffer, |
||||
'startOffset' => $this->offset - mb_strlen($this->_buffer, 'UTF-8'), |
||||
'endOffset' => $this->offset, |
||||
]); |
||||
$this->_buffer = ''; |
||||
} |
||||
|
||||
/** |
||||
* Adds the specified length to the current offset. |
||||
* @param int $length |
||||
* @throws InvalidParamException |
||||
*/ |
||||
private function advance($length) |
||||
{ |
||||
if ($length <= 0) { |
||||
throw new InvalidParamException('Length must be greater than 0.'); |
||||
} |
||||
|
||||
$this->offset += $length; |
||||
$this->_substrings = []; |
||||
} |
||||
|
||||
/** |
||||
* Returns whether the SQL code is completely traversed. |
||||
* @return bool |
||||
*/ |
||||
private function isEof() |
||||
{ |
||||
return $this->offset >= $this->length; |
||||
} |
||||
} |
@ -0,0 +1,288 @@
|
||||
<?php |
||||
/** |
||||
* @link http://www.yiiframework.com/ |
||||
* @copyright Copyright (c) 2008 Yii Software LLC |
||||
* @license http://www.yiiframework.com/license/ |
||||
*/ |
||||
|
||||
namespace yii\db\sqlite; |
||||
|
||||
/** |
||||
* SqlTokenizer splits SQLite query into individual SQL tokens. |
||||
* It's used to obtain a `CHECK` constraint information from a `CREATE TABLE` SQL code. |
||||
* |
||||
* @see http://www.sqlite.org/draft/tokenreq.html |
||||
* @see https://sqlite.org/lang.html |
||||
* @author Sergey Makinen <sergey@makinen.ru> |
||||
* @since 2.0.13 |
||||
*/ |
||||
class SqlTokenizer extends \yii\db\SqlTokenizer |
||||
{ |
||||
/** |
||||
* @inheritDoc |
||||
*/ |
||||
protected function isWhitespace(&$length) |
||||
{ |
||||
static $whitespaces = [ |
||||
"\f" => true, |
||||
"\n" => true, |
||||
"\r" => true, |
||||
"\t" => true, |
||||
' ' => true, |
||||
]; |
||||
|
||||
$length = 1; |
||||
return isset($whitespaces[$this->substring($length)]); |
||||
} |
||||
|
||||
/** |
||||
* @inheritDoc |
||||
*/ |
||||
protected function isComment(&$length) |
||||
{ |
||||
static $comments = [ |
||||
'--' => true, |
||||
'/*' => true, |
||||
]; |
||||
|
||||
$length = 2; |
||||
if (!isset($comments[$this->substring($length)])) { |
||||
return false; |
||||
} |
||||
|
||||
if ($this->substring($length) === '--') { |
||||
$length = $this->indexAfter("\n") - $this->offset; |
||||
} else { |
||||
$length = $this->indexAfter('*/') - $this->offset; |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* @inheritDoc |
||||
*/ |
||||
protected function isOperator(&$length, &$content) |
||||
{ |
||||
static $operators = [ |
||||
'!=', |
||||
'%', |
||||
'&', |
||||
'(', |
||||
')', |
||||
'*', |
||||
'+', |
||||
',', |
||||
'-', |
||||
'.', |
||||
'/', |
||||
';', |
||||
'<', |
||||
'<<', |
||||
'<=', |
||||
'<>', |
||||
'=', |
||||
'==', |
||||
'>', |
||||
'>=', |
||||
'>>', |
||||
'|', |
||||
'||', |
||||
'~', |
||||
]; |
||||
|
||||
return $this->startsWithAnyLongest($operators, true, $length); |
||||
} |
||||
|
||||
/** |
||||
* @inheritDoc |
||||
*/ |
||||
protected function isIdentifier(&$length, &$content) |
||||
{ |
||||
static $identifierDelimiters = [ |
||||
'"' => '"', |
||||
'[' => ']', |
||||
'`' => '`', |
||||
]; |
||||
|
||||
if (!isset($identifierDelimiters[$this->substring(1)])) { |
||||
return false; |
||||
} |
||||
|
||||
$delimiter = $identifierDelimiters[$this->substring(1)]; |
||||
$offset = $this->offset; |
||||
while (true) { |
||||
$offset = $this->indexAfter($delimiter, $offset + 1); |
||||
if ($delimiter === ']' || $this->substring(1, true, $offset) !== $delimiter) { |
||||
break; |
||||
} |
||||
} |
||||
$length = $offset - $this->offset; |
||||
$content = $this->substring($length - 2, true, $this->offset + 1); |
||||
if ($delimiter !== ']') { |
||||
$content = strtr($content, ["$delimiter$delimiter" => $delimiter]); |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* @inheritDoc |
||||
*/ |
||||
protected function isStringLiteral(&$length, &$content) |
||||
{ |
||||
if ($this->substring(1) !== "'") { |
||||
return false; |
||||
} |
||||
|
||||
$offset = $this->offset; |
||||
while (true) { |
||||
$offset = $this->indexAfter("'", $offset + 1); |
||||
if ($this->substring(1, true, $offset) !== "'") { |
||||
break; |
||||
} |
||||
} |
||||
$length = $offset - $this->offset; |
||||
$content = strtr($this->substring($length - 2, true, $this->offset + 1), ["''" => "'"]); |
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* @inheritDoc |
||||
*/ |
||||
protected function isKeyword($string, &$content) |
||||
{ |
||||
static $keywords = [ |
||||
'ABORT' => true, |
||||
'ACTION' => true, |
||||
'ADD' => true, |
||||
'AFTER' => true, |
||||
'ALL' => true, |
||||
'ALTER' => true, |
||||
'ANALYZE' => true, |
||||
'AND' => true, |
||||
'AS' => true, |
||||
'ASC' => true, |
||||
'ATTACH' => true, |
||||
'AUTOINCREMENT' => true, |
||||
'BEFORE' => true, |
||||
'BEGIN' => true, |
||||
'BETWEEN' => true, |
||||
'BY' => true, |
||||
'CASCADE' => true, |
||||
'CASE' => true, |
||||
'CAST' => true, |
||||
'CHECK' => true, |
||||
'COLLATE' => true, |
||||
'COLUMN' => true, |
||||
'COMMIT' => true, |
||||
'CONFLICT' => true, |
||||
'CONSTRAINT' => true, |
||||
'CREATE' => true, |
||||
'CROSS' => true, |
||||
'CURRENT_DATE' => true, |
||||
'CURRENT_TIME' => true, |
||||
'CURRENT_TIMESTAMP' => true, |
||||
'DATABASE' => true, |
||||
'DEFAULT' => true, |
||||
'DEFERRABLE' => true, |
||||
'DEFERRED' => true, |
||||
'DELETE' => true, |
||||
'DESC' => true, |
||||
'DETACH' => true, |
||||
'DISTINCT' => true, |
||||
'DROP' => true, |
||||
'EACH' => true, |
||||
'ELSE' => true, |
||||
'END' => true, |
||||
'ESCAPE' => true, |
||||
'EXCEPT' => true, |
||||
'EXCLUSIVE' => true, |
||||
'EXISTS' => true, |
||||
'EXPLAIN' => true, |
||||
'FAIL' => true, |
||||
'FOR' => true, |
||||
'FOREIGN' => true, |
||||
'FROM' => true, |
||||
'FULL' => true, |
||||
'GLOB' => true, |
||||
'GROUP' => true, |
||||
'HAVING' => true, |
||||
'IF' => true, |
||||
'IGNORE' => true, |
||||
'IMMEDIATE' => true, |
||||
'IN' => true, |
||||
'INDEX' => true, |
||||
'INDEXED' => true, |
||||
'INITIALLY' => true, |
||||
'INNER' => true, |
||||
'INSERT' => true, |
||||
'INSTEAD' => true, |
||||
'INTERSECT' => true, |
||||
'INTO' => true, |
||||
'IS' => true, |
||||
'ISNULL' => true, |
||||
'JOIN' => true, |
||||
'KEY' => true, |
||||
'LEFT' => true, |
||||
'LIKE' => true, |
||||
'LIMIT' => true, |
||||
'MATCH' => true, |
||||
'NATURAL' => true, |
||||
'NO' => true, |
||||
'NOT' => true, |
||||
'NOTNULL' => true, |
||||
'NULL' => true, |
||||
'OF' => true, |
||||
'OFFSET' => true, |
||||
'ON' => true, |
||||
'OR' => true, |
||||
'ORDER' => true, |
||||
'OUTER' => true, |
||||
'PLAN' => true, |
||||
'PRAGMA' => true, |
||||
'PRIMARY' => true, |
||||
'QUERY' => true, |
||||
'RAISE' => true, |
||||
'RECURSIVE' => true, |
||||
'REFERENCES' => true, |
||||
'REGEXP' => true, |
||||
'REINDEX' => true, |
||||
'RELEASE' => true, |
||||
'RENAME' => true, |
||||
'REPLACE' => true, |
||||
'RESTRICT' => true, |
||||
'RIGHT' => true, |
||||
'ROLLBACK' => true, |
||||
'ROW' => true, |
||||
'SAVEPOINT' => true, |
||||
'SELECT' => true, |
||||
'SET' => true, |
||||
'TABLE' => true, |
||||
'TEMP' => true, |
||||
'TEMPORARY' => true, |
||||
'THEN' => true, |
||||
'TO' => true, |
||||
'TRANSACTION' => true, |
||||
'TRIGGER' => true, |
||||
'UNION' => true, |
||||
'UNIQUE' => true, |
||||
'UPDATE' => true, |
||||
'USING' => true, |
||||
'VACUUM' => true, |
||||
'VALUES' => true, |
||||
'VIEW' => true, |
||||
'VIRTUAL' => true, |
||||
'WHEN' => true, |
||||
'WHERE' => true, |
||||
'WITH' => true, |
||||
'WITHOUT' => true, |
||||
]; |
||||
|
||||
$string = mb_strtoupper($string, 'UTF-8'); |
||||
if (!isset($keywords[$string])) { |
||||
return false; |
||||
} |
||||
|
||||
$content = $string; |
||||
return true; |
||||
} |
||||
} |
@ -0,0 +1,28 @@
|
||||
<?php |
||||
/** |
||||
* @link http://www.yiiframework.com/ |
||||
* @copyright Copyright (c) 2008 Yii Software LLC |
||||
* @license http://www.yiiframework.com/license/ |
||||
*/ |
||||
|
||||
namespace yiiunit\framework\db; |
||||
|
||||
class AnyCaseValue extends CompareValue |
||||
{ |
||||
public $value; |
||||
|
||||
/** |
||||
* Constructor. |
||||
* @param string|string[] $value |
||||
* @param array $config |
||||
*/ |
||||
public function __construct($value, $config = []) |
||||
{ |
||||
if (is_array($value)) { |
||||
$this->value = array_map('strtolower', $value); |
||||
} else { |
||||
$this->value = strtolower($value); |
||||
} |
||||
parent::__construct($config); |
||||
} |
||||
} |
@ -0,0 +1,24 @@
|
||||
<?php |
||||
/** |
||||
* @link http://www.yiiframework.com/ |
||||
* @copyright Copyright (c) 2008 Yii Software LLC |
||||
* @license http://www.yiiframework.com/license/ |
||||
*/ |
||||
|
||||
namespace yiiunit\framework\db; |
||||
|
||||
class AnyValue extends CompareValue |
||||
{ |
||||
/** |
||||
* @var self |
||||
*/ |
||||
private static $_instance; |
||||
|
||||
public static function getInstance() |
||||
{ |
||||
if (self::$_instance === null) { |
||||
self::$_instance = new self(); |
||||
} |
||||
return self::$_instance; |
||||
} |
||||
} |
@ -0,0 +1,14 @@
|
||||
<?php |
||||
/** |
||||
* @link http://www.yiiframework.com/ |
||||
* @copyright Copyright (c) 2008 Yii Software LLC |
||||
* @license http://www.yiiframework.com/license/ |
||||
*/ |
||||
|
||||
namespace yiiunit\framework\db; |
||||
|
||||
use yii\base\Object; |
||||
|
||||
abstract class CompareValue extends Object |
||||
{ |
||||
} |
Loading…
Reference in new issue