From 91551c70abbc9c7436344cf2a0e0aa0e233c3c42 Mon Sep 17 00:00:00 2001 From: Ibrahim BinAlshikh Date: Tue, 4 Nov 2025 00:29:29 +0300 Subject: [PATCH] feat: Result Set Even for Other Type of Queries --- WebFiori/Database/Database.php | 22 ++++++--- WebFiori/Database/MsSql/MSSQLConnection.php | 13 ++++- WebFiori/Database/MySql/MySQLConnection.php | 48 ++++++++++--------- .../Database/MsSql/MSSQLQueryBuilderTest.php | 24 ++++++++++ .../Database/MySql/MySQLQueryBuilderTest.php | 24 ++++++++++ 5 files changed, 102 insertions(+), 29 deletions(-) diff --git a/WebFiori/Database/Database.php b/WebFiori/Database/Database.php index a3c77855..5b6d4c29 100644 --- a/WebFiori/Database/Database.php +++ b/WebFiori/Database/Database.php @@ -351,13 +351,9 @@ public function execute() { throw new DatabaseException($conn->getLastErrCode().' - '.$conn->getLastErrMessage(), $conn->getLastErrCode()); } $this->queries[] = $lastQuery; - $lastQueryType = $this->getQueryGenerator()->getLastQueryType(); $this->clear(); - $resultSet = null; - - if (in_array($lastQueryType, ['select', 'show', 'describe'])) { - $resultSet = $this->getLastResultSet(); - } + $resultSet = $this->getLastResultSet(); + $this->getQueryGenerator()->setQuery(null); // Record performance metrics @@ -808,6 +804,20 @@ public function setPerformanceConfig(array $config): void { * @throws DatabaseException */ public function setQuery(string $query) : Database { + + return $this->raw($query); + } + /** + * Sets the database query to a raw SQL query. + * + * @param string $query A string that represents the query. + * + * @return Database The method will return the same instance at which the + * method is called on. + * + * @throws DatabaseException + */ + public function raw(string $query) : Database { $t = $this->getQueryGenerator()->getTable(); if ($t !== null) { diff --git a/WebFiori/Database/MsSql/MSSQLConnection.php b/WebFiori/Database/MsSql/MSSQLConnection.php index 64ea93a3..1bc91dfc 100644 --- a/WebFiori/Database/MsSql/MSSQLConnection.php +++ b/WebFiori/Database/MsSql/MSSQLConnection.php @@ -244,6 +244,17 @@ private function runOtherQuery() { $this->setSqlErr(); return false; + } else { + + + if (sqlsrv_has_rows($r)) { + $data = []; + while ($row = sqlsrv_fetch_array($r, SQLSRV_FETCH_ASSOC)) { + $data[] = $row; + } + $this->setResultSet(new ResultSet($data)); + } + } return true; @@ -258,7 +269,7 @@ private function runSelectQuery() { if (is_resource($r)) { $data = []; - while ($row = sqlsrv_fetch_array($r,SQLSRV_FETCH_ASSOC)) { + while ($row = sqlsrv_fetch_array($r, SQLSRV_FETCH_ASSOC)) { $data[] = $row; } $this->setResultSet(new ResultSet($data)); diff --git a/WebFiori/Database/MySql/MySQLConnection.php b/WebFiori/Database/MySql/MySQLConnection.php index 9b39fc3e..104a5b8f 100644 --- a/WebFiori/Database/MySql/MySQLConnection.php +++ b/WebFiori/Database/MySql/MySQLConnection.php @@ -274,12 +274,13 @@ private function runInsertQuery() { } private function runOtherQuery() { $query = $this->getLastQuery()->getQuery(); - $retVal = false; $sql = $this->getLastQuery()->getQuery(); $params = $this->getLastQuery()->getBindings()['bind']; $values = array_merge($this->getLastQuery()->getBindings()['values']); + $r = false; + if (count($values) != 0 && !empty($params)) { // Count the number of ? placeholders in the SQL $paramCount = substr_count($sql, '?'); @@ -288,7 +289,8 @@ private function runOtherQuery() { if ($paramCount == count($values) && strlen($params) == count($values)) { $sqlStatement = mysqli_prepare($this->link, $sql); $sqlStatement->bind_param($params, ...$values); - $r = $sqlStatement->execute(); + $sqlStatement->execute(); + $r = $sqlStatement->get_result(); if ($sqlStatement) { mysqli_stmt_close($sqlStatement); @@ -298,37 +300,39 @@ private function runOtherQuery() { $r = mysqli_query($this->link, $sql); } } else { - if (!$this->getLastQuery()->isMultiQuery()) { - $r = mysqli_query($this->link, $query); - } else { - $r = mysqli_multi_query($this->link, $query); - - // Clean up multi-query results to prevent "Commands out of sync" - if ($r) { - while (mysqli_next_result($this->link)) { - // Consume all result sets - } - } - } + $r = mysqli_query($this->link, $query); } - - if (!$r) { $this->setErrMessage($this->link->error); $this->setErrCode($this->link->errno); + return false; } else { $this->setErrMessage('NO ERRORS'); $this->setErrCode(0); $this->getLastQuery()->setIsBlobInsertOrUpdate(false); - $retVal = true; - } - - if ($r === true || gettype($r) == 'object') { - $retVal = true; + + // Handle result sets + + if (gettype($r) == 'object' && method_exists($r, 'fetch_assoc')) { + $data = []; + while ($row = $r->fetch_assoc()) { + $data[] = $row; + } + $this->setResultSet(new ResultSet($data)); + mysqli_free_result($r); + } + + // Clean up any additional result sets (for stored procedures) + while (mysqli_more_results($this->link)) { + mysqli_next_result($this->link); + if ($result = mysqli_store_result($this->link)) { + mysqli_free_result($result); + } + } } - return $retVal; + return true; } private function runSelectQuery() { $sql = $this->getLastQuery()->getQuery(); diff --git a/tests/WebFiori/Tests/Database/MsSql/MSSQLQueryBuilderTest.php b/tests/WebFiori/Tests/Database/MsSql/MSSQLQueryBuilderTest.php index aff410c7..edf18069 100644 --- a/tests/WebFiori/Tests/Database/MsSql/MSSQLQueryBuilderTest.php +++ b/tests/WebFiori/Tests/Database/MsSql/MSSQLQueryBuilderTest.php @@ -1324,4 +1324,28 @@ public function testAfreggate07() { ->groupBy('function'); $this->assertEquals('select [reports_list].[function], count(*) as count from [reports_list] group by [reports_list].[function] order by [reports_list].[count]', $schema->getLastQuery()); } + /** + * @test + */ + public function testStoredProcedureExecution() { + $schema = new MSSQLTestSchema(); + + // Clean up first in case procedure exists + $schema->raw("IF OBJECT_ID('GetUserCount', 'P') IS NOT NULL DROP PROCEDURE GetUserCount")->execute(); + + // Create stored procedure that returns results + $schema->raw("CREATE PROCEDURE GetUserCount AS BEGIN SELECT COUNT(*) as user_count FROM users END")->execute(); + + // Execute stored procedure - this should call runOtherQuery and return results + $result = $schema->raw("EXEC GetUserCount")->execute(); + $this->assertInstanceOf('WebFiori\\Database\\ResultSet', $result); + + $this->assertEquals(1, $result->getRowsCount()); + $row = $result->getRows()[0]; + $this->assertArrayHasKey('user_count', $row); + $this->assertIsInt($row['user_count']); + + // Clean up + $schema->raw("DROP PROCEDURE GetUserCount")->execute(); + } } diff --git a/tests/WebFiori/Tests/Database/MySql/MySQLQueryBuilderTest.php b/tests/WebFiori/Tests/Database/MySql/MySQLQueryBuilderTest.php index c07f2c2c..4f45343c 100644 --- a/tests/WebFiori/Tests/Database/MySql/MySQLQueryBuilderTest.php +++ b/tests/WebFiori/Tests/Database/MySql/MySQLQueryBuilderTest.php @@ -2179,4 +2179,28 @@ public function testAggregate06() { $q->table('users')->selectCount('id'); $this->assertEquals('select count(`users`.`id`) as `count` from `users`', $q->getQuery()); } + /** + * @test + */ + public function testStoredProcedureExecution() { + $schema = new MySQLTestSchema(); + + // Clean up first in case procedure exists + $schema->raw("DROP PROCEDURE IF EXISTS GetUserCount")->execute(); + + // Create stored procedure that returns results + $schema->raw("CREATE PROCEDURE GetUserCount() BEGIN SELECT COUNT(*) as user_count FROM users; END")->execute(); + + // Execute stored procedure - this should call runOtherQuery and return results + $result = $schema->raw("CALL GetUserCount()")->execute(); + $this->assertInstanceOf('WebFiori\\Database\\ResultSet', $result); + + $this->assertEquals(1, $result->getRowsCount()); + $row = $result->getRows()[0]; + $this->assertArrayHasKey('user_count', $row); + $this->assertIsNumeric($row['user_count']); + + // Clean up + $schema->raw("DROP PROCEDURE GetUserCount")->execute(); + } }