From 1885d1505095c5b86e7249e01dd056d9e222c29b Mon Sep 17 00:00:00 2001
From: Carsten  Rose <carsten.rose@math.uzh.ch>
Date: Thu, 28 Apr 2016 22:29:07 +0200
Subject: [PATCH] #1925: Report: <level>.line.total sollte bei INSERT
 affected_rows enthalten Report.php, Database.php: triggerReport() supports
 stat[] with num_rows, affected_rows and insert_id. rowTotal does not contain
 anymore inserId (last_insert_id) from fired INSERT queries. Instead num_rows
 or affected_rows are choosen. New: <level>.line.inserId contains the
 insertId.

---
 extension/Documentation/UsersManual/Index.rst | 12 ++++----
 extension/qfq/qfq/Constants.php               |  8 ++++-
 extension/qfq/qfq/Database.php                | 29 ++++++++++++-------
 extension/qfq/qfq/report/Report.php           | 11 ++++---
 extension/qfq/tests/phpunit/DatabaseTest.php  | 23 ++++++++++-----
 5 files changed, 55 insertions(+), 28 deletions(-)

diff --git a/extension/Documentation/UsersManual/Index.rst b/extension/Documentation/UsersManual/Index.rst
index 73c922fe9..0dbf8b674 100644
--- a/extension/Documentation/UsersManual/Index.rst
+++ b/extension/Documentation/UsersManual/Index.rst
@@ -989,16 +989,16 @@ Syntax
 
         Variables from specific stores: {{<name>[:<store/s>[:<sanitize class>]]}}
 
-        Row index and total rows: {{<level>.line.count}} or {{<level>.line.total}}
+        Current row index: {{<level>.line.count}}
 
-        'last_insert_id' and 'affected_rows': {{<level>.line.total}} (*total* may have a different meaning, depending on the type of the SQL command)
+        Total rows (num_rows for SELECT and SHOW, affected_rows for UPDATE and INSERT): {{<level>.line.total}}
 
-        See :ref:`variables` for a full list of all available variables.
+        Last insert id for INSERT: {{<level>.line.insertId}}
 
-    Be aware of the following restrictions to {{<level>.line.count}} or {{<level>.line.total}}:
+        See :ref:`variables` for a full list of all available variables.
 
-       line.count / line.total have to be known when the query is fired. E.g. `10.sql = SELECT {{10.line.count}}, ... WHERE {{10.line.count}} = ...`
-       won't work as expected. `{{10.line.count}}` can't be replaced before the query is fired, but will be replaced during processing the result!
+    Be aware that line.count / line.total have to be known before the query is fired. E.g. `10.sql = SELECT {{10.line.count}}, ... WHERE {{10.line.count}} = ...`
+    won't work as expected. `{{10.line.count}}` can't be replaced before the query is fired, but will be replaced during processing the result!
 
 
     Different types of SQL queries are possible: SELECT, INSERT, UPDATE, DELETE, SHOW
diff --git a/extension/qfq/qfq/Constants.php b/extension/qfq/qfq/Constants.php
index 443a62aec..3e356854b 100644
--- a/extension/qfq/qfq/Constants.php
+++ b/extension/qfq/qfq/Constants.php
@@ -405,4 +405,10 @@ const FILES_FLAG_DELETE = 'flagDelete';
 const UPLOAD_CACHED = '.cached';
 const FILE_ACTION = 'action';
 const FILE_ACTION_UPLOAD = 'upload';
