From ff9877efb568c67d34b2cddcd793442e5baa96da Mon Sep 17 00:00:00 2001 From: mpyw Date: Fri, 28 Feb 2020 06:36:18 +0900 Subject: [PATCH 1/3] Feat: Introduce a wrapper for scalar values --- src/Value.php | 172 +++++++++++++++++++++++++++++++++++++++++ src/ValueInterface.php | 39 ++++++++++ 2 files changed, 211 insertions(+) create mode 100644 src/Value.php create mode 100644 src/ValueInterface.php diff --git a/src/Value.php b/src/Value.php new file mode 100644 index 0000000..b6feca8 --- /dev/null +++ b/src/Value.php @@ -0,0 +1,172 @@ +value = $value; + $this->type = $type; + } + + /** + * Return original value. + * + * @return bool|float|int|string + */ + public function getValue() + { + return $this->value; + } + + /** + * Return type. + * + * @return string + */ + public function getType(): string + { + return $this->type; + } + + /** + * Return PDO::PARAM_* type. + * + * @return int + */ + public function getParamType(): int + { + switch ($this->type) { + case static::TYPE_INT: + return PDO::PARAM_INT; + case static::TYPE_BOOL: + return PDO::PARAM_BOOL; + case static::TYPE_FLOAT: + case static::TYPE_STR: + default: + return PDO::PARAM_STR; + } + } + + /** + * Return a placeholder format. + * + * @return string + */ + public function getPlaceholder(): string + { + switch ($this->type) { + case static::TYPE_FLOAT: + return 'cast(? as decimal(65, 30))'; + case static::TYPE_INT: + case static::TYPE_BOOL: + case static::TYPE_STR: + default: + return '?'; + } + } +} diff --git a/src/ValueInterface.php b/src/ValueInterface.php new file mode 100644 index 0000000..6d880e3 --- /dev/null +++ b/src/ValueInterface.php @@ -0,0 +1,39 @@ + Date: Fri, 28 Feb 2020 06:42:58 +0900 Subject: [PATCH 2/3] Refactor: Refactor using Value wrapper --- src/SystemVariableAssigner.php | 4 +++- src/SystemVariableGrammar.php | 35 +--------------------------------- 2 files changed, 4 insertions(+), 35 deletions(-) diff --git a/src/SystemVariableAssigner.php b/src/SystemVariableAssigner.php index a928ac3..2e631c7 100644 --- a/src/SystemVariableAssigner.php +++ b/src/SystemVariableAssigner.php @@ -3,6 +3,7 @@ namespace Mpyw\LaravelMySqlSystemVariableManager; use Closure; +use Mpyw\LaravelMySqlSystemVariableManager\Value as BindingValue; use Mpyw\LaravelPdoEmulationControl\EmulationController; use Mpyw\Unclosure\Value; use PDO; @@ -86,7 +87,8 @@ protected static function withStatementFor(PDO $pdo, string $query, array $value { $statement = $pdo->prepare($query); foreach (array_values($values) as $i => $value) { - $statement->bindValue($i + 1, $value, Grammar::paramTypeFor($value)); + $value = BindingValue::wrap($value); + $statement->bindValue($i + 1, $value->getValue(), $value->getParamType()); } $statement->execute(); diff --git a/src/SystemVariableGrammar.php b/src/SystemVariableGrammar.php index b51ecb9..16f5b5e 100644 --- a/src/SystemVariableGrammar.php +++ b/src/SystemVariableGrammar.php @@ -2,8 +2,6 @@ namespace Mpyw\LaravelMySqlSystemVariableManager; -use PDO; - class SystemVariableGrammar { /** @@ -23,42 +21,11 @@ public static function assignmentExpressions(array $values): array { $expressions = []; foreach ($values as $name => $value) { - $expressions[] = static::escapeIdentifier($name) . '=' . static::placeholderFor($value); + $expressions[] = static::escapeIdentifier($name) . '=' . Value::wrap($value)->getPlaceholder(); } return $expressions; } - /** - * @param mixed $value - * @return int - */ - public static function paramTypeFor($value): int - { - switch (gettype($value)) { - case 'integer': - return PDO::PARAM_INT; - case 'boolean': - return PDO::PARAM_BOOL; - case 'NULL': - default: - return PDO::PARAM_STR; - } - } - - /** - * @param mixed $value - * @return string - */ - public static function placeholderFor($value): string - { - switch (gettype($value)) { - case 'double': - return 'cast(? as decimal(65, 30))'; - default: - return '?'; - } - } - /** * @param string $identifier * @return string From bd53b917fcb220cee3017cd81c0ec4c1eedf1c17 Mon Sep 17 00:00:00 2001 From: mpyw Date: Fri, 28 Feb 2020 06:44:34 +0900 Subject: [PATCH 3/3] Test: Update tests allowing minor breaking changes --- tests/BasicVariableAssignmentTest.php | 32 +++++++++++++++++++++------ 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/tests/BasicVariableAssignmentTest.php b/tests/BasicVariableAssignmentTest.php index 58d53ac..f992ab6 100644 --- a/tests/BasicVariableAssignmentTest.php +++ b/tests/BasicVariableAssignmentTest.php @@ -2,8 +2,9 @@ namespace Mpyw\LaravelMySqlSystemVariableManager\Tests; +use InvalidArgumentException; use Mpyw\LaravelMySqlSystemVariableManager\MySqlConnection; -use PDOException; +use Mpyw\LaravelMySqlSystemVariableManager\Value; class BasicVariableAssignmentTest extends TestCase { @@ -39,13 +40,21 @@ public function provideBasicVariables(): array 'assigning boolean (emulated)' => ['foreign_key_checks', true, '1', false, '0'], 'assigning string (native)' => ['tx_isolation', false, 'REPEATABLE-READ', 'read-committed', 'READ-COMMITTED'], 'assigning string (emulated)' => ['tx_isolation', true, 'REPEATABLE-READ', 'read-committed', 'READ-COMMITTED'], + 'assigning wrapped float (native)' => ['long_query_time', false, 10.0, Value::float(15.0), 15.0], + 'assigning wrapped float (emulated)' => ['long_query_time', true, '10.000000', Value::float(15.0), '15.000000'], + 'assigning wrapped integer (native)' => ['long_query_time', false, 10.0, Value::int(15), 15.0], + 'assigning wrapped integer (emulated)' => ['long_query_time', true, '10.000000', Value::int(15), '15.000000'], + 'assigning wrapped boolean (native)' => ['foreign_key_checks', false, 1, Value::bool(false), 0], + 'assigning wrapped boolean (emulated)' => ['foreign_key_checks', true, '1', Value::bool(false), '0'], + 'assigning wrapped string (native)' => ['tx_isolation', false, 'REPEATABLE-READ', Value::str('read-committed'), 'READ-COMMITTED'], + 'assigning wrapped string (emulated)' => ['tx_isolation', true, 'REPEATABLE-READ', Value::str('read-committed'), 'READ-COMMITTED'], ]; } public function testAssigningNullThrowsExceptionOnNative(): void { - $this->expectException(PDOException::class); - $this->expectExceptionMessage("SQLSTATE[42000]: Syntax error or access violation: 1231 Variable 'foreign_key_checks' can't be set to the value of 'NULL'"); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('The value must be a scalar or Mpyw\LaravelMySqlSystemVariableManager\ValueInterface instance.'); $this->onNativeConnection(function (MySqlConnection $db) { $db->setSystemVariable('foreign_key_checks', null); @@ -55,8 +64,8 @@ public function testAssigningNullThrowsExceptionOnNative(): void public function testAssigningNullThrowsExceptionOnEmulation(): void { - $this->expectException(PDOException::class); - $this->expectExceptionMessage("SQLSTATE[42000]: Syntax error or access violation: 1231 Variable 'foreign_key_checks' can't be set to the value of 'NULL'"); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('The value must be a scalar or Mpyw\LaravelMySqlSystemVariableManager\ValueInterface instance.'); $this->onEmulatedConnection(function (MySqlConnection $db) { $db->setSystemVariable('foreign_key_checks', null); @@ -64,15 +73,24 @@ public function testAssigningNullThrowsExceptionOnEmulation(): void }); } - public function testAssigningNullDoesNotThrowOnUnresolvedConnection(): void + public function testAssigningNullThrowsOnUnresolvedNativeConnection(): void { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('The value must be a scalar or Mpyw\LaravelMySqlSystemVariableManager\ValueInterface instance.'); + $this->onNativeConnection(function (MySqlConnection $db) { $db->setSystemVariable('foreign_key_checks', null); }); + } + + public function testAssigningNullThrowsOnUnresolvedEmulatedConnection(): void + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('The value must be a scalar or Mpyw\LaravelMySqlSystemVariableManager\ValueInterface instance.'); + $this->onEmulatedConnection(function (MySqlConnection $db) { $db->setSystemVariable('foreign_key_checks', null); }); - $this->assertTrue(true); } public function testAssignmentPriorityOnLazilyResolvedConnection(): void