views:

291

answers:

3

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.

A: 

hmmm, 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";

danseagrave
I though s was to denote a string for binding?
Joshxtothe4
+1  A: 

You 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 'bound' queries (as supported by mysqi's 'execute()' function with unbound queries (as done with '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);
}
Alnitak
then assigning $brand as $brand = "% ".$brand." %"; should work fine?
Joshxtothe4
yes, so long as the rest of the SQL is valid
Alnitak
It it, and yet I still get the error.
Joshxtothe4
I tried exactly as you suggest and still get the message that the error is near ?
Joshxtothe4
perhaps if you actually told us what the error was, and quoted the specific SQL that it's trying to execute?
Alnitak
I updated my question to add this
Joshxtothe4
please note you are using spaces that should most probably not be there on '$brand = "% ".$brand." %";'
jcinacio
spaces or no the error is the same.
Joshxtothe4
+1  A: 

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

jcinacio
I already answered the execute vs query issue. I also disagree with re-writing his function the way you describe - better to return the associative arrays than to mix up DB access and HTML rendering in the same function!
Alnitak