init
This commit is contained in:
46
vendor/yiisoft/yii2/db/sqlite/ColumnSchemaBuilder.php
vendored
Normal file
46
vendor/yiisoft/yii2/db/sqlite/ColumnSchemaBuilder.php
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\db\sqlite;
|
||||
|
||||
use yii\db\ColumnSchemaBuilder as AbstractColumnSchemaBuilder;
|
||||
|
||||
/**
|
||||
* ColumnSchemaBuilder is the schema builder for Sqlite databases.
|
||||
*
|
||||
* @author Chris Harris <chris@buckshotsoftware.com>
|
||||
* @since 2.0.8
|
||||
*/
|
||||
class ColumnSchemaBuilder extends AbstractColumnSchemaBuilder
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function buildUnsignedString()
|
||||
{
|
||||
return $this->isUnsigned ? ' UNSIGNED' : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
switch ($this->getTypeCategory()) {
|
||||
case self::CATEGORY_PK:
|
||||
$format = '{type}{check}{append}';
|
||||
break;
|
||||
case self::CATEGORY_NUMERIC:
|
||||
$format = '{type}{length}{unsigned}{notnull}{unique}{check}{default}{append}';
|
||||
break;
|
||||
default:
|
||||
$format = '{type}{length}{notnull}{unique}{check}{default}{append}';
|
||||
}
|
||||
|
||||
return $this->buildCompleteString($format);
|
||||
}
|
||||
}
|
||||
116
vendor/yiisoft/yii2/db/sqlite/Command.php
vendored
Normal file
116
vendor/yiisoft/yii2/db/sqlite/Command.php
vendored
Normal file
@@ -0,0 +1,116 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\db\sqlite;
|
||||
|
||||
use yii\db\SqlToken;
|
||||
use yii\helpers\StringHelper;
|
||||
|
||||
/**
|
||||
* Command represents an SQLite's SQL statement to be executed against a database.
|
||||
*
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @author Sergey Makinen <sergey@makinen.ru>
|
||||
* @since 2.0.14
|
||||
*/
|
||||
class Command extends \yii\db\Command
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function execute()
|
||||
{
|
||||
$sql = $this->getSql();
|
||||
$params = $this->params;
|
||||
$statements = $this->splitStatements($sql, $params);
|
||||
if ($statements === false) {
|
||||
return parent::execute();
|
||||
}
|
||||
|
||||
$result = null;
|
||||
foreach ($statements as $statement) {
|
||||
list($statementSql, $statementParams) = $statement;
|
||||
$this->setSql($statementSql)->bindValues($statementParams);
|
||||
$result = parent::execute();
|
||||
}
|
||||
$this->setSql($sql)->bindValues($params);
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function queryInternal($method, $fetchMode = null)
|
||||
{
|
||||
$sql = $this->getSql();
|
||||
$params = $this->params;
|
||||
$statements = $this->splitStatements($sql, $params);
|
||||
if ($statements === false) {
|
||||
return parent::queryInternal($method, $fetchMode);
|
||||
}
|
||||
|
||||
list($lastStatementSql, $lastStatementParams) = array_pop($statements);
|
||||
foreach ($statements as $statement) {
|
||||
list($statementSql, $statementParams) = $statement;
|
||||
$this->setSql($statementSql)->bindValues($statementParams);
|
||||
parent::execute();
|
||||
}
|
||||
$this->setSql($lastStatementSql)->bindValues($lastStatementParams);
|
||||
$result = parent::queryInternal($method, $fetchMode);
|
||||
$this->setSql($sql)->bindValues($params);
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Splits the specified SQL code into individual SQL statements and returns them
|
||||
* or `false` if there's a single statement.
|
||||
* @param string $sql
|
||||
* @param array $params
|
||||
* @return string[]|false
|
||||
*/
|
||||
private function splitStatements($sql, $params)
|
||||
{
|
||||
$semicolonIndex = strpos($sql, ';');
|
||||
if ($semicolonIndex === false || $semicolonIndex === StringHelper::byteLength($sql) - 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$tokenizer = new SqlTokenizer($sql);
|
||||
$codeToken = $tokenizer->tokenize();
|
||||
if (count($codeToken->getChildren()) === 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$statements = [];
|
||||
foreach ($codeToken->getChildren() as $statement) {
|
||||
$statements[] = [$statement->getSql(), $this->extractUsedParams($statement, $params)];
|
||||
}
|
||||
return $statements;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns named bindings used in the specified statement token.
|
||||
* @param SqlToken $statement
|
||||
* @param array $params
|
||||
* @return array
|
||||
*/
|
||||
private function extractUsedParams(SqlToken $statement, $params)
|
||||
{
|
||||
preg_match_all('/(?P<placeholder>[:][a-zA-Z0-9_]+)/', $statement->getSql(), $matches, PREG_SET_ORDER);
|
||||
$result = [];
|
||||
foreach ($matches as $match) {
|
||||
$phName = ltrim($match['placeholder'], ':');
|
||||
if (isset($params[$phName])) {
|
||||
$result[$phName] = $params[$phName];
|
||||
} elseif (isset($params[':' . $phName])) {
|
||||
$result[':' . $phName] = $params[':' . $phName];
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
544
vendor/yiisoft/yii2/db/sqlite/QueryBuilder.php
vendored
Normal file
544
vendor/yiisoft/yii2/db/sqlite/QueryBuilder.php
vendored
Normal file
@@ -0,0 +1,544 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\db\sqlite;
|
||||
|
||||
use yii\base\InvalidArgumentException;
|
||||
use yii\base\NotSupportedException;
|
||||
use yii\db\Connection;
|
||||
use yii\db\Constraint;
|
||||
use yii\db\Expression;
|
||||
use yii\db\ExpressionInterface;
|
||||
use yii\db\Query;
|
||||
use yii\helpers\StringHelper;
|
||||
|
||||
/**
|
||||
* QueryBuilder is the query builder for SQLite databases.
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @since 2.0
|
||||
*/
|
||||
class QueryBuilder extends \yii\db\QueryBuilder
|
||||
{
|
||||
/**
|
||||
* @var array mapping from abstract column types (keys) to physical column types (values).
|
||||
*/
|
||||
public $typeMap = [
|
||||
Schema::TYPE_PK => 'integer PRIMARY KEY AUTOINCREMENT NOT NULL',
|
||||
Schema::TYPE_UPK => 'integer UNSIGNED PRIMARY KEY AUTOINCREMENT NOT NULL',
|
||||
Schema::TYPE_BIGPK => 'integer PRIMARY KEY AUTOINCREMENT NOT NULL',
|
||||
Schema::TYPE_UBIGPK => 'integer UNSIGNED PRIMARY KEY AUTOINCREMENT NOT NULL',
|
||||
Schema::TYPE_CHAR => 'char(1)',
|
||||
Schema::TYPE_STRING => 'varchar(255)',
|
||||
Schema::TYPE_TEXT => 'text',
|
||||
Schema::TYPE_TINYINT => 'tinyint',
|
||||
Schema::TYPE_SMALLINT => 'smallint',
|
||||
Schema::TYPE_INTEGER => 'integer',
|
||||
Schema::TYPE_BIGINT => 'bigint',
|
||||
Schema::TYPE_FLOAT => 'float',
|
||||
Schema::TYPE_DOUBLE => 'double',
|
||||
Schema::TYPE_DECIMAL => 'decimal(10,0)',
|
||||
Schema::TYPE_DATETIME => 'datetime',
|
||||
Schema::TYPE_TIMESTAMP => 'timestamp',
|
||||
Schema::TYPE_TIME => 'time',
|
||||
Schema::TYPE_DATE => 'date',
|
||||
Schema::TYPE_BINARY => 'blob',
|
||||
Schema::TYPE_BOOLEAN => 'boolean',
|
||||
Schema::TYPE_MONEY => 'decimal(19,4)',
|
||||
];
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function defaultExpressionBuilders()
|
||||
{
|
||||
return array_merge(parent::defaultExpressionBuilders(), [
|
||||
'yii\db\conditions\LikeCondition' => 'yii\db\sqlite\conditions\LikeConditionBuilder',
|
||||
'yii\db\conditions\InCondition' => 'yii\db\sqlite\conditions\InConditionBuilder',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* @see https://stackoverflow.com/questions/15277373/sqlite-upsert-update-or-insert/15277374#15277374
|
||||
*/
|
||||
public function upsert($table, $insertColumns, $updateColumns, &$params)
|
||||
{
|
||||
/** @var Constraint[] $constraints */
|
||||
list($uniqueNames, $insertNames, $updateNames) = $this->prepareUpsertColumns($table, $insertColumns, $updateColumns, $constraints);
|
||||
if (empty($uniqueNames)) {
|
||||
return $this->insert($table, $insertColumns, $params);
|
||||
}
|
||||
|
||||
list(, $placeholders, $values, $params) = $this->prepareInsertValues($table, $insertColumns, $params);
|
||||
$insertSql = 'INSERT OR IGNORE INTO ' . $this->db->quoteTableName($table)
|
||||
. (!empty($insertNames) ? ' (' . implode(', ', $insertNames) . ')' : '')
|
||||
. (!empty($placeholders) ? ' VALUES (' . implode(', ', $placeholders) . ')' : $values);
|
||||
if ($updateColumns === false) {
|
||||
return $insertSql;
|
||||
}
|
||||
|
||||
$updateCondition = ['or'];
|
||||
$quotedTableName = $this->db->quoteTableName($table);
|
||||
foreach ($constraints as $constraint) {
|
||||
$constraintCondition = ['and'];
|
||||
foreach ($constraint->columnNames as $name) {
|
||||
$quotedName = $this->db->quoteColumnName($name);
|
||||
$constraintCondition[] = "$quotedTableName.$quotedName=(SELECT $quotedName FROM `EXCLUDED`)";
|
||||
}
|
||||
$updateCondition[] = $constraintCondition;
|
||||
}
|
||||
if ($updateColumns === true) {
|
||||
$updateColumns = [];
|
||||
foreach ($updateNames as $name) {
|
||||
$quotedName = $this->db->quoteColumnName($name);
|
||||
if (strrpos($quotedName, '.') === false) {
|
||||
$quotedName = "(SELECT $quotedName FROM `EXCLUDED`)";
|
||||
}
|
||||
$updateColumns[$name] = new Expression($quotedName);
|
||||
}
|
||||
}
|
||||
$updateSql = 'WITH "EXCLUDED" (' . implode(', ', $insertNames)
|
||||
. ') AS (' . (!empty($placeholders) ? 'VALUES (' . implode(', ', $placeholders) . ')' : ltrim($values, ' ')) . ') '
|
||||
. $this->update($table, $updateColumns, $updateCondition, $params);
|
||||
return "$updateSql; $insertSql;";
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a batch INSERT SQL statement.
|
||||
*
|
||||
* For example,
|
||||
*
|
||||
* ```php
|
||||
* $connection->createCommand()->batchInsert('user', ['name', 'age'], [
|
||||
* ['Tom', 30],
|
||||
* ['Jane', 20],
|
||||
* ['Linda', 25],
|
||||
* ])->execute();
|
||||
* ```
|
||||
*
|
||||
* Note that the values in each row must match the corresponding column names.
|
||||
*
|
||||
* @param string $table the table that new rows will be inserted into.
|
||||
* @param array $columns the column names
|
||||
* @param array|\Generator $rows the rows to be batch inserted into the table
|
||||
* @return string the batch INSERT SQL statement
|
||||
*/
|
||||
public function batchInsert($table, $columns, $rows, &$params = [])
|
||||
{
|
||||
if (empty($rows)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
// SQLite supports batch insert natively since 3.7.11
|
||||
// http://www.sqlite.org/releaselog/3_7_11.html
|
||||
$this->db->open(); // ensure pdo is not null
|
||||
if (version_compare($this->db->getServerVersion(), '3.7.11', '>=')) {
|
||||
return parent::batchInsert($table, $columns, $rows, $params);
|
||||
}
|
||||
|
||||
$schema = $this->db->getSchema();
|
||||
if (($tableSchema = $schema->getTableSchema($table)) !== null) {
|
||||
$columnSchemas = $tableSchema->columns;
|
||||
} else {
|
||||
$columnSchemas = [];
|
||||
}
|
||||
|
||||
$values = [];
|
||||
foreach ($rows as $row) {
|
||||
$vs = [];
|
||||
foreach ($row as $i => $value) {
|
||||
if (isset($columnSchemas[$columns[$i]])) {
|
||||
$value = $columnSchemas[$columns[$i]]->dbTypecast($value);
|
||||
}
|
||||
if (is_string($value)) {
|
||||
$value = $schema->quoteValue($value);
|
||||
} elseif (is_float($value)) {
|
||||
// ensure type cast always has . as decimal separator in all locales
|
||||
$value = StringHelper::floatToString($value);
|
||||
} elseif ($value === false) {
|
||||
$value = 0;
|
||||
} elseif ($value === null) {
|
||||
$value = 'NULL';
|
||||
} elseif ($value instanceof ExpressionInterface) {
|
||||
$value = $this->buildExpression($value, $params);
|
||||
}
|
||||
$vs[] = $value;
|
||||
}
|
||||
$values[] = implode(', ', $vs);
|
||||
}
|
||||
if (empty($values)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
foreach ($columns as $i => $name) {
|
||||
$columns[$i] = $schema->quoteColumnName($name);
|
||||
}
|
||||
|
||||
return 'INSERT INTO ' . $schema->quoteTableName($table)
|
||||
. ' (' . implode(', ', $columns) . ') SELECT ' . implode(' UNION SELECT ', $values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a SQL statement for resetting 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 string $tableName the name of the table 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.
|
||||
* @return string the SQL statement for resetting sequence
|
||||
* @throws InvalidArgumentException if the table does not exist or there is no sequence associated with the table.
|
||||
*/
|
||||
public function resetSequence($tableName, $value = null)
|
||||
{
|
||||
$db = $this->db;
|
||||
$table = $db->getTableSchema($tableName);
|
||||
if ($table !== null && $table->sequenceName !== null) {
|
||||
$tableName = $db->quoteTableName($tableName);
|
||||
if ($value === null) {
|
||||
$key = $this->db->quoteColumnName(reset($table->primaryKey));
|
||||
$value = $this->db->useMaster(function (Connection $db) use ($key, $tableName) {
|
||||
return $db->createCommand("SELECT MAX($key) FROM $tableName")->queryScalar();
|
||||
});
|
||||
} else {
|
||||
$value = (int) $value - 1;
|
||||
}
|
||||
|
||||
return "UPDATE sqlite_sequence SET seq='$value' WHERE name='{$table->name}'";
|
||||
} elseif ($table === null) {
|
||||
throw new InvalidArgumentException("Table not found: $tableName");
|
||||
}
|
||||
|
||||
throw new InvalidArgumentException("There is not sequence associated with table '$tableName'.'");
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables or disables integrity check.
|
||||
* @param bool $check whether to turn on or off the integrity check.
|
||||
* @param string $schema the schema of the tables. Meaningless for SQLite.
|
||||
* @param string $table the table name. Meaningless for SQLite.
|
||||
* @return string the SQL statement for checking integrity
|
||||
* @throws NotSupportedException this is not supported by SQLite
|
||||
*/
|
||||
public function checkIntegrity($check = true, $schema = '', $table = '')
|
||||
{
|
||||
return 'PRAGMA foreign_keys=' . (int) $check;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
public function truncateTable($table)
|
||||
{
|
||||
return 'DELETE FROM ' . $this->db->quoteTableName($table);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
public function dropIndex($name, $table)
|
||||
{
|
||||
return 'DROP INDEX ' . $this->db->quoteTableName($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @throws NotSupportedException this is not supported by SQLite
|
||||
*/
|
||||
public function dropColumn($table, $column)
|
||||
{
|
||||
throw new NotSupportedException(__METHOD__ . ' is not supported by SQLite.');
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 $oldName 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.
|
||||
* @throws NotSupportedException this is not supported by SQLite
|
||||
*/
|
||||
public function renameColumn($table, $oldName, $newName)
|
||||
{
|
||||
throw new NotSupportedException(__METHOD__ . ' is not supported by SQLite.');
|
||||
}
|
||||
|
||||
/**
|
||||
* 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|array $columns the name of the column to that the constraint will be added on.
|
||||
* If there are multiple columns, separate them with commas or use an array to represent them.
|
||||
* @param string $refTable the table that the foreign key references to.
|
||||
* @param string|array $refColumns the name of the column that the foreign key references to.
|
||||
* If there are multiple columns, separate them with commas or use an array to represent them.
|
||||
* @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.
|
||||
* @throws NotSupportedException this is not supported by SQLite
|
||||
*/
|
||||
public function addForeignKey($name, $table, $columns, $refTable, $refColumns, $delete = null, $update = null)
|
||||
{
|
||||
throw new NotSupportedException(__METHOD__ . ' is not supported by SQLite.');
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @throws NotSupportedException this is not supported by SQLite
|
||||
*/
|
||||
public function dropForeignKey($name, $table)
|
||||
{
|
||||
throw new NotSupportedException(__METHOD__ . ' is not supported by SQLite.');
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
public function renameTable($table, $newName)
|
||||
{
|
||||
return 'ALTER TABLE ' . $this->db->quoteTableName($table) . ' RENAME TO ' . $this->db->quoteTableName($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 [[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.
|
||||
* @throws NotSupportedException this is not supported by SQLite
|
||||
*/
|
||||
public function alterColumn($table, $column, $type)
|
||||
{
|
||||
throw new NotSupportedException(__METHOD__ . ' is not supported by SQLite.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a SQL statement for adding a primary key constraint to an existing table.
|
||||
* @param string $name the name of the primary key constraint.
|
||||
* @param string $table the table that the primary key constraint will be added to.
|
||||
* @param string|array $columns comma separated string or array of columns that the primary key will consist of.
|
||||
* @return string the SQL statement for adding a primary key constraint to an existing table.
|
||||
* @throws NotSupportedException this is not supported by SQLite
|
||||
*/
|
||||
public function addPrimaryKey($name, $table, $columns)
|
||||
{
|
||||
throw new NotSupportedException(__METHOD__ . ' is not supported by SQLite.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a SQL statement for removing a primary key constraint to an existing table.
|
||||
* @param string $name the name of the primary key constraint to be removed.
|
||||
* @param string $table the table that the primary key constraint will be removed from.
|
||||
* @return string the SQL statement for removing a primary key constraint from an existing table.
|
||||
* @throws NotSupportedException this is not supported by SQLite
|
||||
*/
|
||||
public function dropPrimaryKey($name, $table)
|
||||
{
|
||||
throw new NotSupportedException(__METHOD__ . ' is not supported by SQLite.');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* @throws NotSupportedException this is not supported by SQLite.
|
||||
*/
|
||||
public function addUnique($name, $table, $columns)
|
||||
{
|
||||
throw new NotSupportedException(__METHOD__ . ' is not supported by SQLite.');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* @throws NotSupportedException this is not supported by SQLite.
|
||||
*/
|
||||
public function dropUnique($name, $table)
|
||||
{
|
||||
throw new NotSupportedException(__METHOD__ . ' is not supported by SQLite.');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* @throws NotSupportedException this is not supported by SQLite.
|
||||
*/
|
||||
public function addCheck($name, $table, $expression)
|
||||
{
|
||||
throw new NotSupportedException(__METHOD__ . ' is not supported by SQLite.');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* @throws NotSupportedException this is not supported by SQLite.
|
||||
*/
|
||||
public function dropCheck($name, $table)
|
||||
{
|
||||
throw new NotSupportedException(__METHOD__ . ' is not supported by SQLite.');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* @throws NotSupportedException this is not supported by SQLite.
|
||||
*/
|
||||
public function addDefaultValue($name, $table, $column, $value)
|
||||
{
|
||||
throw new NotSupportedException(__METHOD__ . ' is not supported by SQLite.');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* @throws NotSupportedException this is not supported by SQLite.
|
||||
*/
|
||||
public function dropDefaultValue($name, $table)
|
||||
{
|
||||
throw new NotSupportedException(__METHOD__ . ' is not supported by SQLite.');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* @throws NotSupportedException
|
||||
* @since 2.0.8
|
||||
*/
|
||||
public function addCommentOnColumn($table, $column, $comment)
|
||||
{
|
||||
throw new NotSupportedException(__METHOD__ . ' is not supported by SQLite.');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* @throws NotSupportedException
|
||||
* @since 2.0.8
|
||||
*/
|
||||
public function addCommentOnTable($table, $comment)
|
||||
{
|
||||
throw new NotSupportedException(__METHOD__ . ' is not supported by SQLite.');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* @throws NotSupportedException
|
||||
* @since 2.0.8
|
||||
*/
|
||||
public function dropCommentFromColumn($table, $column)
|
||||
{
|
||||
throw new NotSupportedException(__METHOD__ . ' is not supported by SQLite.');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* @throws NotSupportedException
|
||||
* @since 2.0.8
|
||||
*/
|
||||
public function dropCommentFromTable($table)
|
||||
{
|
||||
throw new NotSupportedException(__METHOD__ . ' is not supported by SQLite.');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildLimit($limit, $offset)
|
||||
{
|
||||
$sql = '';
|
||||
if ($this->hasLimit($limit)) {
|
||||
$sql = 'LIMIT ' . $limit;
|
||||
if ($this->hasOffset($offset)) {
|
||||
$sql .= ' OFFSET ' . $offset;
|
||||
}
|
||||
} elseif ($this->hasOffset($offset)) {
|
||||
// limit is not optional in SQLite
|
||||
// http://www.sqlite.org/syntaxdiagrams.html#select-stmt
|
||||
$sql = "LIMIT 9223372036854775807 OFFSET $offset"; // 2^63-1
|
||||
}
|
||||
|
||||
return $sql;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function build($query, $params = [])
|
||||
{
|
||||
$query = $query->prepare($this);
|
||||
|
||||
$params = empty($params) ? $query->params : array_merge($params, $query->params);
|
||||
|
||||
$clauses = [
|
||||
$this->buildSelect($query->select, $params, $query->distinct, $query->selectOption),
|
||||
$this->buildFrom($query->from, $params),
|
||||
$this->buildJoin($query->join, $params),
|
||||
$this->buildWhere($query->where, $params),
|
||||
$this->buildGroupBy($query->groupBy),
|
||||
$this->buildHaving($query->having, $params),
|
||||
];
|
||||
|
||||
$sql = implode($this->separator, array_filter($clauses));
|
||||
$sql = $this->buildOrderByAndLimit($sql, $query->orderBy, $query->limit, $query->offset);
|
||||
|
||||
if (!empty($query->orderBy)) {
|
||||
foreach ($query->orderBy as $expression) {
|
||||
if ($expression instanceof ExpressionInterface) {
|
||||
$this->buildExpression($expression, $params);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!empty($query->groupBy)) {
|
||||
foreach ($query->groupBy as $expression) {
|
||||
if ($expression instanceof ExpressionInterface) {
|
||||
$this->buildExpression($expression, $params);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$union = $this->buildUnion($query->union, $params);
|
||||
if ($union !== '') {
|
||||
$sql = "$sql{$this->separator}$union";
|
||||
}
|
||||
|
||||
return [$sql, $params];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildUnion($unions, &$params)
|
||||
{
|
||||
if (empty($unions)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$result = '';
|
||||
|
||||
foreach ($unions as $i => $union) {
|
||||
$query = $union['query'];
|
||||
if ($query instanceof Query) {
|
||||
list($unions[$i]['query'], $params) = $this->build($query, $params);
|
||||
}
|
||||
|
||||
$result .= ' UNION ' . ($union['all'] ? 'ALL ' : '') . ' ' . $unions[$i]['query'];
|
||||
}
|
||||
|
||||
return trim($result);
|
||||
}
|
||||
}
|
||||
456
vendor/yiisoft/yii2/db/sqlite/Schema.php
vendored
Normal file
456
vendor/yiisoft/yii2/db/sqlite/Schema.php
vendored
Normal file
@@ -0,0 +1,456 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\db\sqlite;
|
||||
|
||||
use yii\base\NotSupportedException;
|
||||
use yii\db\CheckConstraint;
|
||||
use yii\db\ColumnSchema;
|
||||
use yii\db\Constraint;
|
||||
use yii\db\ConstraintFinderInterface;
|
||||
use yii\db\ConstraintFinderTrait;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Schema is the class for retrieving metadata from a SQLite (2/3) database.
|
||||
*
|
||||
* @property string $transactionIsolationLevel The transaction isolation level to use for this transaction.
|
||||
* This can be either [[Transaction::READ_UNCOMMITTED]] or [[Transaction::SERIALIZABLE]].
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @since 2.0
|
||||
*/
|
||||
class Schema extends \yii\db\Schema implements ConstraintFinderInterface
|
||||
{
|
||||
use ConstraintFinderTrait;
|
||||
|
||||
/**
|
||||
* @var array mapping from physical column types (keys) to abstract column types (values)
|
||||
*/
|
||||
public $typeMap = [
|
||||
'tinyint' => self::TYPE_TINYINT,
|
||||
'bit' => self::TYPE_SMALLINT,
|
||||
'boolean' => self::TYPE_BOOLEAN,
|
||||
'bool' => self::TYPE_BOOLEAN,
|
||||
'smallint' => self::TYPE_SMALLINT,
|
||||
'mediumint' => self::TYPE_INTEGER,
|
||||
'int' => self::TYPE_INTEGER,
|
||||
'integer' => self::TYPE_INTEGER,
|
||||
'bigint' => self::TYPE_BIGINT,
|
||||
'float' => self::TYPE_FLOAT,
|
||||
'double' => self::TYPE_DOUBLE,
|
||||
'real' => self::TYPE_FLOAT,
|
||||
'decimal' => self::TYPE_DECIMAL,
|
||||
'numeric' => self::TYPE_DECIMAL,
|
||||
'tinytext' => self::TYPE_TEXT,
|
||||
'mediumtext' => self::TYPE_TEXT,
|
||||
'longtext' => self::TYPE_TEXT,
|
||||
'text' => self::TYPE_TEXT,
|
||||
'varchar' => self::TYPE_STRING,
|
||||
'string' => self::TYPE_STRING,
|
||||
'char' => self::TYPE_CHAR,
|
||||
'blob' => self::TYPE_BINARY,
|
||||
'datetime' => self::TYPE_DATETIME,
|
||||
'year' => self::TYPE_DATE,
|
||||
'date' => self::TYPE_DATE,
|
||||
'time' => self::TYPE_TIME,
|
||||
'timestamp' => self::TYPE_TIMESTAMP,
|
||||
'enum' => self::TYPE_STRING,
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $tableQuoteCharacter = '`';
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $columnQuoteCharacter = '`';
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function findTableNames($schema = '')
|
||||
{
|
||||
$sql = "SELECT DISTINCT tbl_name FROM sqlite_master WHERE tbl_name<>'sqlite_sequence' ORDER BY tbl_name";
|
||||
return $this->db->createCommand($sql)->queryColumn();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function loadTableSchema($name)
|
||||
{
|
||||
$table = new TableSchema();
|
||||
$table->name = $name;
|
||||
$table->fullName = $name;
|
||||
|
||||
if ($this->findColumns($table)) {
|
||||
$this->findConstraints($table);
|
||||
return $table;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function loadTablePrimaryKey($tableName)
|
||||
{
|
||||
return $this->loadTableConstraints($tableName, 'primaryKey');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function loadTableForeignKeys($tableName)
|
||||
{
|
||||
$foreignKeys = $this->db->createCommand('PRAGMA FOREIGN_KEY_LIST (' . $this->quoteValue($tableName) . ')')->queryAll();
|
||||
$foreignKeys = $this->normalizePdoRowKeyCase($foreignKeys, true);
|
||||
$foreignKeys = ArrayHelper::index($foreignKeys, null, 'table');
|
||||
ArrayHelper::multisort($foreignKeys, 'seq', SORT_ASC, SORT_NUMERIC);
|
||||
$result = [];
|
||||
foreach ($foreignKeys as $table => $foreignKey) {
|
||||
$result[] = new ForeignKeyConstraint([
|
||||
'columnNames' => ArrayHelper::getColumn($foreignKey, 'from'),
|
||||
'foreignTableName' => $table,
|
||||
'foreignColumnNames' => ArrayHelper::getColumn($foreignKey, 'to'),
|
||||
'onDelete' => isset($foreignKey[0]['on_delete']) ? $foreignKey[0]['on_delete'] : null,
|
||||
'onUpdate' => isset($foreignKey[0]['on_update']) ? $foreignKey[0]['on_update'] : null,
|
||||
]);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function loadTableIndexes($tableName)
|
||||
{
|
||||
return $this->loadTableConstraints($tableName, 'indexes');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function loadTableUniques($tableName)
|
||||
{
|
||||
return $this->loadTableConstraints($tableName, 'uniques');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
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();
|
||||
$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) {
|
||||
$pattern = (new SqlTokenizer('any CHECK()'))->tokenize();
|
||||
if (!$createTableToken->matches($pattern, $offset, $firstMatchIndex, $offset)) {
|
||||
break;
|
||||
}
|
||||
|
||||
$checkSql = $createTableToken[$offset - 1]->getSql();
|
||||
$name = null;
|
||||
$pattern = (new SqlTokenizer('CONSTRAINT any'))->tokenize();
|
||||
if (isset($createTableToken[$firstMatchIndex - 2]) && $createTableToken->matches($pattern, $firstMatchIndex - 2)) {
|
||||
$name = $createTableToken[$firstMatchIndex - 1]->content;
|
||||
}
|
||||
$result[] = new CheckConstraint([
|
||||
'name' => $name,
|
||||
'expression' => $checkSql,
|
||||
]);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* @throws NotSupportedException if this method is called.
|
||||
*/
|
||||
protected function loadTableDefaultValues($tableName)
|
||||
{
|
||||
throw new NotSupportedException('SQLite does not support default value constraints.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a query builder for the MySQL database.
|
||||
* This method may be overridden by child classes to create a DBMS-specific query builder.
|
||||
* @return QueryBuilder query builder instance
|
||||
*/
|
||||
public function createQueryBuilder()
|
||||
{
|
||||
return new QueryBuilder($this->db);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* @return ColumnSchemaBuilder column schema builder instance
|
||||
*/
|
||||
public function createColumnSchemaBuilder($type, $length = null)
|
||||
{
|
||||
return new ColumnSchemaBuilder($type, $length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Collects the table column metadata.
|
||||
* @param TableSchema $table the table metadata
|
||||
* @return bool whether the table exists in the database
|
||||
*/
|
||||
protected function findColumns($table)
|
||||
{
|
||||
$sql = 'PRAGMA table_info(' . $this->quoteSimpleTableName($table->name) . ')';
|
||||
$columns = $this->db->createCommand($sql)->queryAll();
|
||||
if (empty($columns)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ($columns as $info) {
|
||||
$column = $this->loadColumnSchema($info);
|
||||
$table->columns[$column->name] = $column;
|
||||
if ($column->isPrimaryKey) {
|
||||
$table->primaryKey[] = $column->name;
|
||||
}
|
||||
}
|
||||
if (count($table->primaryKey) === 1 && !strncasecmp($table->columns[$table->primaryKey[0]]->dbType, 'int', 3)) {
|
||||
$table->sequenceName = '';
|
||||
$table->columns[$table->primaryKey[0]]->autoIncrement = true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Collects the foreign key column details for the given table.
|
||||
* @param TableSchema $table the table metadata
|
||||
*/
|
||||
protected function findConstraints($table)
|
||||
{
|
||||
$sql = 'PRAGMA foreign_key_list(' . $this->quoteSimpleTableName($table->name) . ')';
|
||||
$keys = $this->db->createCommand($sql)->queryAll();
|
||||
foreach ($keys as $key) {
|
||||
$id = (int) $key['id'];
|
||||
if (!isset($table->foreignKeys[$id])) {
|
||||
$table->foreignKeys[$id] = [$key['table'], $key['from'] => $key['to']];
|
||||
} else {
|
||||
// composite FK
|
||||
$table->foreignKeys[$id][$key['from']] = $key['to'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all unique indexes for the given table.
|
||||
*
|
||||
* Each array element is of the following structure:
|
||||
*
|
||||
* ```php
|
||||
* [
|
||||
* 'IndexName1' => ['col1' [, ...]],
|
||||
* 'IndexName2' => ['col2' [, ...]],
|
||||
* ]
|
||||
* ```
|
||||
*
|
||||
* @param TableSchema $table the table metadata
|
||||
* @return array all unique indexes for the given table.
|
||||
*/
|
||||
public function findUniqueIndexes($table)
|
||||
{
|
||||
$sql = 'PRAGMA index_list(' . $this->quoteSimpleTableName($table->name) . ')';
|
||||
$indexes = $this->db->createCommand($sql)->queryAll();
|
||||
$uniqueIndexes = [];
|
||||
|
||||
foreach ($indexes as $index) {
|
||||
$indexName = $index['name'];
|
||||
$indexInfo = $this->db->createCommand('PRAGMA index_info(' . $this->quoteValue($index['name']) . ')')->queryAll();
|
||||
|
||||
if ($index['unique']) {
|
||||
$uniqueIndexes[$indexName] = [];
|
||||
foreach ($indexInfo as $row) {
|
||||
$uniqueIndexes[$indexName][] = $row['name'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $uniqueIndexes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the column information into a [[ColumnSchema]] object.
|
||||
* @param array $info column information
|
||||
* @return ColumnSchema the column schema object
|
||||
*/
|
||||
protected function loadColumnSchema($info)
|
||||
{
|
||||
$column = $this->createColumnSchema();
|
||||
$column->name = $info['name'];
|
||||
$column->allowNull = !$info['notnull'];
|
||||
$column->isPrimaryKey = $info['pk'] != 0;
|
||||
|
||||
$column->dbType = strtolower($info['type']);
|
||||
$column->unsigned = strpos($column->dbType, 'unsigned') !== false;
|
||||
|
||||
$column->type = self::TYPE_STRING;
|
||||
if (preg_match('/^(\w+)(?:\(([^\)]+)\))?/', $column->dbType, $matches)) {
|
||||
$type = strtolower($matches[1]);
|
||||
if (isset($this->typeMap[$type])) {
|
||||
$column->type = $this->typeMap[$type];
|
||||
}
|
||||
|
||||
if (!empty($matches[2])) {
|
||||
$values = explode(',', $matches[2]);
|
||||
$column->size = $column->precision = (int) $values[0];
|
||||
if (isset($values[1])) {
|
||||
$column->scale = (int) $values[1];
|
||||
}
|
||||
if ($column->size === 1 && ($type === 'tinyint' || $type === 'bit')) {
|
||||
$column->type = 'boolean';
|
||||
} elseif ($type === 'bit') {
|
||||
if ($column->size > 32) {
|
||||
$column->type = 'bigint';
|
||||
} elseif ($column->size === 32) {
|
||||
$column->type = 'integer';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$column->phpType = $this->getColumnPhpType($column);
|
||||
|
||||
if (!$column->isPrimaryKey) {
|
||||
if ($info['dflt_value'] === 'null' || $info['dflt_value'] === '' || $info['dflt_value'] === null) {
|
||||
$column->defaultValue = null;
|
||||
} elseif ($column->type === 'timestamp' && $info['dflt_value'] === 'CURRENT_TIMESTAMP') {
|
||||
$column->defaultValue = new Expression('CURRENT_TIMESTAMP');
|
||||
} else {
|
||||
$value = trim($info['dflt_value'], "'\"");
|
||||
$column->defaultValue = $column->phpTypecast($value);
|
||||
}
|
||||
}
|
||||
|
||||
return $column;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the isolation level of the current transaction.
|
||||
* @param string $level The transaction isolation level to use for this transaction.
|
||||
* This can be either [[Transaction::READ_UNCOMMITTED]] or [[Transaction::SERIALIZABLE]].
|
||||
* @throws NotSupportedException when unsupported isolation levels are used.
|
||||
* SQLite only supports SERIALIZABLE and READ UNCOMMITTED.
|
||||
* @see http://www.sqlite.org/pragma.html#pragma_read_uncommitted
|
||||
*/
|
||||
public function setTransactionIsolationLevel($level)
|
||||
{
|
||||
switch ($level) {
|
||||
case Transaction::SERIALIZABLE:
|
||||
$this->db->createCommand('PRAGMA read_uncommitted = False;')->execute();
|
||||
break;
|
||||
case Transaction::READ_UNCOMMITTED:
|
||||
$this->db->createCommand('PRAGMA read_uncommitted = True;')->execute();
|
||||
break;
|
||||
default:
|
||||
throw new NotSupportedException(get_class($this) . ' only supports transaction isolation levels READ UNCOMMITTED and SERIALIZABLE.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads multiple types of constraints and returns the specified ones.
|
||||
* @param string $tableName table name.
|
||||
* @param string $returnType return type:
|
||||
* - primaryKey
|
||||
* - indexes
|
||||
* - uniques
|
||||
* @return mixed constraints.
|
||||
*/
|
||||
private function loadTableConstraints($tableName, $returnType)
|
||||
{
|
||||
$indexes = $this->db->createCommand('PRAGMA INDEX_LIST (' . $this->quoteValue($tableName) . ')')->queryAll();
|
||||
$indexes = $this->normalizePdoRowKeyCase($indexes, true);
|
||||
$tableColumns = null;
|
||||
if (!empty($indexes) && !isset($indexes[0]['origin'])) {
|
||||
/*
|
||||
* SQLite may not have an "origin" column in INDEX_LIST
|
||||
* See https://www.sqlite.org/src/info/2743846cdba572f6
|
||||
*/
|
||||
$tableColumns = $this->db->createCommand('PRAGMA TABLE_INFO (' . $this->quoteValue($tableName) . ')')->queryAll();
|
||||
$tableColumns = $this->normalizePdoRowKeyCase($tableColumns, true);
|
||||
$tableColumns = ArrayHelper::index($tableColumns, 'cid');
|
||||
}
|
||||
$result = [
|
||||
'primaryKey' => null,
|
||||
'indexes' => [],
|
||||
'uniques' => [],
|
||||
];
|
||||
foreach ($indexes as $index) {
|
||||
$columns = $this->db->createCommand('PRAGMA INDEX_INFO (' . $this->quoteValue($index['name']) . ')')->queryAll();
|
||||
$columns = $this->normalizePdoRowKeyCase($columns, true);
|
||||
ArrayHelper::multisort($columns, 'seqno', SORT_ASC, SORT_NUMERIC);
|
||||
if ($tableColumns !== null) {
|
||||
// SQLite may not have an "origin" column in INDEX_LIST
|
||||
$index['origin'] = 'c';
|
||||
if (!empty($columns) && $tableColumns[$columns[0]['cid']]['pk'] > 0) {
|
||||
$index['origin'] = 'pk';
|
||||
} elseif ($index['unique'] && $this->isSystemIdentifier($index['name'])) {
|
||||
$index['origin'] = 'u';
|
||||
}
|
||||
}
|
||||
$result['indexes'][] = new IndexConstraint([
|
||||
'isPrimary' => $index['origin'] === 'pk',
|
||||
'isUnique' => (bool) $index['unique'],
|
||||
'name' => $index['name'],
|
||||
'columnNames' => ArrayHelper::getColumn($columns, 'name'),
|
||||
]);
|
||||
if ($index['origin'] === 'u') {
|
||||
$result['uniques'][] = new Constraint([
|
||||
'name' => $index['name'],
|
||||
'columnNames' => ArrayHelper::getColumn($columns, 'name'),
|
||||
]);
|
||||
} elseif ($index['origin'] === 'pk') {
|
||||
$result['primaryKey'] = new Constraint([
|
||||
'columnNames' => ArrayHelper::getColumn($columns, 'name'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
foreach ($result as $type => $data) {
|
||||
$this->setTableMetadata($tableName, $type, $data);
|
||||
}
|
||||
|
||||
return $result[$returnType];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether the specified identifier is a SQLite system identifier.
|
||||
* @param string $identifier
|
||||
* @return bool
|
||||
* @see https://www.sqlite.org/src/artifact/74108007d286232f
|
||||
*/
|
||||
private function isSystemIdentifier($identifier)
|
||||
{
|
||||
return strncmp($identifier, 'sqlite_', 7) === 0;
|
||||
}
|
||||
}
|
||||
290
vendor/yiisoft/yii2/db/sqlite/SqlTokenizer.php
vendored
Normal file
290
vendor/yiisoft/yii2/db/sqlite/SqlTokenizer.php
vendored
Normal file
@@ -0,0 +1,290 @@
|
||||
<?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;
|
||||
}
|
||||
}
|
||||
58
vendor/yiisoft/yii2/db/sqlite/conditions/InConditionBuilder.php
vendored
Normal file
58
vendor/yiisoft/yii2/db/sqlite/conditions/InConditionBuilder.php
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\db\sqlite\conditions;
|
||||
|
||||
use yii\base\NotSupportedException;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @author Dmytro Naumenko <d.naumenko.a@gmail.com>
|
||||
* @since 2.0.14
|
||||
*/
|
||||
class InConditionBuilder extends \yii\db\conditions\InConditionBuilder
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* @throws NotSupportedException if `$columns` is an array
|
||||
*/
|
||||
protected function buildSubqueryInCondition($operator, $columns, $values, &$params)
|
||||
{
|
||||
if (is_array($columns)) {
|
||||
throw new NotSupportedException(__METHOD__ . ' is not supported by SQLite.');
|
||||
}
|
||||
|
||||
return parent::buildSubqueryInCondition($operator, $columns, $values, $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function buildCompositeInCondition($operator, $columns, $values, &$params)
|
||||
{
|
||||
$quotedColumns = [];
|
||||
foreach ($columns as $i => $column) {
|
||||
$quotedColumns[$i] = strpos($column, '(') === false ? $this->queryBuilder->db->quoteColumnName($column) : $column;
|
||||
}
|
||||
$vss = [];
|
||||
foreach ($values as $value) {
|
||||
$vs = [];
|
||||
foreach ($columns as $i => $column) {
|
||||
if (isset($value[$column])) {
|
||||
$phName = $this->queryBuilder->bindParam($value[$column], $params);
|
||||
$vs[] = $quotedColumns[$i] . ($operator === 'IN' ? ' = ' : ' != ') . $phName;
|
||||
} else {
|
||||
$vs[] = $quotedColumns[$i] . ($operator === 'IN' ? ' IS' : ' IS NOT') . ' NULL';
|
||||
}
|
||||
}
|
||||
$vss[] = '(' . implode($operator === 'IN' ? ' AND ' : ' OR ', $vs) . ')';
|
||||
}
|
||||
|
||||
return '(' . implode($operator === 'IN' ? ' OR ' : ' AND ', $vss) . ')';
|
||||
}
|
||||
}
|
||||
19
vendor/yiisoft/yii2/db/sqlite/conditions/LikeConditionBuilder.php
vendored
Normal file
19
vendor/yiisoft/yii2/db/sqlite/conditions/LikeConditionBuilder.php
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\db\sqlite\conditions;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
class LikeConditionBuilder extends \yii\db\conditions\LikeConditionBuilder
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $escapeCharacter = '\\';
|
||||
}
|
||||
Reference in New Issue
Block a user