Commit d0c9ef84 authored by Steve Müller's avatar Steve Müller

add SAP SQL Anywhere database vendor

parent 6ea864db
...@@ -4,9 +4,9 @@ Portability ...@@ -4,9 +4,9 @@ Portability
There are often cases when you need to write an application or library that is portable 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 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, a library. It is an abstraction layer over all the currently supported vendors (MySQL, Oracle,
PostgreSQL, SQLite and Microsoft SQL Server). If you want to use the DBAL to write a portable application PostgreSQL, SQLite, SAP SQL Anywhere and Microsoft SQL Server). If you want to use the DBAL
or library you have to follow lots of rules to make all the different vendors work the to write a portable application or library you have to follow lots of rules to make
same. all the different vendors work the same.
There are many different layers that you need to take care of, here is a quick list: There are many different layers that you need to take care of, here is a quick list:
...@@ -39,7 +39,7 @@ Connection Wrapper ...@@ -39,7 +39,7 @@ Connection Wrapper
This functionality is only implemented with Doctrine 2.1 upwards. This functionality is only implemented with Doctrine 2.1 upwards.
To handle all the points 1-3 you have to use a special wrapper around the database To handle all the points 1-3 you have to use a special wrapper around the database
connection. The handling and differences to tackle are all taken from the great connection. The handling and differences to tackle are all taken from the great
`PEAR MDB2 library <http://pear.php.net/package/MDB2/redirected>`_. `PEAR MDB2 library <http://pear.php.net/package/MDB2/redirected>`_.
Using the following code block in your initialization will: Using the following code block in your initialization will:
......
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\DBAL\Driver\SQLAnywhere;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Platforms\SQLAnywhere12Platform;
use Doctrine\DBAL\Schema\SQLAnywhereSchemaManager;
/**
* A Doctrine DBAL driver for the SAP Sybase SQL Anywhere PHP extension.
*
* @author Steve Müller <st.mueller@dzh-online.de>
* @link www.doctrine-project.org
* @since 2.5
*/
class Driver implements \Doctrine\DBAL\Driver
{
/**
* Build the connection string for given connection parameters and driver options.
*
* @param string $host Host address to connect to.
* @param integer $port Port to use for the connection (default to SQL Anywhere standard port 2683).
* @param string $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 $dbname Name of the database on the server instance to connect to.
* @param string $username User name to use for connection authentication.
* @param string $password Password to use for connection authentication.
* @param array $driverOptions Additional parameters to use for the connection.
*
* @return string
*/
public function buildDsn($host, $port, $server, $dbname, $username = null, $password = null, array $driverOptions = array())
{
$port = $port ?: 2683;
return
'LINKS=tcpip(HOST=' . $host . ';PORT=' . $port . ';DoBroadcast=Direct)' .
';SERVER=' . $server .
';DBN=' . $dbname .
';UID=' . $username .
';PWD=' . $password .
';' . implode(
';',
array_map(function ($key, $value) {
return $key . '=' . $value;
}, array_keys($driverOptions), $driverOptions)
);
}
/**
* {@inheritdoc}
*
* @throws SQLAnywhereException
*/
public function connect(array $params, $username = null, $password = null, array $driverOptions = array())
{
if ( ! isset($params['host'])) {
throw new SQLAnywhereException("Missing 'host' in configuration for sqlanywhere driver.");
}
if ( ! isset($params['server'])) {
throw new SQLAnywhereException("Missing 'server' in configuration for sqlanywhere driver.");
}
if ( ! isset($params['dbname'])) {
throw new SQLAnywhereException("Missing 'dbname' in configuration for sqlanywhere driver.");
}
return new SQLAnywhereConnection(
$this->buildDsn(
$params['host'],
isset($params['port']) ? $params['port'] : null,
$params['server'],
$params['dbname'],
$username,
$password,
$driverOptions
),
isset($params['persistent']) ? $params['persistent'] : false
);
}
/**
* {@inheritdoc}
*/
public function getDatabase(Connection $conn)
{
$params = $conn->getParams();
return $params['dbname'];
}
/**
* {@inheritdoc}
*/
public function getDatabasePlatform()
{
return new SQLAnywhere12Platform();
}
/**
* {@inheritdoc}
*/
public function getName()
{
return 'sqlanywhere';
}
/**
* {@inheritdoc}
*/
public function getSchemaManager(Connection $conn)
{
return new SQLAnywhereSchemaManager($conn);
}
}
\ No newline at end of file
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\DBAL\Driver\SQLAnywhere;
use Doctrine\DBAL\Driver\Connection;
/**
* SAP Sybase SQL Anywhere implementation of the Connection interface.
*
* @author Steve Müller <st.mueller@dzh-online.de>
* @link www.doctrine-project.org
* @since 2.5
*/
class SQLAnywhereConnection implements Connection
{
/**
* @var resource The SQL Anywhere connection resource.
*/
private $conn;
/**
* Constructor.
*
* Connects to database with given connection string.
*
* @param string $dsn The connection string.
* @param boolean $persistent Whether or not to establish a persistent connection.
*
* @throws SQLAnywhereException
*/
public function __construct($dsn, $persistent = false)
{
$this->conn = $persistent ? @sasql_pconnect($dsn) : @sasql_connect($dsn);
if ( ! is_resource($this->conn) || get_resource_type($this->conn) != 'SQLAnywhere connection') {
throw SQLAnywhereException::fromSQLAnywhereError();
}
/**
* Disable PHP warnings on error
*/
if ( ! sasql_set_option($this->conn, 'verbose_errors', false)) {
throw SQLAnywhereException::fromSQLAnywhereError($this->conn);
}
/**
* Enable auto committing by default
*/
if ( ! sasql_set_option($this->conn, 'auto_commit', 'on')) {
throw SQLAnywhereException::fromSQLAnywhereError($this->conn);
}
/**
* Enable exact, non-approximated row count retrieval
*/
if ( ! sasql_set_option($this->conn, 'row_counts', true)) {
throw SQLAnywhereException::fromSQLAnywhereError($this->conn);
}
}
/**
* {@inheritdoc}
*
* @throws SQLAnywhereException
*/
public function beginTransaction()
{
if ( ! sasql_set_option($this->conn, 'auto_commit', 'off')) {
throw SQLAnywhereException::fromSQLAnywhereError($this->conn);
}
return true;
}
/**
* {@inheritdoc}
*
* @throws SQLAnywhereException
*/
public function commit()
{
if ( ! sasql_commit($this->conn)) {
throw SQLAnywhereException::fromSQLAnywhereError($this->conn);
}
$this->endTransaction();
return true;
}
/**
* {@inheritdoc}
*/
public function errorCode()
{
return sasql_errorcode($this->conn);
}
/**
* {@inheritdoc}
*/
public function errorInfo()
{
return sasql_error($this->conn);
}
/**
* {@inheritdoc}
*/
public function exec($statement)
{
$stmt = $this->prepare($statement);
$stmt->execute();
return $stmt->rowCount();
}
/**
* {@inheritdoc}
*/
public function lastInsertId($name = null)
{
if ($name === null) {
return sasql_insert_id($this->conn);
}
return $this->query('SELECT ' . $name . '.CURRVAL')->fetchColumn();
}
/**
* {@inheritdoc}
*/
public function prepare($prepareString)
{
return new SQLAnywhereStatement($this->conn, $prepareString);
}
/**
* {@inheritdoc}
*/
public function query()
{
$args = func_get_args();
$stmt = $this->prepare($args[0]);
$stmt->execute();
return $stmt;
}
/**
* {@inheritdoc}
*/
public function quote($input, $type = \PDO::PARAM_STR)
{
if (is_int($input) || is_float($input)) {
return $input;
}
return "'" . sasql_escape_string($this->conn, $input) . "'";
}
/**
* {@inheritdoc}
*
* @throws SQLAnywhereException
*/
public function rollBack()
{
if ( ! sasql_rollback($this->conn)) {
throw SQLAnywhereException::fromSQLAnywhereError($this->conn);
}
$this->endTransaction();
return true;
}
/**
* Ends transactional mode and enables auto commit again.
*
* @throws SQLAnywhereException
*
* @return boolean Whether or not ending transactional mode succeeded.
*/
private function endTransaction()
{
if ( ! sasql_set_option($this->conn, 'auto_commit', 'on')) {
throw SQLAnywhereException::fromSQLAnywhereError($this->conn);
}
return true;
}
}
\ No newline at end of file
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\DBAL\Driver\SQLAnywhere;
use Doctrine\DBAL\DBALException;
/**
* SAP Sybase SQL Anywhere driver exception.
*
* @author Steve Müller <st.mueller@dzh-online.de>
* @link www.doctrine-project.org
* @since 2.5
*/
class SQLAnywhereException extends DBALException
{
/**
* 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)
{
if ($conn !== null && ! (is_resource($conn) && get_resource_type($conn) == 'SQLAnywhere connection')) {
throw new \InvalidArgumentException('Invalid SQL Anywhere connection resource given: ' . $conn);
}
if ($stmt !== null && ! (is_resource($stmt) && get_resource_type($stmt) == 'SQLAnywhere statement')) {
throw new \InvalidArgumentException('Invalid SQL Anywhere statement resource given: ' . $stmt);
}
$state = $conn ? sasql_sqlstate($conn) : sasql_sqlstate();
$code = null;
$message = null;
/**
* Try retrieving the last error from statement resource if given
*/
if ($stmt) {
$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 && ! $code) {
$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 || ! $code) {
$code = sasql_errorcode();
$message = sasql_error();
}
if ($message) {
$message = 'SQLSTATE [' . $state . '] [' . $code . '] ' . $message;
} else {
$message = 'SQL Anywhere error occurred but no error message was retrieved from driver.';
}
return new self($message, $code);
}
}
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\DBAL\Driver\SQLAnywhere;
use IteratorAggregate;
use PDO;
use Doctrine\DBAL\Driver\Statement;
/**
* SAP SQL Anywhere implementation of the Statement interface.
*
* @author Steve Müller <st.mueller@dzh-online.de>
* @link www.doctrine-project.org
* @since 2.5
*/
class SQLAnywhereStatement implements IteratorAggregate, Statement
{
/**
* @var resource The connection resource.
*/
private $conn;
/**
* @var string Name of the default class to instantiate when fetch mode is \PDO::FETCH_CLASS.
*/
private $defaultFetchClass = '\stdClass';
/**
* @var string Constructor arguments for the default class to instantiate when fetch mode is \PDO::FETCH_CLASS.
*/
private $defaultFetchClassCtorArgs = array();
/**
* @var int Default fetch mode to use.
*/
private $defaultFetchMode = PDO::FETCH_BOTH;
/**
* @var resource The result set resource to fetch.
*/
private $result;
/**
* @var resource The prepared SQL statement to execute.
*/
private $stmt;
/**
* Constructor.
*
* 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) || get_resource_type($conn) != 'SQLAnywhere connection') {
throw new SQLAnywhereException('Invalid SQL Anywhere connection resource: ' . $conn);
}
$this->conn = $conn;
$this->stmt = sasql_prepare($conn, $sql);
if ( ! is_resource($this->stmt) || get_resource_type($this->stmt) != 'SQLAnywhere statement') {
throw SQLAnywhereException::fromSQLAnywhereError($conn);
}
}
/**
* {@inheritdoc}
*
* @throws SQLAnywhereException
*/
public function bindParam($column, &$variable, $type = null, $length = null)
{
switch ($type) {
case PDO::PARAM_INT:
case PDO::PARAM_BOOL:
$type = 'i';
break;
case PDO::PARAM_LOB:
$type = 'b';
break;
case PDO::PARAM_NULL:
case PDO::PARAM_STR:
$type = 's';
break;
default:
throw new SQLAnywhereException('Unknown type: ' . $type);
}
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 = null)
{
return $this->bindParam($param, $value, $type);
}
/**
* {@inheritdoc}
*
* @throws SQLAnywhereException
*/
public function closeCursor()
{
if ( ! sasql_stmt_free_result($this->stmt)) {
throw SQLAnywhereException::fromSQLAnywhereError($this->conn, $this->stmt);
}
return true;
}
/**
* {@inheritdoc}
*/
public function columnCount()
{
return sasql_stmt_field_count($this->stmt);
}
/**
* {@inheritdoc}
*/
public function errorCode()
{
return sasql_stmt_errno($this->stmt);
}
/**
* {@inheritdoc}
*/
public function errorInfo()
{
return sasql_stmt_error($this->stmt);
}
/**
* {@inheritdoc}
*
* @throws SQLAnywhereException
*/
public function execute($params = null)
{
if ($params) {
$hasZeroIndex = array_key_exists(0, $params);
foreach ($params as $key => $val) {
$key = ($hasZeroIndex && is_numeric($key)) ? $key + 1 : $key;
$this->bindValue($key, $val);
}
}
if ( ! sasql_stmt_execute($this->stmt)) {
throw SQLAnywhereException::fromSQLAnywhereError($this->conn, $this->stmt);
}
$this->result = sasql_stmt_result_metadata($this->stmt);
return true;
}
/**
* {@inheritdoc}
*
* @throws SQLAnywhereException
*/
public function fetch($fetchMode = null)
{
if ( ! is_resource($this->result) || get_resource_type($this->result) != 'SQLAnywhere result') {
return false;
}
$fetchMode = $fetchMode ?: $this->defaultFetchMode;
switch ($fetchMode) {
case PDO::FETCH_ASSOC:
return sasql_fetch_assoc($this->result);
case PDO::FETCH_BOTH:
return sasql_fetch_array($this->result, SASQL_BOTH);
case PDO::FETCH_CLASS:
$className = $this->defaultFetchClass;
$ctorArgs = $this->defaultFetchClassCtorArgs;
if (func_num_args() >= 2) {
$args = func_get_args();
$className = $args[1];
$ctorArgs = isset($args[2]) ? $args[2] : array();
}
$result = sasql_fetch_object($this->result);
if ($result instanceof \stdClass) {
$result = $this->castObject($result, $className, $ctorArgs);
}
return $result;
case PDO::FETCH_NUM:
return sasql_fetch_row($this->result);
case PDO::FETCH_OBJ:
return sasql_fetch_object($this->result);
default:
throw new SQLAnywhereException('Fetch mode is not supported: ' . $fetchMode);
}
}
/**
* {@inheritdoc}
*/
public function fetchAll($fetchMode = null)
{
$rows = array();
switch ($fetchMode) {
case PDO::FETCH_CLASS:
while ($row = call_user_func_array(array($this, 'fetch'), func_get_args())) {
$rows[] = $row;
}
break;
case PDO::FETCH_COLUMN:
while ($row = $this->fetchColumn()) {
$rows[] = $row;
}
break;
default:
while ($row = $this->fetch($fetchMode)) {
$rows[] = $row;
}
}
return $rows;
}
/**
* {@inheritdoc}
*/
public function fetchColumn($columnIndex = 0)
{
$row = $this->fetch(PDO::FETCH_NUM);
if ($row && isset($row[$columnIndex])) {
return $row[$columnIndex];
}
return false;
}
/**
* {@inheritdoc}
*/
public function getIterator()
{
return new \ArrayIterator($this->fetchAll());
}
/**
* {@inheritdoc}
*/
public function rowCount()
{
return sasql_stmt_affected_rows($this->stmt);
}
/**
* {@inheritdoc}
*/
public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null)
{
$this->defaultFetchMode = $fetchMode;
$this->defaultFetchClass = $arg2 ? $arg2 : $this->defaultFetchClass;
$this->defaultFetchClassCtorArgs = $arg3 ? (array) $arg3 : $this->defaultFetchClassCtorArgs;
}
/**
* Casts a stdClass object to the given class name mapping its' properties.
*
* @param \stdClass $sourceObject Object to cast from.
* @param string|object $destinationClass Name of the class or class instance to cast to.
* @param array $ctorArgs Arguments to use for constructing the destination class instance.
*
* @return object
*
* @throws SQLAnywhereException
*/
private function castObject(\stdClass $sourceObject, $destinationClass, array $ctorArgs = array())
{
if ( ! is_string($destinationClass)) {
if ( ! is_object($destinationClass)) {
throw new SQLAnywhereException(sprintf(
'Destination class has to be of type string or object, %s given.', gettype($destinationClass)
));
}
} else {
$destinationClass = new \ReflectionClass($destinationClass);
$destinationClass = $destinationClass->newInstanceArgs($ctorArgs);
}
$sourceReflection = new \ReflectionObject($sourceObject);
$destinationClassReflection = new \ReflectionObject($destinationClass);
foreach ($sourceReflection->getProperties() as $sourceProperty) {
$sourceProperty->setAccessible(true);
$name = $sourceProperty->getName();
$value = $sourceProperty->getValue($sourceObject);
if ($destinationClassReflection->hasProperty($name)) {
$destinationProperty = $destinationClassReflection->getProperty($name);
$destinationProperty->setAccessible(true);
$destinationProperty->setValue($destinationClass, $value);
} else {
$destinationClass->$name = $value;
}
}
return $destinationClass;
}
}
...@@ -38,18 +38,19 @@ final class DriverManager ...@@ -38,18 +38,19 @@ final class DriverManager
* @var array * @var array
*/ */
private static $_driverMap = array( private static $_driverMap = array(
'pdo_mysql' => 'Doctrine\DBAL\Driver\PDOMySql\Driver', 'pdo_mysql' => 'Doctrine\DBAL\Driver\PDOMySql\Driver',
'pdo_sqlite' => 'Doctrine\DBAL\Driver\PDOSqlite\Driver', 'pdo_sqlite' => 'Doctrine\DBAL\Driver\PDOSqlite\Driver',
'pdo_pgsql' => 'Doctrine\DBAL\Driver\PDOPgSql\Driver', 'pdo_pgsql' => 'Doctrine\DBAL\Driver\PDOPgSql\Driver',
'pdo_oci' => 'Doctrine\DBAL\Driver\PDOOracle\Driver', 'pdo_oci' => 'Doctrine\DBAL\Driver\PDOOracle\Driver',
'oci8' => 'Doctrine\DBAL\Driver\OCI8\Driver', 'oci8' => 'Doctrine\DBAL\Driver\OCI8\Driver',
'ibm_db2' => 'Doctrine\DBAL\Driver\IBMDB2\DB2Driver', 'ibm_db2' => 'Doctrine\DBAL\Driver\IBMDB2\DB2Driver',
'pdo_ibm' => 'Doctrine\DBAL\Driver\PDOIbm\Driver', 'pdo_ibm' => 'Doctrine\DBAL\Driver\PDOIbm\Driver',
'pdo_sqlsrv' => 'Doctrine\DBAL\Driver\PDOSqlsrv\Driver', 'pdo_sqlsrv' => 'Doctrine\DBAL\Driver\PDOSqlsrv\Driver',
'mysqli' => 'Doctrine\DBAL\Driver\Mysqli\Driver', 'mysqli' => 'Doctrine\DBAL\Driver\Mysqli\Driver',
'drizzle_pdo_mysql' => 'Doctrine\DBAL\Driver\DrizzlePDOMySql\Driver', 'drizzle_pdo_mysql' => 'Doctrine\DBAL\Driver\DrizzlePDOMySql\Driver',
'sqlsrv' => 'Doctrine\DBAL\Driver\SQLSrv\Driver', 'sqlanywhere' => 'Doctrine\DBAL\Driver\SQLAnywhere\Driver',
); 'sqlsrv' => 'Doctrine\DBAL\Driver\SQLSrv\Driver'
);
/** /**
* Private constructor. This class cannot be instantiated. * Private constructor. This class cannot be instantiated.
...@@ -75,6 +76,7 @@ final class DriverManager ...@@ -75,6 +76,7 @@ final class DriverManager
* pdo_ibm (unstable) * pdo_ibm (unstable)
* pdo_sqlsrv * pdo_sqlsrv
* mysqli * mysqli
* sqlanywhere
* sqlsrv * sqlsrv
* ibm_db2 (unstable) * ibm_db2 (unstable)
* drizzle_pdo_mysql * drizzle_pdo_mysql
......
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\DBAL\Platforms\Keywords;
/**
* SAP Sybase SQL Anywhere 11 reserved keywords list.
*
* @author Steve Müller <st.mueller@dzh-online.de>
*/
class SQLAnywhere11Keywords extends SQLAnywhereKeywords
{
/**
* {@inheritdoc}
*/
public function getName()
{
return 'SQLAnywhere11';
}
/**
* {@inheritdoc}
*
* @link http://dcx.sybase.com/1100/en/dbreference_en11/alhakeywords.html
*/
protected function getKeywords()
{
return array_merge(array_diff(parent::getKeywords(), array('IQ')), array(
'MERGE',
'OPENSTRING'
));
}
}
\ No newline at end of file
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\DBAL\Platforms\Keywords;
/**
* SAP Sybase SQL Anywhere 12 reserved keywords list.
*
* @author Steve Müller <st.mueller@dzh-online.de>
*/
class SQLAnywhere12Keywords extends SQLAnywhere11Keywords
{
/**
* {@inheritdoc}
*/
public function getName()
{
return 'SQLAnywhere12';
}
/**
* {@inheritdoc}
*
* @link http://dcx.sybase.com/1200/en/dbreference/alhakeywords.html
*/
protected function getKeywords()
{
return array_merge(array_diff(parent::getKeywords(), array(
'INDEX_LPAREN',
'SYNTAX_ERROR',
'WITH_CUBE',
'WITH_LPAREN',
'WITH_ROLLUP'
)), array(
'DATETIMEOFFSET',
'LIMIT',
'OPENXML',
'SPATIAL',
'TREAT'
));
}
}
\ No newline at end of file
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\DBAL\Platforms\Keywords;
/**
* SAP Sybase SQL Anywhere 10 reserved keywords list.
*
* @author Steve Müller <st.mueller@dzh-online.de>
*/
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 array(
'ADD',
'ALL',
'ALTER',
'AND',
'ANY',
'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',
'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',
'INDEX_LPAREN',
'INNER',
'INOUT',
'INSENSITIVE',
'INSERT',
'INSERTING',
'INSTALL',
'INSTEAD',
'INT',
'INTEGER',
'INTEGRATED',
'INTERSECT',
'INTO',
'IQ',
'IS',
'ISOLATION',
'JOIN',
'KERBEROS',
'KEY',
'LATERAL',
'LEFT',
'LIKE',
'LOCK',
'LOGIN',
'LONG',
'MATCH',
'MEMBERSHIP',
'MESSAGE',
'MODE',
'MODIFY',
'NATURAL',
'NCHAR',
'NEW',
'NO',
'NOHOLDLOCK',
'NOT',
'NOTIFY',
'NULL',
'NUMERIC',
'NVARCHAR',
'OF',
'OFF',
'ON',
'OPEN',
'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',
'SAVE',
'SAVEPOINT',
'SCROLL',
'SELECT',
'SENSITIVE',
'SESSION',
'SET',
'SETUSER',
'SHARE',
'SMALLINT',
'SOME',
'SQLCODE',
'SQLSTATE',
'START',
'STOP',
'SUBTRANS',
'SUBTRANSACTION',
'SYNCHRONIZE',
'SYNTAX_ERROR',
'TABLE',
'TEMPORARY',
'THEN',
'TIME',
'TIMESTAMP',
'TINYINT',
'TO',
'TOP',
'TRAN',
'TRIGGER',
'TRUNCATE',
'TSEQUAL',
'UNBOUNDED',
'UNION',
'UNIQUE',
'UNIQUEIDENTIFIER',
'UNKNOWN',
'UNSIGNED',
'UPDATE',
'UPDATING',
'USER',
'USING',
'VALIDATE',
'VALUES',
'VARBINARY',
'VARBIT',
'VARCHAR',
'VARIABLE',
'VARYING',
'VIEW',
'WAIT',
'WAITFOR',
'WHEN',
'WHERE',
'WHILE',
'WINDOW',
'WITH',
'WITH_CUBE',
'WITH_LPAREN',
'WITH_ROLLUP',
'WITHIN',
'WORK',
'WRITETEXT',
'XML'
);
}
}
\ No newline at end of file
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\DBAL\Platforms;
/**
* The SQLAnywhere11Platform provides the behavior, features and SQL dialect of the
* SAP Sybase SQL Anywhere 11 database platform.
*
* @author Steve Müller <st.mueller@dzh-online.de>
* @link www.doctrine-project.org
* @since 2.5
*/
class SQLAnywhere11Platform extends SQLAnywherePlatform
{
/**
* {@inheritdoc}
*/
public function getRegexpExpression()
{
return 'REGEXP';
}
/**
* {@inheritdoc}
*/
protected function getReservedKeywordsClass()
{
return 'Doctrine\DBAL\Platforms\Keywords\SQLAnywhere11Keywords';
}
}
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\DBAL\Platforms;
use Doctrine\DBAL\Schema\Index;
use Doctrine\DBAL\Schema\Sequence;
/**
* The SQLAnywhere12Platform provides the behavior, features and SQL dialect of the
* SAP Sybase SQL Anywhere 12 database platform.
*
* @author Steve Müller <st.mueller@dzh-online.de>
* @link www.doctrine-project.org
* @since 2.5
*/
class SQLAnywhere12Platform extends SQLAnywhere11Platform
{
/**
* {@inheritdoc}
*/
public function getCreateSequenceSQL(Sequence $sequence)
{
return 'CREATE SEQUENCE ' . $sequence->getQuotedName($this) .
' INCREMENT BY ' . $sequence->getAllocationSize() .
' START WITH ' . $sequence->getInitialValue() .
' MINVALUE ' . $sequence->getInitialValue();
}
/**
* {@inheritdoc}
*/
public function getAlterSequenceSQL(Sequence $sequence)
{
return 'ALTER SEQUENCE ' . $sequence->getQuotedName($this) .
' INCREMENT BY ' . $sequence->getAllocationSize();
}
/**
* {@inheritdoc}
*/
public function getDateTimeTzFormatString()
{
return 'Y-m-d H:i:s.uP';
}
/**
* {@inheritdoc}
*/
public function getDateTimeTzTypeDeclarationSQL(array $fieldDeclaration)
{
return 'TIMESTAMP WITH TIME ZONE';
}
/**
* {@inheritdoc}
*/
public function getDropSequenceSQL($sequence)
{
if ($sequence instanceof Sequence) {
$sequence = $sequence->getQuotedName($this);
}
/** @var string $sequence */
return 'DROP SEQUENCE ' . $sequence;
}
/**
* {@inheritdoc}
*/
public function getListSequencesSQL($database)
{
return 'SELECT sequence_name, increment_by, start_with, min_value FROM SYS.SYSSEQUENCE';
}
/**
* {@inheritdoc}
*/
public function getSequenceNextValSQL($sequenceName)
{
return 'SELECT ' . $sequenceName . '.NEXTVAL';
}
/**
* {@inheritdoc}
*/
public function supportsSequences()
{
return true;
}
/**
* {@inheritdoc}
*/
protected function getAdvancedIndexOptionsSQL(Index $index)
{
$sql = '';
if (!$index->isPrimary() && $index->isUnique() && $index->hasFlag('with_nulls_not_distinct')) {
$sql .= ' WITH NULLS NOT DISTINCT';
}
return $sql . parent::getAdvancedIndexOptionsSQL($index);
}
/**
* {@inheritdoc}
*/
protected function getReservedKeywordsClass()
{
return 'Doctrine\DBAL\Platforms\Keywords\SQLAnywhere12Keywords';
}
/**
* {@inheritDoc}
*/
protected function initializeDoctrineTypeMappings()
{
parent::initializeDoctrineTypeMappings();
$this->doctrineTypeMapping['timestamp with time zone'] = 'datetime';
}
}
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\DBAL\Platforms;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\DBALException;
use Doctrine\DBAL\LockMode;
use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Schema\Constraint;
use Doctrine\DBAL\Schema\ForeignKeyConstraint;
use Doctrine\DBAL\Schema\Index;
use Doctrine\DBAL\Schema\Table;
use Doctrine\DBAL\Schema\TableDiff;
/**
* The SQLAnywherePlatform provides the behavior, features and SQL dialect of the
* SAP Sybase SQL Anywhere 10 database platform.
*
* @author Steve Müller <st.mueller@dzh-online.de>
* @link www.doctrine-project.org
* @since 2.5
*/
class SQLAnywherePlatform extends AbstractPlatform
{
/**
* @var integer
*/
const FOREIGN_KEY_MATCH_SIMPLE = 1;
/**
* @var integer
*/
const FOREIGN_KEY_MATCH_FULL = 2;
/**
* @var integer
*/
const FOREIGN_KEY_MATCH_SIMPLE_UNIQUE = 129;
/**
* @var integer
*/
const FOREIGN_KEY_MATCH_FULL_UNIQUE = 130;
/**
* {@inheritdoc}
*
* @throws \InvalidArgumentException
*/
public function appendLockHint($fromClause, $lockMode)
{
switch (true) {
case $lockMode === LockMode::NONE:
$lockClause = ' WITH (NOLOCK)';
break;
case $lockMode === LockMode::PESSIMISTIC_READ:
$lockClause = ' WITH (UPDLOCK)';
break;
case $lockMode === LockMode::PESSIMISTIC_WRITE:
$lockClause = ' WITH (XLOCK)';
break;
default:
throw new \InvalidArgumentException('Invalid lock mode: ' . $lockMode);
}
return $fromClause . $lockClause;
}
/**
* {@inheritdoc}
*
* SQL Anywhere supports a maximum length of 128 bytes for identifiers.
*/
public function fixSchemaElementName($schemaElementName)
{
$maxIdentifierLength = $this->getMaxIdentifierLength();
if (strlen($schemaElementName) > $maxIdentifierLength) {
return substr($schemaElementName, 0, $maxIdentifierLength);
}
return $schemaElementName;
}
/**
* {@inheritdoc}
*/
public function getAdvancedForeignKeyOptionsSQL(ForeignKeyConstraint $foreignKey)
{
$query = '';
if ($foreignKey->hasOption('match')) {
$query = ' MATCH ' . $this->getForeignKeyMatchClauseSQL($foreignKey->getOption('match'));
}
$query .= parent::getAdvancedForeignKeyOptionsSQL($foreignKey);
if ($foreignKey->hasOption('check_on_commit') && (boolean) $foreignKey->getOption('check_on_commit')) {
$query .= ' CHECK ON COMMIT';
}
if ($foreignKey->hasOption('clustered') && (boolean) $foreignKey->getOption('clustered')) {
$query .= ' CLUSTERED';
}
if ($foreignKey->hasOption('for_olap_workload') && (boolean) $foreignKey->getOption('for_olap_workload')) {
$query .= ' FOR OLAP WORKLOAD';
}
return $query;
}
/**
* {@inheritdoc}
*/
public function getAlterTableSQL(TableDiff $diff)
{
$sql = array();
$columnSql = array();
$commentsSQL = array();
$tableSql = array();
$queryParts = array();
/** @var \Doctrine\DBAL\Schema\Column $column */
foreach ($diff->addedColumns as $column) {
if ($this->onSchemaAlterTableAddColumn($column, $diff, $columnSql)) {
continue;
}
$queryParts[] = 'ADD ' . $this->getColumnDeclarationSQL($column->getQuotedName($this), $column->toArray());
if ($comment = $this->getColumnComment($column)) {
$commentsSQL[] = $this->getCommentOnColumnSQL($diff->name, $column->getName(), $comment);
}
}
/** @var \Doctrine\DBAL\Schema\Column $column */
foreach ($diff->removedColumns as $column) {
if ($this->onSchemaAlterTableRemoveColumn($column, $diff, $columnSql)) {
continue;
}
$queryParts[] = 'DROP ' . $column->getQuotedName($this);
}
/** @var \Doctrine\DBAL\Schema\ColumnDiff $columnDiff */
foreach ($diff->changedColumns as $columnDiff) {
if ($this->onSchemaAlterTableChangeColumn($columnDiff, $diff, $columnSql)) {
continue;
}
$column = $columnDiff->column;
$columnHasChangedComment = $columnDiff->hasChanged('comment');
/**
* Do not add query part if only comment has changed
*/
if ( ! ($columnHasChangedComment && count($columnDiff->changedProperties) === 1)) {
$queryParts[] = 'ALTER ' .
$this->getColumnDeclarationSQL($column->getQuotedName($this), $column->toArray());
}
if ($columnHasChangedComment) {
$commentsSQL[] = $this->getCommentOnColumnSQL(
$diff->name,
$column->getName(),
$this->getColumnComment($column)
);
}
}
foreach ($diff->renamedColumns as $oldColumnName => $column) {
if ($this->onSchemaAlterTableRenameColumn($oldColumnName, $column, $diff, $columnSql)) {
continue;
}
$sql[] = 'ALTER TABLE ' . $diff->name . ' RENAME ' . $oldColumnName .' TO ' . $column->getQuotedName($this);
}
if ( ! $this->onSchemaAlterTable($diff, $tableSql)) {
if ( ! empty($queryParts)) {
$sql[] = 'ALTER TABLE ' . $diff->name . ' ' . implode(", ", $queryParts);
}
if ($diff->newName !== false) {
$sql[] = 'ALTER TABLE ' . $diff->name . ' RENAME ' . $diff->newName;
}
$sql = array_merge($sql, $this->_getAlterTableIndexForeignKeySQL($diff), $commentsSQL);
}
return array_merge($sql, $tableSql, $columnSql);
}
/**
* {@inheritdoc}
*/
public function getBigIntTypeDeclarationSQL(array $columnDef)
{
$columnDef['integer_type'] = 'BIGINT';
return $this->_getCommonIntegerTypeDeclarationSQL($columnDef);
}
/**
* {@inheritdoc}
*/
public function getBlobTypeDeclarationSQL(array $field)
{
return 'LONG BINARY';
}
/**
* {@inheritdoc}
*
* BIT type columns require an explicit NULL declaration
* in SQL Anywhere if they shall be nullable.
* Otherwise by just omitting the NOT NULL clause,
* SQL Anywhere will declare them NOT NULL nonetheless.
*/
public function getBooleanTypeDeclarationSQL(array $columnDef)
{
$nullClause = isset($columnDef['notnull']) && (boolean) $columnDef['notnull'] === false ? ' NULL' : '';
return 'BIT' . $nullClause;
}
/**
* {@inheritdoc}
*/
public function getClobTypeDeclarationSQL(array $field)
{
return 'TEXT';
}
/**
* {@inheritdoc}
*/
public function getCommentOnColumnSQL($tableName, $columnName, $comment)
{
$comment = $comment === null ? 'NULL' : "'$comment'";
return "COMMENT ON COLUMN $tableName.$columnName IS $comment";
}
/**
* {@inheritdoc}
*/
public function getConcatExpression()
{
return 'STRING(' . join(', ', (array) func_get_args()) . ')';
}
/**
* {@inheritdoc}
*/
public function getCreateConstraintSQL(Constraint $constraint, $table)
{
if ($constraint instanceof ForeignKeyConstraint) {
return $this->getCreateForeignKeySQL($constraint, $table);
}
if ($table instanceof Table) {
$table = $table->getQuotedName($this);
}
/** @var string $table */
$query = 'ALTER TABLE ' . $table . ' ADD ';
if ($constraint instanceof Index) {
if ($constraint->isPrimary()) {
$query .= $this->getPrimaryKeyDeclarationSQL($constraint, $constraint->getQuotedName($this));
} elseif ($constraint->isUnique()) {
$query .= $this->getUniqueConstraintDeclarationSQL($constraint->getQuotedName($this), $constraint);
} else {
throw new \InvalidArgumentException(
'Can only create primary or unique constraints, no common indexes with getCreateConstraintSQL().'
);
}
} else {
throw new \InvalidArgumentException('Unsupported constraint type: ' . get_class($constraint));
}
return $query;
}
/**
* {@inheritdoc}
*/
public function getCreateDatabaseSQL($database)
{
return "CREATE DATABASE '$database'";
}
/**
* {@inheritdoc}
*
* Appends SQL Anywhere specific flags if given.
*/
public function getCreateIndexSQL(Index $index, $table)
{
return parent::getCreateIndexSQL($index, $table). $this->getAdvancedIndexOptionsSQL($index);
}
/**
* {@inheritdoc}
*/
public function getCreatePrimaryKeySQL(Index $index, $table)
{
if ($table instanceof Table) {
$table = $table->getQuotedName($this);
}
/** @var string $table */
return 'ALTER TABLE ' . $table . ' ADD ' . $this->getPrimaryKeyDeclarationSQL($index);
}
/**
* {@inheritdoc}
*/
public function getCreateTemporaryTableSnippetSQL()
{
return 'CREATE ' . $this->getTemporaryTableSQL() . ' TABLE';
}
/**
* {@inheritdoc}
*/
public function getCreateViewSQL($name, $sql)
{
return 'CREATE VIEW ' . $name . ' AS ' . $sql;
}
/**
* {@inheritdoc}
*/
public function getCurrentDateSQL()
{
return 'CURRENT DATE';
}
/**
* {@inheritdoc}
*/
public function getCurrentTimeSQL()
{
return 'CURRENT TIME';
}
/**
* {@inheritdoc}
*/
public function getCurrentTimestampSQL()
{
return 'CURRENT TIMESTAMP';
}
/**
* {@inheritdoc}
*/
public function getDateAddDaysExpression($date, $days)
{
return 'DATEADD(day, ' . $days . ', ' . $date . ')';
}
/**
* {@inheritdoc}
*/
public function getDateAddMonthExpression($date, $months)
{
return 'DATEADD(month, ' . $months . ', ' . $date . ')';
}
/**
* {@inheritdoc}
*/
public function getDateDiffExpression($date1, $date2)
{
return 'DATEDIFF(day, ' . $date2 . ', ' . $date1 . ')';
}
/**
* {@inheritdoc}
*/
public function getDateSubDaysExpression($date, $days)
{
return 'DATEADD(day, -1 * ' . $days . ', ' . $date . ')';
}
/**
* {@inheritdoc}
*/
public function getDateSubMonthExpression($date, $months)
{
return 'DATEADD(month, -1 * ' . $months . ', ' . $date . ')';
}
/**
* {@inheritdoc}
*/
public function getDateTimeFormatString()
{
return 'Y-m-d H:i:s.u';
}
/**
* {@inheritdoc}
*/
public function getDateTimeTypeDeclarationSQL(array $fieldDeclaration)
{
return 'DATETIME';
}
/**
* {@inheritdoc}
*/
public function getDateTypeDeclarationSQL(array $fieldDeclaration)
{
return 'DATE';
}
/**
* {@inheritdoc}
*/
public function getDefaultTransactionIsolationLevel()
{
return Connection::TRANSACTION_READ_UNCOMMITTED;
}
/**
* {@inheritdoc}
*/
public function getDropDatabaseSQL($database)
{
return "DROP DATABASE '$database'";
}
/**
* {@inheritdoc}
*/
public function getDropIndexSQL($index, $table = null)
{
if ($index instanceof Index) {
$index = $index->getQuotedName($this);
} elseif ( ! is_string($index)) {
throw new \InvalidArgumentException(
'SQLAnywherePlatform::getDropIndexSQL() expects $index parameter to be string or ' .
'\Doctrine\DBAL\Schema\Index.'
);
}
if ( ! isset($table)) {
return 'DROP INDEX ' . $index;
}
if ($table instanceof Table) {
$table = $table->getQuotedName($this);
} elseif ( ! is_string($table)) {
throw new \InvalidArgumentException(
'SQLAnywherePlatform::getDropIndexSQL() expects $table parameter to be string or ' .
'\Doctrine\DBAL\Schema\Table.'
);
}
return 'DROP INDEX ' . $table . '.' . $index;
}
/**
* {@inheritdoc}
*/
public function getDropViewSQL($name)
{
return 'DROP VIEW ' . $name;
}
/**
* {@inheritdoc}
*/
public function getForeignKeyBaseDeclarationSQL(ForeignKeyConstraint $foreignKey)
{
$sql = '';
$foreignKeyName = $foreignKey->getName();
$localColumns = $foreignKey->getLocalColumns();
$foreignColumns = $foreignKey->getForeignColumns();
$foreignTableName = $foreignKey->getForeignTableName();
if ( ! empty($foreignKeyName)) {
$sql .= 'CONSTRAINT ' . $foreignKey->getQuotedName($this) . ' ';
}
if (empty($localColumns)) {
throw new \InvalidArgumentException("Incomplete definition. 'local' required.");
}
if (empty($foreignColumns)) {
throw new \InvalidArgumentException("Incomplete definition. 'foreign' required.");
}
if (empty($foreignTableName)) {
throw new \InvalidArgumentException("Incomplete definition. 'foreignTable' required.");
}
if ($foreignKey->hasOption('notnull') && (boolean) $foreignKey->getOption('notnull')) {
$sql .= 'NOT NULL ';
}
return $sql .
'FOREIGN KEY (' . $this->getIndexFieldDeclarationListSQL($localColumns) . ') ' .
'REFERENCES ' . $foreignKey->getQuotedForeignTableName($this) .
' (' . $this->getIndexFieldDeclarationListSQL($foreignColumns) . ')';
}
/**
* Returns foreign key MATCH clause for given type.
*
* @param integer $type The foreign key match type
*
* @return string
*
* @throws \InvalidArgumentException if unknown match type given
*/
public function getForeignKeyMatchClauseSQL($type)
{
switch ((int) $type) {
case self::FOREIGN_KEY_MATCH_SIMPLE:
return 'SIMPLE';
break;
case self::FOREIGN_KEY_MATCH_FULL:
return 'FULL';
break;
case self::FOREIGN_KEY_MATCH_SIMPLE_UNIQUE:
return 'UNIQUE SIMPLE';
break;
case self::FOREIGN_KEY_MATCH_FULL_UNIQUE:
return 'UNIQUE FULL';
default:
throw new \InvalidArgumentException('Invalid foreign key match type: ' . $type);
}
}
/**
* {@inheritdoc}
*/
public function getForeignKeyReferentialActionSQL($action)
{
$action = strtoupper($action);
switch ($action) {
case 'CASCADE':
case 'SET NULL':
case 'SET DEFAULT':
case 'RESTRICT':
return $action;
default:
throw new \InvalidArgumentException('Invalid foreign key action: ' . $action);
}
}
/**
* {@inheritdoc}
*/
public function getForUpdateSQL()
{
return 'FOR UPDATE BY LOCK';
}
/**
* {@inheritdoc}
*/
public function getGuidExpression()
{
return 'NEWID()';
}
/**
* {@inheritdoc}
*/
public function getGuidTypeDeclarationSQL(array $field)
{
return 'UNIQUEIDENTIFIER';
}
/**
* {@inheritdoc}
*/
public function getIndexDeclarationSQL($name, Index $index)
{
/**
* Index declaration in statements like CREATE TABLE is not supported
*/
throw DBALException::notSupported(__METHOD__);
}
/**
* {@inheritdoc}
*/
public function getIntegerTypeDeclarationSQL(array $columnDef)
{
$columnDef['integer_type'] = 'INT';
return $this->_getCommonIntegerTypeDeclarationSQL($columnDef);
}
/**
* {@inheritdoc}
*/
public function getListDatabasesSQL()
{
return 'SELECT db_name(number) AS name FROM sa_db_list()';
}
/**
* {@inheritdoc}
*/
public function getListTableColumnsSQL($table, $database = null)
{
return "SELECT col.column_name,
COALESCE(def.user_type_name, def.domain_name) AS 'type',
def.declared_width AS 'length',
def.scale,
CHARINDEX('unsigned', def.domain_name) AS 'unsigned',
IF col.nulls = 'Y' THEN 0 ELSE 1 ENDIF AS 'notnull',
col.\"default\",
def.is_autoincrement AS 'autoincrement',
rem.remarks AS 'comment'
FROM sa_describe_query('SELECT * FROM \"$table\"') AS def
JOIN SYS.SYSTABCOL AS col
ON col.table_id = def.base_table_id AND col.column_id = def.base_column_id
LEFT JOIN SYS.SYSREMARK AS rem
ON col.object_id = rem.object_id
ORDER BY def.base_column_id ASC";
}
/**
* {@inheritdoc}
*
* @todo Where is this used? Which information should be retrieved?
*/
public function getListTableConstraintsSQL($table)
{
return "SELECT con.*
FROM SYS.SYSCONSTRAINT AS con
JOIN SYS.SYSTABLE AS tab ON con.table_object_id = tab.object_id
WHERE tab.table_name = '$table'";
}
/**
* {@inheritdoc}
*/
public function getListTableForeignKeysSQL($table)
{
return "SELECT fcol.column_name AS local_column,
ptbl.table_name AS foreign_table,
pcol.column_name AS foreign_column,
idx.index_name,
IF fk.nulls = 'N'
THEN 1
ELSE NULL
ENDIF AS notnull,
CASE ut.referential_action
WHEN 'C' THEN 'CASCADE'
WHEN 'D' THEN 'SET DEFAULT'
WHEN 'N' THEN 'SET NULL'
WHEN 'R' THEN 'RESTRICT'
ELSE NULL
END AS on_update,
CASE dt.referential_action
WHEN 'C' THEN 'CASCADE'
WHEN 'D' THEN 'SET DEFAULT'
WHEN 'N' THEN 'SET NULL'
WHEN 'R' THEN 'RESTRICT'
ELSE NULL
END AS on_delete,
IF fk.check_on_commit = 'Y'
THEN 1
ELSE NULL
ENDIF AS check_on_commit, -- check_on_commit flag
IF ftbl.clustered_index_id = idx.index_id
THEN 1
ELSE NULL
ENDIF AS 'clustered', -- clustered flag
IF fk.match_type = 0
THEN NULL
ELSE fk.match_type
ENDIF AS 'match', -- match option
IF pidx.max_key_distance = 1
THEN 1
ELSE NULL
ENDIF AS for_olap_workload -- for_olap_workload flag
FROM SYS.SYSFKEY AS fk
JOIN SYS.SYSIDX AS idx
ON fk.foreign_table_id = idx.table_id
AND fk.foreign_index_id = idx.index_id
JOIN SYS.SYSPHYSIDX pidx
ON idx.table_id = pidx.table_id
AND idx.phys_index_id = pidx.phys_index_id
JOIN SYS.SYSTAB AS ptbl
ON fk.primary_table_id = ptbl.table_id
JOIN SYS.SYSTAB AS ftbl
ON fk.foreign_table_id = ftbl.table_id
JOIN SYS.SYSIDXCOL AS idxcol
ON idx.table_id = idxcol.table_id
AND idx.index_id = idxcol.index_id
JOIN SYS.SYSTABCOL AS pcol
ON ptbl.table_id = pcol.table_id
AND idxcol.primary_column_id = pcol.column_id
JOIN SYS.SYSTABCOL AS fcol
ON ftbl.table_id = fcol.table_id
AND idxcol.column_id = fcol.column_id
LEFT JOIN SYS.SYSTRIGGER ut
ON fk.foreign_table_id = ut.foreign_table_id
AND fk.foreign_index_id = ut.foreign_key_id
AND ut.event = 'C'
LEFT JOIN SYS.SYSTRIGGER dt
ON fk.foreign_table_id = dt.foreign_table_id
AND fk.foreign_index_id = dt.foreign_key_id
AND dt.event = 'D'
WHERE ftbl.table_name = '$table'
ORDER BY fk.foreign_index_id ASC, idxcol.sequence ASC";
}
/**
* {@inheritdoc}
*/
public function getListTableIndexesSQL($table, $currentDatabase = null)
{
return "SELECT idx.index_name AS key_name,
IF idx.index_category = 1
THEN 1
ELSE 0
ENDIF AS 'primary',
col.column_name,
IF idx.\"unique\" IN(1, 2, 5)
THEN 0
ELSE 1
ENDIF AS non_unique,
IF tbl.clustered_index_id = idx.index_id
THEN 1
ELSE NULL
ENDIF AS 'clustered', -- clustered flag
IF idx.\"unique\" = 5
THEN 1
ELSE NULL
ENDIF AS with_nulls_not_distinct, -- with_nulls_not_distinct flag
IF pidx.max_key_distance = 1
THEN 1
ELSE NULL
ENDIF AS for_olap_workload -- for_olap_workload flag
FROM SYS.SYSIDX AS idx
JOIN SYS.SYSPHYSIDX pidx
ON idx.table_id = pidx.table_id
AND idx.phys_index_id = pidx.phys_index_id
JOIN SYS.SYSIDXCOL AS idxcol
ON idx.table_id = idxcol.table_id AND idx.index_id = idxcol.index_id
JOIN SYS.SYSTABCOL AS col
ON idxcol.table_id = col.table_id AND idxcol.column_id = col.column_id
JOIN SYS.SYSTAB AS tbl
ON idx.table_id = tbl.table_id
WHERE tbl.table_name = '$table'
ORDER BY idx.index_id ASC, idxcol.sequence ASC";
}
/**
* {@inheritdoc}
*/
public function getListTablesSQL()
{
return "SELECT tbl.table_name
FROM SYS.SYSTAB AS tbl
JOIN SYS.SYSUSER AS usr ON tbl.creator = usr.user_id
JOIN dbo.SYSOBJECTS AS obj ON tbl.object_id = obj.id
WHERE tbl.table_type IN(1, 3) -- 'BASE', 'GBL TEMP'
AND usr.user_name NOT IN('SYS', 'dbo', 'rs_systabgroup') -- exclude system users
AND obj.type = 'U' -- user created tables only
ORDER BY tbl.table_name ASC";
}
/**
* {@inheritdoc}
*
* @todo Where is this used? Which information should be retrieved?
*/
public function getListUsersSQL()
{
return 'SELECT * FROM SYS.SYSUSER ORDER BY user_name ASC';
}
/**
* {@inheritdoc}
*/
public function getListViewsSQL($database)
{
return "SELECT tbl.table_name, v.view_def
FROM SYS.SYSVIEW v
JOIN SYS.SYSTAB tbl ON v.view_object_id = tbl.object_id
JOIN SYS.SYSUSER usr ON tbl.creator = usr.user_id
JOIN dbo.SYSOBJECTS obj ON tbl.object_id = obj.id
WHERE usr.user_name NOT IN('SYS', 'dbo', 'rs_systabgroup') -- exclude system users
ORDER BY tbl.table_name ASC";
}
/**
* {@inheritdoc}
*/
public function getLocateExpression($str, $substr, $startPos = false)
{
if ($startPos == false) {
return 'CHARINDEX(' . $substr . ', ' . $str . ')';
}
return 'CHARINDEX(' . $substr . ', SUBSTR(' . $str . ', ' . ($startPos + 1) . '))';
}
/**
* {@inheritdoc}
*/
public function getMaxIdentifierLength()
{
return 128;
}
/**
* {@inheritdoc}
*/
public function getMd5Expression($column)
{
return "HASH(" . $column . ", 'MD5')";
}
/**
* {@inheritdoc}
*/
public function getName()
{
return 'sqlanywhere';
}
/**
* Obtain DBMS specific SQL code portion needed to set a primary key
* declaration to be used in statements like ALTER TABLE.
*
* @param Index $index Index definition
* @param string $name Name of the primary key
*
* @return string DBMS specific SQL code portion needed to set a primary key
*
* @throws \InvalidArgumentException
*/
public function getPrimaryKeyDeclarationSQL(Index $index, $name = null)
{
$indexColumns = $index->getColumns();
if (empty($indexColumns)) {
throw new \InvalidArgumentException("Incomplete definition. 'columns' required.");
}
$sql = '';
$flags = '';
if ( ! empty($name)) {
$sql .= 'CONSTRAINT ' . $name . ' ';
}
if ($index->hasFlag('clustered')) {
$flags = 'CLUSTERED ';
}
return $sql . 'PRIMARY KEY ' . $flags . '('. $this->getIndexFieldDeclarationListSQL($indexColumns) . ')';
}
/**
* {@inheritdoc}
*/
public function getSetTransactionIsolationSQL($level)
{
return 'SET TEMPORARY OPTION isolation_level = ' . $this->_getTransactionIsolationLevelSQL($level);
}
/**
* {@inheritdoc}
*/
public function getSmallIntTypeDeclarationSQL(array $columnDef)
{
$columnDef['integer_type'] = 'SMALLINT';
return $this->_getCommonIntegerTypeDeclarationSQL($columnDef);
}
/**
* Returns the SQL statement for starting an existing database.
*
* In SQL Anywhere you can start and stop databases on a
* database server instance.
* This is a required statement after having created a new database
* as it has to be explicitly started to be usable.
* SQL Anywhere does not automatically start a database after creation!
*
* @param string $database Name of the database to start.
*
* @return string
*/
public function getStartDatabaseSQL($database)
{
return "START DATABASE '$database' AUTOSTOP OFF";
}
/**
* Returns the SQL statement for stopping a running database.
*
* In SQL Anywhere you can start and stop databases on a
* database server instance.
* This is a required statement before dropping an existing database
* as it has to be explicitly stopped before it can be dropped.
*
* @param string $database Name of the database to stop.
*
* @return string
*/
public function getStopDatabaseSQL($database)
{
return 'STOP DATABASE "' . $database . '" UNCONDITIONALLY';
}
/**
* {@inheritdoc}
*/
public function getSubstringExpression($value, $from, $length = null)
{
if ($length === null) {
return 'SUBSTRING(' . $value . ', ' . $from . ')';
}
return 'SUBSTRING(' . $value . ', ' . $from . ', ' . $length . ')';
}
/**
* {@inheritdoc}
*/
public function getTemporaryTableSQL()
{
return 'GLOBAL TEMPORARY';
}
/**
* {@inheritdoc}
*/
public function getTimeFormatString()
{
return 'H:i:s.u';
}
/**
* {@inheritdoc}
*/
public function getTimeTypeDeclarationSQL(array $fieldDeclaration)
{
return 'TIME';
}
/**
* {@inheritdoc}
*/
public function getTrimExpression($str, $pos = self::TRIM_UNSPECIFIED, $char = false)
{
if ( ! $char) {
switch ($pos) {
case self::TRIM_LEADING:
return $this->getLtrimExpression($str);
case self::TRIM_TRAILING:
return $this->getRtrimExpression($str);
default:
return 'TRIM(' . $str . ')';
}
}
$pattern = "'%[^$char]%'";
switch ($pos) {
case self::TRIM_LEADING:
return 'SUBSTR(' . $str . ', PATINDEX(' . $pattern . ', ' . $str . '))';
case self::TRIM_TRAILING:
return 'REVERSE(SUBSTR(REVERSE(' . $str . '), PATINDEX(' . $pattern . ', REVERSE(' . $str . '))))';
default:
return
'REVERSE(SUBSTR(REVERSE(SUBSTR(' . $str . ', PATINDEX(' . $pattern . ', ' . $str . '))), ' .
'PATINDEX(' . $pattern . ', REVERSE(SUBSTR(' . $str . ', PATINDEX(' . $pattern . ', ' . $str . '))))))';
}
}
/**
* {@inheritdoc}
*/
public function getTruncateTableSQL($tableName, $cascade = false)
{
return 'TRUNCATE TABLE ' . $tableName;
}
/**
* {@inheritdoc}
*/
public function getUniqueConstraintDeclarationSQL($name, Index $index)
{
$indexColumns = $index->getColumns();
if (empty($indexColumns)) {
throw new \InvalidArgumentException("Incomplete definition. 'columns' required.");
}
$sql = '';
$flags = '';
if ( ! empty($name)) {
$sql .= 'CONSTRAINT ' . $name . ' ';
}
if ($index->hasFlag('clustered')) {
$flags = 'CLUSTERED ';
}
return $sql . $this->getUniqueFieldDeclarationSQL() . ' ' . $flags .
'(' . $this->getIndexFieldDeclarationListSQL($indexColumns) . ')';
}
/**
* {@inheritdoc}
*/
public function getVarcharDefaultLength()
{
return 1;
}
/**
* {@inheritdoc}
*/
public function getVarcharMaxLength()
{
return 32767;
}
/**
* {@inheritdoc}
*/
public function hasNativeGuidType()
{
return true;
}
/**
* {@inheritdoc}
*/
public function prefersIdentityColumns()
{
return true;
}
/**
* {@inheritdoc}
*/
public function supportsCommentOnStatement()
{
return true;
}
/**
* {@inheritdoc}
*/
public function supportsIdentityColumns()
{
return true;
}
/**
* {@inheritdoc}
*/
public function supportsSchemas()
{
return true;
}
/**
* {@inheritdoc}
*/
protected function _getCommonIntegerTypeDeclarationSQL(array $columnDef)
{
$unsigned = ! empty($columnDef['unsigned']) ? 'UNSIGNED ' : '';
$autoincrement = ! empty($columnDef['autoincrement']) ? ' IDENTITY' : '';
return $unsigned . $columnDef['integer_type'] . $autoincrement;
}
/**
* {@inheritdoc}
*/
protected function _getCreateTableSQL($tableName, array $columns, array $options = array())
{
$columnListSql = $this->getColumnDeclarationListSQL($columns);
$indexSql = array();
if ( ! empty($options['uniqueConstraints'])) {
foreach ((array) $options['uniqueConstraints'] as $name => $definition) {
$columnListSql .= ', ' . $this->getUniqueConstraintDeclarationSQL($name, $definition);
}
}
if ( ! empty($options['indexes'])) {
/** @var \Doctrine\DBAL\Schema\Index $index */
foreach ((array) $options['indexes'] as $name => $index) {
if ($index->isUnique()) {
$columnListSql .= ', ' . $this->getUniqueConstraintDeclarationSQL($name, $index);
} else {
$indexSql[] = $this->getCreateIndexSQL($index, $tableName);
}
}
}
if ( ! empty($options['primary'])) {
$flags = '';
if (isset($options['primary_index']) && $options['primary_index']->hasFlag('clustered')) {
$flags = ' CLUSTERED ';
}
$columnListSql .= ', PRIMARY KEY' . $flags . ' (' . implode(', ', array_unique(array_values((array) $options['primary']))) . ')';
}
if ( ! empty($options['foreignKeys'])) {
foreach ((array) $options['foreignKeys'] as $definition) {
$columnListSql .= ', ' . $this->getForeignKeyDeclarationSQL($definition);
}
}
$query = 'CREATE TABLE ' . $tableName . ' (' . $columnListSql;
$check = $this->getCheckDeclarationSQL($columns);
if ( ! empty($check)) {
$query .= ', ' . $check;
}
$query .= ')';
return array_merge(array($query), $indexSql);
}
/**
* {@inheritdoc}
*/
protected function _getTransactionIsolationLevelSQL($level)
{
switch ($level) {
case Connection::TRANSACTION_READ_UNCOMMITTED:
return 0;
case Connection::TRANSACTION_READ_COMMITTED:
return 1;
case Connection::TRANSACTION_REPEATABLE_READ:
return 2;
case Connection::TRANSACTION_SERIALIZABLE:
return 3;
default:
throw new \InvalidArgumentException('Invalid isolation level:' . $level);
}
}
/**
* {@inheritdoc}
*/
protected function doModifyLimitQuery($query, $limit, $offset)
{
$limitOffsetClause = '';
if ($limit > 0) {
$limitOffsetClause = 'TOP ' . $limit . ' ';
}
if ($offset > 0) {
if ($limit == 0) {
$limitOffsetClause = 'TOP ALL ';
}
$limitOffsetClause .= 'START AT ' . ($offset + 1) . ' ';
}
if ($limitOffsetClause) {
$query = preg_replace('/^\s*(SELECT\s+(DISTINCT\s+)?)/i', '\1' . $limitOffsetClause, $query);
}
return $query;
}
/**
* Return the INDEX query section dealing with non-standard
* SQL Anywhere options.
*
* @param Index $index Index definition
*
* @return string
*/
protected function getAdvancedIndexOptionsSQL(Index $index)
{
$sql = '';
if ( ! $index->isPrimary() && $index->hasFlag('for_olap_workload')) {
$sql .= ' FOR OLAP WORKLOAD';
}
return $sql;
}
/**
* {@inheritdoc}
*/
protected function getCreateIndexSQLFlags(Index $index)
{
$type = '';
if ($index->hasFlag('virtual')) {
$type .= 'VIRTUAL ';
}
if ($index->isUnique()) {
$type .= 'UNIQUE ';
}
if ($index->hasFlag('clustered')) {
$type .= 'CLUSTERED ';
}
return $type;
}
/**
* {@inheritdoc}
*/
protected function getReservedKeywordsClass()
{
return 'Doctrine\DBAL\Platforms\Keywords\SQLAnywhereKeywords';
}
/**
* {@inheritdoc}
*/
protected function getVarcharTypeDeclarationSQLSnippet($length, $fixed)
{
return $fixed
? ($length ? 'CHAR(' . $length . ')' : 'CHAR(' . $this->getVarcharDefaultLength() . ')')
: ($length ? 'VARCHAR(' . $length . ')' : 'VARCHAR(' . $this->getVarcharDefaultLength() . ')');
}
/**
* {@inheritdoc}
*/
protected function initializeDoctrineTypeMappings()
{
$this->doctrineTypeMapping = array(
'char' => 'string',
'long nvarchar' => 'text',
'long varchar' => 'text',
'nchar' => 'string',
'ntext' => 'text',
'nvarchar' => 'string',
'text' => 'text',
'uniqueidentifierstr' => 'guid',
'varchar' => 'string',
'xml' => 'text',
'bigint' => 'bigint',
'unsigned bigint' => 'bigint',
'bit' => 'boolean',
'decimal' => 'decimal',
'double' => 'float',
'float' => 'float',
'int' => 'integer',
'unsigned int' => 'integer',
'numeric' => 'decimal',
'smallint' => 'smallint',
'unsigned smallint', 'smallint',
'tinyint' => 'smallint',
'unsigned tinyint', 'smallint',
'money' => 'decimal',
'smallmoney' => 'decimal',
'long varbit' => 'text',
'varbit' => 'string',
'date' => 'date',
'datetime' => 'datetime',
'smalldatetime' => 'datetime',
'time' => 'time',
'timestamp' => 'datetime',
'binary' => 'blob',
'image' => 'blob',
'long binary' => 'blob',
'uniqueidentifier' => 'guid',
'varbinary' => 'blob',
);
}
}
...@@ -42,6 +42,7 @@ class Connection extends \Doctrine\DBAL\Connection ...@@ -42,6 +42,7 @@ class Connection extends \Doctrine\DBAL\Connection
const PORTABILITY_SQLITE = 13; const PORTABILITY_SQLITE = 13;
const PORTABILITY_OTHERVENDORS = 12; const PORTABILITY_OTHERVENDORS = 12;
const PORTABILITY_DRIZZLE = 13; const PORTABILITY_DRIZZLE = 13;
const PORTABILITY_SQLANYWHERE = 13;
const PORTABILITY_SQLSRV = 13; const PORTABILITY_SQLSRV = 13;
/** /**
...@@ -71,6 +72,8 @@ class Connection extends \Doctrine\DBAL\Connection ...@@ -71,6 +72,8 @@ class Connection extends \Doctrine\DBAL\Connection
$params['portability'] = $params['portability'] & self::PORTABILITY_SQLITE; $params['portability'] = $params['portability'] & self::PORTABILITY_SQLITE;
} else if ($this->_platform->getName() === "drizzle") { } else if ($this->_platform->getName() === "drizzle") {
$params['portability'] = self::PORTABILITY_DRIZZLE; $params['portability'] = self::PORTABILITY_DRIZZLE;
} else if ($this->_platform->getName() === 'sqlanywhere') {
$params['portability'] = self::PORTABILITY_SQLANYWHERE;
} else if ($this->_platform->getName() === 'sqlsrv') { } else if ($this->_platform->getName() === 'sqlsrv') {
$params['portability'] = $params['portabililty'] & self::PORTABILITY_SQLSRV; $params['portability'] = $params['portabililty'] & self::PORTABILITY_SQLSRV;
} else { } else {
......
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\DBAL\Schema;
use Doctrine\DBAL\Driver\SQLAnywhere\SQLAnywhereException;
use Doctrine\DBAL\Schema\AbstractSchemaManager;
use Doctrine\DBAL\Schema\Column;
use Doctrine\DBAL\Schema\ForeignKeyConstraint;
use Doctrine\DBAL\Schema\Sequence;
use Doctrine\DBAL\Schema\View;
use Doctrine\DBAL\Types\Type;
/**
* SAP Sybase SQL Anywhere schema manager.
*
* @author Steve Müller <st.mueller@dzh-online.de>
* @link www.doctrine-project.org
* @since 2.5
*/
class SQLAnywhereSchemaManager extends AbstractSchemaManager
{
/**
* Holds instance of the database platform used for this schema manager
*
* @var \Doctrine\DBAL\Platforms\SQLAnywherePlatform $_platform
*/
protected $_platform;
/**
* {@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.
*/
public function startDatabase($database)
{
$this->_execSql($this->_platform->getStartDatabaseSQL($database));
}
/**
* Stops a database.
*
* @param string $database The name of the database to stop.
*/
public function stopDatabase($database)
{
$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']) {
/**
* Strip quotes from default value
*/
$default = preg_replace(array("/^'(.*)'$/", "/''/"), array("$1", "'"), $tableColumn['default']);
}
switch ($tableColumn['type']) {
case 'binary':
case 'char':
case 'nchar':
$fixed = true;
}
switch ($type) {
case 'decimal':
case 'float':
$precision = $tableColumn['length'];
$scale = $tableColumn['scale'];
}
return new Column(
$tableColumn['column_name'],
Type::getType($type),
array(
'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' => $tableColumn['comment']
));
}
/**
* {@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 = array();
foreach ($tableForeignKeys as $tableForeignKey) {
if (!isset($foreignKeys[$tableForeignKey['index_name']])) {
$foreignKeys[$tableForeignKey['index_name']] = array(
'local_columns' => array($tableForeignKey['local_column']),
'foreign_table' => $tableForeignKey['foreign_table'],
'foreign_columns' => array($tableForeignKey['foreign_column']),
'name' => $tableForeignKey['index_name'],
'options' => array(
'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'] = (boolean) $tableIndex['primary'];
$tableIndex['flags'] = array();
if ($tableIndex['clustered']) {
$tableIndex['flags'][] = 'clustered';
}
if ($tableIndex['with_nulls_not_distinct']) {
$tableIndex['flags'][] = 'with_nulls_not_distinct';
}
if ($tableIndex['for_olap_workload']) {
$tableIndex['flags'][] = 'for_olap_workload';
}
}
return parent::_getPortableTableIndexesList($tableIndexRows, $tableName);
}
/**
* {@inheritdoc}
*/
protected function _getPortableViewDefinition($view)
{
return new View(
$view['table_name'],
preg_replace('/^.*\s+as\s+SELECT(.*)/i', "SELECT$1", $view['view_def'])
);
}
}
...@@ -41,6 +41,9 @@ class ReservedWordsCommand extends Command ...@@ -41,6 +41,9 @@ class ReservedWordsCommand extends Command
'pgsql' => 'Doctrine\DBAL\Platforms\Keywords\PostgreSQLKeywords', 'pgsql' => 'Doctrine\DBAL\Platforms\Keywords\PostgreSQLKeywords',
'oracle' => 'Doctrine\DBAL\Platforms\Keywords\OracleKeywords', 'oracle' => 'Doctrine\DBAL\Platforms\Keywords\OracleKeywords',
'db2' => 'Doctrine\DBAL\Platforms\Keywords\DB2Keywords', 'db2' => 'Doctrine\DBAL\Platforms\Keywords\DB2Keywords',
'sqlanywhere' => 'Doctrine\DBAL\Platforms\Keywords\SQLAnywhereKeywords',
'sqlanywhere11' => 'Doctrine\DBAL\Platforms\Keywords\SQLAnywhere11Keywords',
'sqlanywhere12' => 'Doctrine\DBAL\Platforms\Keywords\SQLAnywhere12Keywords'
); );
/** /**
...@@ -73,8 +76,8 @@ class ReservedWordsCommand extends Command ...@@ -73,8 +76,8 @@ class ReservedWordsCommand extends Command
Checks if the current database contains tables and columns Checks if the current database contains tables and columns
with names that are identifiers in this dialect or in other SQL dialects. with names that are identifiers in this dialect or in other SQL dialects.
By default SQLite, MySQL, PostgreSQL, Microsoft SQL Server and Oracle By default SQLite, MySQL, PostgreSQL, Microsoft SQL Server, Oracle
keywords are checked: and SQL Anywhere keywords are checked:
<info>%command.full_name%</info> <info>%command.full_name%</info>
...@@ -93,6 +96,9 @@ The following keyword lists are currently shipped with Doctrine: ...@@ -93,6 +96,9 @@ The following keyword lists are currently shipped with Doctrine:
* sqlserver2005 * sqlserver2005
* sqlserver2008 * sqlserver2008
* sqlserver2012 * sqlserver2012
* sqlanywhere
* sqlanywhere11
* sqlanywhere12
* db2 (Not checked by default) * db2 (Not checked by default)
EOT EOT
); );
...@@ -116,7 +122,10 @@ EOT ...@@ -116,7 +122,10 @@ EOT
'sqlserver', 'sqlserver',
'sqlserver2005', 'sqlserver2005',
'sqlserver2008', 'sqlserver2008',
'sqlserver2012' 'sqlserver2012',
'sqlanywhere',
'sqlanywhere11',
'sqlanywhere12'
); );
} }
......
...@@ -4,18 +4,19 @@ ...@@ -4,18 +4,19 @@
# Just create the phpunit.xmls as described in the array below and configure the specific files <php /> section # Just create the phpunit.xmls as described in the array below and configure the specific files <php /> section
# to connect to that database. Just omit a file if you dont have that database and the tests will be skipped. # to connect to that database. Just omit a file if you dont have that database and the tests will be skipped.
configs[1]="mysql.phpunit.xml" configs[1]="mysql.phpunit.xml"
configs[2]='postgres.phpunit.xml' configs[2]='postgres.phpunit.xml'
configs[3]='sqlite.phpunit.xml' configs[3]='sqlite.phpunit.xml'
configs[4]='oracle.phpunit.xml' configs[4]='oracle.phpunit.xml'
configs[5]='db2.phpunit.xml' configs[5]='db2.phpunit.xml'
configs[6]='pdo-ibm.phpunit.xml' configs[6]='pdo-ibm.phpunit.xml'
configs[7]='sqlsrv.phpunit.xml' configs[7]='sqlsrv.phpunit.xml'
configs[8]='sqlanywhere.phpunit.xml'
for i in "${configs[@]}"; do for i in "${configs[@]}"; do
if [ -f "$i" ]; if [ -f "$i" ];
then then
echo "RUNNING TESTS WITH CONFIG $i" echo "RUNNING TESTS WITH CONFIG $i"
phpunit -c "$i" "$@" phpunit -c "$i" "$@"
fi; fi;
done done
<?php
namespace Doctrine\Tests\DBAL\Functional\Schema;
use Doctrine\DBAL\Schema\Index;
use Doctrine\DBAL\Schema\Table;
use Doctrine\DBAL\Schema\View;
class SQLAnywhereSchemaManagerTest extends SchemaManagerFunctionalTestCase
{
public function testCreateAndListViews()
{
$this->createTestTable('view_test_table');
$name = "doctrine_test_view";
$sql = "SELECT * from DBA.view_test_table";
$view = new View($name, $sql);
$this->_sm->dropAndCreateView($view);
$views = $this->_sm->listViews();
$this->assertEquals(1, count($views), "Database has to have one view.");
$this->assertInstanceOf('Doctrine\DBAL\Schema\View', $views[$name]);
$this->assertEquals($name, $views[$name]->getName());
$this->assertEquals($sql, $views[$name]->getSql());
}
public function testDropAndCreateAdvancedIndex()
{
$table = $this->getTestTable('test_create_advanced_index');
$this->_sm->dropAndCreateTable($table);
$this->_sm->dropAndCreateIndex(
new Index('test', array('test'), true, false, array('clustered', 'with_nulls_not_distinct', 'for_olap_workload')),
$table->getName()
);
$tableIndexes = $this->_sm->listTableIndexes('test_create_advanced_index');
$this->assertInternalType('array', $tableIndexes);
$this->assertEquals('test', $tableIndexes['test']->getName());
$this->assertEquals(array('test'), $tableIndexes['test']->getColumns());
$this->assertTrue($tableIndexes['test']->isUnique());
$this->assertFalse($tableIndexes['test']->isPrimary());
$this->assertTrue($tableIndexes['test']->hasFlag('clustered'));
$this->assertTrue($tableIndexes['test']->hasFlag('with_nulls_not_distinct'));
$this->assertTrue($tableIndexes['test']->hasFlag('for_olap_workload'));
}
public function testListTableColumnsWithFixedStringTypeColumn()
{
$table = new Table('list_table_columns_char');
$table->addColumn('id', 'integer', array('notnull' => true));
$table->addColumn('test', 'string', array('fixed' => true));
$table->setPrimaryKey(array('id'));
$this->_sm->dropAndCreateTable($table);
$columns = $this->_sm->listTableColumns('list_table_columns_char');
$this->assertArrayHasKey('test', $columns);
$this->assertTrue($columns['test']->getFixed());
}
}
<?php
namespace Doctrine\Tests\DBAL\Platforms;
use Doctrine\DBAL\Platforms\SQLAnywhere11Platform;
class SQLAnywhere11PlatformTest extends SQLAnywherePlatformTest
{
/**
* @var \Doctrine\DBAL\Platforms\SQLAnywhere11Platform
*/
protected $_platform;
public function createPlatform()
{
return new SQLAnywhere11Platform;
}
public function testDoesNotSupportRegexp()
{
$this->markTestSkipped('This version of the platform now supports regular expressions.');
}
public function testGeneratesRegularExpressionSQLSnippet()
{
$this->assertEquals('REGEXP', $this->_platform->getRegexpExpression());
}
}
<?php
namespace Doctrine\Tests\DBAL\Platforms;
use Doctrine\DBAL\Platforms\SQLAnywhere12Platform;
use Doctrine\DBAL\Schema\Index;
use Doctrine\DBAL\Schema\Sequence;
class SQLAnywhere12PlatformTest extends SQLAnywhere11PlatformTest
{
/**
* @var \Doctrine\DBAL\Platforms\SQLAnywhere12Platform
*/
protected $_platform;
public function createPlatform()
{
return new SQLAnywhere12Platform;
}
public function testDoesNotSupportSequences()
{
$this->markTestSkipped('This version of the platform now supports sequences.');
}
public function testSupportsSequences()
{
$this->assertTrue($this->_platform->supportsSequences());
}
public function testGeneratesSequenceSqlCommands()
{
$sequence = new Sequence('myseq', 20, 1);
$this->assertEquals(
'CREATE SEQUENCE myseq INCREMENT BY 20 START WITH 1 MINVALUE 1',
$this->_platform->getCreateSequenceSQL($sequence)
);
$this->assertEquals(
'ALTER SEQUENCE myseq INCREMENT BY 20',
$this->_platform->getAlterSequenceSQL($sequence)
);
$this->assertEquals(
'DROP SEQUENCE myseq',
$this->_platform->getDropSequenceSQL('myseq')
);
$this->assertEquals(
'DROP SEQUENCE myseq',
$this->_platform->getDropSequenceSQL($sequence)
);
$this->assertEquals(
"SELECT myseq.NEXTVAL",
$this->_platform->getSequenceNextValSQL('myseq')
);
$this->assertEquals(
'SELECT sequence_name, increment_by, start_with, min_value FROM SYS.SYSSEQUENCE',
$this->_platform->getListSequencesSQL(null)
);
}
public function testGeneratesDateTimeTzColumnTypeDeclarationSQL()
{
$this->assertEquals(
'TIMESTAMP WITH TIME ZONE',
$this->_platform->getDateTimeTzTypeDeclarationSQL(array(
'length' => 10,
'fixed' => true,
'unsigned' => true,
'autoincrement' => true
))
);
}
public function testHasCorrectDateTimeTzFormatString()
{
$this->assertEquals('Y-m-d H:i:s.uP', $this->_platform->getDateTimeTzFormatString());
}
public function testInitializesDateTimeTzTypeMapping()
{
$this->assertTrue($this->_platform->hasDoctrineTypeMappingFor('timestamp with time zone'));
$this->assertEquals('datetime', $this->_platform->getDoctrineTypeMapping('timestamp with time zone'));
}
public function testGeneratesCreateIndexWithAdvancedPlatformOptionsSQL()
{
$this->assertEquals(
'CREATE VIRTUAL UNIQUE CLUSTERED INDEX fooindex ON footable (a, b) WITH NULLS NOT DISTINCT FOR OLAP WORKLOAD',
$this->_platform->getCreateIndexSQL(
new Index(
'fooindex',
array('a', 'b'),
true,
false,
array('virtual', 'clustered', 'with_nulls_not_distinct', 'for_olap_workload')
),
'footable'
)
);
$this->assertEquals(
'CREATE VIRTUAL CLUSTERED INDEX fooindex ON footable (a, b) FOR OLAP WORKLOAD',
$this->_platform->getCreateIndexSQL(
new Index(
'fooindex',
array('a', 'b'),
false,
false,
array('virtual', 'clustered', 'with_nulls_not_distinct', 'for_olap_workload')
),
'footable'
)
);
}
}
<?php
namespace Doctrine\Tests\DBAL\Platforms;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\LockMode;
use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Platforms\SQLAnywherePlatform;
use Doctrine\DBAL\Schema\Column;
use Doctrine\DBAL\Schema\ColumnDiff;
use Doctrine\DBAL\Schema\ForeignKeyConstraint;
use Doctrine\DBAL\Schema\Index;
use Doctrine\DBAL\Schema\Table;
use Doctrine\DBAL\Schema\TableDiff;
use Doctrine\DBAL\Types\Type;
class SQLAnywherePlatformTest extends AbstractPlatformTestCase
{
/**
* @var \Doctrine\DBAL\Platforms\SQLAnywherePlatform
*/
protected $_platform;
public function createPlatform()
{
return new SQLAnywherePlatform;
}
public function getGenerateAlterTableSql()
{
return array(
"ALTER TABLE mytable ADD quota INT DEFAULT NULL, DROP foo, ALTER baz VARCHAR(1) DEFAULT 'def' NOT NULL, ALTER bloo BIT DEFAULT '0' NOT NULL",
'ALTER TABLE mytable RENAME userlist'
);
}
public function getGenerateForeignKeySql()
{
return 'ALTER TABLE test ADD FOREIGN KEY (fk_name_id) REFERENCES other_table (id)';
}
public function getGenerateIndexSql()
{
return 'CREATE INDEX my_idx ON mytable (user_name, last_login)';
}
public function getGenerateTableSql()
{
return 'CREATE TABLE test (id INT IDENTITY NOT NULL, test VARCHAR(255) DEFAULT NULL, PRIMARY KEY (id))';
}
public function getGenerateTableWithMultiColumnUniqueIndexSql()
{
return array(
'CREATE TABLE test (foo VARCHAR(255) DEFAULT NULL, bar VARCHAR(255) DEFAULT NULL, CONSTRAINT UNIQ_D87F7E0C8C73652176FF8CAA UNIQUE (foo, bar))',
);
}
public function getGenerateUniqueIndexSql()
{
return 'CREATE UNIQUE INDEX index_name ON test (test, test2)';
}
protected function getQuotedColumnInIndexSQL()
{
return array(
'CREATE TABLE "quoted" ("key" VARCHAR(255) NOT NULL)',
'CREATE INDEX IDX_22660D028A90ABA9 ON "quoted" ("key")'
);
}
protected function getQuotedColumnInPrimaryKeySQL()
{
return array(
'CREATE TABLE "quoted" ("key" VARCHAR(255) NOT NULL, PRIMARY KEY ("key"))'
);
}
public function getCreateTableColumnCommentsSQL()
{
return array(
"CREATE TABLE test (id INT NOT NULL, PRIMARY KEY (id))",
"COMMENT ON COLUMN test.id IS 'This is a comment'",
);
}
public function getAlterTableColumnCommentsSQL()
{
return array(
"ALTER TABLE mytable ADD quota INT NOT NULL",
"COMMENT ON COLUMN mytable.quota IS 'A comment'",
"COMMENT ON COLUMN mytable.baz IS 'B comment'",
);
}
public function getCreateTableColumnTypeCommentsSQL()
{
return array(
"CREATE TABLE test (id INT NOT NULL, data TEXT NOT NULL, PRIMARY KEY (id))",
"COMMENT ON COLUMN test.data IS '(DC2Type:array)'"
);
}
public function testHasCorrectPlatformName()
{
$this->assertEquals('sqlanywhere', $this->_platform->getName());
}
public function testGeneratesCreateTableSQLWithCommonIndexes()
{
$table = new Table('test');
$table->addColumn('id', 'integer');
$table->addColumn('name', 'string', array('length' => 50));
$table->setPrimaryKey(array('id'));
$table->addIndex(array('name'));
$table->addIndex(array('id', 'name'), 'composite_idx');
$this->assertEquals(
array(
'CREATE TABLE test (id INT NOT NULL, name VARCHAR(50) NOT NULL, PRIMARY KEY (id))',
'CREATE INDEX IDX_D87F7E0C5E237E06 ON test (name)',
'CREATE INDEX composite_idx ON test (id, name)'
),
$this->_platform->getCreateTableSQL($table)
);
}
public function testGeneratesCreateTableSQLWithForeignKeyConstraints()
{
$table = new Table('test');
$table->addColumn('id', 'integer');
$table->addColumn('fk_1', 'integer');
$table->addColumn('fk_2', 'integer');
$table->setPrimaryKey(array('id'));
$table->addForeignKeyConstraint('foreign_table', array('fk_1', 'fk_2'), array('pk_1', 'pk_2'));
$table->addForeignKeyConstraint(
'foreign_table2',
array('fk_1', 'fk_2'),
array('pk_1', 'pk_2'),
array(),
'named_fk'
);
$this->assertEquals(
array(
'CREATE TABLE test (id INT NOT NULL, fk_1 INT NOT NULL, fk_2 INT NOT NULL, ' .
'CONSTRAINT FK_D87F7E0C177612A38E7F4319 FOREIGN KEY (fk_1, fk_2) REFERENCES foreign_table (pk_1, pk_2), ' .
'CONSTRAINT named_fk FOREIGN KEY (fk_1, fk_2) REFERENCES foreign_table2 (pk_1, pk_2))'
),
$this->_platform->getCreateTableSQL($table, AbstractPlatform::CREATE_FOREIGNKEYS)
);
}
public function testGeneratesCreateTableSQLWithCheckConstraints()
{
$table = new Table('test');
$table->addColumn('id', 'integer');
$table->addColumn('check_max', 'integer', array('platformOptions' => array('max' => 10)));
$table->addColumn('check_min', 'integer', array('platformOptions' => array('min' => 10)));
$table->setPrimaryKey(array('id'));
$this->assertEquals(
array(
'CREATE TABLE test (id INT NOT NULL, check_max INT NOT NULL, check_min INT NOT NULL, PRIMARY KEY (id), CHECK (check_max <= 10), CHECK (check_min >= 10))'
),
$this->_platform->getCreateTableSQL($table)
);
}
public function testGeneratesTableAlterationWithRemovedColumnCommentSql()
{
$table = new Table('mytable');
$table->addColumn('foo', 'string', array('comment' => 'foo comment'));
$tableDiff = new TableDiff('mytable');
$tableDiff->fromTable = $table;
$tableDiff->changedColumns['foo'] = new ColumnDiff(
'foo',
new Column('foo', Type::getType('string')),
array('comment')
);
$this->assertEquals(
array(
"COMMENT ON COLUMN mytable.foo IS NULL"
),
$this->_platform->getAlterTableSQL($tableDiff)
);
}
public function testAppendsLockHints()
{
$fromClause = 'SELECT * FROM lock_hints';
$this->assertEquals(
$fromClause . ' WITH (NOLOCK)',
$this->_platform->appendLockHint($fromClause, LockMode::NONE)
);
$this->assertEquals(
$fromClause . ' WITH (UPDLOCK)',
$this->_platform->appendLockHint($fromClause, LockMode::PESSIMISTIC_READ)
);
$this->assertEquals(
$fromClause . ' WITH (XLOCK)',
$this->_platform->appendLockHint($fromClause, LockMode::PESSIMISTIC_WRITE)
);
}
public function testCannotAppendInvalidLockHint()
{
$this->setExpectedException('\InvalidArgumentException');
$this->_platform->appendLockHint('SELECT * FROM lock_hints', 'invalid_lock_mode');
}
public function testHasCorrectMaxIdentifierLength()
{
$this->assertEquals(128, $this->_platform->getMaxIdentifierLength());
}
public function testFixesSchemaElementNames()
{
$maxIdentifierLength = $this->_platform->getMaxIdentifierLength();
$characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
$schemaElementName = '';
for ($i = 0; $i < $maxIdentifierLength + 100; $i++) {
$schemaElementName .= $characters[mt_rand(0, strlen($characters) - 1)];
}
$fixedSchemaElementName = substr($schemaElementName, 0, $maxIdentifierLength);
$this->assertEquals(
$fixedSchemaElementName,
$this->_platform->fixSchemaElementName($schemaElementName)
);
$this->assertEquals(
$fixedSchemaElementName,
$this->_platform->fixSchemaElementName($fixedSchemaElementName)
);
}
public function testGeneratesColumnTypesDeclarationSQL()
{
$fullColumnDef = array(
'length' => 10,
'fixed' => true,
'unsigned' => true,
'autoincrement' => true
);
$this->assertEquals('SMALLINT', $this->_platform->getSmallIntTypeDeclarationSQL(array()));
$this->assertEquals('UNSIGNED SMALLINT', $this->_platform->getSmallIntTypeDeclarationSQL(array(
'unsigned' => true
)));
$this->assertEquals('UNSIGNED SMALLINT IDENTITY', $this->_platform->getSmallIntTypeDeclarationSQL($fullColumnDef));
$this->assertEquals('INT', $this->_platform->getIntegerTypeDeclarationSQL(array()));
$this->assertEquals('UNSIGNED INT', $this->_platform->getIntegerTypeDeclarationSQL(array(
'unsigned' => true
)));
$this->assertEquals('UNSIGNED INT IDENTITY', $this->_platform->getIntegerTypeDeclarationSQL($fullColumnDef));
$this->assertEquals('BIGINT', $this->_platform->getBigIntTypeDeclarationSQL(array()));
$this->assertEquals('UNSIGNED BIGINT', $this->_platform->getBigIntTypeDeclarationSQL(array(
'unsigned' => true
)));
$this->assertEquals('UNSIGNED BIGINT IDENTITY', $this->_platform->getBigIntTypeDeclarationSQL($fullColumnDef));
$this->assertEquals('LONG BINARY', $this->_platform->getBlobTypeDeclarationSQL($fullColumnDef));
$this->assertEquals('BIT', $this->_platform->getBooleanTypeDeclarationSQL($fullColumnDef));
$this->assertEquals('TEXT', $this->_platform->getClobTypeDeclarationSQL($fullColumnDef));
$this->assertEquals('DATE', $this->_platform->getDateTypeDeclarationSQL($fullColumnDef));
$this->assertEquals('DATETIME', $this->_platform->getDateTimeTypeDeclarationSQL($fullColumnDef));
$this->assertEquals('TIME', $this->_platform->getTimeTypeDeclarationSQL($fullColumnDef));
$this->assertEquals('UNIQUEIDENTIFIER', $this->_platform->getGuidTypeDeclarationSQL($fullColumnDef));
$this->assertEquals(1, $this->_platform->getVarcharDefaultLength());
$this->assertEquals(32767, $this->_platform->getVarcharMaxLength());
}
public function testHasNativeGuidType()
{
$this->assertTrue($this->_platform->hasNativeGuidType());
}
public function testGeneratesDDLSnippets()
{
$this->assertEquals("CREATE DATABASE 'foobar'", $this->_platform->getCreateDatabaseSQL('foobar'));
$this->assertEquals("DROP DATABASE 'foobar'", $this->_platform->getDropDatabaseSQL('foobar'));
$this->assertEquals('CREATE GLOBAL TEMPORARY TABLE', $this->_platform->getCreateTemporaryTableSnippetSQL());
$this->assertEquals("START DATABASE 'foobar' AUTOSTOP OFF", $this->_platform->getStartDatabaseSQL('foobar'));
$this->assertEquals('STOP DATABASE "foobar" UNCONDITIONALLY', $this->_platform->getStopDatabaseSQL('foobar'));
$this->assertEquals('TRUNCATE TABLE foobar', $this->_platform->getTruncateTableSQL('foobar'));
$this->assertEquals('TRUNCATE TABLE foobar', $this->_platform->getTruncateTableSQL('foobar'), true);
$viewSql = 'SELECT * FROM footable';
$this->assertEquals('CREATE VIEW fooview AS ' . $viewSql, $this->_platform->getCreateViewSQL('fooview', $viewSql));
$this->assertEquals('DROP VIEW fooview', $this->_platform->getDropViewSQL('fooview'));
}
public function testGeneratesPrimaryKeyDeclarationSQL()
{
$this->assertEquals(
'CONSTRAINT pk PRIMARY KEY CLUSTERED (a, b)',
$this->_platform->getPrimaryKeyDeclarationSQL(
new Index(null, array('a', 'b'), true, true, array('clustered')),
'pk'
)
);
$this->assertEquals(
'PRIMARY KEY (a, b)',
$this->_platform->getPrimaryKeyDeclarationSQL(
new Index(null, array('a', 'b'), true, true)
)
);
}
public function testCannotGeneratePrimaryKeyDeclarationSQLWithEmptyColumns()
{
$this->setExpectedException('\InvalidArgumentException');
$this->_platform->getPrimaryKeyDeclarationSQL(new Index('pk', array(), true, true));
}
public function testGeneratesCreateUnnamedPrimaryKeySQL()
{
$this->assertEquals(
'ALTER TABLE foo ADD PRIMARY KEY CLUSTERED (a, b)',
$this->_platform->getCreatePrimaryKeySQL(
new Index('pk', array('a', 'b'), true, true, array('clustered')),
'foo'
)
);
$this->assertEquals(
'ALTER TABLE foo ADD PRIMARY KEY (a, b)',
$this->_platform->getCreatePrimaryKeySQL(
new Index('any_pk_name', array('a', 'b'), true, true),
new Table('foo')
)
);
}
public function testGeneratesUniqueConstraintDeclarationSQL()
{
$this->assertEquals(
'CONSTRAINT unique_constraint UNIQUE CLUSTERED (a, b)',
$this->_platform->getUniqueConstraintDeclarationSQL(
'unique_constraint',
new Index(null, array('a', 'b'), true, false, array('clustered'))
)
);
$this->assertEquals(
'UNIQUE (a, b)',
$this->_platform->getUniqueConstraintDeclarationSQL(null, new Index(null, array('a', 'b'), true, false))
);
}
public function testCannotGenerateUniqueConstraintDeclarationSQLWithEmptyColumns()
{
$this->setExpectedException('\InvalidArgumentException');
$this->_platform->getUniqueConstraintDeclarationSQL('constr', new Index('constr', array(), true));
}
public function testGeneratesForeignKeyConstraintsWithAdvancedPlatformOptionsSQL()
{
$this->assertEquals(
'CONSTRAINT fk ' .
'NOT NULL FOREIGN KEY (a, b) ' .
'REFERENCES foreign_table (c, d) ' .
'MATCH UNIQUE SIMPLE ON UPDATE CASCADE ON DELETE SET NULL CHECK ON COMMIT CLUSTERED FOR OLAP WORKLOAD',
$this->_platform->getForeignKeyDeclarationSQL(
new ForeignKeyConstraint(array('a', 'b'), 'foreign_table', array('c', 'd'), 'fk', array(
'notnull' => true,
'match' => SQLAnywherePlatform::FOREIGN_KEY_MATCH_SIMPLE_UNIQUE,
'onUpdate' => 'CASCADE',
'onDelete' => 'SET NULL',
'check_on_commit' => true,
'clustered' => true,
'for_olap_workload' => true
))
)
);
$this->assertEquals(
'FOREIGN KEY (a, b) REFERENCES foreign_table (c, d)',
$this->_platform->getForeignKeyDeclarationSQL(
new ForeignKeyConstraint(array('a', 'b'), 'foreign_table', array('c', 'd'))
)
);
}
public function testGeneratesForeignKeyMatchClausesSQL()
{
$this->assertEquals('SIMPLE', $this->_platform->getForeignKeyMatchClauseSQL(1));
$this->assertEquals('FULL', $this->_platform->getForeignKeyMatchClauseSQL(2));
$this->assertEquals('UNIQUE SIMPLE', $this->_platform->getForeignKeyMatchClauseSQL(129));
$this->assertEquals('UNIQUE FULL', $this->_platform->getForeignKeyMatchClauseSQL(130));
}
public function testCannotGenerateInvalidForeignKeyMatchClauseSQL()
{
$this->setExpectedException('\InvalidArgumentException');
$this->_platform->getForeignKeyMatchCLauseSQL(3);
}
public function testCannotGenerateNoActionForeignKeyReferentialActionClauseSQL()
{
$this->setExpectedException('\InvalidArgumentException');
$this->_platform->getForeignKeyReferentialActionSQL('no action');
}
public function testCannotGenerateForeignKeyConstraintSQLWithEmptyLocalColumns()
{
$this->setExpectedException('\InvalidArgumentException');
$this->_platform->getForeignKeyDeclarationSQL(new ForeignKeyConstraint(array(), 'foreign_tbl', array('c', 'd')));
}
public function testCannotGenerateForeignKeyConstraintSQLWithEmptyForeignColumns()
{
$this->setExpectedException('\InvalidArgumentException');
$this->_platform->getForeignKeyDeclarationSQL(new ForeignKeyConstraint(array('a', 'b'), 'foreign_tbl', array()));
}
public function testCannotGenerateForeignKeyConstraintSQLWithEmptyForeignTableName()
{
$this->setExpectedException('\InvalidArgumentException');
$this->_platform->getForeignKeyDeclarationSQL(new ForeignKeyConstraint(array('a', 'b'), '', array('c', 'd')));
}
public function testCannotGenerateCommonIndexWithCreateConstraintSQL()
{
$this->setExpectedException('\InvalidArgumentException');
$this->_platform->getCreateConstraintSQL(new Index('fooindex', array()), new Table('footable'));
}
public function testCannotGenerateCustomConstraintWithCreateConstraintSQL()
{
$this->setExpectedException('\InvalidArgumentException');
$this->_platform->getCreateConstraintSQL($this->getMock('\Doctrine\DBAL\Schema\Constraint'), 'footable');
}
public function testGeneratesCreateIndexWithAdvancedPlatformOptionsSQL()
{
$this->assertEquals(
'CREATE VIRTUAL UNIQUE CLUSTERED INDEX fooindex ON footable (a, b) FOR OLAP WORKLOAD',
$this->_platform->getCreateIndexSQL(
new Index(
'fooindex',
array('a', 'b'),
true,
false,
array('virtual', 'clustered', 'for_olap_workload')
),
'footable'
)
);
}
public function testDoesNotSupportIndexDeclarationInCreateAlterTableStatements()
{
$this->setExpectedException('\Doctrine\DBAL\DBALException');
$this->_platform->getIndexDeclarationSQL('index', new Index('index', array()));
}
public function testGeneratesDropIndexSQL()
{
$index = new Index('fooindex', array());
$this->assertEquals('DROP INDEX fooindex', $this->_platform->getDropIndexSQL($index));
$this->assertEquals('DROP INDEX footable.fooindex', $this->_platform->getDropIndexSQL($index, 'footable'));
$this->assertEquals('DROP INDEX footable.fooindex', $this->_platform->getDropIndexSQL(
$index,
new Table('footable')
));
}
public function testCannotGenerateDropIndexSQLWithInvalidIndexParameter()
{
$this->setExpectedException('\InvalidArgumentException');
$this->_platform->getDropIndexSQL(array('index'), 'table');
}
public function testCannotGenerateDropIndexSQLWithInvalidTableParameter()
{
$this->setExpectedException('\InvalidArgumentException');
$this->_platform->getDropIndexSQL('index', array('table'));
}
public function testGeneratesSQLSnippets()
{
$this->assertEquals('STRING(column1, "string1", column2, "string2")', $this->_platform->getConcatExpression(
'column1',
'"string1"',
'column2',
'"string2"'
));
$this->assertEquals('CURRENT DATE', $this->_platform->getCurrentDateSQL());
$this->assertEquals('CURRENT TIME', $this->_platform->getCurrentTimeSQL());
$this->assertEquals('CURRENT TIMESTAMP', $this->_platform->getCurrentTimestampSQL());
$this->assertEquals("DATEADD(day, 4, '1987/05/02')", $this->_platform->getDateAddDaysExpression("'1987/05/02'", 4));
$this->assertEquals("DATEADD(month, 102, '1987/05/02')", $this->_platform->getDateAddMonthExpression("'1987/05/02'", 102));
$this->assertEquals("DATEDIFF(day, '1987/04/01', '1987/05/02')", $this->_platform->getDateDiffExpression("'1987/05/02'", "'1987/04/01'"));
$this->assertEquals("DATEADD(day, -1 * 4, '1987/05/02')", $this->_platform->getDateSubDaysExpression("'1987/05/02'", 4));
$this->assertEquals("DATEADD(month, -1 * 102, '1987/05/02')", $this->_platform->getDateSubMonthExpression("'1987/05/02'", 102));
$this->assertEquals("Y-m-d H:i:s.u", $this->_platform->getDateTimeFormatString());
$this->assertEquals("H:i:s.u", $this->_platform->getTimeFormatString());
$this->assertEquals('FOR UPDATE BY LOCK', $this->_platform->getForUpdateSQL());
$this->assertEquals('NEWID()', $this->_platform->getGuidExpression());
$this->assertEquals('CHARINDEX(substring_column, string_column)', $this->_platform->getLocateExpression('string_column', 'substring_column'));
$this->assertEquals('CHARINDEX(substring_column, string_column)', $this->_platform->getLocateExpression('string_column', 'substring_column'));
$this->assertEquals('CHARINDEX(substring_column, SUBSTR(string_column, 2))', $this->_platform->getLocateExpression('string_column', 'substring_column', 1));
$this->assertEquals("HASH(column, 'MD5')", $this->_platform->getMd5Expression('column'));
$this->assertEquals('SUBSTRING(column, 5)', $this->_platform->getSubstringExpression('column', 5));
$this->assertEquals('SUBSTRING(column, 5, 2)', $this->_platform->getSubstringExpression('column', 5, 2));
$this->assertEquals('GLOBAL TEMPORARY', $this->_platform->getTemporaryTableSQL());
$this->assertEquals(
'LTRIM(column)',
$this->_platform->getTrimExpression('column', AbstractPlatform::TRIM_LEADING)
);
$this->assertEquals(
'RTRIM(column)',
$this->_platform->getTrimExpression('column', AbstractPlatform::TRIM_TRAILING)
);
$this->assertEquals(
'TRIM(column)',
$this->_platform->getTrimExpression('column')
);
$this->assertEquals(
'TRIM(column)',
$this->_platform->getTrimExpression('column', AbstractPlatform::TRIM_UNSPECIFIED)
);
$this->assertEquals(
"SUBSTR(column, PATINDEX('%[^c]%', column))",
$this->_platform->getTrimExpression('column', AbstractPlatform::TRIM_LEADING, 'c')
);
$this->assertEquals(
"REVERSE(SUBSTR(REVERSE(column), PATINDEX('%[^c]%', REVERSE(column))))",
$this->_platform->getTrimExpression('column', AbstractPlatform::TRIM_TRAILING, 'c')
);
$this->assertEquals(
"REVERSE(SUBSTR(REVERSE(SUBSTR(column, PATINDEX('%[^c]%', column))), PATINDEX('%[^c]%', REVERSE(SUBSTR(column, PATINDEX('%[^c]%', column))))))",
$this->_platform->getTrimExpression('column', null, 'c')
);
$this->assertEquals(
"REVERSE(SUBSTR(REVERSE(SUBSTR(column, PATINDEX('%[^c]%', column))), PATINDEX('%[^c]%', REVERSE(SUBSTR(column, PATINDEX('%[^c]%', column))))))",
$this->_platform->getTrimExpression('column', AbstractPlatform::TRIM_UNSPECIFIED, 'c')
);
}
public function testDoesNotSupportRegexp()
{
$this->setExpectedException('\Doctrine\DBAL\DBALException');
$this->_platform->getRegexpExpression();
}
public function testHasCorrectDefaultTransactionIsolationLevel()
{
$this->assertEquals(
Connection::TRANSACTION_READ_UNCOMMITTED,
$this->_platform->getDefaultTransactionIsolationLevel()
);
}
public function testGeneratesTransactionsCommands()
{
$this->assertEquals(
'SET TEMPORARY OPTION isolation_level = 0',
$this->_platform->getSetTransactionIsolationSQL(Connection::TRANSACTION_READ_UNCOMMITTED)
);
$this->assertEquals(
'SET TEMPORARY OPTION isolation_level = 1',
$this->_platform->getSetTransactionIsolationSQL(Connection::TRANSACTION_READ_COMMITTED)
);
$this->assertEquals(
'SET TEMPORARY OPTION isolation_level = 2',
$this->_platform->getSetTransactionIsolationSQL(Connection::TRANSACTION_REPEATABLE_READ)
);
$this->assertEquals(
'SET TEMPORARY OPTION isolation_level = 3',
$this->_platform->getSetTransactionIsolationSQL(Connection::TRANSACTION_SERIALIZABLE)
);
}
public function testCannotGenerateTransactionCommandWithInvalidIsolationLevel()
{
$this->setExpectedException('\InvalidArgumentException');
$this->_platform->getSetTransactionIsolationSQL('invalid_transaction_isolation_level');
}
public function testModifiesLimitQuery()
{
$this->assertEquals(
'SELECT TOP 10 * FROM user',
$this->_platform->modifyLimitQuery('SELECT * FROM user', 10, 0)
);
}
public function testModifiesLimitQueryWithEmptyOffset()
{
$this->assertEquals(
'SELECT TOP 10 * FROM user',
$this->_platform->modifyLimitQuery('SELECT * FROM user', 10)
);
}
public function testModifiesLimitQueryWithOffset()
{
$this->assertEquals(
'SELECT TOP 10 START AT 6 * FROM user',
$this->_platform->modifyLimitQuery('SELECT * FROM user', 10, 5)
);
$this->assertEquals(
'SELECT TOP ALL START AT 6 * FROM user',
$this->_platform->modifyLimitQuery('SELECT * FROM user', 0, 5)
);
}
public function testModifiesLimitQueryWithSubSelect()
{
$this->assertEquals(
'SELECT TOP 10 * FROM (SELECT u.id as uid, u.name as uname FROM user) AS doctrine_tbl',
$this->_platform->modifyLimitQuery('SELECT * FROM (SELECT u.id as uid, u.name as uname FROM user) AS doctrine_tbl', 10)
);
}
public function testPrefersIdentityColumns()
{
$this->assertTrue($this->_platform->prefersIdentityColumns());
}
public function testDoesNotPreferSequences()
{
$this->assertFalse($this->_platform->prefersSequences());
}
public function testSupportsIdentityColumns()
{
$this->assertTrue($this->_platform->supportsIdentityColumns());
}
public function testSupportsPrimaryConstraints()
{
$this->assertTrue($this->_platform->supportsPrimaryConstraints());
}
public function testSupportsForeignKeyConstraints()
{
$this->assertTrue($this->_platform->supportsForeignKeyConstraints());
}
public function testSupportsForeignKeyOnUpdate()
{
$this->assertTrue($this->_platform->supportsForeignKeyOnUpdate());
}
public function testSupportsAlterTable()
{
$this->assertTrue($this->_platform->supportsAlterTable());
}
public function testSupportsTransactions()
{
$this->assertTrue($this->_platform->supportsTransactions());
}
public function testSupportsSchemas()
{
$this->assertTrue($this->_platform->supportsSchemas());
}
public function testSupportsIndexes()
{
$this->assertTrue($this->_platform->supportsIndexes());
}
public function testSupportsCommentOnStatement()
{
$this->assertTrue($this->_platform->supportsCommentOnStatement());
}
public function testSupportsSavePoints()
{
$this->assertTrue($this->_platform->supportsSavepoints());
}
public function testSupportsReleasePoints()
{
$this->assertTrue($this->_platform->supportsReleaseSavepoints());
}
public function testSupportsCreateDropDatabase()
{
$this->assertTrue($this->_platform->supportsCreateDropDatabase());
}
public function testSupportsGettingAffectedRows()
{
$this->assertTrue($this->_platform->supportsGettingAffectedRows());
}
public function testDoesNotSupportSequences()
{
$this->assertFalse($this->_platform->supportsSequences());
}
public function testDoesNotSupportInlineColumnComments()
{
$this->assertFalse($this->_platform->supportsInlineColumnComments());
}
public function testCannotEmulateSchemas()
{
$this->assertFalse($this->_platform->canEmulateSchemas());
}
}
...@@ -17,6 +17,8 @@ class TestUtil ...@@ -17,6 +17,8 @@ class TestUtil
* 'db_username' : The username to use for connecting. * 'db_username' : The username to use for connecting.
* 'db_password' : The password to use for connecting. * 'db_password' : The password to use for connecting.
* 'db_host' : The hostname of the database to connect to. * 'db_host' : The hostname of the database to connect to.
* 'db_server' : The server name of the database to connect to
* (optional, some vendors allow multiple server instances with different names on the same host).
* 'db_name' : The name of the database to connect to. * 'db_name' : The name of the database to connect to.
* 'db_port' : The port of the database to connect to. * 'db_port' : The port of the database to connect to.
* *
...@@ -53,10 +55,18 @@ class TestUtil ...@@ -53,10 +55,18 @@ class TestUtil
'port' => $GLOBALS['tmpdb_port'] 'port' => $GLOBALS['tmpdb_port']
); );
if (isset($GLOBALS['db_server'])) {
$realDbParams['server'] = $GLOBALS['db_server'];
}
if (isset($GLOBALS['db_unix_socket'])) { if (isset($GLOBALS['db_unix_socket'])) {
$realDbParams['unix_socket'] = $GLOBALS['db_unix_socket']; $realDbParams['unix_socket'] = $GLOBALS['db_unix_socket'];
} }
if (isset($GLOBALS['tmpdb_server'])) {
$tmpDbParams['server'] = $GLOBALS['tmpdb_server'];
}
if (isset($GLOBALS['tmpdb_unix_socket'])) { if (isset($GLOBALS['tmpdb_unix_socket'])) {
$tmpDbParams['unix_socket'] = $GLOBALS['tmpdb_unix_socket']; $tmpDbParams['unix_socket'] = $GLOBALS['tmpdb_unix_socket'];
} }
...@@ -124,6 +134,10 @@ class TestUtil ...@@ -124,6 +134,10 @@ class TestUtil
'port' => $GLOBALS['tmpdb_port'] 'port' => $GLOBALS['tmpdb_port']
); );
if (isset($GLOBALS['tmpdb_server'])) {
$tmpDbParams['server'] = $GLOBALS['tmpdb_server'];
}
// Connect to tmpdb in order to drop and create the real test db. // Connect to tmpdb in order to drop and create the real test db.
return \Doctrine\DBAL\DriverManager::getConnection($tmpDbParams); return \Doctrine\DBAL\DriverManager::getConnection($tmpDbParams);
} }
......
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