Question

I am having problems executing a prepared statement via mysqli.

First I was getting Command out of sync errors. I am storing the result and closing the connection, and I have stopped getting this error, so hopefully the problem has stopped.

However, the error in my sql syntax error, which was working fine while the commands were not in sync, has reappeared. Here is my current code:

I have tried many different approaches to correct this snytax error, from Using CONCAT, which is commented out as it failed, from assigning % signs to the variable before binding etc..nothing works.

Attempting to use:

$numRecords->bind_param("s",  "%".$brand."%");

Results in an error to pass by reference.

<?php
$con = mysqli_connect("localhost", "blah", "blah", "blah");
if (!$con) {
    echo "Can't connect to MySQL Server. Errorcode: %s\n". mysqli_connect_error();
    exit;
}
$con->query("SET NAMES 'utf8'");
$brand = "o";
$brand = "% ".$brand." %";
echo "\n".$brand;
$countQuery = "SELECT ARTICLE_NO FROM AUCTIONS WHERE upper(ARTICLE_NAME) LIKE ?";
//CONCAT('%', ?, '%')";
echo "\ntest";
if ($numRecords = $con->prepare($countQuery)) {
    $numRecords->bind_param("s",  $brand);
    echo "\ntest bind";
    $numRecords->execute();
    echo "\ntest exec";
    $numRecords->store_result();
    $data = $con->query($countQuery) or die(print_r($con->error));
    $rowcount = $data->num_rows;
    $numRecords->free_result();
    $numRecords->close();
    echo "/ntest before rows";
    $rows = getRowsByArticleSearch("test", "Auctions", " ");
    $last = ceil($rowcount/$page_rows);
} else {
    print_r($con->error);
}
foreach ($rows as $row) {
    $pk = $row['ARTICLE_NO'];
    echo '<tr>' . "\n";
    echo '<td><a href="#" onclick="updateByPk(\'Layer2\', \'' . $pk . '\')">'.$row['USERNAME'].'</a></td>' . "\n";
    echo '<td><a href="#" onclick="updateByPk(\'Layer2\', \'' . $pk . '\')">'.$row['shortDate'].'</a></td>' . "\n";
    echo '<td><a href="#" onclick="deleterec(\'Layer2\', \'' . $pk . '\')">DELETE RECORD</a></td>' . "\n";
    echo '</tr>' . "\n";
}
function getRowsByArticleSearch($searchString, $table, $max) {
    $con = mysqli_connect("localhost", "blah", "blah", "blah");
    //global $con;
    $recordsQuery = "SELECT ARTICLE_NO, USERNAME, ACCESSSTARTS, ARTICLE_NAME, date_format(str_to_date(ACCESSSTARTS, '%d/%m/%Y %k:%i:%s'), '%d %m %Y' ) AS shortDate FROM $table WHERE upper(ARTICLE_NAME) LIKE '%?%' ORDER BY str_to_date(ACCESSSTARTS, '%d/%m/%Y %k:%i:%s')" . $max;
    if ($getRecords = $con->prepare($recordsQuery)) {
        $getRecords->bind_param("s", $searchString);
        $getRecords->execute();
        $getRecords->bind_result($ARTICLE_NO, $USERNAME, $ACCESSSTARTS, $ARTICLE_NAME, $shortDate);
        while ($getRecords->fetch()) {
            $result = $con->query($recordsQuery);
            $rows = array();
            while($row = $result->fetch_assoc()) {
                $rows[] = $row;
            }
            return $rows;
        }
    }
}

The exact error is:

You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '?' at line 11

Line 11 is the line defining $countQuery.

as you can see, brand is assined as "o";

So the SQL statement should be

SELECT ARTICLE_NO FROM AUCTIONS WHERE upper(ARTICLE_NAME) LIKE %o%;

Which works fine when I put it in manually.

Was it helpful?

Solution

mysqli_stmt::bind_param can only bind a specific variable, not an expression. The supplied variable is passed to 'bind' by reference, and not by value, meaning that the underlying SQL gets whatever value that variable has at the time the command is executed, not when it's bound.

Use:

WHERE field LIKE CONCAT('%', ?, '%")

or do:

$brand = '%' . $brand . '%'

immediately before the command is executed.

What you can't do is:

WHERE field LIKE '%?%

because the ? bound variable must correspond to a single string or numeric value, not to a substring (or field name).

EDIT in this case, your real problem appears to be mixing up prepared statements (as supported by mysqli::prepare and mysqli_stmt::execute()) with plain old queries (as done with mysqli::query()). You should also just ask for the number of rows directly from the DB server, rather than pull the data and use num_rows:

$countQuery = "SELECT COUNT(ARTICLE_NO) FROM AUCTIONS WHERE upper(ARTICLE_NAME) LIKE ?";
if ($numRecords = $con->prepare($countQuery)) {
    $numRecords->bind_param("s",  $brand);
    $numRecords->execute();
    $numRecords->bind_result($num_rows);
    $numRecords->fetch();
    $numRecords->free_result();
    $numRecords->close();
    $last = ceil($rowcount/$page_rows);
} else {
    print_r($con->error);
}

OTHER TIPS

The problem is not in the prepared statement, but in the call to the 'query' method that shouldn't be there - as it is used to execute "standard" (not prepared) statements.

$data = $con->query($countQuery) or die(print_r($con->error));
$rowcount = $data->num_rows;

should be

$rowcount = $numRecords->num_rows;

in the getRowsByArticleSearch function, you should again drop the query and use the variables passed to bind_result for the output:

  $getRecords->bind_result($ARTICLE_NO, $USERNAME, $ACCESSSTARTS, $ARTICLE_NAME, $shortDate);
  while ($getRecords->fetch()) {
    $pk = $ARTICLE_NO;
    echo '<tr>' . "\n";
    echo '<td><a href="#" onclick="updateByPk(\'Layer2\', \'' . $pk . '\')">'.$USERNAME.'</a></td>' . "\n";
    // etc...
  }

for a bit more info, check PHP's manual of bind_result: http://php.net/manual/en/mysqli-stmt.bind-result.php

This post on mysql.com seems to suggest that CONCAT() should work: http://forums.mysql.com/read.php?98,111039,111060#msg-111060

Have you tried using named params?

You try to call:

$numRecords->bind_param("s", "%".$brand."%");

But your sql is:

$countQuery = "SELECT ARTICLE_NO FROM AUCTIONS WHERE upper(ARTICLE_NAME) LIKE ?";

Shouldn't it be? (note the LIKE ?s)

$countQuery = "SELECT ARTICLE_NO FROM AUCTIONS WHERE upper(ARTICLE_NAME) LIKE ?s";
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top