Remove SQL Anywhere platform and driver

parent 97fc7ffd
......@@ -53,19 +53,9 @@ In order to fetch a column with an index other than `0`, use `FetchMode::NUMERIC
`EchoSQLLogger` is no longer available as part of the package.
## BC BREAK: Removed support for SQL Anywhere 12 and older
## BC BREAK: Removed support for SQL Anywhere
DBAL now requires SQL Anywhere 16 or newer, support for unmaintained versions has been dropped.
If you are using any of the legacy versions, you have to upgrade to a newer SQL Anywhere version (16+).
The following classes have been removed:
* `Doctrine\DBAL\Platforms\SQLAnywherePlatform`
* `Doctrine\DBAL\Platforms\SQLAnywhere11Platform`
* `Doctrine\DBAL\Platforms\SQLAnywhere12Platform`
* `Doctrine\DBAL\Platforms\Keywords\SQLAnywhereKeywords`
* `Doctrine\DBAL\Platforms\Keywords\SQLAnywhere11Keywords`
* `Doctrine\DBAL\Platforms\Keywords\SQLAnywhere12Keywords`
The support for the SQL Anywhere database platform and the corresponding driver has been removed.
## BC BREAK: Removed support for PostgreSQL 9.3 and older
......
......@@ -18,7 +18,6 @@
"queryobject",
"sasql",
"sql",
"sqlanywhere",
"sqlite",
"sqlserver",
"sqlsrv"
......
......@@ -133,7 +133,6 @@ interfaces to use. It can be configured in one of three ways:
- ``pdo_sqlsrv``: A Microsoft SQL Server driver that uses pdo_sqlsrv PDO
- ``sqlsrv``: A Microsoft SQL Server driver that uses the sqlsrv PHP extension.
- ``oci8``: An Oracle driver that uses the oci8 PHP extension.
- ``sqlanywhere``: A SAP Sybase SQL Anywhere driver that uses the sqlanywhere PHP extension.
- ``driverClass``: Specifies a custom driver implementation if no
'driver' is specified. This allows the use of custom drivers that
......@@ -292,27 +291,6 @@ pdo_sqlsrv / sqlsrv
- ``port`` (integer): Port of the database to connect to.
- ``dbname`` (string): Name of the database/schema to connect to.
sqlanywhere
^^^^^^^^^^^
- ``user`` (string): Username to use when connecting to the
database.
- ``password`` (string): Password to use when connecting to the
database.
- ``server`` (string): Name of a running database server to connect to.
- ``host`` (string): Hostname of the database to connect to.
- ``port`` (integer): Port of the database to connect to.
- ``dbname`` (string): Name of the database/schema to connect to.
- ``persistent`` (boolean): Whether to establish a persistent connection.
Depending on the used underlying platform version, you can specify
any other connection parameter that is supported by the particular
platform version via the ``driverOptions`` option.
You can find a list of supported connection parameters for the
currently supported platform here:
- `SAP Sybase SQL Anywhere 16.0 <http://dcx.sybase.com/index.html#sa160/en/dbadmin/da-conparm.html>`_
Automatic platform version detection
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
......@@ -337,11 +315,7 @@ without any extra configuration required:
- ``sqlsrv``
Some drivers cannot provide the version of the underlying database server without
having to query for it explicitly. For performance reasons (to save one extra query
on every connect), Doctrine does not enable automatic database platform version
detection for the following drivers:
- ``sqlanywhere``
having to query for it explicitly.
If you still want to tell Doctrine which database server version you are using in
order to choose the appropriate platform implementation, you can pass the
......
......@@ -19,7 +19,6 @@ The following database vendors are currently supported:
- Oracle
- Microsoft SQL Server
- PostgreSQL
- SAP Sybase SQL Anywhere
- SQLite
The Doctrine 2 database layer can be used independently of the
......
......@@ -58,11 +58,6 @@ PostgreSQL
- ``PostgreSQL94Platform`` for version 9.4 and above.
- ``PostgreSQL100Platform`` for version 10.0 and above.
SAP Sybase SQL Anywhere
^^^^^^^^^^^^^^^^^^^^^^^
- ``SQLAnywhere16Platform`` for version 16 and above.
SQLite
^^^^^^
......
......@@ -4,7 +4,7 @@ Portability
There are often cases when you need to write an application or library that is portable
across multiple different database vendors. The Doctrine ORM is one example of such
a library. It is an abstraction layer over all the currently supported vendors (MySQL, Oracle,
PostgreSQL, SQLite, SAP SQL Anywhere and Microsoft SQL Server). If you want to use the DBAL
PostgreSQL, SQLite and Microsoft SQL Server). If you want to use the DBAL
to write a portable application or library you have to follow lots of rules to make
all the different vendors work the same.
......
......@@ -116,10 +116,10 @@ The following options are not completely portable but are supported by most of t
vendors:
- **unsigned** (boolean): Whether a ``smallint``, ``integer`` or ``bigint`` Doctrine
type column should allow unsigned values only. Supported by MySQL and SQL Anywhere.
type column should allow unsigned values only. Supported only by MySQL.
Defaults to ``false``.
- **comment** (integer|string): The column comment. Supported by MySQL, PostgreSQL,
Oracle, SQL Server and SQL Anywhere. Defaults to ``null``.
Oracle and SQL Server. Defaults to ``null``.
Vendor specific options
^^^^^^^^^^^^^^^^^^^^^^^
......
This diff is collapsed.
......@@ -43,7 +43,6 @@
</TooFewArguments>
<UndefinedConstant>
<errorLevel type="suppress">
<directory name="src/Driver/SQLAnywhere"/>
<!--
Requires a release of
https://github.com/JetBrains/phpstorm-stubs/pull/732
......@@ -51,11 +50,6 @@
<file name="tests/Driver/PDOPgSql/DriverTest.php" />
</errorLevel>
</UndefinedConstant>
<UndefinedFunction>
<errorLevel type="suppress">
<directory name="src/Driver/SQLAnywhere"/>
</errorLevel>
</UndefinedFunction>
<UndefinedClass>
<errorLevel type="suppress">
<!-- Contains references to optional dependencies -->
......
<?php
namespace Doctrine\DBAL\Driver;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\DBALException;
use Doctrine\DBAL\Exception;
use Doctrine\DBAL\Platforms\SQLAnywhere16Platform;
use Doctrine\DBAL\Schema\SQLAnywhereSchemaManager;
use Doctrine\DBAL\VersionAwarePlatformDriver;
use function preg_match;
/**
* Abstract base implementation of the {@link Doctrine\DBAL\Driver} interface for SAP Sybase SQL Anywhere based drivers.
*/
abstract class AbstractSQLAnywhereDriver implements ExceptionConverterDriver, VersionAwarePlatformDriver
{
/**
* {@inheritdoc}
*
* @link http://dcx.sybase.com/index.html#sa160/en/saerrors/sqlerror.html
*/
public function convertException($message, DriverException $exception)
{
switch ($exception->getErrorCode()) {
case '-306':
case '-307':
case '-684':
return new Exception\DeadlockException($message, $exception);
case '-210':
case '-1175':
case '-1281':
return new Exception\LockWaitTimeoutException($message, $exception);
case '-100':
case '-103':
case '-832':
return new Exception\ConnectionException($message, $exception);
case '-143':
return new Exception\InvalidFieldNameException($message, $exception);
case '-193':
case '-196':
return new Exception\UniqueConstraintViolationException($message, $exception);
case '-194':
case '-198':
return new Exception\ForeignKeyConstraintViolationException($message, $exception);
case '-144':
return new Exception\NonUniqueFieldNameException($message, $exception);
case '-184':
case '-195':
return new Exception\NotNullConstraintViolationException($message, $exception);
case '-131':
return new Exception\SyntaxErrorException($message, $exception);
case '-110':
return new Exception\TableExistsException($message, $exception);
case '-141':
case '-1041':
return new Exception\TableNotFoundException($message, $exception);
}
return new Exception\DriverException($message, $exception);
}
/**
* {@inheritdoc}
*/
public function createDatabasePlatformForVersion($version)
{
if (
preg_match(
'/^(?P<major>\d+)(?:\.(?P<minor>\d+)(?:\.(?P<patch>\d+)(?:\.(?P<build>\d+))?)?)?/',
$version,
$versionParts
) === 0
) {
throw DBALException::invalidPlatformVersionSpecified(
$version,
'<major_version>.<minor_version>.<patch_version>.<build_version>'
);
}
$majorVersion = $versionParts['major'];
$minorVersion = $versionParts['minor'] ?? 0;
$patchVersion = $versionParts['patch'] ?? 0;
$buildVersion = $versionParts['build'] ?? 0;
$version = $majorVersion . '.' . $minorVersion . '.' . $patchVersion . '.' . $buildVersion;
switch (true) {
default:
return new SQLAnywhere16Platform();
}
}
/**
* {@inheritdoc}
*
* @deprecated Use Connection::getDatabase() instead.
*/
public function getDatabase(Connection $conn)
{
$params = $conn->getParams();
return $params['dbname'] ?? $conn->query('SELECT DB_NAME()')->fetchOne();
}
/**
* {@inheritdoc}
*/
public function getDatabasePlatform()
{
return new SQLAnywhere16Platform();
}
/**
* {@inheritdoc}
*/
public function getSchemaManager(Connection $conn)
{
return new SQLAnywhereSchemaManager($conn);
}
}
<?php
namespace Doctrine\DBAL\Driver\SQLAnywhere;
use Doctrine\DBAL\DBALException;
use Doctrine\DBAL\Driver\AbstractSQLAnywhereDriver;
use function array_keys;
use function array_map;
use function implode;
/**
* A Doctrine DBAL driver for the SAP Sybase SQL Anywhere PHP extension.
*/
class Driver extends AbstractSQLAnywhereDriver
{
/**
* {@inheritdoc}
*
* @throws DBALException If there was a problem establishing the connection.
*/
public function connect(array $params, $username = null, $password = null, array $driverOptions = [])
{
return new SQLAnywhereConnection(
$this->buildDsn(
$params['host'] ?? null,
$params['port'] ?? null,
$params['server'] ?? null,
$params['dbname'] ?? null,
$username,
$password,
$driverOptions
),
$params['persistent'] ?? false
);
}
/**
* {@inheritdoc}
*
* @deprecated
*/
public function getName()
{
return 'sqlanywhere';
}
/**
* Build the connection string for given connection parameters and driver options.
*
* @param string|null $host Host address to connect to.
* @param int|null $port Port to use for the connection (default to SQL Anywhere standard port 2638).
* @param string|null $server Database server name on the host to connect to.
* SQL Anywhere allows multiple database server instances on the same host,
* therefore specifying the server instance name to use is mandatory.
* @param string|null $dbname Name of the database on the server instance to connect to.
* @param string|null $username User name to use for connection authentication.
* @param string|null $password Password to use for connection authentication.
* @param mixed[] $driverOptions Additional parameters to use for the connection.
*
* @return string
*/
private function buildDsn($host, $port, $server, $dbname, $username = null, $password = null, array $driverOptions = [])
{
$host = $host ?? 'localhost';
$port = $port ?? 2638;
if (! empty($server)) {
$server = ';ServerName=' . $server;
}
return 'HOST=' . $host . ':' . $port .
$server .
';DBN=' . $dbname .
';UID=' . $username .
';PWD=' . $password .
';' . implode(
';',
array_map(static function ($key, $value): string {
return $key . '=' . $value;
}, array_keys($driverOptions), $driverOptions)
);
}
}
<?php
declare(strict_types=1);
namespace Doctrine\DBAL\Driver\SQLAnywhere;
use Doctrine\DBAL\Driver\FetchUtils;
use Doctrine\DBAL\Driver\Result as ResultInterface;
use function sasql_fetch_assoc;
use function sasql_fetch_row;
use function sasql_stmt_affected_rows;
use function sasql_stmt_field_count;
use function sasql_stmt_reset;
use function sasql_stmt_result_metadata;
final class Result implements ResultInterface
{
/** @var resource */
private $statement;
/** @var resource */
private $result;
/**
* @param resource $statement
*/
public function __construct($statement)
{
$this->statement = $statement;
$this->result = sasql_stmt_result_metadata($statement);
}
/**
* {@inheritDoc}
*/
public function fetchNumeric()
{
return sasql_fetch_row($this->result);
}
/**
* {@inheritDoc}
*/
public function fetchAssociative()
{
return sasql_fetch_assoc($this->result);
}
/**
* {@inheritDoc}
*/
public function fetchOne()
{
return FetchUtils::fetchOne($this);
}
/**
* {@inheritDoc}
*/
public function fetchAllNumeric(): array
{
return FetchUtils::fetchAllNumeric($this);
}
/**
* {@inheritDoc}
*/
public function fetchAllAssociative(): array
{
return FetchUtils::fetchAllAssociative($this);
}
/**
* {@inheritDoc}
*/
public function fetchFirstColumn(): array
{
return FetchUtils::fetchFirstColumn($this);
}
public function rowCount(): int
{
return sasql_stmt_affected_rows($this->statement);
}
public function columnCount(): int
{
return sasql_stmt_field_count($this->statement);
}
public function free(): void
{
sasql_stmt_reset($this->statement);
}
}
<?php
namespace Doctrine\DBAL\Driver\SQLAnywhere;
use Doctrine\DBAL\Driver\Result as ResultInterface;
use Doctrine\DBAL\Driver\ServerInfoAwareConnection;
use Doctrine\DBAL\Driver\Statement;
use Doctrine\DBAL\ParameterType;
use function assert;
use function is_float;
use function is_int;
use function is_resource;
use function is_string;
use function sasql_affected_rows;
use function sasql_commit;
use function sasql_connect;
use function sasql_escape_string;
use function sasql_insert_id;
use function sasql_pconnect;
use function sasql_real_query;
use function sasql_rollback;
use function sasql_set_option;
/**
* SAP Sybase SQL Anywhere implementation of the Connection interface.
*/
class SQLAnywhereConnection implements ServerInfoAwareConnection
{
/** @var resource The SQL Anywhere connection resource. */
private $connection;
/**
* Connects to database with given connection string.
*
* @param string $dsn The connection string.
* @param bool $persistent Whether or not to establish a persistent connection.
*
* @throws SQLAnywhereException
*/
public function __construct($dsn, $persistent = false)
{
$this->connection = $persistent ? @sasql_pconnect($dsn) : @sasql_connect($dsn);
if (! is_resource($this->connection)) {
throw SQLAnywhereException::fromSQLAnywhereError();
}
// Disable PHP warnings on error.
if (! sasql_set_option($this->connection, 'verbose_errors', false)) {
throw SQLAnywhereException::fromSQLAnywhereError($this->connection);
}
// Enable auto committing by default.
if (! sasql_set_option($this->connection, 'auto_commit', 'on')) {
throw SQLAnywhereException::fromSQLAnywhereError($this->connection);
}
}
/**
* {@inheritdoc}
*
* @throws SQLAnywhereException
*/
public function beginTransaction()
{
if (! sasql_set_option($this->connection, 'auto_commit', 'off')) {
throw SQLAnywhereException::fromSQLAnywhereError($this->connection);
}
return true;
}
/**
* {@inheritdoc}
*
* @throws SQLAnywhereException
*/
public function commit()
{
if (! sasql_commit($this->connection)) {
throw SQLAnywhereException::fromSQLAnywhereError($this->connection);
}
$this->endTransaction();
return true;
}
public function exec(string $statement): int
{
if (sasql_real_query($this->connection, $statement) === false) {
throw SQLAnywhereException::fromSQLAnywhereError($this->connection);
}
return sasql_affected_rows($this->connection);
}
/**
* {@inheritdoc}
*/
public function getServerVersion()
{
$version = $this->query("SELECT PROPERTY('ProductVersion')")->fetchOne();
assert(is_string($version));
return $version;
}
/**
* {@inheritdoc}
*/
public function lastInsertId($name = null)
{
if ($name === null) {
return sasql_insert_id($this->connection);
}
return $this->query('SELECT ' . $name . '.CURRVAL')->fetchOne();
}
public function prepare(string $sql): Statement
{
return new SQLAnywhereStatement($this->connection, $sql);
}
public function query(string $sql): ResultInterface
{
return $this->prepare($sql)->execute();
}
/**
* {@inheritdoc}
*/
public function quote($input, $type = ParameterType::STRING)
{
if (is_int($input) || is_float($input)) {
return $input;
}
return "'" . sasql_escape_string($this->connection, $input) . "'";
}
/**
* {@inheritdoc}
*/
public function requiresQueryForServerVersion()
{
return true;
}
/**
* {@inheritdoc}
*
* @throws SQLAnywhereException
*/
public function rollBack()
{
if (! sasql_rollback($this->connection)) {
throw SQLAnywhereException::fromSQLAnywhereError($this->connection);
}
$this->endTransaction();
return true;
}
/**
* Ends transactional mode and enables auto commit again.
*
* @return bool Whether or not ending transactional mode succeeded.
*
* @throws SQLAnywhereException
*/
private function endTransaction()
{
if (! sasql_set_option($this->connection, 'auto_commit', 'on')) {
throw SQLAnywhereException::fromSQLAnywhereError($this->connection);
}
return true;
}
}
<?php
namespace Doctrine\DBAL\Driver\SQLAnywhere;
use Doctrine\DBAL\Driver\AbstractDriverException;
use InvalidArgumentException;
use function sasql_error;
use function sasql_errorcode;
use function sasql_sqlstate;
use function sasql_stmt_errno;
use function sasql_stmt_error;
/**
* SAP Sybase SQL Anywhere driver exception.
*
* @psalm-immutable
*/
class SQLAnywhereException extends AbstractDriverException
{
/**
* Helper method to turn SQL Anywhere error into exception.
*
* @param resource|null $conn The SQL Anywhere connection resource to retrieve the last error from.
* @param resource|null $stmt The SQL Anywhere statement resource to retrieve the last error from.
*
* @return SQLAnywhereException
*
* @throws InvalidArgumentException
*/
public static function fromSQLAnywhereError($conn = null, $stmt = null)
{
$state = $conn !== null ? sasql_sqlstate($conn) : sasql_sqlstate();
$code = 0;
$message = null;
/**
* Try retrieving the last error from statement resource if given
*/
if ($stmt !== null) {
$code = sasql_stmt_errno($stmt);
$message = sasql_stmt_error($stmt);
}
/**
* Try retrieving the last error from the connection resource
* if either the statement resource is not given or the statement
* resource is given but the last error could not be retrieved from it (fallback).
* Depending on the type of error, it is sometimes necessary to retrieve
* it from the connection resource even though it occurred during
* a prepared statement.
*/
if ($conn !== null && $code === 0) {
$code = sasql_errorcode($conn);
$message = sasql_error($conn);
}
/**
* Fallback mode if either no connection resource is given
* or the last error could not be retrieved from the given
* connection / statement resource.
*/
if ($conn === null || $code === 0) {
$code = sasql_errorcode();
$message = sasql_error();
}
if ($message) {
return new self('SQLSTATE [' . $state . '] [' . $code . '] ' . $message, $state, $code);
}
return new self('SQL Anywhere error occurred but no error message was retrieved from driver.', $state, $code);
}
}
<?php
namespace Doctrine\DBAL\Driver\SQLAnywhere;
use Doctrine\DBAL\Driver\Result as ResultInterface;
use Doctrine\DBAL\Driver\Statement;
use Doctrine\DBAL\ParameterType;
use function array_key_exists;
use function assert;
use function is_int;
use function is_resource;
/**
* SAP SQL Anywhere implementation of the Statement interface.
*/
class SQLAnywhereStatement implements Statement
{
/** @var resource The connection resource. */
private $conn;
/** @var resource The prepared SQL statement to execute. */
private $stmt;
/** @var mixed[] The references to bound parameter values. */
private $boundValues = [];
/**
* Prepares given statement for given connection.
*
* @param resource $conn The connection resource to use.
* @param string $sql The SQL statement to prepare.
*
* @throws SQLAnywhereException
*/
public function __construct($conn, $sql)
{
if (! is_resource($conn)) {
throw new SQLAnywhereException('Invalid SQL Anywhere connection resource: ' . $conn);
}
$this->conn = $conn;
$this->stmt = sasql_prepare($conn, $sql);
if (! is_resource($this->stmt)) {
throw SQLAnywhereException::fromSQLAnywhereError($conn);
}
}
/**
* {@inheritdoc}
*
* @throws SQLAnywhereException
*/
public function bindParam($column, &$variable, $type = ParameterType::STRING, $length = null)
{
assert(is_int($column));
switch ($type) {
case ParameterType::INTEGER:
case ParameterType::BOOLEAN:
$type = 'i';
break;
case ParameterType::LARGE_OBJECT:
$type = 'b';
break;
case ParameterType::NULL:
case ParameterType::STRING:
case ParameterType::BINARY:
$type = 's';
break;
default:
throw new SQLAnywhereException('Unknown type: ' . $type);
}
$this->boundValues[$column] =& $variable;
if (! sasql_stmt_bind_param_ex($this->stmt, $column - 1, $variable, $type, $variable === null)) {
throw SQLAnywhereException::fromSQLAnywhereError($this->conn, $this->stmt);
}
return true;
}
/**
* {@inheritdoc}
*/
public function bindValue($param, $value, $type = ParameterType::STRING)
{
return $this->bindParam($param, $value, $type);
}
/**
* {@inheritdoc}
*
* @throws SQLAnywhereException
*/
public function execute($params = null): ResultInterface
{
if ($params !== null) {
$hasZeroIndex = array_key_exists(0, $params);
foreach ($params as $key => $val) {
if ($hasZeroIndex && is_int($key)) {
$this->bindValue($key + 1, $val);
} else {
$this->bindValue($key, $val);
}
}
}
if (! sasql_stmt_execute($this->stmt)) {
throw SQLAnywhereException::fromSQLAnywhereError($this->conn, $this->stmt);
}
return new Result($this->stmt);
}
public function free(): void
{
sasql_stmt_reset($this->stmt);
}
}
......@@ -11,7 +11,6 @@ use Doctrine\DBAL\Driver\PDOOracle\Driver as PDOOCIDriver;
use Doctrine\DBAL\Driver\PDOPgSql\Driver as PDOPgSQLDriver;
use Doctrine\DBAL\Driver\PDOSqlite\Driver as PDOSQLiteDriver;
use Doctrine\DBAL\Driver\PDOSqlsrv\Driver as PDOSQLSrvDriver;
use Doctrine\DBAL\Driver\SQLAnywhere\Driver as SQLAnywhereDriver;
use Doctrine\DBAL\Driver\SQLSrv\Driver as SQLSrvDriver;
use function array_keys;
......@@ -51,7 +50,6 @@ final class DriverManager
'ibm_db2' => DB2Driver::class,
'pdo_sqlsrv' => PDOSQLSrvDriver::class,
'mysqli' => MySQLiDriver::class,
'sqlanywhere' => SQLAnywhereDriver::class,
'sqlsrv' => SQLSrvDriver::class,
];
......
<?php
namespace Doctrine\DBAL\Platforms\Keywords;
/**
* SAP Sybase SQL Anywhere 16 reserved keywords list.
*/
class SQLAnywhereKeywords extends KeywordList
{
/**
* {@inheritdoc}
*/
public function getName()
{
return 'SQLAnywhere';
}
/**
* {@inheritdoc}
*
* @link http://infocenter.sybase.com/help/topic/com.sybase.dbrfen10/pdf/dbrfen10.pdf?noframes=true
*/
protected function getKeywords()
{
return [
'ADD',
'ALL',
'ALTER',
'AND',
'ANY',
'ARRAY',
'AS',
'ASC',
'ATTACH',
'BACKUP',
'BEGIN',
'BETWEEN',
'BIGINT',
'BINARY',
'BIT',
'BOTTOM',
'BREAK',
'BY',
'CALL',
'CAPABILITY',
'CASCADE',
'CASE',
'CAST',
'CHAR',
'CHAR_CONVERT',
'CHARACTER',
'CHECK',
'CHECKPOINT',
'CLOSE',
'COMMENT',
'COMMIT',
'COMPRESSED',
'CONFLICT',
'CONNECT',
'CONSTRAINT',
'CONTAINS',
'CONTINUE',
'CONVERT',
'CREATE',
'CROSS',
'CUBE',
'CURRENT',
'CURRENT_TIMESTAMP',
'CURRENT_USER',
'CURSOR',
'DATE',
'DATETIMEOFFSET',
'DBSPACE',
'DEALLOCATE',
'DEC',
'DECIMAL',
'DECLARE',
'DEFAULT',
'DELETE',
'DELETING',
'DESC',
'DETACH',
'DISTINCT',
'DO',
'DOUBLE',
'DROP',
'DYNAMIC',
'ELSE',
'ELSEIF',
'ENCRYPTED',
'END',
'ENDIF',
'ESCAPE',
'EXCEPT',
'EXCEPTION',
'EXEC',
'EXECUTE',
'EXISTING',
'EXISTS',
'EXTERNLOGIN',
'FETCH',
'FIRST',
'FLOAT',
'FOR',
'FORCE',
'FOREIGN',
'FORWARD',
'FROM',
'FULL',
'GOTO',
'GRANT',
'GROUP',
'HAVING',
'HOLDLOCK',
'IDENTIFIED',
'IF',
'IN',
'INDEX',
'INNER',
'INOUT',
'INSENSITIVE',
'INSERT',
'INSERTING',
'INSTALL',
'INSTEAD',
'INT',
'INTEGER',
'INTEGRATED',
'INTERSECT',
'INTO',
'IS',
'ISOLATION',
'JOIN',
'JSON',
'KERBEROS',
'KEY',
'LATERAL',
'LEFT',
'LIKE',
'LIMIT',
'LOCK',
'LOGIN',
'LONG',
'MATCH',
'MEMBERSHIP',
'MERGE',
'MESSAGE',
'MODE',
'MODIFY',
'NATURAL',
'NCHAR',
'NEW',
'NO',
'NOHOLDLOCK',
'NOT',
'NOTIFY',
'NULL',
'NUMERIC',
'NVARCHAR',
'OF',
'OFF',
'ON',
'OPEN',
'OPENSTRING',
'OPENXML',
'OPTION',
'OPTIONS',
'OR',
'ORDER',
'OTHERS',
'OUT',
'OUTER',
'OVER',
'PASSTHROUGH',
'PRECISION',
'PREPARE',
'PRIMARY',
'PRINT',
'PRIVILEGES',
'PROC',
'PROCEDURE',
'PUBLICATION',
'RAISERROR',
'READTEXT',
'REAL',
'REFERENCE',
'REFERENCES',
'REFRESH',
'RELEASE',
'REMOTE',
'REMOVE',
'RENAME',
'REORGANIZE',
'RESOURCE',
'RESTORE',
'RESTRICT',
'RETURN',
'REVOKE',
'RIGHT',
'ROLLBACK',
'ROLLUP',
'ROW',
'ROWTYPE',
'SAVE',
'SAVEPOINT',
'SCROLL',
'SELECT',
'SENSITIVE',
'SESSION',
'SET',
'SETUSER',
'SHARE',
'SMALLINT',
'SOME',
'SPATIAL',
'SQLCODE',
'SQLSTATE',
'START',
'STOP',
'SUBTRANS',
'SUBTRANSACTION',
'SYNCHRONIZE',
'TABLE',
'TEMPORARY',
'THEN',
'TIME',
'TIMESTAMP',
'TINYINT',
'TO',
'TOP',
'TRAN',
'TREAT',
'TRIGGER',
'TRUNCATE',
'TSEQUAL',
'UNBOUNDED',
'UNION',
'UNIQUE',
'UNIQUEIDENTIFIER',
'UNKNOWN',
'UNNEST',
'UNSIGNED',
'UPDATE',
'UPDATING',
'USER',
'USING',
'VALIDATE',
'VALUES',
'VARBINARY',
'VARBIT',
'VARCHAR',
'VARIABLE',
'VARRAY',
'VARYING',
'VIEW',
'WAIT',
'WAITFOR',
'WHEN',
'WHERE',
'WHILE',
'WINDOW',
'WITH',
'WITHIN',
'WORK',
'WRITETEXT',
'XML',
];
}
}
This diff is collapsed.
......@@ -8,7 +8,6 @@ use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Platforms\DB2Platform;
use Doctrine\DBAL\Platforms\OraclePlatform;
use Doctrine\DBAL\Platforms\PostgreSQL94Platform;
use Doctrine\DBAL\Platforms\SQLAnywhere16Platform;
use Doctrine\DBAL\Platforms\SqlitePlatform;
use Doctrine\DBAL\Platforms\SQLServer2012Platform;
......@@ -24,7 +23,6 @@ final class OptimizeFlags
DB2Platform::class => 0,
OraclePlatform::class => Connection::PORTABILITY_EMPTY_TO_NULL,
PostgreSQL94Platform::class => 0,
SQLAnywhere16Platform::class => 0,
SqlitePlatform::class => 0,
SQLServer2012Platform::class => 0,
];
......
<?php
namespace Doctrine\DBAL\Schema;
use Doctrine\DBAL\Platforms\SQLAnywhere16Platform;
use Doctrine\DBAL\Types\Type;
use function assert;
use function is_string;
use function preg_replace;
/**
* SAP Sybase SQL Anywhere schema manager.
*/
class SQLAnywhereSchemaManager extends AbstractSchemaManager
{
/**
* {@inheritdoc}
*
* Starts a database after creation
* as SQL Anywhere needs a database to be started
* before it can be used.
*
* @see startDatabase
*/
public function createDatabase($database)
{
parent::createDatabase($database);
$this->startDatabase($database);
}
/**
* {@inheritdoc}
*
* Tries stopping a database before dropping
* as SQL Anywhere needs a database to be stopped
* before it can be dropped.
*
* @see stopDatabase
*/
public function dropDatabase($database)
{
$this->tryMethod('stopDatabase', $database);
parent::dropDatabase($database);
}
/**
* Starts a database.
*
* @param string $database The name of the database to start.
*
* @return void
*/
public function startDatabase($database)
{
assert($this->_platform instanceof SQLAnywhere16Platform);
$this->_execSql($this->_platform->getStartDatabaseSQL($database));
}
/**
* Stops a database.
*
* @param string $database The name of the database to stop.
*
* @return void
*/
public function stopDatabase($database)
{
assert($this->_platform instanceof SQLAnywhere16Platform);
$this->_execSql($this->_platform->getStopDatabaseSQL($database));
}
/**
* {@inheritdoc}
*/
protected function _getPortableDatabaseDefinition($database)
{
return $database['name'];
}
/**
* {@inheritdoc}
*/
protected function _getPortableSequenceDefinition($sequence)
{
return new Sequence($sequence['sequence_name'], $sequence['increment_by'], $sequence['start_with']);
}
/**
* {@inheritdoc}
*/
protected function _getPortableTableColumnDefinition($tableColumn)
{
$type = $this->_platform->getDoctrineTypeMapping($tableColumn['type']);
$type = $this->extractDoctrineTypeFromComment($tableColumn['comment'], $type);
$tableColumn['comment'] = $this->removeDoctrineTypeFromComment($tableColumn['comment'], $type);
$precision = null;
$scale = null;
$fixed = false;
$default = null;
if ($tableColumn['default'] !== null) {
// Strip quotes from default value.
$default = preg_replace(["/^'(.*)'$/", "/''/"], ['$1', "'"], $tableColumn['default']);
if ($default === 'autoincrement') {
$default = null;
}
}
switch ($tableColumn['type']) {
case 'binary':
case 'char':
case 'nchar':
$fixed = true;
break;
}
switch ($type) {
case 'decimal':
case 'float':
$precision = $tableColumn['length'];
$scale = $tableColumn['scale'];
break;
}
return new Column(
$tableColumn['column_name'],
Type::getType($type),
[
'length' => $type === 'string' ? $tableColumn['length'] : null,
'precision' => $precision,
'scale' => $scale,
'unsigned' => (bool) $tableColumn['unsigned'],
'fixed' => $fixed,
'notnull' => (bool) $tableColumn['notnull'],
'default' => $default,
'autoincrement' => (bool) $tableColumn['autoincrement'],
'comment' => isset($tableColumn['comment']) && $tableColumn['comment'] !== ''
? $tableColumn['comment']
: null,
]
);
}
/**
* {@inheritdoc}
*/
protected function _getPortableTableDefinition($table)
{
return $table['table_name'];
}
/**
* {@inheritdoc}
*/
protected function _getPortableTableForeignKeyDefinition($tableForeignKey)
{
return new ForeignKeyConstraint(
$tableForeignKey['local_columns'],
$tableForeignKey['foreign_table'],
$tableForeignKey['foreign_columns'],
$tableForeignKey['name'],
$tableForeignKey['options']
);
}
/**
* {@inheritdoc}
*/
protected function _getPortableTableForeignKeysList($tableForeignKeys)
{
$foreignKeys = [];
foreach ($tableForeignKeys as $tableForeignKey) {
if (! isset($foreignKeys[$tableForeignKey['index_name']])) {
$foreignKeys[$tableForeignKey['index_name']] = [
'local_columns' => [$tableForeignKey['local_column']],
'foreign_table' => $tableForeignKey['foreign_table'],
'foreign_columns' => [$tableForeignKey['foreign_column']],
'name' => $tableForeignKey['index_name'],
'options' => [
'notnull' => $tableForeignKey['notnull'],
'match' => $tableForeignKey['match'],
'onUpdate' => $tableForeignKey['on_update'],
'onDelete' => $tableForeignKey['on_delete'],
'check_on_commit' => $tableForeignKey['check_on_commit'],
'clustered' => $tableForeignKey['clustered'],
'for_olap_workload' => $tableForeignKey['for_olap_workload'],
],
];
} else {
$foreignKeys[$tableForeignKey['index_name']]['local_columns'][] = $tableForeignKey['local_column'];
$foreignKeys[$tableForeignKey['index_name']]['foreign_columns'][] = $tableForeignKey['foreign_column'];
}
}
return parent::_getPortableTableForeignKeysList($foreignKeys);
}
/**
* {@inheritdoc}
*/
protected function _getPortableTableIndexesList($tableIndexRows, $tableName = null)
{
foreach ($tableIndexRows as &$tableIndex) {
$tableIndex['primary'] = (bool) $tableIndex['primary'];
$tableIndex['flags'] = [];
if ($tableIndex['clustered']) {
$tableIndex['flags'][] = 'clustered';
}
if ($tableIndex['with_nulls_not_distinct']) {
$tableIndex['flags'][] = 'with_nulls_not_distinct';
}
if (! $tableIndex['for_olap_workload']) {
continue;
}
$tableIndex['flags'][] = 'for_olap_workload';
}
return parent::_getPortableTableIndexesList($tableIndexRows, $tableName);
}
/**
* {@inheritdoc}
*/
protected function _getPortableViewDefinition($view)
{
$definition = preg_replace('/^.*\s+as\s+SELECT(.*)/i', 'SELECT$1', $view['view_def']);
assert(is_string($definition));
return new View($view['table_name'], $definition);
}
}
......@@ -12,7 +12,6 @@ use Doctrine\DBAL\Platforms\Keywords\OracleKeywords;
use Doctrine\DBAL\Platforms\Keywords\PostgreSQL100Keywords;
use Doctrine\DBAL\Platforms\Keywords\PostgreSQL94Keywords;
use Doctrine\DBAL\Platforms\Keywords\ReservedKeywordsValidator;
use Doctrine\DBAL\Platforms\Keywords\SQLAnywhereKeywords;
use Doctrine\DBAL\Platforms\Keywords\SQLiteKeywords;
use Doctrine\DBAL\Platforms\Keywords\SQLServer2012Keywords;
use Doctrine\DBAL\Tools\Console\ConnectionProvider;
......@@ -40,7 +39,6 @@ class ReservedWordsCommand extends Command
'oracle' => OracleKeywords::class,
'pgsql' => PostgreSQL94Keywords::class,
'pgsql100' => PostgreSQL100Keywords::class,
'sqlanywhere' => SQLAnywhereKeywords::class,
'sqlite' => SQLiteKeywords::class,
'sqlserver' => SQLServer2012Keywords::class,
];
......@@ -86,8 +84,8 @@ class ReservedWordsCommand extends Command
Checks if the current database contains tables and columns
with names that are identifiers in this dialect or in other SQL dialects.
By default SQLite, MySQL, PostgreSQL, Microsoft SQL Server, Oracle
and SQL Anywhere keywords are checked:
By default SQLite, MySQL, PostgreSQL, Microsoft SQL Server and Oracle
keywords are checked:
<info>%command.full_name%</info>
......@@ -108,7 +106,6 @@ The following keyword lists are currently shipped with Doctrine:
* oracle
* sqlserver
* sqlserver2012
* sqlanywhere
* db2 (Not checked by default)
EOT
);
......
<?php
namespace Doctrine\DBAL\Tests\Driver;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Driver;
use Doctrine\DBAL\Driver\AbstractSQLAnywhereDriver;
use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Platforms\SQLAnywhere16Platform;
use Doctrine\DBAL\Schema\AbstractSchemaManager;
use Doctrine\DBAL\Schema\SQLAnywhereSchemaManager;
class AbstractSQLAnywhereDriverTest extends AbstractDriverTest
{
protected function createDriver(): Driver
{
return $this->getMockForAbstractClass(AbstractSQLAnywhereDriver::class);
}
protected function createPlatform(): AbstractPlatform
{
return new SQLAnywhere16Platform();
}
protected function createSchemaManager(Connection $connection): AbstractSchemaManager
{
return new SQLAnywhereSchemaManager($connection);
}
/**
* {@inheritDoc}
*/
protected function getDatabasePlatformsForVersions(): array
{
return [
['16', SQLAnywhere16Platform::class],
['16.0', SQLAnywhere16Platform::class],
['16.0.0', SQLAnywhere16Platform::class],
['16.0.0.0', SQLAnywhere16Platform::class],
['16.1.2.3', SQLAnywhere16Platform::class],
['16.9.9.9', SQLAnywhere16Platform::class],
['17', SQLAnywhere16Platform::class],
];
}
/**
* {@inheritDoc}
*/
protected static function getExceptionConversionData(): array
{
return [
self::EXCEPTION_CONNECTION => [
['-100', null, null],
['-103', null, null],
['-832', null, null],
],
self::EXCEPTION_FOREIGN_KEY_CONSTRAINT_VIOLATION => [
['-198', null, null],
],
self::EXCEPTION_INVALID_FIELD_NAME => [
['-143', null, null],
],
self::EXCEPTION_NON_UNIQUE_FIELD_NAME => [
['-144', null, null],
],
self::EXCEPTION_NOT_NULL_CONSTRAINT_VIOLATION => [
['-184', null, null],
['-195', null, null],
],
self::EXCEPTION_SYNTAX_ERROR => [
['-131', null, null],
],
self::EXCEPTION_TABLE_EXISTS => [
['-110', null, null],
],
self::EXCEPTION_TABLE_NOT_FOUND => [
['-141', null, null],
['-1041', null, null],
],
self::EXCEPTION_UNIQUE_CONSTRAINT_VIOLATION => [
['-193', null, null],
['-196', null, null],
],
self::EXCEPTION_DEADLOCK => [
['-306', null, null],
['-307', null, null],
['-684', null, null],
],
self::EXCEPTION_LOCK_WAIT_TIMEOUT => [
['-210', null, null],
['-1175', null, null],
['-1281', null, null],
],
];
}
}
<?php
namespace Doctrine\DBAL\Tests\Driver\SQLAnywhere;
use Doctrine\DBAL\Driver as DriverInterface;
use Doctrine\DBAL\Driver\SQLAnywhere\Driver;
use Doctrine\DBAL\Tests\Driver\AbstractSQLAnywhereDriverTest;
class DriverTest extends AbstractSQLAnywhereDriverTest
{
public function testReturnsName(): void
{
self::assertSame('sqlanywhere', $this->driver->getName());
}
protected function createDriver(): DriverInterface
{
return new Driver();
}
}
<?php
namespace Doctrine\DBAL\Tests\Driver\SQLAnywhere;
use Doctrine\DBAL\Driver\SQLAnywhere\SQLAnywhereConnection;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use function extension_loaded;
class SQLAnywhereConnectionTest extends TestCase
{
/**
* The sqlanywhere driver connection mock under test.
*
* @var SQLAnywhereConnection|MockObject
*/
private $connectionMock;
protected function setUp(): void
{
if (! extension_loaded('sqlanywhere')) {
$this->markTestSkipped('sqlanywhere is not installed.');
}
parent::setUp();
$this->connectionMock = $this->getMockBuilder(SQLAnywhereConnection::class)
->disableOriginalConstructor()
->getMockForAbstractClass();
}
public function testRequiresQueryForServerVersion(): void
{
self::assertTrue($this->connectionMock->requiresQueryForServerVersion());
}
}
<?php
namespace Doctrine\DBAL\Tests\Functional\Driver\SQLAnywhere;
use Doctrine\DBAL\Driver\SQLAnywhere\Driver;
use Doctrine\DBAL\DriverManager;
use Doctrine\DBAL\Tests\FunctionalTestCase;
use function extension_loaded;
class ConnectionTest extends FunctionalTestCase
{
protected function setUp(): void
{
if (! extension_loaded('sqlanywhere')) {
self::markTestSkipped('sqlanywhere is not installed.');
}
parent::setUp();
if ($this->connection->getDriver() instanceof Driver) {
return;
}
self::markTestSkipped('sqlanywhere only test.');
}
public function testNonPersistentConnection(): void
{
$params = $this->connection->getParams();
$params['persistent'] = false;
$conn = DriverManager::getConnection($params);
$conn->connect();
self::assertTrue($conn->isConnected(), 'No SQLAnywhere-nonpersistent connection established');
}
public function testPersistentConnection(): void
{
$params = $this->connection->getParams();
$params['persistent'] = true;
$conn = DriverManager::getConnection($params);
$conn->connect();
self::assertTrue($conn->isConnected(), 'No SQLAnywhere-persistent connection established');
}
}
<?php
namespace Doctrine\DBAL\Tests\Functional\Driver\SQLAnywhere;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Driver as DriverInterface;
use Doctrine\DBAL\Driver\SQLAnywhere\Driver;
use Doctrine\DBAL\Tests\Functional\Driver\AbstractDriverTest;
use function extension_loaded;
class DriverTest extends AbstractDriverTest
{
protected function setUp(): void
{
if (! extension_loaded('sqlanywhere')) {
self::markTestSkipped('sqlanywhere is not installed.');
}
parent::setUp();
if ($this->connection->getDriver() instanceof Driver) {
return;
}
self::markTestSkipped('sqlanywhere only test.');
}
public function testReturnsDatabaseNameWithoutDatabaseNameParameter(): void
{
$params = $this->connection->getParams();
unset($params['dbname']);
$connection = new Connection(
$params,
$this->connection->getDriver(),
$this->connection->getConfiguration(),
$this->connection->getEventManager()
);
// SQL Anywhere has no "default" database. The name of the default database
// is defined on server startup and therefore can be arbitrary.
self::assertIsString($this->driver->getDatabase($connection));
}
protected function createDriver(): DriverInterface
{
return new Driver();
}
}
<?php
namespace Doctrine\DBAL\Tests\Functional\Driver\SQLAnywhere;
use Doctrine\DBAL\Driver\SQLAnywhere\Driver;
use Doctrine\DBAL\DriverManager;
use Doctrine\DBAL\Tests\FunctionalTestCase;
use function extension_loaded;
class StatementTest extends FunctionalTestCase
{
protected function setUp(): void
{
if (! extension_loaded('sqlanywhere')) {
self::markTestSkipped('sqlanywhere is not installed.');
}
parent::setUp();
if ($this->connection->getDriver() instanceof Driver) {
return;
}
self::markTestSkipped('sqlanywhere only test.');
}
public function testNonPersistentStatement(): void
{
$params = $this->connection->getParams();
$params['persistent'] = false;
$conn = DriverManager::getConnection($params);
$conn->connect();
self::assertTrue($conn->isConnected(), 'No SQLAnywhere-Connection established');
$prepStmt = $conn->prepare('SELECT 1');
self::assertTrue($prepStmt->execute(), ' Statement non-persistent failed');
}
public function testPersistentStatement(): void
{
$params = $this->connection->getParams();
$params['persistent'] = true;
$conn = DriverManager::getConnection($params);
$conn->connect();
self::assertTrue($conn->isConnected(), 'No SQLAnywhere-Connection established');
$prepStmt = $conn->prepare('SELECT 1');
self::assertTrue($prepStmt->execute(), ' Statement persistent failed');
}
}
<?php
namespace Doctrine\DBAL\Tests\Functional\Schema;
use Doctrine\DBAL\Schema\Index;
use Doctrine\DBAL\Schema\Table;
use Doctrine\DBAL\Schema\View;
class SQLAnywhereSchemaManagerTest extends SchemaManagerFunctionalTestCase
{
public function testCreateAndListViews(): void
{
$this->createTestTable('view_test_table');
$name = 'doctrine_test_view';
$sql = 'SELECT * from DBA.view_test_table';
$view = new View($name, $sql);
$this->schemaManager->dropAndCreateView($view);
$views = $this->schemaManager->listViews();
self::assertCount(1, $views, 'Database has to have one view.');
self::assertInstanceOf(View::class, $views[$name]);
self::assertEquals($name, $views[$name]->getName());
self::assertMatchesRegularExpression(
'/^SELECT \* from "?DBA"?\."?view_test_table"?$/',
$views[$name]->getSql()
);
}
public function testDropAndCreateAdvancedIndex(): void
{
$table = $this->getTestTable('test_create_advanced_index');
$this->schemaManager->dropAndCreateTable($table);
$this->schemaManager->dropAndCreateIndex(
new Index('test', ['test'], true, false, ['clustered', 'with_nulls_not_distinct', 'for_olap_workload']),
$table->getName()
);
$tableIndexes = $this->schemaManager->listTableIndexes('test_create_advanced_index');
self::assertIsArray($tableIndexes);
self::assertEquals('test', $tableIndexes['test']->getName());
self::assertEquals(['test'], $tableIndexes['test']->getColumns());
self::assertTrue($tableIndexes['test']->isUnique());
self::assertFalse($tableIndexes['test']->isPrimary());
self::assertTrue($tableIndexes['test']->hasFlag('clustered'));
self::assertTrue($tableIndexes['test']->hasFlag('with_nulls_not_distinct'));
self::assertTrue($tableIndexes['test']->hasFlag('for_olap_workload'));
}
public function testListTableColumnsWithFixedStringTypeColumn(): void
{
$table = new Table('list_table_columns_char');
$table->addColumn('id', 'integer', ['notnull' => true]);
$table->addColumn('test', 'string', ['fixed' => true]);
$table->setPrimaryKey(['id']);
$this->schemaManager->dropAndCreateTable($table);
$columns = $this->schemaManager->listTableColumns('list_table_columns_char');
self::assertArrayHasKey('test', $columns);
self::assertTrue($columns['test']->getFixed());
}
public function testCommentInTable(): void
{
self::markTestSkipped('Table level comments are not supported on SQLAnywhere');
}
}
......@@ -36,11 +36,8 @@ class TemporaryTableTest extends FunctionalTestCase
*/
public function testDropTemporaryTableNotAutoCommitTransaction(): void
{
if (
$this->connection->getDatabasePlatform()->getName() === 'sqlanywhere' ||
$this->connection->getDatabasePlatform()->getName() === 'oracle'
) {
self::markTestSkipped('Test does not work on Oracle and SQL Anywhere.');
if ($this->connection->getDatabasePlatform()->getName() === 'oracle') {
self::markTestSkipped('Test does not work on Oracle.');
}
$platform = $this->connection->getDatabasePlatform();
......@@ -73,11 +70,8 @@ class TemporaryTableTest extends FunctionalTestCase
*/
public function testCreateTemporaryTableNotAutoCommitTransaction(): void
{
if (
$this->connection->getDatabasePlatform()->getName() === 'sqlanywhere' ||
$this->connection->getDatabasePlatform()->getName() === 'oracle'
) {
self::markTestSkipped('Test does not work on Oracle and SQL Anywhere.');
if ($this->connection->getDatabasePlatform()->getName() === 'oracle') {
self::markTestSkipped('Test does not work on Oracle.');
}
$platform = $this->connection->getDatabasePlatform();
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment