Unverified Commit f4f987d7 authored by Sergei Morozov's avatar Sergei Morozov Committed by GitHub

Merge pull request #3149 from morozov/issues/2787

Introduced binary binding type to support binary parameters on Oracle
parents 997b1938 2ec1743e
......@@ -39,6 +39,7 @@ class MysqliStatement implements \IteratorAggregate, Statement
*/
protected static $_paramTypeMap = [
ParameterType::STRING => 's',
ParameterType::BINARY => 's',
ParameterType::BOOLEAN => 'i',
ParameterType::NULL => 's',
ParameterType::INTEGER => 'i',
......
......@@ -25,6 +25,7 @@ use Doctrine\DBAL\FetchMode;
use Doctrine\DBAL\ParameterType;
use IteratorAggregate;
use const OCI_ASSOC;
use const OCI_B_BIN;
use const OCI_B_BLOB;
use const OCI_BOTH;
use const OCI_D_LOB;
......@@ -35,6 +36,7 @@ use const OCI_RETURN_LOBS;
use const OCI_RETURN_NULLS;
use const OCI_TEMP_BLOB;
use const PREG_OFFSET_CAPTURE;
use const SQLT_CHR;
use function array_key_exists;
use function count;
use function implode;
......@@ -301,18 +303,35 @@ class OCI8Statement implements IteratorAggregate, Statement
$lob = oci_new_descriptor($this->_dbh, OCI_D_LOB);
$lob->writeTemporary($variable, OCI_TEMP_BLOB);
$this->boundValues[$column] =& $lob;
return oci_bind_by_name($this->_sth, $column, $lob, -1, OCI_B_BLOB);
} elseif ($length !== null) {
$this->boundValues[$column] =& $variable;
return oci_bind_by_name($this->_sth, $column, $variable, $length);
$variable =& $lob;
}
$this->boundValues[$column] =& $variable;
return oci_bind_by_name($this->_sth, $column, $variable);
return oci_bind_by_name(
$this->_sth,
$column,
$variable,
$length ?? -1,
$this->convertParameterType($type)
);
}
/**
* Converts DBAL parameter type to oci8 parameter type
*/
private function convertParameterType(int $type) : int
{
switch ($type) {
case ParameterType::BINARY:
return OCI_B_BIN;
case ParameterType::LARGE_OBJECT:
return OCI_B_BLOB;
default:
return SQLT_CHR;
}
}
/**
......
......@@ -33,7 +33,9 @@ class Statement extends PDOStatement
*/
public function bindParam($column, &$variable, $type = ParameterType::STRING, $length = null, $driverOptions = null)
{
if ($type === ParameterType::LARGE_OBJECT && $driverOptions === null) {
if (($type === ParameterType::LARGE_OBJECT || $type === ParameterType::BINARY)
&& $driverOptions === null
) {
$driverOptions = PDO::SQLSRV_ENCODING_BINARY;
}
......
......@@ -41,6 +41,7 @@ class PDOStatement extends \PDOStatement implements Statement
ParameterType::NULL => PDO::PARAM_NULL,
ParameterType::INTEGER => PDO::PARAM_INT,
ParameterType::STRING => PDO::PARAM_STR,
ParameterType::BINARY => PDO::PARAM_LOB,
ParameterType::LARGE_OBJECT => PDO::PARAM_LOB,
ParameterType::BOOLEAN => PDO::PARAM_BOOL,
];
......
......@@ -132,6 +132,7 @@ class SQLAnywhereStatement implements IteratorAggregate, Statement
case ParameterType::NULL:
case ParameterType::STRING:
case ParameterType::BINARY:
$type = 's';
break;
......
......@@ -44,6 +44,7 @@ use function sqlsrv_get_field;
use function sqlsrv_next_result;
use function sqlsrv_num_fields;
use function SQLSRV_PHPTYPE_STREAM;
use function SQLSRV_PHPTYPE_STRING;
use function sqlsrv_prepare;
use function sqlsrv_rows_affected;
use function SQLSRV_SQLTYPE_VARBINARY;
......@@ -283,15 +284,27 @@ class SQLSrvStatement implements IteratorAggregate, Statement
$params = [];
foreach ($this->variables as $column => &$variable) {
if ($this->types[$column] === ParameterType::LARGE_OBJECT) {
$params[$column - 1] = [
&$variable,
SQLSRV_PARAM_IN,
SQLSRV_PHPTYPE_STREAM(SQLSRV_ENC_BINARY),
SQLSRV_SQLTYPE_VARBINARY('max'),
];
} else {
$params[$column - 1] =& $variable;
switch ($this->types[$column]) {
case ParameterType::LARGE_OBJECT:
$params[$column - 1] = [
&$variable,
SQLSRV_PARAM_IN,
SQLSRV_PHPTYPE_STREAM(SQLSRV_ENC_BINARY),
SQLSRV_SQLTYPE_VARBINARY('max'),
];
break;
case ParameterType::BINARY:
$params[$column - 1] = [
&$variable,
SQLSRV_PARAM_IN,
SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_BINARY),
];
break;
default:
$params[$column - 1] =& $variable;
break;
}
}
......
......@@ -42,6 +42,11 @@ final class ParameterType
*/
public const BOOLEAN = \PDO::PARAM_BOOL;
/**
* Represents a binary string data type.
*/
public const BINARY = 16;
/**
* This class cannot be instantiated.
*/
......
......@@ -79,6 +79,6 @@ class BinaryType extends Type
*/
public function getBindingType()
{
return ParameterType::LARGE_OBJECT;
return ParameterType::BINARY;
}
}
......@@ -5,7 +5,6 @@ declare(strict_types=1);
namespace Doctrine\Tests\DBAL\Functional\Types;
use Doctrine\DBAL\Driver\IBMDB2\DB2Driver;
use Doctrine\DBAL\Driver\OCI8\Driver as OCI8Driver;
use Doctrine\DBAL\ParameterType;
use Doctrine\DBAL\Schema\Table;
use Doctrine\Tests\DbalFunctionalTestCase;
......@@ -20,11 +19,6 @@ class BinaryTest extends DbalFunctionalTestCase
{
parent::setUp();
/** @see https://github.com/doctrine/dbal/issues/2787 */
if ($this->_conn->getDriver() instanceof OCI8Driver) {
$this->markTestSkipped('Filtering by binary fields is currently not supported on Oracle');
}
$table = new Table('binary_table');
$table->addColumn('id', 'binary', [
'length' => 16,
......@@ -64,8 +58,8 @@ class BinaryTest extends DbalFunctionalTestCase
'id' => $id,
'val' => $value,
], [
ParameterType::LARGE_OBJECT,
ParameterType::LARGE_OBJECT,
ParameterType::BINARY,
ParameterType::BINARY,
]);
self::assertSame(1, $result);
......@@ -77,7 +71,7 @@ class BinaryTest extends DbalFunctionalTestCase
'SELECT val FROM binary_table WHERE id = ?',
[$id],
0,
[ParameterType::LARGE_OBJECT]
[ParameterType::BINARY]
);
// Currently, `BinaryType` mistakenly converts string values fetched from the DB to a stream.
......
......@@ -32,7 +32,7 @@ class BinaryTest extends \Doctrine\Tests\DbalTestCase
public function testReturnsBindingType()
{
self::assertSame(ParameterType::LARGE_OBJECT, $this->type->getBindingType());
self::assertSame(ParameterType::BINARY, $this->type->getBindingType());
}
public function testReturnsName()
......
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