%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/SqlsrvDriver.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 SQL Server 2005 and later database driver. */ class SqlsrvDriver implements Nette\Database\Driver { use Nette\SmartObject; /** @var Nette\Database\Connection */ private $connection; /** @var string */ private $version; public function initialize(Nette\Database\Connection $connection, array $options): void { $this->connection = $connection; $this->version = $connection->getPdo()->getAttribute(\PDO::ATTR_SERVER_VERSION); } public function convertException(\PDOException $e): Nette\Database\DriverException { return Nette\Database\DriverException::from($e); } /********************* SQL ****************d*g**/ public function delimite(string $name): string { /** @see https://msdn.microsoft.com/en-us/library/ms176027.aspx */ return '[' . str_replace(']', ']]', $name) . ']'; } public function formatDateTime(\DateTimeInterface $value): string { /** @see https://msdn.microsoft.com/en-us/library/ms187819.aspx */ return $value->format("'Y-m-d\\TH:i:s'"); } public function formatDateInterval(\DateInterval $value): string { throw new Nette\NotSupportedException; } public function formatLike(string $value, int $pos): string { /** @see https://msdn.microsoft.com/en-us/library/ms179859.aspx */ $value = strtr($value, ["'" => "''", '%' => '[%]', '_' => '[_]', '[' => '[[]']); return ($pos <= 0 ? "'%" : "'") . $value . ($pos >= 0 ? "%'" : "'"); } public function applyLimit(string &$sql, ?int $limit, ?int $offset): void { if ($limit < 0 || $offset < 0) { throw new Nette\InvalidArgumentException('Negative offset or limit.'); } elseif (version_compare($this->version, '11', '<')) { // 11 == SQL Server 2012 if ($offset) { throw new Nette\NotSupportedException('Offset is not supported by this database.'); } elseif ($limit !== null) { $sql = preg_replace('#^\s*(SELECT(\s+DISTINCT|\s+ALL)?|UPDATE|DELETE)#i', '$0 TOP ' . $limit, $sql, 1, $count); if (!$count) { throw new Nette\InvalidArgumentException('SQL query must begin with SELECT, UPDATE or DELETE command.'); } } } elseif ($limit !== null || $offset) { // requires ORDER BY, see https://technet.microsoft.com/en-us/library/gg699618(v=sql.110).aspx $sql .= ' OFFSET ' . (int) $offset . ' ROWS ' . 'FETCH NEXT ' . (int) $limit . ' ROWS ONLY'; } } /********************* reflection ****************d*g**/ public function getTables(): array { $tables = []; foreach ($this->connection->query(" SELECT name, CASE type WHEN 'U' THEN 0 WHEN 'V' THEN 1 END AS [view] FROM sys.objects WHERE type IN ('U', 'V') ") as $row) { $tables[] = [ 'name' => $row->name, 'view' => (bool) $row->view, ]; } return $tables; } public function getColumns(string $table): array { $columns = []; foreach ($this->connection->query(" SELECT c.name AS name, o.name AS [table], UPPER(t.name) AS nativetype, NULL AS size, c.is_nullable AS nullable, OBJECT_DEFINITION(c.default_object_id) AS [default], c.is_identity AS autoincrement, CASE WHEN i.index_id IS NULL THEN 0 ELSE 1 END AS [primary] FROM sys.columns c JOIN sys.objects o ON c.object_id = o.object_id LEFT JOIN sys.types t ON c.user_type_id = t.user_type_id LEFT JOIN sys.key_constraints k ON o.object_id = k.parent_object_id AND k.type = 'PK' LEFT JOIN sys.index_columns i ON k.parent_object_id = i.object_id AND i.index_id = k.unique_index_id AND i.column_id = c.column_id WHERE o.type IN ('U', 'V') AND o.name = {$this->connection->quote($table)} ") as $row) { $row = (array) $row; $row['vendor'] = $row; $row['nullable'] = (bool) $row['nullable']; $row['autoincrement'] = (bool) $row['autoincrement']; $row['primary'] = (bool) $row['primary']; $columns[] = $row; } return $columns; } public function getIndexes(string $table): array { $indexes = []; foreach ($this->connection->query(" SELECT i.name AS name, CASE WHEN i.is_unique = 1 OR i.is_unique_constraint = 1 THEN 1 ELSE 0 END AS [unique], i.is_primary_key AS [primary], c.name AS [column] FROM sys.indexes i JOIN sys.index_columns ic ON i.object_id = ic.object_id AND i.index_id = ic.index_id JOIN sys.columns c ON ic.object_id = c.object_id AND ic.column_id = c.column_id JOIN sys.tables t ON i.object_id = t.object_id WHERE t.name = {$this->connection->quote($table)} ORDER BY i.index_id, ic.index_column_id ") as $row) { $id = $row['name']; $indexes[$id]['name'] = $id; $indexes[$id]['unique'] = (bool) $row['unique']; $indexes[$id]['primary'] = (bool) $row['primary']; $indexes[$id]['columns'][] = $row['column']; } return array_values($indexes); } public function getForeignKeys(string $table): array { // Does't work with multicolumn foreign keys $keys = []; foreach ($this->connection->query(" SELECT fk.name AS name, cl.name AS local, tf.name AS [table], cf.name AS [column] FROM sys.foreign_keys fk JOIN sys.foreign_key_columns fkc ON fk.object_id = fkc.constraint_object_id JOIN sys.tables tl ON fkc.parent_object_id = tl.object_id JOIN sys.columns cl ON fkc.parent_object_id = cl.object_id AND fkc.parent_column_id = cl.column_id JOIN sys.tables tf ON fkc.referenced_object_id = tf.object_id JOIN sys.columns cf ON fkc.referenced_object_id = cf.object_id AND fkc.referenced_column_id = cf.column_id WHERE tl.name = {$this->connection->quote($table)} ") as $row) { $keys[$row->name] = (array) $row; } 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['sqlsrv:decl_type']) && $meta['sqlsrv:decl_type'] !== 'timestamp' ) { // timestamp does not mean time in sqlsrv $types[$meta['name']] = Nette\Database\Helpers::detectType($meta['sqlsrv: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_SUBSELECT; } }