mysqli подготовил оператор UPDATE, не обновляющий значения в базе данных - PullRequest
2 голосов
/ 25 июня 2019

После поиска и обращения к различным частям документации я не могу понять, что я делаю неправильно.

Что я пытаюсь сделать

Япытаюсь выполнить подготовленный оператор обновления для базы данных, используя следующую функцию:

function _UPDATE_IP_BAD(&$mysqli, $id_of_ip, &$value){

    ini_set('display_errors', 1); ini_set('log_errors',1); error_reporting(E_ALL); mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);

    $timestamp = time();

    //  UPDATE `dbmxpca_ipinfo`.`list` SET `is_bad` = '0.0111000000000000000', `cached_bad` = '1553849540' WHERE (`id` = '2');
    $exec_data = array();

    $prepare = "UPDATE dbmxpca_ipinfo.list SET `is_bad`=?, `cached_bad`=? WHERE `id`=?";
    //$prepare = 'UPDATE dbmxpca_ipinfo.list SET `is_bad`=?, `cached_bad`=? WHERE `id`=?;';
    //$prepare = 'UPDATE dbmxpca_ipinfo.list SET is_bad=?, cached_bad=? WHERE id=?;';



    // $prepare = 'UPDATE `dbmxpca_ipinfo`.`list` SET is_bad=?, cached_bad=? WHERE id=?;';


    //$prepare = 'UPDATE `dbmxpca_ipinfo`.`list` SET ( `is_bad`, `cached_bad` ) VALUES (?, ?) WHERE (`id`=' . $id_of_ip . ');';

    //$prepare = 'UPDATE `dbmxpca_ipinfo`.`list` SET ( `is_bad`, `cached_bad` ) VALUES (?, ?) WHERE (`id`=' . $id_of_ip . ');';
    //$prepare = 'UPDATE `dbmxpca_ipinfo`.`list` SET `is_bad`=?, `cached_bad`=? WHERE (`id`=?);';

    //$prepare = 'UPDATE `dbmxpca_ipinfo`.`list` SET `is_bad`=?, `cached_bad`=? WHERE (`id`=?);';
    //$prepare = 'UPDATE `dbmxpca_ipinfo`.`list` SET `is_bad` = ?, `cached_bad` = ? WHERE (`id` = ?);';
    // $prepare = 'UPDATE `dbmxpca_ipinfo`.`list` SET `is_bad` = \'?\', `cached_bad` = \'?\' WHERE (`id` = \'?\');';
    //$bind_types = 'iii';
    $bind_types = 'dii';
    //$bind_types = 'idi';
    // $bind_types = 'di';
    //$bind_values = array($value, $timestamp);
    $bind_values = array($value, $timestamp, $id_of_ip);
    $exec_result = DB_EXEC2($mysqli, $prepare, $bind_types, $bind_values, $exec_data);

    if ($exec_result){

        return true;
    }

    return false;
}

Я вызываю его так:

UPDATE_IP_BAD($mysqli, 2, 0);

($ mysqliуже определено и инициализировано в другом месте).

Проблема

Проблема в том, что DB_EXEC2 () сообщает об успешном запросе (затронуты 1 строка, как и должно быть),но ни одно из двух значений не обновляется в базе данных. Об ошибках не сообщается, но значения базы данных остаются неизменными.Я что-то не так делаю?

Я пробовал МНОГИЕ разные способы написания подготовленного оператора (все закомментированные строки не работали), а также не закомментированный.Я даже экспериментировал с различными типами связывания (целое число против двойного), но все безрезультатно.Я смотрю на это часами и совершенно не понимаю, в чем проблема.Даже добавление дополнительных отчетов об ошибках в верхней части функции, как я видел, не вызывало ошибок.

DB_EXEC2 () - это пользовательская функция для выполнения подготовленного оператора.Он записывает результаты действий в файл.Определение функции выглядит следующим образом:

