From 2d6c9c0c8def67233eab9bc8dda2eddf21f7512d Mon Sep 17 00:00:00 2001 From: Ibrahim BinAlshikh Date: Mon, 28 Oct 2024 18:30:21 +0300 Subject: [PATCH 1/6] test: Added Additional Test Case --- .../tests/mssql/MSSQLQueryBuilderTest.php | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tests/webfiori/database/tests/mssql/MSSQLQueryBuilderTest.php b/tests/webfiori/database/tests/mssql/MSSQLQueryBuilderTest.php index 3c6e337..a26562c 100644 --- a/tests/webfiori/database/tests/mssql/MSSQLQueryBuilderTest.php +++ b/tests/webfiori/database/tests/mssql/MSSQLQueryBuilderTest.php @@ -201,6 +201,7 @@ public function testTransaction00() { 'details' => 'This task is about testing if transactions work as intended.', ] ], $tasks); + return intval($userId); } /** @@ -710,6 +711,22 @@ public function testInsert05() { . "([user_id], [details], [created_on], [is_finished]) " . "values (?, ?, ?, ?);", $schema->getLastQuery()); } + /** + * @test + */ + public function testInsert06() { + $schema = new MSSQLTestSchema(); + $q = $schema->table('users_tasks'); + $q->insert([ + 'user-id' => null, + 'details' => 'OK task', + 'not-exist' => 7 + ]); + $this->assertEquals("insert into [users_tasks] " + . "([user_id], [details], [not_exist], [created_on], [is_finished]) " + . "values (?, ?, ?, ?, ?);", $schema->getLastQuery()); + $q->execute(); + } /** * @test */ From d67e1d8675463d51f0468a8a41a77493d7d11024 Mon Sep 17 00:00:00 2001 From: Ibrahim BinAlshikh Date: Mon, 28 Oct 2024 18:30:47 +0300 Subject: [PATCH 2/6] feat: Handel Query Preparation Error --- webfiori/database/mssql/MSSQLConnection.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/webfiori/database/mssql/MSSQLConnection.php b/webfiori/database/mssql/MSSQLConnection.php index fd1fa43..d3d4136 100644 --- a/webfiori/database/mssql/MSSQLConnection.php +++ b/webfiori/database/mssql/MSSQLConnection.php @@ -212,6 +212,11 @@ private function setSqlErr() { $this->sqlState = $lastErr['SQLSTATE']; $this->setErrMessage($lastErr['message']); $this->setErrCode($lastErr['code']); + } else if (strpos($lastErr['message'], 'Statement(s) could not be prepared') === true) { + $lastErr = $allErrs[count($allErrs) - 1]; + $this->sqlState = $lastErr['SQLSTATE']; + $this->setErrMessage('Statement(s) could not be prepared: '.$lastErr['message']); + $this->setErrCode($lastErr['code']); } else { $lastErr = $allErrs[count($allErrs) - 2]; $this->sqlState = $lastErr['SQLSTATE']; From b7cda0cba610e5855bda54b5a2f9e6e5328ca5cd Mon Sep 17 00:00:00 2001 From: Ibrahim BinAlshikh Date: Mon, 28 Oct 2024 18:33:31 +0300 Subject: [PATCH 3/6] Update MSSQLConnection.php --- webfiori/database/mssql/MSSQLConnection.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/webfiori/database/mssql/MSSQLConnection.php b/webfiori/database/mssql/MSSQLConnection.php index d3d4136..931fb5e 100644 --- a/webfiori/database/mssql/MSSQLConnection.php +++ b/webfiori/database/mssql/MSSQLConnection.php @@ -208,17 +208,17 @@ private function setSqlErr() { $allErrs = sqlsrv_errors(SQLSRV_ERR_ERRORS); $lastErr = $allErrs[count($allErrs) - 1]; - if (strpos($lastErr['message'], 'The statement has been terminated') === false) { + if (strpos($lastErr['message'], 'The statement has been terminated') === true) { + $lastErr = $allErrs[count($allErrs) - 2]; $this->sqlState = $lastErr['SQLSTATE']; $this->setErrMessage($lastErr['message']); - $this->setErrCode($lastErr['code']); } else if (strpos($lastErr['message'], 'Statement(s) could not be prepared') === true) { $lastErr = $allErrs[count($allErrs) - 1]; $this->sqlState = $lastErr['SQLSTATE']; $this->setErrMessage('Statement(s) could not be prepared: '.$lastErr['message']); $this->setErrCode($lastErr['code']); } else { - $lastErr = $allErrs[count($allErrs) - 2]; + $this->setErrCode($lastErr['code']); $this->sqlState = $lastErr['SQLSTATE']; $this->setErrMessage($lastErr['message']); $this->setErrCode($lastErr['code']); From a482f813a8807da210b493ebc8288f65768c13d6 Mon Sep 17 00:00:00 2001 From: Ibrahim BinAlshikh Date: Mon, 28 Oct 2024 18:52:32 +0300 Subject: [PATCH 4/6] fix: Fix to Error Detection closes #91 --- tests/webfiori/database/tests/mssql/MSSQLQueryBuilderTest.php | 2 ++ tests/webfiori/database/tests/mssql/MSSQLTestSchema.php | 2 +- webfiori/database/mssql/MSSQLConnection.php | 4 ++-- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/webfiori/database/tests/mssql/MSSQLQueryBuilderTest.php b/tests/webfiori/database/tests/mssql/MSSQLQueryBuilderTest.php index a26562c..3ceb3bf 100644 --- a/tests/webfiori/database/tests/mssql/MSSQLQueryBuilderTest.php +++ b/tests/webfiori/database/tests/mssql/MSSQLQueryBuilderTest.php @@ -715,6 +715,8 @@ public function testInsert05() { * @test */ public function testInsert06() { + $this->expectException(DatabaseException::class); + $this->expectExceptionMessage("207 - Statement(s) could not be prepared: [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]Invalid column name 'not_exist'."); $schema = new MSSQLTestSchema(); $q = $schema->table('users_tasks'); $q->insert([ diff --git a/tests/webfiori/database/tests/mssql/MSSQLTestSchema.php b/tests/webfiori/database/tests/mssql/MSSQLTestSchema.php index db5fc24..9fc536f 100644 --- a/tests/webfiori/database/tests/mssql/MSSQLTestSchema.php +++ b/tests/webfiori/database/tests/mssql/MSSQLTestSchema.php @@ -13,7 +13,7 @@ */ class MSSQLTestSchema extends Database { public function __construct() { - parent::__construct(new ConnectionInfo('mssql','sa', '1234567890@Eu', 'testing_db', 'localhost')); + parent::__construct(new ConnectionInfo('mssql','sa', '1234567890@Eu', 'testing_db', 'localhost\SQLEXPRESS')); $table00 = new MSSQLTable('users'); $table00->setComment('This table is used to hold users info.'); diff --git a/webfiori/database/mssql/MSSQLConnection.php b/webfiori/database/mssql/MSSQLConnection.php index 931fb5e..12517cc 100644 --- a/webfiori/database/mssql/MSSQLConnection.php +++ b/webfiori/database/mssql/MSSQLConnection.php @@ -212,8 +212,8 @@ private function setSqlErr() { $lastErr = $allErrs[count($allErrs) - 2]; $this->sqlState = $lastErr['SQLSTATE']; $this->setErrMessage($lastErr['message']); - } else if (strpos($lastErr['message'], 'Statement(s) could not be prepared') === true) { - $lastErr = $allErrs[count($allErrs) - 1]; + } else if ($lastErr['SQLSTATE'] == '42000' && $lastErr['code'] == 8180) { + $lastErr = $allErrs[count($allErrs) - 2]; $this->sqlState = $lastErr['SQLSTATE']; $this->setErrMessage('Statement(s) could not be prepared: '.$lastErr['message']); $this->setErrCode($lastErr['code']); From c7114386611a8cb8e9fb3d0281f4f617dada080d Mon Sep 17 00:00:00 2001 From: Ibrahim BinAlshikh Date: Mon, 28 Oct 2024 18:56:42 +0300 Subject: [PATCH 5/6] fix: Fext Test Schema Connection --- tests/webfiori/database/tests/mssql/MSSQLTestSchema.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/webfiori/database/tests/mssql/MSSQLTestSchema.php b/tests/webfiori/database/tests/mssql/MSSQLTestSchema.php index 9fc536f..db5fc24 100644 --- a/tests/webfiori/database/tests/mssql/MSSQLTestSchema.php +++ b/tests/webfiori/database/tests/mssql/MSSQLTestSchema.php @@ -13,7 +13,7 @@ */ class MSSQLTestSchema extends Database { public function __construct() { - parent::__construct(new ConnectionInfo('mssql','sa', '1234567890@Eu', 'testing_db', 'localhost\SQLEXPRESS')); + parent::__construct(new ConnectionInfo('mssql','sa', '1234567890@Eu', 'testing_db', 'localhost')); $table00 = new MSSQLTable('users'); $table00->setComment('This table is used to hold users info.'); From 6924c948841660902e270e0bd678c810eff530d0 Mon Sep 17 00:00:00 2001 From: Ibrahim BinAlshikh Date: Mon, 28 Oct 2024 23:21:14 +0300 Subject: [PATCH 6/6] test: Fix Test Cases --- tests/boot.php | 3 ++- .../database/tests/mssql/MSSQLQueryBuilderTest.php | 11 ++++++----- .../webfiori/database/tests/mssql/MSSQLTestSchema.php | 2 +- webfiori/database/mssql/MSSQLConnection.php | 7 ++++--- 4 files changed, 13 insertions(+), 10 deletions(-) diff --git a/tests/boot.php b/tests/boot.php index 25102df..de3241c 100644 --- a/tests/boot.php +++ b/tests/boot.php @@ -4,6 +4,7 @@ ini_set('display_startup_errors', 1); ini_set('display_errors', 1); error_reporting(-1); +define('SQL_SERVER_HOST', 'localhost'); $stderr = fopen('php://stderr', 'w'); $testsDirName = 'tests'; $rootDir = substr(__DIR__, 0, strlen(__DIR__) - strlen($testsDirName)); @@ -104,7 +105,7 @@ } else { echo "Dropping test tables from MSSQL Server...\n"; try{ - $mssqlConnInfo = new ConnectionInfo('mssql','sa', '1234567890@Eu', 'testing_db', 'localhost'); + $mssqlConnInfo = new ConnectionInfo('mssql','sa', '1234567890@Eu', 'testing_db', SQL_SERVER_HOST); $mssqlConn = new MSSQLConnection($mssqlConnInfo); $mssqlSchema = new MSSQLTestSchema(); $mssqlSchema->setConnection($mssqlConn); diff --git a/tests/webfiori/database/tests/mssql/MSSQLQueryBuilderTest.php b/tests/webfiori/database/tests/mssql/MSSQLQueryBuilderTest.php index 3ceb3bf..cb1ec5d 100644 --- a/tests/webfiori/database/tests/mssql/MSSQLQueryBuilderTest.php +++ b/tests/webfiori/database/tests/mssql/MSSQLQueryBuilderTest.php @@ -285,7 +285,7 @@ public function testTransaction02(int $userId) { }); }, [$userId]); } catch (DatabaseException $ex) { - $this->assertEquals("515 - [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]Cannot insert the value NULL into column 'age', table 'testing_db.dbo.users'; column does not allow nulls. INSERT fails.", $ex->getMessage()); + $this->assertEquals("515 - The statement has been terminated due to following: [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]Cannot insert the value NULL into column 'age', table 'testing_db.dbo.users'; column does not allow nulls. INSERT fails.", $ex->getMessage()); $this->assertEquals(515, $ex->getCode()); $user = $schema->table('users')->select()->where('id', $userId)->execute()->getRows()[0]; $this->assertEquals([ @@ -549,9 +549,10 @@ public function testDelete01() { /** * @test * @param MSSQLTestSchema $schema - * @depends testCreateTable */ - public function testInsert03(MSSQLTestSchema $schema) { + public function testInsert03() { + $schema = new MSSQLTestSchema(); + $schema->createTables()->execute(); $schema->table('users')->insert([ 'first-name' => 'Ibrahim', 'last-name' => 'BinAlshikh', @@ -716,7 +717,7 @@ public function testInsert05() { */ public function testInsert06() { $this->expectException(DatabaseException::class); - $this->expectExceptionMessage("207 - Statement(s) could not be prepared: [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]Invalid column name 'not_exist'."); + $this->expectExceptionMessage("207 - Statement(s) could not be prepared due to the following: [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]Invalid column name 'not_exist'."); $schema = new MSSQLTestSchema(); $q = $schema->table('users_tasks'); $q->insert([ @@ -1163,7 +1164,7 @@ public function testSetConnection00() { if (PHP_MAJOR_VERSION == 5) { $this->markTestSkipped('PHP 5 has no MSSQL driver in selected setup.'); } else { - $connInfo = new ConnectionInfo('mssql','sa', '1234567890@Eu', 'testing_db', 'localhost'); + $connInfo = new ConnectionInfo('mssql','sa', '1234567890@Eu', 'testing_db', SQL_SERVER_HOST); $conn = new MSSQLConnection($connInfo); $schema = new MSSQLTestSchema(); $schema->setConnection($conn); diff --git a/tests/webfiori/database/tests/mssql/MSSQLTestSchema.php b/tests/webfiori/database/tests/mssql/MSSQLTestSchema.php index db5fc24..9248451 100644 --- a/tests/webfiori/database/tests/mssql/MSSQLTestSchema.php +++ b/tests/webfiori/database/tests/mssql/MSSQLTestSchema.php @@ -13,7 +13,7 @@ */ class MSSQLTestSchema extends Database { public function __construct() { - parent::__construct(new ConnectionInfo('mssql','sa', '1234567890@Eu', 'testing_db', 'localhost')); + parent::__construct(new ConnectionInfo('mssql','sa', '1234567890@Eu', 'testing_db', SQL_SERVER_HOST)); $table00 = new MSSQLTable('users'); $table00->setComment('This table is used to hold users info.'); diff --git a/webfiori/database/mssql/MSSQLConnection.php b/webfiori/database/mssql/MSSQLConnection.php index 12517cc..a4bde2a 100644 --- a/webfiori/database/mssql/MSSQLConnection.php +++ b/webfiori/database/mssql/MSSQLConnection.php @@ -208,14 +208,15 @@ private function setSqlErr() { $allErrs = sqlsrv_errors(SQLSRV_ERR_ERRORS); $lastErr = $allErrs[count($allErrs) - 1]; - if (strpos($lastErr['message'], 'The statement has been terminated') === true) { + if ($lastErr['SQLSTATE'] == '01000' && $lastErr['code'] == 3621) { $lastErr = $allErrs[count($allErrs) - 2]; $this->sqlState = $lastErr['SQLSTATE']; - $this->setErrMessage($lastErr['message']); + $this->setErrMessage('The statement has been terminated due to following: '.$lastErr['message']); + $this->setErrCode($lastErr['code']); } else if ($lastErr['SQLSTATE'] == '42000' && $lastErr['code'] == 8180) { $lastErr = $allErrs[count($allErrs) - 2]; $this->sqlState = $lastErr['SQLSTATE']; - $this->setErrMessage('Statement(s) could not be prepared: '.$lastErr['message']); + $this->setErrMessage('Statement(s) could not be prepared due to the following: '.$lastErr['message']); $this->setErrCode($lastErr['code']); } else { $this->setErrCode($lastErr['code']);