0 follower

Final Class Yiisoft\Db\Sqlite\Schema

InheritanceYiisoft\Db\Sqlite\Schema » Yiisoft\Db\Driver\Pdo\AbstractPdoSchema

Implements the SQLite Server specific schema, supporting SQLite 3.3.0 or higher.

Psalm Types

Name Value
ForeignKeyInfo array{id: string, cid: string, seq: string, table: string, from: string, to: string|null, on_update: \Yiisoft\Db\Constant\ReferentialAction::*, on_delete: \Yiisoft\Db\Constant\ReferentialAction::*}
GroupedForeignKeyInfo array<string, list<\Yiisoft\Db\Sqlite\ForeignKeyInfo>>
IndexInfo array{seqno: string, cid: string, name: string}
IndexListInfo array{seq: string, name: string, unique: string, origin: string, partial: string}
ColumnInfo array{cid: string, name: string, type: string, notnull: string, dflt_value: string|null, pk: string, size?: integer, scale?: integer, schema: string|null, table: string}

Public Methods

Hide inherited methods

Method Description Defined By
getSchemaDefaultValues() Yiisoft\Db\Sqlite\Schema

Method Details

Hide inherited methods

findColumns() protected method

Collects the table column metadata.

protected boolean findColumns ( \Yiisoft\Db\Schema\TableSchemaInterface $table )
$table \Yiisoft\Db\Schema\TableSchemaInterface

The table metadata.

return boolean

Whether the table exists in the database.

                protected function findColumns(TableSchemaInterface $table): bool
{
    $tableName = $table->getName();
    $columns = $this->loadTableColumnsInfo($tableName);
    $jsonColumns = $this->getJsonColumns($table);
    $checks = $this->getTableChecks($tableName);
    foreach ($columns as $info) {
        if (in_array($info['name'], $jsonColumns, true)) {
            $info['type'] = ColumnType::JSON;
        }
        $info['schema'] = $table->getSchemaName();
        $info['table'] = $tableName;
        $column = $this->loadColumn($info, $checks);
        $table->column($info['name'], $column);
    }
    $column = count($table->getPrimaryKey()) === 1 ? $table->getColumn($table->getPrimaryKey()[0]) : null;
    if ($column !== null && !strncasecmp($column->getDbType() ?? '', 'int', 3)) {
        $table->sequenceName('');
        $column->autoIncrement();
    }
    return !empty($columns);
}

            
findConstraints() protected method

protected void findConstraints ( \Yiisoft\Db\Schema\TableSchemaInterface $table )
$table \Yiisoft\Db\Schema\TableSchemaInterface

                protected function findConstraints(TableSchemaInterface $table): void
{
    $tableName = $this->resolveFullName($table->getName(), $table->getSchemaName());
    $table->checks(...$this->getTableMetadata($tableName, SchemaInterface::CHECKS));
    $table->foreignKeys(...$this->getTableMetadata($tableName, SchemaInterface::FOREIGN_KEYS));
    $table->indexes(...$this->getTableMetadata($tableName, SchemaInterface::INDEXES));
}

            
findTableNames() protected method

protected array findTableNames ( string $schema '' )
$schema string

                protected function findTableNames(string $schema = ''): array
{
    /** @var string[] */
    return $this->db->createCommand(
        "SELECT DISTINCT tbl_name FROM sqlite_master WHERE tbl_name<>'sqlite_sequence' ORDER BY tbl_name",
    )->queryColumn();
}

            
findViewNames() protected method

protected array findViewNames ( string $schema '' )
$schema string

                protected function findViewNames(string $schema = ''): array
{
    /** @var string[] */
    return $this->db->createCommand(
        <<<SQL
        SELECT name FROM sqlite_master WHERE type = 'view' AND name NOT LIKE 'sqlite_%'
        SQL,
    )->queryColumn();
}

            
getSchemaDefaultValues() public method

public array getSchemaDefaultValues ( string $schema '', boolean $refresh false )
$schema string
$refresh boolean
throws \Yiisoft\Db\Exception\NotSupportedException

                public function getSchemaDefaultValues(string $schema = '', bool $refresh = false): array
{
    throw new NotSupportedException(__METHOD__ . ' is not supported by SQLite.');
}

            
loadResultColumn() protected method

protected \Yiisoft\Db\Schema\Column\ColumnInterface|null loadResultColumn ( array $metadata )
$metadata array

                protected function loadResultColumn(array $metadata): ?ColumnInterface
{
    if (empty($metadata['sqlite:decl_type']) && (empty($metadata['native_type']) || $metadata['native_type'] === 'null')) {
        return null;
    }
    $dbType = $metadata['sqlite:decl_type'] ?? $metadata['native_type'];
    $columnInfo = ['source' => ColumnInfoSource::QUERY_RESULT];
    if (!empty($metadata['table'])) {
        $columnInfo['table'] = $metadata['table'];
        $columnInfo['name'] = $metadata['name'];
    } elseif (!empty($metadata['name'])) {
        $columnInfo['name'] = $metadata['name'];
    }
    return $this->db->getColumnFactory()->fromDefinition($dbType, $columnInfo);
}

            
loadTableChecks() protected method

