Skip to content

Commit

Permalink
Fix bindings
Browse files Browse the repository at this point in the history
  • Loading branch information
simPod committed Aug 14, 2018
1 parent 85c6b23 commit c4e466e
Show file tree
Hide file tree
Showing 6 changed files with 98 additions and 67 deletions.
1 change: 1 addition & 0 deletions phpunit.xml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
<env name="CLICKHOUSE_PORT" value="8123" />
<env name="CLICKHOUSE_USER" value="default" />
<env name="CLICKHOUSE_PASSWORD" value="" />
<env name="CLICKHOUSE_DATABASE" value="php_clickhouse" />
<env name="CLICKHOUSE_TMPPATH" value="/tmp" />
</php>

Expand Down
18 changes: 18 additions & 0 deletions src/Exception/UnsupportedParameterType.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php

declare(strict_types=1);

namespace ClickHouseDB\Exception;

use function gettype;

final class UnsupportedParameterType extends QueryException implements ClickHouseException
{
/**
* @param mixed $parameter
*/
public static function new($parameter) : self
{
return new self(sprintf('Parameter of type "%s" cannot be bound', gettype($parameter)));
}
}
106 changes: 43 additions & 63 deletions src/Query/Degeneration/Bindings.php
Original file line number Diff line number Diff line change
@@ -1,25 +1,29 @@
<?php

declare(strict_types=1);

namespace ClickHouseDB\Query\Degeneration;

use ClickHouseDB\Exception\UnsupportedParameterType;
use ClickHouseDB\Query\Degeneration;
use DateTimeInterface;
use function array_map;
use function implode;
use function is_array;
use function is_bool;
use function is_callable;
use function is_float;
use function is_int;
use function is_string;
use function sprintf;
use function str_ireplace;

class Bindings implements \ClickHouseDB\Query\Degeneration
class Bindings implements Degeneration
{
/**
* @var array
*/
protected $bindings = [];


/**
* @param array $bindings
*/
Expand All @@ -37,10 +41,6 @@ public function bindParams(array $bindings)
*/
public function bindParam($column, $value)
{
if ($value instanceof DateTimeInterface) {
$value = $value->format('Y-m-d H:i:s');
}

$this->bindings[$column] = $value;
}

Expand All @@ -52,32 +52,9 @@ public function bindParam($column, $value)
*/
private function escapeString($value)
{
// return str_replace("'", "''", remove_invisible_characters($str, FALSE));
return addslashes($value);
}

/**
* Escape an array
*
* @param array $values
* @return array
*/
private function escapeArray($values)
{
$escapedValues = [];
foreach ($values as $value) {
if (is_numeric($value)) {
$escapedValues[] = $value;
} elseif (is_string($value)) {
$escapedValues[] = $this->escapeString($value);
} elseif (is_array($value)) {
$escapedValues[] = $this->escapeArray($value);
}
}

return $escapedValues;
}

/**
* Binds a list of values to the corresponding parameters.
* This is similar to [[bindValue()]] except that it binds multiple values at a time.
Expand All @@ -92,13 +69,12 @@ public function compile_binds($sql, $binds,$pattern)
return preg_replace_callback($pattern, function($m) use ($binds){
if(isset($binds[$m[1]])){ // If it exists in our array
return $binds[$m[1]]; // Then replace it from our array
}else{
return $m[0]; // Otherwise return the whole match (basically we won't change it)
}

return $m[0]; // Otherwise return the whole match (basically we won't change it)
}, $sql);
}


/**
* Compile Bindings
*
Expand All @@ -107,44 +83,23 @@ public function compile_binds($sql, $binds,$pattern)
*/
public function process($sql)
{
arsort($this->bindings);

$bindFormatted=[];
$bindRaw=[];
foreach ($this->bindings as $key => $value) {
$valueSet = null;
$formattedParameter = null;

if ($value === null || $value === false) {
$formattedParameter = '';
}

if (is_array($value)) {
$escapedValues = $this->escapeArray($value);
$valueSet = implode(', ', $value);

$escapedValues = array_map(
function ($escapedValue) {
if (is_string($escapedValue)) {
return $this->formatStringParameter($escapedValue);
}

return $escapedValue;
$values = array_map(
function ($value) {
return $this->formatParameter($value);
},
$escapedValues
$value
);

$formattedParameter = implode(',', $escapedValues);
$valueSet = implode(', ', $escapedValues);
}

if (is_float($value) || is_int($value)) {
$formattedParameter = $value;
$valueSet = $value;
}

if (is_string($value)) {
$valueSet = $value;
$formattedParameter = $this->formatStringParameter($this->escapeString($value));
$formattedParameter = implode(',', $values);
} else {
$valueSet = $value;
$formattedParameter = $this->formatParameter($value);
}

if ($formattedParameter !== null) {
Expand All @@ -167,6 +122,31 @@ function ($escapedValue) {
return $sql;
}

/**
* @param mixed $value
* @return mixed
*/
private function formatParameter($value)
{
if ($value instanceof DateTimeInterface) {
$value = $value->format('Y-m-d H:i:s');
}

if (is_float($value) || is_int($value) || is_bool($value) || $value === null) {
return $value;
}

if (is_object($value) && is_callable([$value, '__toString'])) {
$value = (string) $value;
}

if (is_string($value)) {
return $this->formatStringParameter($this->escapeString($value));
}

throw UnsupportedParameterType::new($value);
}

/**
* @return string
*/
Expand Down
28 changes: 27 additions & 1 deletion tests/BindingsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@

namespace ClickHouseDB\Tests;

use ClickHouseDB\Exception\UnsupportedParameterType;
use ClickHouseDB\Query\Degeneration\Bindings;
use function curl_init;
use DateTimeImmutable;
use PHPUnit\Framework\TestCase;

/**
Expand Down Expand Up @@ -30,6 +33,21 @@ public function escapeDataProvider()
['id' => '1'],
"select * from test. WHERE id = '1'",
],
[
'select * from test. WHERE date_column = :dateParam',
['dateParam' => new DateTimeImmutable('2018-08-31 23:54:02')],
"select * from test. WHERE date_column = '2018-08-31 23:54:02'",
],
[
'select * from test. WHERE a_column = :objectWithToString',
['objectWithToString' => new class() {
public function __toString()
{
return 'expectedValue';
}
}],
"select * from test. WHERE a_column = 'expectedValue'",
],
[
'select * from test. WHERE id IN (:id)',
['id' => [1, 2]],
Expand Down Expand Up @@ -153,13 +171,21 @@ public function testBindselectAsync()
*/
public function testEscape($sql, $params, $expectedSql)
{

$bindings = new Bindings();
$bindings->bindParams($params);
$sql = $bindings->process($sql);
$this->assertSame($expectedSql, $sql);
}

public function testEscapeFail()
{
$this->expectException(UnsupportedParameterType::class);

$bindings = new Bindings();
$bindings->bindParams(['unsupportedParam' => curl_init()]);
$bindings->process('SELECT * FROM test WHERE id = :unsupportedParam');
}

public function testSelectAsKeys()
{
// chr(0....255);
Expand Down
5 changes: 2 additions & 3 deletions tests/ClientTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -504,11 +504,10 @@ private function make_csv_SelectWhereIn($file_name, $array)
fclose($handle);
}

/**
*
*/
public function testSelectWhereIn()
{
$this->create_table_summing_url_views();

$file_data_names = [
$this->tmpPath . '_testInsertCSV_clickHouseDB_test.1.data'
];
Expand Down
7 changes: 7 additions & 0 deletions tests/WithClient.php
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
<?php

declare(strict_types=1);

namespace ClickHouseDB\Tests;

use ClickHouseDB\Client;
use function sprintf;

trait WithClient
{
Expand Down Expand Up @@ -30,5 +33,9 @@ public function restartClickHouseClient()

];
$this->client = new Client($config);
$databaseName = getenv('CLICKHOUSE_DATABASE');
$this->client->write(sprintf('DROP DATABASE IF EXISTS "%s"', $databaseName));
$this->client->write(sprintf('CREATE DATABASE "%s"', $databaseName));
$this->client->database($databaseName);
}
}

0 comments on commit c4e466e

Please sign in to comment.