function DB_EXEC2(&$mysqli, $prepare, $bind_types, &$bind_values, &$result_data = null){

    //  Get number of bind types.
    $nBindTypeCount = strlen($bind_types);

    //  Get number of bind values.
    $nBindValCount = count($bind_values);

    //  Make sure they match.
    if ($nBindTypeCount != $nBindValCount){

        $errmsg = 'DB_EXEC2 Error: [Number of bind types does not match number of bind parameters].';
        if (ENABLE_LOG_DB){
            \SYSTEM\DBMSLOG2(DB_LOGNAME, 'ERROR', $errmsg);
        }

        return false;
    }

    //  Prepare
    $stmt = $mysqli->prepare($prepare);
    if ($stmt === false){

        //  ------------ Prepared statement error ------------

        $errmsg = 'SQL Prepared-Statement Error: [' . $mysqli->errno . ': ' . $mysqli->error . '].';
        if (ENABLE_LOG_DB){
            \SYSTEM\DBMSLOG2(DB_LOGNAME, 'ERROR', $errmsg);
        }

        $stmt->close();

        return false;
    }

    //  Make array of all params.
    $fparams = array();
    array_push($fparams, $bind_types);
    foreach($bind_values as $bvk){
        array_push($fparams, $bvk);
    }
    //  "hack" for a function I don't like: call_user_func_array().
    $ptrParams = array();
    $nParamCount = count($fparams);
    for ($i = 0; $i < $nParamCount; $i++){
        $ptrParams[$i] = &$fparams[$i];
    }

    //  Dump values to log file for debugging.
    if (ENABLE_LOG_DB){

        \SYSTEM\DBMSLOG2(DB_LOGNAME, 'INFO', 'ptrParams Dump:');
        \SYSTEM\DBMSLOG2(DB_LOGNAME, 'INFO', '-----------------------');
        foreach ($ptrParams as $ptrParamsK){
            \SYSTEM\DBMSLOG2(DB_LOGNAME, 'INFO', '  ' . $ptrParamsK);
        }
        \SYSTEM\DBMSLOG2(DB_LOGNAME, 'INFO', '-----------------------');
    }

    //  Bind.
    call_user_func_array(array($stmt, 'bind_param'), $ptrParams);

    //  Attempt to execute.
    if ($stmt->execute() === true){

        //  ------------ Execution success ------------

        $errmsg = 'SQL execution successful:';
        if (ENABLE_LOG_DB){

            $errmsg = 'SQL execution successful.';
            \SYSTEM\DBMSLOG2(DB_LOGNAME, 'INFO', $errmsg);

            \SYSTEM\DBMSLOG2(DB_LOGNAME, 'INFO', 'Affected Rows = [' . $stmt->affected_rows . '].');
            \SYSTEM\DBMSLOG2(DB_LOGNAME, 'INFO', 'Error = [' . $stmt->error . '].');

        }

        //  TODO: If $result_data is null, just return true on success.     

        $result = $stmt->get_result();      
        if (!$result){

            //  ------------ GetResult Execution error ------------
            if (ENABLE_LOG_DB){
                $errmsg = 'GetResult Error: [' . $mysqli->error . ' - ' . mysqli_error($mysqli) . '].';
                \SYSTEM\DBMSLOG2(DB_LOGNAME, 'ERROR', $errmsg);
            }

            $stmt->close();
            return false;
        }
        else{

            //  ------------ GetResult Execution success ------------

            //  Create structure to store the results.
            if (!isset($result_data)){

                $result_data = array();
            }

            if (mysqli_num_rows($result) > 0){

                //  $result_data should hold all resulting rows. If we get 1 result as
                //  we normally should, all payload should be at $result_data[0].

                while($row = mysqli_fetch_assoc($result)){

                    array_push($result_data, $row);
                }

                $stmt->close();
                return true;
            }
            else{

                //  No results
                $stmt->close();
                return true;
            }
        }


        $stmt->close();

        return true;

    }
    else{

        //  ------------ Execution error ------------

        $errsql = $stmt->error;
        $errsql2 = 'N/A';
        $errmsg = 'SQL Error: [' . $errsql . ': ' . $errsql2 . '].';
        if (ENABLE_LOG_DB){
            \SYSTEM\DBMSLOG2(DB_LOGNAME, 'ERROR', $errmsg);
        }

        $stmt->close();

        return false;
    }

}

Вывод журнала (для справки):

[06/25/2019 @ 01:18:34 AM EDT] [INFO] [@DB_EXEC2]: ptrParams Dump:
[06/25/2019 @ 01:18:34 AM EDT] [INFO] [@DB_EXEC2]: -----------------------
[06/25/2019 @ 01:18:34 AM EDT] [INFO] [@DB_EXEC2]:   dii
[06/25/2019 @ 01:18:34 AM EDT] [INFO] [@DB_EXEC2]:   0
[06/25/2019 @ 01:18:34 AM EDT] [INFO] [@DB_EXEC2]:   1561439914
[06/25/2019 @ 01:18:34 AM EDT] [INFO] [@DB_EXEC2]:   2
[06/25/2019 @ 01:18:34 AM EDT] [INFO] [@DB_EXEC2]: -----------------------
[06/25/2019 @ 01:18:34 AM EDT] [INFO] [@DB_EXEC2]: SQL execution successful.
[06/25/2019 @ 01:18:34 AM EDT] [INFO] [@DB_EXEC2]: Affected Rows = [1].
[06/25/2019 @ 01:18:34 AM EDT] [INFO] [@DB_EXEC2]: Error = [].
[06/25/2019 @ 01:18:34 AM EDT] [ERROR] [@DB_EXEC2]: GetResult Error: [ - ].
[06/25/2019 @ 01:18:34 AM EDT] [INFO] [@DB_CLOSE]: Closing database connection...
[06/25/2019 @ 01:18:34 AM EDT] [INFO] [@DB_CLOSE]: Done.

** ОБНОВЛЕНИЕ 1 **

Добавлен этот код благодаря @Ваш здравый смысл:

    $stmt = DB_EXEC3($mysqli, $sql, $aParams, $strBindTypes);

    if ($stmt === true){

        \SYSTEM\DBMSLOG2(DB_LOGNAME, 'INFO', "Success!");
        return true;
    }

    \SYSTEM\DBMSLOG2(DB_LOGNAME, 'ERROR', "stmt->execute() did not return true.");
    \SYSTEM\DBMSLOG2(DB_LOGNAME, 'INFO', "-- Error ID: $stmt->errno");
    \SYSTEM\DBMSLOG2(DB_LOGNAME, 'INFO', "-- Error: $stmt->error");
    if (isset($stmt->error_list)){

        \SYSTEM\DBMSLOG2(DB_LOGNAME, 'INFO', "-- Error List:");
        foreach ($stmt->error_list as $errk => $errv){
            \SYSTEM\DBMSLOG2(DB_LOGNAME, 'INFO', "---- $errk -> $errv");
        }
    }
    \SYSTEM\DBMSLOG2(DB_LOGNAME, 'INFO', "-- Affected rows: $stmt->affected_rows");

и полученный журнал выводит следующее:

[06/25/2019 @ 04:14:25 AM EDT] [INFO] [@DB_CONNECT]: Attempting mysqli initialization... please wait.
[06/25/2019 @ 04:14:25 AM EDT] [ERROR] [@UPDATE_IP_BAD]: stmt->execute() did not return true.
[06/25/2019 @ 04:14:25 AM EDT] [INFO] [@UPDATE_IP_BAD]: -- Error ID: 0
[06/25/2019 @ 04:14:25 AM EDT] [INFO] [@UPDATE_IP_BAD]: -- Error: 
[06/25/2019 @ 04:14:25 AM EDT] [INFO] [@UPDATE_IP_BAD]: -- Error List:
[06/25/2019 @ 04:14:25 AM EDT] [INFO] [@UPDATE_IP_BAD]: -- Affected rows: 1
[06/25/2019 @ 04:14:25 AM EDT] [INFO] [@DB_CLOSE]: Closing database connection...
[06/25/2019 @ 04:14:25 AM EDT] [INFO] [@DB_CLOSE]: Done.

