Skip to content

Commit

Permalink
Merge pull request #1 from cebe/db-constraints
Browse files Browse the repository at this point in the history
Changes to db constraints
  • Loading branch information
sergeymakinen authored Jul 5, 2017
2 parents e8088f3 + a7d92c6 commit 921e124
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 10 deletions.
19 changes: 19 additions & 0 deletions db/ConstraintFinderTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,25 @@
*/
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.
Expand Down
18 changes: 13 additions & 5 deletions db/SqlToken.php
Original file line number Diff line number Diff line change
Expand Up @@ -195,17 +195,25 @@ public function getSql()

/**
* Returns whether this token (including its children) matches the specified "pattern" SQL code.
* Currently this implementation uses [[\yii\db\sqlite\SqlTokenizer]] to process a pattern SQL code.
* @param string $pattern SQL code. Everything supported in SQLite is supported here as well.
* In addition, `any` keyword is supported which is treated as any number of keywords, identifiers, whitespaces.
*
* 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($pattern, $offset = 0, &$firstMatchIndex = null, &$lastMatchIndex = null)
public function matches(SqlToken $patternToken, $offset = 0, &$firstMatchIndex = null, &$lastMatchIndex = null)
{
$patternToken = (new \yii\db\sqlite\SqlTokenizer($pattern))->tokenize();
if (!$patternToken->getHasChildren()) {
return false;
}
Expand Down
4 changes: 2 additions & 2 deletions db/SqlTokenizer.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@

namespace yii\db;

use yii\base\Component;
use yii\base\InvalidParamException;
use yii\base\Object;

/**
* SqlTokenizer splits an SQL query into individual SQL tokens.
Expand All @@ -28,7 +28,7 @@
* @author Sergey Makinen <[email protected]>
* @since 2.0.13
*/
abstract class SqlTokenizer extends Object
abstract class SqlTokenizer extends Component
{
/**
* @var string SQL code.
Expand Down
11 changes: 8 additions & 3 deletions db/sqlite/Schema.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
use yii\db\Expression;
use yii\db\ForeignKeyConstraint;
use yii\db\IndexConstraint;
use yii\db\SqlToken;
use yii\db\TableSchema;
use yii\db\Transaction;
use yii\helpers\ArrayHelper;
Expand Down Expand Up @@ -146,22 +147,26 @@ protected function loadTableChecks($tableName)
$sql = $this->db->createCommand('SELECT `sql` FROM `sqlite_master` WHERE name = :tableName', [
':tableName' => $tableName,
])->queryScalar();
/** @var $code SqlToken[]|SqlToken[][]|SqlToken[][][] */
$code = (new SqlTokenizer($sql))->tokenize();
if (!$code[0]->matches('any CREATE any TABLE any()', 0, $firstMatchIndex, $lastMatchIndex)) {
$pattern = (new SqlTokenizer('any CREATE any TABLE any()'))->tokenize();
if (!$code[0]->matches($pattern, 0, $firstMatchIndex, $lastMatchIndex)) {
return [];
}

$createTableToken = $code[0][$lastMatchIndex - 1];
$result = [];
$offset = 0;
while (true) {
if (!$createTableToken->matches('any CHECK()', $offset, $firstMatchIndex, $offset)) {
$pattern = (new SqlTokenizer('any CHECK()'))->tokenize();
if (!$createTableToken->matches($pattern, $offset, $firstMatchIndex, $offset)) {
break;
}

$checkSql = $createTableToken[$offset - 1]->getSql();
$name = null;
if (isset($createTableToken[$firstMatchIndex - 2]) && $createTableToken->matches('CONSTRAINT any', $firstMatchIndex - 2)) {
$pattern = (new SqlTokenizer('CONSTRAINT any'))->tokenize();
if (isset($createTableToken[$firstMatchIndex - 2]) && $createTableToken->matches($pattern, $firstMatchIndex - 2)) {
$name = $createTableToken[$firstMatchIndex - 1]->content;
}
$result[] = new CheckConstraint([
Expand Down

0 comments on commit 921e124

Please sign in to comment.