简体   繁体   中英

Fatal Error in mysqli prepared statement

I am trying to learn how to do a prepared statement using some example code below.

I have an initial SQL statement, and for each record returned by that, do another SQL check against the results returned.

<?php

$sql_b = "SELECT fld_title, fld_tag FROM j_oracle_cat WHERE fld_tag IS NOT NULL ORDER BY fld_title";

if (!$result_b = $conn -> query($sql_b)) {

    die('There was an error running the query [' . $conn -> error . ']');

} else {

    if (!$result_b -> num_rows) {

        echo "<h4>No Categories Defined</h4>";

    } else {

        while($row_b = $result_b -> fetch_assoc()) {

            $cat_ttl = $row_b["fld_title"];
            $cat_tag = $row_b["fld_tag"];

            echo "<h4><a href='category.php?tag=" . $cat_tag . "'>" . $cat_ttl . "</a></h4>";

            $sql_c = "SELECT p.fld_tag FROM j_oracle_cat c, j_oracle_pages p WHERE c.fld_id = p.fld_catid AND c.fld_tag = ?";

            /* Prepare statement */
            $stmt = $conn->prepare($sql_c);
            if($stmt === false) {
                trigger_error('Wrong SQL: ' . $sql_c . '<hr />Error: ' . $conn->error, E_USER_ERROR);
            }

            /* Bind parameters. Types: s = string, i = integer, d = double,  b = blob */
            $stmt->bind_param('s',$cat_tag);

            /* Execute statement */
            $stmt->execute();                       

        }

        $result_b -> free();

    }

}

?>

When I run the code, it gets this far:

<h4><a href='category.php?tag=accounts-payable'>Accounts Payable</a></h4>
<h4><a href='category.php?tag=accounts-receivable'>Accounts Receivable</a></h4>

But then errors with:

Fatal error : Wrong SQL: SELECT p.fld_is_parent FROM j_oracle_cat c, j_oracle_pages p WHERE c.fld_id = p.fld_catid AND c.fld_tag = ? Error: in C:\\xampp\\htdocs\\php\\a.php on line 95

Line 95 is this one:

trigger_error('Wrong SQL: ' . $sql_c . '<hr />Error: ' . $conn->error, E_USER_ERROR);

Table structure:

CREATE TABLE `j_oracle_cat` (
  `fld_id` int(11) NOT NULL AUTO_INCREMENT,
  `fld_title` varchar(255) DEFAULT NULL,
  `fld_desc` varchar(255) DEFAULT NULL,
  `fld_tag` varchar(255) DEFAULT NULL,
  `fld_label` varchar(255) DEFAULT NULL,
  `fld_parent` int(2) DEFAULT '0',
  PRIMARY KEY (`fld_id`)
) ENGINE=MyISAM AUTO_INCREMENT=16 DEFAULT CHARSET=latin1

CREATE TABLE `j_oracle_pages` (
  `fld_id` int(11) NOT NULL AUTO_INCREMENT,
  `fld_title` varchar(255) DEFAULT NULL,
  `fld_catid` int(11) DEFAULT NULL,
  `fld_cols` int(2) DEFAULT '1',
  `fld_left` text,
  `fld_content` text,
  `fld_tag` varchar(255) DEFAULT NULL,
  `fld_date` date DEFAULT NULL,
  `fld_is_parent` char(1) DEFAULT NULL,
  PRIMARY KEY (`fld_id`)
) ENGINE=MyISAM AUTO_INCREMENT=83 DEFAULT CHARSET=latin1

I have tried running the sql direct and it does not error, for a sample tag and it returns eg 3 rows:

SELECT p.fld_tag FROM j_oracle_cat c, j_oracle_pages p WHERE c.fld_id = p.fld_catid AND c.fld_tag = 'accounts-receivable';

Connection to db:

<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);

$servername = "localhost";
$username = "root";
$password = "";
$dbname = "mydb";

// Create connection
$conn = new mysqli($servername, $username, $password, $dbname);

if($conn -> connect_errno > 0){
    die('Unable to connect to database [' . $conn->connect_error . ']');
}

?>

Presumably I am doing something silly, but I can't see what?

So here are my recommendations; I don't see anything obviously wrong with your code, but these steps should make it easier to diagnose the problem, if not fix it outright. First, move the prepare() call out of the loop*. Next, explicitly create the statement object , so that if there's a problem with preparation you can get the error directly from the statement object. Finally, check for a valid return during every stage of the process, including parameter binding and statement execution .

$sql_b = "SELECT fld_title, fld_tag FROM j_oracle_cat WHERE fld_tag IS NOT NULL ORDER BY fld_title";
if (!$result_b = $conn->query($sql_b)) {
    trigger_error("Error executing query: $conn->error<br/>SQL query: $sql_b", E_USER_ERROR);
} else {
    if (!$result_b->num_rows) {
        echo "<h4>No Categories Defined</h4>";
    } else {
        /* Prepare statement */
        $sql_c = "SELECT p.fld_tag FROM j_oracle_cat c, j_oracle_pages p WHERE c.fld_id = p.fld_catid AND c.fld_tag = ?";    
        $stmt = $conn->stmt_init();
        if (!$stmt) {
            trigger_error("Error creating statement: $conn->error", E_USER_ERROR);
        }
        $result = $stmt->prepare($sql_c);
        if(!$result) {
            trigger_error("Error preparing statement: $stmt->error<br/>SQL query: $sql_c", E_USER_ERROR);
        }
        /* Bind parameters. Types: s = string, i = integer, d = double,  b = blob */
        // needs a dummy value for the initial bind
        $row_b = array("fld_tag"=>"");
        $result = $stmt->bind_param("s", $row_b["fld_tag"]);
        if(!$result) {
            trigger_error("Error binding parameter: $stmt->error<br/>", E_USER_ERROR);
        }

        while($row_b = $result_b -> fetch_assoc()) {
            $cat_ttl = htmlspecialchars($row_b["fld_title"]);
            $cat_tag = htmlspecialchars($row_b["fld_tag"]);
            echo "<h4><a href='category.php?tag=$cat_tag'>$cat_ttl</a></h4>";
            /* Execute statement */
            $result = $stmt->execute();
            if(!$result) {
                trigger_error("Error executing statement: $stmt->error<br/>Bound parameter value: $row_b[fld_tag]", E_USER_ERROR);
            }
            // I assume you'll be doing something with $result down here?
        }
        $result_b->free();
        $stmt->close();
    }
}

Couple of side notes: You should always escape database results with htmlspecialchars() before putting them into HTML, to avoid risk of injections. You can use double quotes to include variables inside strings, and avoid having dozens of unnecessary . operators everywhere. This is a matter of personal preference, but many find it more readable.

*One of the big benefits of prepared statements is that they separate the preparation of the query from its execution , avoiding the overhead involved in setting up MySQL to run the query. By repeatedly preparing a statement, you remove that benefit entirely.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM