EDIT: You’re not allowed to have the word “question” in the title. Q-mark means “question-mark”
EDIT 2: Realized I should remove my personal contact info from the dummy customer record
I’m trying to making some basic functions to reduce maintenance of a recent project. Among these is the following simple function so I can add columns to the database at a later date without needing to change my update queries:
function update( $table, $fields ) {
global $db; // A slightly modified PDO object
if( count( $fields ) > 0 ) {
$query = "UPDATE `" . $table . "` SET ";
foreach( $customer as $key => $value ) {
$query .= "`" . $key . "` = ?, ";
}
$query = substr( $query, 0, -2 );
$query .= " WHERE `id` = " . $_REQUEST['id'];
$db->prepare( $query );
$db->execute( $fields );
} else { return true; }
}
This function was working when I passed one or two fields, but the moment I tried passing more it failed. Here’s the query, value of $fields, and error I’m receiving:
Query:
string 'UPDATE `customers` SET `5v` = ?, `contactaddress` = ?, `contactaddress2` = ?, `contactcity` = ?, `contactemail` = ?, `contactname` = ?, `contactphone` = ?, `contactstate` = ?, `contactzip` = ?, `corrugated` = ?, `name` = ?, `permalok` = ?, `residential` = ?, `secureseam` = ?, `tax` = ? WHERE `id` = 1' (length=301)
$fields:
array
'5v' => string '120' (length=3)
'contactaddress' => string '999 Street Dr' (length=13)
'contactaddress2' => string 'Apt 2' (length=7)
'contactcity' => string 'City' (length=9)
'contactemail' => string 'steven.abarnett@gmail.com' (length=25)
'contactname' => string 'Steven Barnett' (length=14)
'contactphone' => string '(555) 555-5555' (length=14)
'contactstate' => string 'KY' (length=2)
'contactzip' => string '55555' (length=5)
'corrugated' => string '90' (length=2)
'name' => string 'Steven's Metals' (length=15)
'permalok' => string '130' (length=3)
'residential' => string '100' (length=3)
'secureseam' => string '130' (length=3)
'tax' => string '6' (length=1)
Error:
string 'Statement execution failed: SQLSTATE[HY093]: Invalid parameter number: parameter was not defined' (length=96)
Googling this error, it sounds like an issue with named parameters, not question-mark parameters. Why am I getting this error?
UPDATE:
I’ve been continuing to debug and experiment and tracing the error I found it’s not the statement execution that fails, but attempting to fetch the result afterwards.
In my modified PDO object I have the following code within my execute() method:
// Load from database
try {
$this->stmt->execute( $args );
$this->lastid = $this->dbh->lastInsertId();
$this->data = $this->stmt->fetchAll();
} catch (PDOException $e) {
$this->error = 'Statement execution failed: ' . $e->getMessage();
return false;
}
Placing echo statements between each line in the try{} section shows that the first two lines run without a hitch, but the third line is throwing the exception.
Is there are reason my query would fail with a general error when I call PDOStatement::fetchAll()?
FINAL UPDATE:
As it turns out PDO and Mysql haven’t been playing nicely for 6 years. The general solution seems to be to unset the PDOStatement object after each call to PDOStatement::execute(), however this didn’t work for me. The issue stems from the fact that MySQL can only have one cursor open at a time pointing to records in a record set, so another proposed solution is to use PDOStatement::fetchAll() instead of PDOStatement::fetch() OR to call PDOStatement::closeCusor(). Again, this didn’t work for me. My issue comes from certain installations of MySQL which will create a cursor during INSERT, UPDATE, and DELETE queries (all of which return no data) which can not be closed since it’s pointing to null data.
My solution was to only call PDOStatement::fetchAll() when I’m running a query that return data. I have a queryhash variable which was used in caching (the big modification I made to the PDO class) which was set to false for these three query types (since you need to send the query to the database rather than deferring to cache). I simply modified my execute() function to check this variable and only call fetchAll() if it was not set to false.
you should be using an index array instead of an associative one.