%PDF- %PDF-
| Direktori : /www/varak.net/losik.varak.net/vendor/nette/database/src/Database/Drivers/ |
| Current File : //www/varak.net/losik.varak.net/vendor/nette/database/src/Database/Drivers/SqliteDriver.php |
<?php
/**
* This file is part of the Nette Framework (https://nette.org)
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
*/
declare(strict_types=1);
namespace Nette\Database\Drivers;
use Nette;
/**
* Supplemental SQLite3 database driver.
*/
class SqliteDriver implements Nette\Database\Driver
{
use Nette\SmartObject;
/** @var Nette\Database\Connection */
private $connection;
/** @var string Datetime format */
private $fmtDateTime;
public function initialize(Nette\Database\Connection $connection, array $options): void
{
$this->connection = $connection;
$this->fmtDateTime = $options['formatDateTime'] ?? 'U';
}
public function convertException(\PDOException $e): Nette\Database\DriverException
{
$code = $e->errorInfo[1] ?? null;
$msg = $e->getMessage();
if ($code !== 19) {
return Nette\Database\DriverException::from($e);
} elseif (
strpos($msg, 'must be unique') !== false
|| strpos($msg, 'is not unique') !== false
|| strpos($msg, 'UNIQUE constraint failed') !== false
) {
return Nette\Database\UniqueConstraintViolationException::from($e);
} elseif (
strpos($msg, 'may not be null') !== false
|| strpos($msg, 'NOT NULL constraint failed') !== false
) {
return Nette\Database\NotNullConstraintViolationException::from($e);
} elseif (
strpos($msg, 'foreign key constraint failed') !== false
|| strpos($msg, 'FOREIGN KEY constraint failed') !== false
) {
return Nette\Database\ForeignKeyConstraintViolationException::from($e);
} else {
return Nette\Database\ConstraintViolationException::from($e);
}
}
/********************* SQL ****************d*g**/
public function delimite(string $name): string
{
return '[' . strtr($name, '[]', ' ') . ']';
}
public function formatDateTime(\DateTimeInterface $value): string
{
return $value->format($this->fmtDateTime);
}
public function formatDateInterval(\DateInterval $value): string
{
throw new Nette\NotSupportedException;
}
public function formatLike(string $value, int $pos): string
{
$value = addcslashes(substr($this->connection->quote($value), 1, -1), '%_\\');
return ($pos <= 0 ? "'%" : "'") . $value . ($pos >= 0 ? "%'" : "'") . " ESCAPE '\\'";
}
public function applyLimit(string &$sql, ?int $limit, ?int $offset): void
{
if ($limit < 0 || $offset < 0) {
throw new Nette\InvalidArgumentException('Negative offset or limit.');
} elseif ($limit !== null || $offset) {
$sql .= ' LIMIT ' . ($limit ?? '-1')
. ($offset ? ' OFFSET ' . $offset : '');
}
}
/********************* reflection ****************d*g**/
public function getTables(): array
{
$tables = [];
foreach ($this->connection->query("
SELECT name, type = 'view' as view FROM sqlite_master WHERE type IN ('table', 'view') AND name NOT LIKE 'sqlite_%'
UNION ALL
SELECT name, type = 'view' as view FROM sqlite_temp_master WHERE type IN ('table', 'view') AND name NOT LIKE 'sqlite_%'
ORDER BY name
") as $row) {
$tables[] = [
'name' => $row->name,
'view' => (bool) $row->view,
];
}
return $tables;
}
public function getColumns(string $table): array
{
$meta = $this->connection->query("
SELECT sql FROM sqlite_master WHERE type = 'table' AND name = {$this->connection->quote($table)}
UNION ALL
SELECT sql FROM sqlite_temp_master WHERE type = 'table' AND name = {$this->connection->quote($table)}
")->fetch();
$columns = [];
foreach ($this->connection->query("PRAGMA table_info({$this->delimite($table)})") as $row) {
$column = $row['name'];
$pattern = "/(\"$column\"|`$column`|\\[$column\\]|$column)\\s+[^,]+\\s+PRIMARY\\s+KEY\\s+AUTOINCREMENT/Ui";
$type = explode('(', $row['type']);
$columns[] = [
'name' => $column,
'table' => $table,
'nativetype' => strtoupper($type[0]),
'size' => isset($type[1]) ? (int) $type[1] : null,
'nullable' => $row['notnull'] === 0,
'default' => $row['dflt_value'],
'autoincrement' => $meta && preg_match($pattern, (string) $meta['sql']),
'primary' => $row['pk'] > 0,
'vendor' => (array) $row,
];
}
return $columns;
}
public function getIndexes(string $table): array
{
$indexes = [];
foreach ($this->connection->query("PRAGMA index_list({$this->delimite($table)})") as $row) {
$id = $row['name'];
$indexes[$id]['name'] = $id;
$indexes[$id]['unique'] = (bool) $row['unique'];
$indexes[$id]['primary'] = false;
}
foreach ($indexes as $index => $values) {
$res = $this->connection->query("PRAGMA index_info({$this->delimite($index)})");
while ($row = $res->fetch()) {
$indexes[$index]['columns'][] = $row['name'];
}
}
$columns = $this->getColumns($table);
foreach ($indexes as $index => $values) {
$column = $indexes[$index]['columns'][0];
foreach ($columns as $info) {
if ($column === $info['name']) {
$indexes[$index]['primary'] = (bool) $info['primary'];
break;
}
}
}
if (!$indexes) { // @see http://www.sqlite.org/lang_createtable.html#rowid
foreach ($columns as $column) {
if ($column['vendor']['pk']) {
$indexes[] = [
'name' => 'ROWID',
'unique' => true,
'primary' => true,
'columns' => [$column['name']],
];
break;
}
}
}
return array_values($indexes);
}
public function getForeignKeys(string $table): array
{
$keys = [];
foreach ($this->connection->query("PRAGMA foreign_key_list({$this->delimite($table)})") as $row) {
$id = $row['id'];
$keys[$id]['name'] = $id;
$keys[$id]['local'] = $row['from'];
$keys[$id]['table'] = $row['table'];
$keys[$id]['foreign'] = $row['to'];
}
return array_values($keys);
}
public function getColumnTypes(\PDOStatement $statement): array
{
$types = [];
$count = $statement->columnCount();
for ($col = 0; $col < $count; $col++) {
$meta = $statement->getColumnMeta($col);
if (isset($meta['sqlite:decl_type'])) {
$types[$meta['name']] = in_array($meta['sqlite:decl_type'], ['DATE', 'DATETIME'], true)
? Nette\Database\IStructure::FIELD_UNIX_TIMESTAMP
: Nette\Database\Helpers::detectType($meta['sqlite:decl_type']);
} elseif (isset($meta['native_type'])) {
$types[$meta['name']] = Nette\Database\Helpers::detectType($meta['native_type']);
}
}
return $types;
}
public function isSupported(string $item): bool
{
return $item === self::SUPPORT_MULTI_INSERT_AS_SELECT || $item === self::SUPPORT_SUBSELECT || $item === self::SUPPORT_MULTI_COLUMN_AS_OR_COND;
}
}