Таким образом, в основном, система не сообщает о каких-либо ошибках (несмотря на то, что все отчеты об ошибках включены, благодаряhttps://phpdelusions.net/mysqli/error_reporting

Кажется, можно предположить, что все прошло хорошо (затронут 1 строка), но на самом деле данные строки остаются неизменными по какой-то таинственной причине ...

Ответы [ 3 ]

0 голосов
/ 25 июня 2019

Если честно, ваши функции очень трудно читать. Позвольте мне предложить вам очень простую вспомогательную функцию mysqli , которую я написал вместо этого. С этим ваш код станет

function UPDATE_IP($mysqli, $id_of_ip, $value){
    $prepare = "UPDATE list SET `is_bad`=?, `cached_bad`=? WHERE `id`=?";
    $bind_values = array($value, time(), $id_of_ip);
    return mysqli($mysqli, $prepare, $bind_values)->affected_rows();
}

Теперь вы можете называть это так

$num_rows = UPDATE_IP_BAD($mysqli, 2, 0);
echo $num_rows;

и должно отображать количество затронутых строк.

Я только что заметил, что ipinfo.list.list не является допустимым именем таблицы, поэтому должно быть ошибкой. Вы должны правильно настроить mysqli, чтобы увидеть ошибки mysql. Пожалуйста, обратитесь к этому каноническому коду подключения mysqli Я написал, что среди прочего настраивает сообщение об ошибке. Установив его, вы сразу увидите ошибку.

0 голосов
/ 26 июня 2019

Решение

Как оказалось, была установлена ​​следующая опция: SET AUTOCOMMIT = 0 в функции DB_CONNECT() (которая не была включена в исходное сообщение). Удаление, похоже, решило проблему.

Так что, действительно, возможен третий результат (вопреки тому, что было сказано в комментариях).

0 голосов
/ 25 июня 2019

Я закомментировал части регистрации ошибок (поскольку я не хотел задавать константы, пути к файлам и т. Д.), Изменил имя таблицы, и код, кажется, работает:

UPDATE_IP_BAD($mysqli, 1, 0);

function UPDATE_IP_BAD(&$mysqli, $id_of_ip, $value){

    ini_set('display_errors', 1); ini_set('log_errors',1); error_reporting(E_ALL); mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);

    $timestamp = time();
    $exec_data = array();

    $prepare = "UPDATE list SET `is_bad`=?, `cached_bad`=? WHERE `id`=?";
    $bind_types = 'dii';
    $bind_values = array($value, $timestamp, $id_of_ip);
    $exec_result = DB_EXEC2($mysqli, $prepare, $bind_types, $bind_values, $exec_data);

    if ($exec_result){

        return true;
    }

    return false;
}



    function DB_EXEC2(&$mysqli, $prepare, $bind_types, &$bind_values, &$result_data = null)
     {

       //  Get number of bind types.
       $nBindTypeCount = strlen($bind_types);

       //  Get number of bind values.
       $nBindValCount = count($bind_values);

       //  Make sure they match.
       if ($nBindTypeCount != $nBindValCount)
        {
            $errmsg = 'DB_EXEC2 Error: [Number of bind types does not match number of bind parameters].';
          /*  if (ENABLE_LOG_DB)
              {
                 \SYSTEM\DBMSLOG2(DB_LOGNAME, 'ERROR', $errmsg);
              }
*/
             return false;
         }

          //  Prepare
         $stmt = $mysqli->prepare($prepare);
         if($stmt === false)
          {
             //  ------------ Prepared statement error ------------
             $errmsg = 'SQL Prepared-Statement Error: [' . $mysqli->errno . ': ' . $mysqli->error . '].';
           /*  if (ENABLE_LOG_DB)
              { 
                  \SYSTEM\DBMSLOG2(DB_LOGNAME, 'ERROR', $errmsg);
              } */
          $stmt->close();
          return false;
         }

         //  Make array of all params.
         $fparams = array();
         array_push($fparams, $bind_types);
         foreach($bind_values as $bvk)
          {
            array_push($fparams, $bvk);
          }

         // "hack" for a function I don't like: call_user_func_array().
         $ptrParams = array();
         $nParamCount = count($fparams);
          for ($i = 0; $i < $nParamCount; $i++)
            {
               $ptrParams[$i] = &$fparams[$i];
            }

          //  Dump values to log file for debugging.
       /*  if(ENABLE_LOG_DB)
          {
             \SYSTEM\DBMSLOG2(DB_LOGNAME, 'INFO', 'ptrParams Dump:');
              \SYSTEM\DBMSLOG2(DB_LOGNAME, 'INFO', '-----------------------');
             foreach ($ptrParams as $ptrParamsK)
               {
                    \SYSTEM\DBMSLOG2(DB_LOGNAME, 'INFO', '  ' . $ptrParamsK);
               }
              \SYSTEM\DBMSLOG2(DB_LOGNAME, 'INFO', '-----------------------');
           } */

         //  Bind.
         call_user_func_array(array($stmt, 'bind_param'), $ptrParams);

         //  Attempt to execute.
         if ($stmt->execute() === true)
           {

              //  ------------ Execution success ------------
              $errmsg = 'SQL execution successful:';
            /*  if(ENABLE_LOG_DB)
               {
                   $errmsg = 'SQL execution successful.';
                   \SYSTEM\DBMSLOG2(DB_LOGNAME, 'INFO', $errmsg);
                   \SYSTEM\DBMSLOG2(DB_LOGNAME, 'INFO', 'Affected Rows = [' . $stmt->affected_rows . '].');
                   \SYSTEM\DBMSLOG2(DB_LOGNAME, 'INFO', 'Error = [' . $stmt->error . '].');
               }
*/
        //  TODO: If $result_data is null, just return true on success.     

        $result = $stmt->get_result();      
        if (!$result){

            //  ------------ GetResult Execution error ------------
        /*    if (ENABLE_LOG_DB){
                $errmsg = 'GetResult Error: [' . $mysqli->error . ' - ' . mysqli_error($mysqli) . '].';
                \SYSTEM\DBMSLOG2(DB_LOGNAME, 'ERROR', $errmsg);
            }
 */
            $stmt->close();
            return false;
        }
        else{

            //  ------------ GetResult Execution success ------------

            //  Create structure to store the results.
            if (!isset($result_data)){

                $result_data = array();
            }

            if (mysqli_num_rows($result) > 0){

                //  $result_data should hold all resulting rows. If we get 1 result as
                //  we normally should, all payload should be at $result_data[0].

                while($row = mysqli_fetch_assoc($result)){

                    array_push($result_data, $row);
                }

                $stmt->close();
                return true;
            }
            else{

                //  No results
                $stmt->close();
                return true;
            }
        }


        $stmt->close();

        return true;

    }
    else{

        //  ------------ Execution error ------------

        $errsql = $stmt->error;
        $errsql2 = 'N/A';
        $errmsg = 'SQL Error: [' . $errsql . ': ' . $errsql2 . '].';
    /*    if (ENABLE_LOG_DB){
            \SYSTEM\DBMSLOG2(DB_LOGNAME, 'ERROR', $errmsg);
        }
*/
        $stmt->close();

        return false;
    }

}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...