protected array loadTableChecks ( string $tableName )
$tableName string

                protected function loadTableChecks(string $tableName): array
{
    $sql = $this->db->createCommand(
        'SELECT "sql" FROM "sqlite_master" WHERE name = :tableName',
        [':tableName' => $tableName],
    )->queryScalar();
    $sql = ($sql === false || $sql === null) ? '' : (string) $sql;
    $code = (new SqlTokenizer($sql))->tokenize();
    $pattern = (new SqlTokenizer('any CREATE any TABLE any()'))->tokenize();
    $result = [];
    if ($code[0] instanceof SqlToken && $code[0]->matches($pattern, 0, $firstMatchIndex, $lastMatchIndex)) {
        $offset = 0;
        $createTableToken = $code[0][(int) $lastMatchIndex - 1];
        $sqlTokenizerAnyCheck = new SqlTokenizer('any CHECK()');
        while (
            $createTableToken instanceof SqlToken
            && $createTableToken->matches($sqlTokenizerAnyCheck->tokenize(), (int) $offset, $firstMatchIndex, $offset)
        ) {
            $name = '';
            $checkSql = (string) $createTableToken[(int) $offset - 1];
            $pattern = (new SqlTokenizer('CONSTRAINT any'))->tokenize();
            if (
                isset($createTableToken[(int) $firstMatchIndex - 2])
                && $createTableToken->matches($pattern, (int) $firstMatchIndex - 2)
            ) {
                $sqlToken = $createTableToken[(int) $firstMatchIndex - 1];
                $name = $sqlToken?->getContent() ?? '';
            }
            $result[] = new Check($name, expression: $checkSql);
        }
    }
    return $result;
}

            
loadTableDefaultValues() protected method

protected array loadTableDefaultValues ( string $tableName )
$tableName string

                protected function loadTableDefaultValues(string $tableName): array
{
    throw new NotSupportedException('SQLite does not support default value constraints.');
}

            
loadTableForeignKeys() protected method

protected array loadTableForeignKeys ( string $tableName )
$tableName string

                protected function loadTableForeignKeys(string $tableName): array
{
    $result = [];
    $foreignKeysList = $this->getPragmaForeignKeyList($tableName);
    /** @psalm-var GroupedForeignKeyInfo $foreignKeysList */
    $foreignKeysList = DbArrayHelper::arrange($foreignKeysList, ['table', 'id']);
    foreach ($foreignKeysList as $table => $foreignKeysById) {
        /**
         * @psalm-var GroupedForeignKeyInfo $foreignKeysById
         * @psalm-var int $id
         */
        foreach ($foreignKeysById as $id => $foreignKey) {
            if ($foreignKey[0]['to'] === null) {
                /** @var Index $primaryKey */
                $primaryKey = $this->getTablePrimaryKey($table);
                $foreignColumnNames = $primaryKey->columnNames;
            } else {
                /** @var string[] $foreignColumnNames */
                $foreignColumnNames = array_column($foreignKey, 'to');
            }
            $result[] = new ForeignKey(
                (string) $id,
                array_column($foreignKey, 'from'),
                '',
                $table,
                $foreignColumnNames,
                $foreignKey[0]['on_delete'],
                $foreignKey[0]['on_update'],
            );
        }
    }
    return $result;
}

            
loadTableIndexes() protected method

protected array loadTableIndexes ( string $tableName )
$tableName string

                protected function loadTableIndexes(string $tableName): array
{
    $indexList = $this->db
        ->createCommand('PRAGMA INDEX_LIST(' . $this->db->getQuoter()->quoteValue($tableName) . ')')
        ->queryAll();
    /** @psalm-var IndexListInfo[] $indexes */
    $indexes = array_map(array_change_key_case(...), $indexList);
    $result = [];
    $hasPrimaryKey = false;
    foreach ($indexes as $index) {
        $columns = $this->getPragmaIndexInfo($index['name']);
        $result[$index['name']] = new Index(
            $index['name'],
            array_column($columns, 'name'),
            (bool) $index['unique'],
            $index['origin'] === 'pk',
        );
        $hasPrimaryKey = $hasPrimaryKey || $index['origin'] === 'pk';
    }
    if (!$hasPrimaryKey) {
        /**
         * Extra check for PK in case of `INTEGER PRIMARY KEY` with ROWID.
         *
         * @link https://www.sqlite.org/lang_createtable.html#primkeyconst
         */
        $tableColumns = $this->loadTableColumnsInfo($tableName);
        foreach ($tableColumns as $tableColumn) {
            if ($tableColumn['pk'] > 0) {
                $result[''] = new Index('', [$tableColumn['name']], true, true);
                break;
            }
        }
    }
    return $result;
}

            
loadTableSchema() protected method

protected \Yiisoft\Db\Schema\TableSchemaInterface|null loadTableSchema ( string $name )
$name string

                protected function loadTableSchema(string $name): ?TableSchemaInterface
{
    $table = new TableSchema($name);
    if ($this->findColumns($table)) {
        $this->findConstraints($table);
        return $table;
    }
    return null;
}