Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add SAP Sybase SQL Anywhere database vendor #293

Merged
merged 14 commits into from
Nov 13, 2013
8 changes: 4 additions & 4 deletions docs/en/reference/portability.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ Portability
There are often cases when you need to write an application or library that is portable
across multiple different database vendors. The Doctrine ORM is one example of such
a library. It is an abstraction layer over all the currently supported vendors (MySQL, Oracle,
PostgreSQL, SQLite and Microsoft SQL Server). If you want to use the DBAL to write a portable application
or library you have to follow lots of rules to make all the different vendors work the
same.
PostgreSQL, SQLite, SAP SQL Anywhere and Microsoft SQL Server). If you want to use the DBAL
to write a portable application or library you have to follow lots of rules to make
all the different vendors work the same.

There are many different layers that you need to take care of, here is a quick list:

Expand Down Expand Up @@ -39,7 +39,7 @@ Connection Wrapper
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
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>`_.

Using the following code block in your initialization will:
Expand Down
134 changes: 134 additions & 0 deletions lib/Doctrine/DBAL/Driver/SQLAnywhere/Driver.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
<?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 <[email protected]>
* @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;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cast to (int)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is that necessary? It will be concatenated to the DSN-String anyways...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wondering about what happens if someone passes in foo


return
'LINKS=tcpip(HOST=' . $host . ';PORT=' . $port . ';DoBroadcast=Direct)' .
';ServerName=' . $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);
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

EOF EOL

210 changes: 210 additions & 0 deletions lib/Doctrine/DBAL/Driver/SQLAnywhere/SQLAnywhereConnection.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,210 @@
<?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 <[email protected]>
* @link www.doctrine-project.org
* @since 2.5
*/
class SQLAnywhereConnection implements Connection
{
/**
* @var resource The SQL Anywhere connection resource.
*/
private $conn;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the abbreviation necessary?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No I think I adopted the notation from other drivers back then. I can change that to $connection

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair enuff - I think it's readable as it is, so ok


/**
* 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();
}

/**
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not docblocks - use single-line comments // or just /*, not /**

* Disable PHP warnings on error
*/
if ( ! sasql_set_option($this->conn, 'verbose_errors', false)) {
throw SQLAnywhereException::fromSQLAnywhereError($this->conn);
}

/**
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not docblocks - use single-line comments // or just /*, not /**

* Enable auto committing by default
*/
if ( ! sasql_set_option($this->conn, 'auto_commit', 'on')) {
throw SQLAnywhereException::fromSQLAnywhereError($this->conn);
}

/**
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not docblocks - use single-line comments // or just /*, not /**

* 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();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Newline before this line


return $stmt->rowCount();
}

/**
* {@inheritdoc}
*/
public function lastInsertId($name = null)
{
if ($name === null) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't have a guideline on this, but I prefer yoda style comparisons

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();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

newline before this line


return $stmt;
}

/**
* {@inheritdoc}
*/
public function quote($input, $type = \PDO::PARAM_STR)
{
if (is_int($input) || is_float($input)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is_numeric? What about doubles?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought doubles and floats are the same in PHP? Am I missing something? Besides that this if checks could be left out I think as it quotes all kind of strings with the driver function.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yep, my mistake - is_float and is_double are the same

Marco Pivetta

http://twitter.com/Ocramius

http://ocramius.github.com/

On 12 November 2013 00:39, Steve Müller [email protected] wrote:

In lib/Doctrine/DBAL/Driver/SQLAnywhere/SQLAnywhereConnection.php:

  • */
    
  • 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)) {
    

I thought doubles and floats are the same in PHP? Am I missing something?
Besides that this if checks could be left out I think as it quotes all kind
of strings with the driver function.


Reply to this email directly or view it on GitHubhttps://github.com//pull/293/files#r7577998
.

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;
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

EOF EOL

Loading