-const FILE_ACTION_DELETE = 'delete';
\ No newline at end of file
+const FILE_ACTION_DELETE = 'delete';
+
+// DATABASE
+const DB_NUM_ROWS = 'numRows';
+const DB_AFFECTED_ROWS = 'affectedRows';
+const DB_INSERT_ID = 'insertId';
+
diff --git a/extension/qfq/qfq/Database.php b/extension/qfq/qfq/Database.php
index 326245503..9d2fb57f3 100644
--- a/extension/qfq/qfq/Database.php
+++ b/extension/qfq/qfq/Database.php
@@ -208,7 +208,7 @@ class Database {
      * @throws \qfq\CodeException
      * @throws \qfq\DbException
      */
-    public function sql($sql, $mode = ROW_REGULAR, array $parameterArray = array(), $specificMessage = '', array &$keys = array()) {
+    public function sql($sql, $mode = ROW_REGULAR, array $parameterArray = array(), $specificMessage = '', array &$keys = array(), array &$stat = array()) {
         $queryType = '';
         $result = array();
         $this->closeMysqliStmt();
@@ -221,7 +221,8 @@ class Database {
         if ($specificMessage)
             $specificMessage .= " ";
 
-        $count = $this->prepareExecute($sql, $parameterArray, $queryType);
+        $count = $this->prepareExecute($sql, $parameterArray, $queryType, $stat);
+
         if ($count === false) {
             throw new DbException($specificMessage . "No idea why this error happens - please take some time and check this: $sql", ERROR_DB_GENERIC_CHECK);
         }
@@ -297,18 +298,20 @@ class Database {
     /**
      * Execute a prepared SQL statement like SELECT, INSERT, UPDATE, DELETE, SHOW, ...
      *
-     * Returns the number of selected rows (SELECT, SHOW, ..) or the affected rows (UPDATE) or the last insert id (INSERT)
+     * Returns the number of selected rows (SELECT, SHOW, ..) or the affected rows (UPDATE, INSERT). $stat contains appropriate num_rows, insert_id or rows_affected.
      *
      * @param string $sql SQL statement with prepared statement variable.
      * @param array $parameterArray parameter array for prepared statement execution.
      * @param string $queryType returns QUERY_TYPE_SELECT | QUERY_TYPE_UPDATE | QUERY_TYPE_INSERT, depending on the query.
+     * @param array $stat
      * @return int|mixed
      * @throws \qfq\CodeException
      * @throws \qfq\DbException
      * @throws \qfq\UserFormException
      */
-    private function prepareExecute($sql, array $parameterArray = array(), &$queryType = '') {
+    private function prepareExecute($sql, array $parameterArray = array(), &$queryType, array &$stat) {
         $result = 0;
+        $stat = array();
         $this->store->setVar(SYSTEM_SQL_FINAL, $sql, STORE_SYSTEM);
         $this->store->setVar(SYSTEM_SQL_PARAM_ARRAY, $parameterArray, STORE_SYSTEM);
 
@@ -343,19 +346,23 @@ class Database {
                 }
             $queryType = QUERY_TYPE_SELECT;
                 $this->mysqli_result = $result;
-                $count = $this->mysqli_result->num_rows;
-            $msg = 'Read rows: ' . $count;
+            $stat[DB_NUM_ROWS] = $this->mysqli_result->num_rows;
+            $count = $stat[DB_NUM_ROWS];
+            $msg = 'Read rows: ' . $stat[DB_NUM_ROWS];
                 break;
             case 'INSERT':
                 $queryType = QUERY_TYPE_INSERT;
-                $count = $this->mysqli->insert_id;
+                $stat[DB_INSERT_ID] = $this->mysqli->insert_id;
+                $stat[DB_AFFECTED_ROWS] = $this->mysqli->affected_rows;
+                $count = $stat[DB_AFFECTED_ROWS];
                 $msg = 'ID: ' . $count;
                 break;
             case 'UPDATE':
             case 'REPLACE':
             case 'DELETE':
             $queryType = QUERY_TYPE_UPDATE;
-                $count = $this->mysqli->affected_rows;
+            $stat[DB_AFFECTED_ROWS] = $this->mysqli->affected_rows;
+            $count = $stat[DB_AFFECTED_ROWS];
                 $msg = 'Affected rows: ' . $count;
                 break;
             default:
@@ -508,12 +515,14 @@ class Database {
      *
      * @param $sql
      * @param array $keys
+     * @param array $stat
      * @return array|bool
+     * @throws \qfq\CodeException
      * @throws \qfq\DbException
      */
-    public function sqlKeys($sql, array &$keys) {
+    public function sqlKeys($sql, array &$keys, array &$stat = array()) {
 
-        return $this->sql($sql, ROW_KEYS, array(), '', $keys);
+        return $this->sql($sql, ROW_KEYS, array(), '', $keys, $stat);
     }
 
     /**
diff --git a/extension/qfq/qfq/report/Report.php b/extension/qfq/qfq/report/Report.php
index c98235783..4f73ad1d2 100644
--- a/extension/qfq/qfq/report/Report.php
+++ b/extension/qfq/qfq/report/Report.php
@@ -316,6 +316,7 @@ class Report {
 
     private function triggerReport($cur_level = 1, array $super_level_array = array(), $counter = 0) {
         $keys = array();
+        $stat = array();
 
         $lineDebug = 0;
         $content = "";
@@ -370,15 +371,17 @@ class Report {
 
             //Execute SQL. All errors have been already catched.
             unset($result);
-            $result = $this->db->sqlKeys($sql, $keys);
+            $result = $this->db->sqlKeys($sql, $keys, $stat);
 
             // If an array is returned, $sql was a query, otherwise an 'insert', 'update', 'delete', ...
             // Query: total nummber of rows
-            // insert: last_insert_id
-            // delete, update: number of affected rows
-            $rowTotal = is_array($result) ? count($result) : $result;
+            // insert, delete, update: number of affected rows
+            $rowTotal = isset($stat[DB_NUM_ROWS]) ? $stat[DB_NUM_ROWS] : $stat[DB_AFFECTED_ROWS];
 
             $this->variables->resultArray[$full_level . ".line."]["total"] = $rowTotal;
+            if (isset($stat[DB_INSERT_ID])) {
+                $this->variables->resultArray[$full_level . ".line."]["insertId"] = $stat[DB_INSERT_ID];
+            }
 
             // HEAD: If there is at least one record, do 'head'.
             if ($rowTotal > 0)
diff --git a/extension/qfq/tests/phpunit/DatabaseTest.php b/extension/qfq/tests/phpunit/DatabaseTest.php
index f0594a275..ef5b36bcf 100644
--- a/extension/qfq/tests/phpunit/DatabaseTest.php
+++ b/extension/qfq/tests/phpunit/DatabaseTest.php
@@ -137,6 +137,9 @@ class DatabaseTest extends AbstractDatabaseTest {
      * @throws \qfq\DbException
      */
     public function testQuerySimpleParameter() {
+        $stat = array();
+        $dummy = array();
+
         // Parameter Susbstitution by '?'
         $dataArray = $this->db->sql('SELECT * FROM Person WHERE name LIKE ? ORDER BY id', ROW_REGULAR, ['Smith']);
         // Check count
@@ -145,11 +148,13 @@ class DatabaseTest extends AbstractDatabaseTest {
         $dataArray = $this->db->sql('UPDATE Person SET groups = ?', ROW_REGULAR, ['a,b,c']);
         $this->assertEquals(2, $this->store->getVar(SYSTEM_SQL_COUNT, STORE_SYSTEM));
 
-        $dataArray = $this->db->sql('INSERT INTO Person (`name`, `firstname`, `groups`) VALUES ( ?, ? ,? )', ROW_REGULAR, ['Meier', 'John', 'a']);
-        $this->assertEquals(3, $this->store->getVar(SYSTEM_SQL_COUNT, STORE_SYSTEM));
+        $dataArray = $this->db->sql('INSERT INTO Person (`name`, `firstname`, `groups`) VALUES ( ?, ? ,? )', ROW_REGULAR, ['Meier', 'John', 'a'], 'fake', $dummy, $stat);
+        $this->assertEquals(1, $this->store->getVar(SYSTEM_SQL_COUNT, STORE_SYSTEM));
+        $this->assertEquals(3, $stat[DB_INSERT_ID]);
 
-        $dataArray = $this->db->sql('INSERT INTO Person (`name`, `firstname`, `groups`) VALUES ( ?, ? ,? )', ROW_REGULAR, ['Meier', 'Jan', 'b']);
-        $this->assertEquals(4, $this->store->getVar(SYSTEM_SQL_COUNT, STORE_SYSTEM));
+        $dataArray = $this->db->sql('INSERT INTO Person (`name`, `firstname`, `groups`) VALUES ( ?, ? ,? )', ROW_REGULAR, ['Meier', 'Jan', 'b'], 'fake', $dummy, $stat);
+        $this->assertEquals(1, $this->store->getVar(SYSTEM_SQL_COUNT, STORE_SYSTEM));
+        $this->assertEquals(4, $stat[DB_INSERT_ID]);
 
         $dataArray = $this->db->sql('DELETE FROM Person WHERE name = ?', ROW_REGULAR, ['Meier']);
         $this->assertEquals(2, $this->store->getVar(SYSTEM_SQL_COUNT, STORE_SYSTEM));
@@ -224,11 +229,13 @@ class DatabaseTest extends AbstractDatabaseTest {
      * @throws \qfq\DbException
      */
     public function testGetLastInsertId() {
+        $dummy = array();
+        $stat = array();
 
         $sql = "INSERT INTO Person (id, name, firstname, gender, groups) VALUES (NULL, 'Doe', 'Jonni', 'male','')";
 
-        $this->db->sql($sql);
-        $this->assertEquals(3, $this->store->getVar(SYSTEM_SQL_COUNT, STORE_SYSTEM));
+        $this->db->sql($sql, ROW_REGULAR, $dummy, 'fake', $dummy, $stat);
+        $this->assertEquals(3, $stat[DB_INSERT_ID]);
     }
 
     /**
@@ -255,7 +262,8 @@ class DatabaseTest extends AbstractDatabaseTest {
             ['0' => '2', '1' => 'Smith', '2' => '0'],
         ];
         // Same as above, but specify 'ROW_REGULAR'
-        $dataArray = $this->db->sqlKeys('SELECT id AS "id", name, "0" AS "id" FROM Person ORDER BY id LIMIT 3', $keys);
+        $stat = array();
+        $dataArray = $this->db->sqlKeys('SELECT id AS "id", name, "0" AS "id" FROM Person ORDER BY id LIMIT 3', $keys, $stat);
 
         // Check rows
         $this->assertEquals($expected, $dataArray);
@@ -263,6 +271,7 @@ class DatabaseTest extends AbstractDatabaseTest {
         // Check keys
         $this->assertEquals(['id', 'name', 'id'], $keys);
     }
+
     /**
      * @throws Exception
      */
-- 
GitLab