PDO bindColumn and PDO::FETCH_BOUND -- compulsory or optional? - php

In many places in our PHP code, (working with postgres if it matters)
we have stuff like:
$q = "SELECT DISTINCT a.id FROM alarms.current a, entities e, installations i ";
$q .= "WHERE i.\"entityId\"=e.id AND a.installationid=i.id AND ";
$q .= "e.id=".$entityId;
$stmt = $db->query($q);
$stmt->bindColumn("id", $alarmId);
if ($stmt->fetch(PDO::FETCH_ASSOC))
....etc
Now according to my reading of the docs, if you want your variables updated from their bound columns you ought to use PDO::FETCH_BOUND. But we don't, and no-one has complained about the performance as far as I'm aware.
Can anyone throw any light on why this apparently faulty code actually apparently works?

While the example in the PHP documentation for bindColumn uses PDO::FETCH_BOUND, which does suggest that this fetch style is necessary in order to use bindColumn, it does not explicitly state that this is a requirement. It only says
PDOStatement::bindColumn() arranges to have a particular variable bound to a given column in the result-set from a query. Each call to PDOStatement::fetch() or PDOStatement::fetchAll() will update all the variables that are bound to columns.
After some testing I determined that this will occur regardless of the fetch style that is used. I think the fact that the fetch call in your code is not actually fetched into a variable really just means that an associative array is created and assigned to nothing, while the side effect of the fetch populates the $alarmId variable.

Continuing from #DontPanic's comments, here is how I prefer to use bound parameters:
/**
* #param $id
*
* #return array|false
*/
public function retrieveImage($id)
{
$conn = $this->dbh->getInstance('LocalMSSQL');
$stmt = $conn->prepare("SELECT inputType, blob FROM images WHERE id = ?");
$stmt->bindValue(1, $id, PDO::PARAM_INT);
$stmt->execute();
$resultSet = [
'inputType' => null,
'blob' => null,
];
$stmt->bindColumn(1, $resultSet['inputType'], PDO::PARAM_STR);
$stmt->bindColumn(2, $resultSet['blob'], PDO::PARAM_LOB, 0, PDO::SQLSRV_ENCODING_BINARY);
if ($stmt->fetch()) {
return $resultSet;
} else {
return false;
}
}

Related

mysqli_free_result () VS mysqli_stmt_free_result() differences and usage?

What are the differences and specific use cases of these two functions? Here's what I found:
mysqli_free_result — Frees the memory associated with a result
mysqli_stmt_free_result — Frees stored result memory for the given statement handle
An example will be nice.
These are two different functions, but you don't need to use any of them.
mysqli_free_result
mysqli_free_result() is the procedural equivalent of $result->free(). All it does is it unsets the results from the variable. The object still exists, but becomes unusable.
$id = 1;
$stmt = $mysqli->prepare('SELECT * FROM student_detail WHERE ID=?');
$stmt->bind_param('s', $id);
$stmt->execute();
$result = $stmt->get_result();
$result->free();
var_dump($result->fetch_assoc()); // error
It also has 2 aliases. These 4 are all the same thing:
$result->free();
$result->close();
$result->free_result();
mysqli_free_result($result);
mysqli_stmt_free_result
Does the same thing, but with the statement itself. It is the equivalent of $stmt->free_result()
$id = 1;
$stmt = $mysqli->prepare('SELECT * FROM student_detail WHERE ID=?');
$stmt->bind_param('s', $id);
$stmt->execute();
$result = $stmt->store_result();
$stmt->free_result();
var_dump($stmt->fetch()); // false
You can assume that if you ever find yourself needing to use any of them, then it means you have probably done something wrong.
For example, some people claim it saves memory for your server when you free the result once you are done with it. In reality you should encapsulate your database queries in such way that the mysqli_result lives only as long as you need it. Take a look at one method I have written a while ago:
public function safeQuery(string $sql, array $params = []): ?array {
$stmt = $this->prepare($sql);
if ($params) {
$stmt->bind_param(str_repeat("s", count($params)), ...$params);
}
$stmt->execute();
if ($result = $stmt->get_result()) {
return $result->fetch_all(MYSQLI_BOTH);
}
return null;
}
It executes prepared statement, gets the result, fetches the records and the mysqli_result is alive as long as it is needed and not a moment more.
They're equivalent, it depends on how you created the results in the first place.
If you use a prepared statement and then use $stmt->store_result(), you would free the results using $stmt->free_result().
If you perform an ordinary query like $result = $conn->query(...), you would free it using $result->free_result().

call_user_func_array for dynamic mysqli_bind_param [duplicate]

I am attempting to create a database query function which can take multiple parameters and be reused elsewhere, however tried a number of methods online similar to my approach and they are not working as expected.
function query($query, $bindings, $type)
I want to be able to run queries on the go with this single function, this type of function is a lot easier with the PDO driver as you could simply enter the binding inside ->execute($binding); however in this case I am forced to use MySQLi as the application currrently relies on it but wanting to upgrade it to use prepared statements.
An example of how I need to be able to use the function to ensure it is reusable and flexible:
$engine->query("SELECT * FROM accounts WHERE email = :mail AND id = :id",array(':mail' => $_POST['mail'], ':id' => 2))->fetch_assoc();
Lets split each of them up. First is the statement, then the array which is used to bind the parameters used, then the types of the parameters, and finally the type of fetch_ to utilize on the query (ASSOC, OBJECT, ARRAY) etc.
"SELECT * FROM accounts WHERE email = :mail AND id = :id",
array(':mail' => $_POST['mail'], ':id' => 2),
"si"
->fetch_assoc();
though to implement named parameters would be quite a task, the rest is pretty doable.
A PHP >= 5.6 variant, implementing splat operator:
function query($query, $params = NULL, $types = NULL)
{
if (!$params)
{
return $mysqli->query($query);
}
$statement = $this->mysqli->prepare($select);
$types = $types ?: str_repeat('s', count($params));
$statement->bind_param($types, ...$params);
$statement->execute();
return $statement->get_result();
}
used like this
$sql = "SELECT * FROM accounts WHERE email = ? AND id = ?";
$row = $engine->query($sql, [$_POST['mail'], 2])->fetch_assoc();
or, if you want to set types explicitly
$row = $engine->query($sql, [$_POST['mail'], 2], "si")->fetch_assoc();

MySQLi dynamic prepared function with array binding

I am attempting to create a database query function which can take multiple parameters and be reused elsewhere, however tried a number of methods online similar to my approach and they are not working as expected.
function query($query, $bindings, $type)
I want to be able to run queries on the go with this single function, this type of function is a lot easier with the PDO driver as you could simply enter the binding inside ->execute($binding); however in this case I am forced to use MySQLi as the application currrently relies on it but wanting to upgrade it to use prepared statements.
An example of how I need to be able to use the function to ensure it is reusable and flexible:
$engine->query("SELECT * FROM accounts WHERE email = :mail AND id = :id",array(':mail' => $_POST['mail'], ':id' => 2))->fetch_assoc();
Lets split each of them up. First is the statement, then the array which is used to bind the parameters used, then the types of the parameters, and finally the type of fetch_ to utilize on the query (ASSOC, OBJECT, ARRAY) etc.
"SELECT * FROM accounts WHERE email = :mail AND id = :id",
array(':mail' => $_POST['mail'], ':id' => 2),
"si"
->fetch_assoc();
though to implement named parameters would be quite a task, the rest is pretty doable.
A PHP >= 5.6 variant, implementing splat operator:
function query($query, $params = NULL, $types = NULL)
{
if (!$params)
{
return $mysqli->query($query);
}
$statement = $this->mysqli->prepare($select);
$types = $types ?: str_repeat('s', count($params));
$statement->bind_param($types, ...$params);
$statement->execute();
return $statement->get_result();
}
used like this
$sql = "SELECT * FROM accounts WHERE email = ? AND id = ?";
$row = $engine->query($sql, [$_POST['mail'], 2])->fetch_assoc();
or, if you want to set types explicitly
$row = $engine->query($sql, [$_POST['mail'], 2], "si")->fetch_assoc();

Memcache and Mysqli Prepared Statement Issue

This has been driving me crazy, the issue is I cannot work out How i can get and set the cached data to be displayed within my view.
public function get_something($id, $account_name)
{
$sql = "SELECT one,two,three FROM table WHERE id = ? and account_name = ? ";
$key = md5("SELECT one,two,three FROM table WHERE id = $id and account_name = $account_name ");
$get_result = $this->Core->Core->Memcache->get($key);
if($get_result)
{
// How would I set the Data
}
else
{
$stmt = $this->Core->Database->prepare($sql);
$stmt->bind_param("is", $id, $account_name);
$stmt->execute();
$stmt->store_result();
$stmt->bind_result($one, $two, $three);
$stmt->fetch();
//Below is how i set the data
$this->Core->Template->set_data('one', $one);
//Set the Memcache
$this->Core->Memcache->set($key, $stmt, TRUE, 20);
}
So my question is how can I get and set the data from a prepared statement fetch within memcache?
Memcache is a key/value storage system with both the key and the value needing to be serialized. From the php.net page:
Remember that resource variables (i.e. file and connection descriptors) cannot be stored in the cache, because they cannot be adequately represented in serialized state.
It appears your sql statement is looking for three values in a single row. I'm no expert on mysqli, but this is kind of what you want to do:
public function get_something($id, $account_name){
$sql = "SELECT one,two,three FROM table WHERE id = ? and account_name = ? ";
$key = md5("SELECT one,two,three FROM table WHERE id = $id and account_name = $account_name ");
$get_result = $this->Core->Core->Memcache->get($key);
if($get_result){
return $get_result;//#1 just return it, the format is an array like what is being built below
}
else{
$stmt = $this->Core->Database->prepare($sql);
$stmt->bind_param("is", $id, $account_name);
$stmt->execute();
$stmt->store_result();
$stmt->bind_result($one, $two, $three);
$stmt->fetch();
//Below is how i set the data
$this->Core->Template->set_data('one', $one);//#2 I don't know what this line does or is for, presumably for something else besides memcache stuff, maybe it acts like return
//Set the Memcache
$array=array();//#3
$array[]=$one;
$array[]=$two;
$array[]=$three;
$this->Core->Memcache->set($key, $array, TRUE, 20);
//this is a function, do you want to return your values somewhere?
}
A few notes, #1 the answer to your question is simple, just return $get_result. It should be an array with three values. #2 I'm not familiar with this line, nor what it does. Is this how your "return" the values to your controller? If so, you'll want to mimick that line where I put the return inside the if #3 This is your problem. You can't save the $stmt variable in memcache, it's a mysqli object, not the data you want. You need to build an array and then save that array. And that should do it for you.
There are other nuances to do, you can loop on the returned values. You should check for mysql not returning anything. But this is the basic starting point to get this going.
Let me know if this works for you.

Why doesn't this prepare statement work in MYSQLI?

I created this code:
$statement = $db->prepare("SELECT * FROM phptech_contact");
$statement->execute();
$result = $statement->result_metadata();
$object = $result->fetch_object();
print_r( $object );
When I run it, it doesn't work. Can anybody tell me why it doesn't work?
I have 20 rows in this table so data should be returned.
From http://ch.php.net/manual/en/mysqli-stmt.result-metadata.php
Note: The result set returned by mysqli_stmt_result_metadata() contains only metadata. It does not contain any row results. The rows are obtained by using the statement handle with mysqli_stmt_fetch().
As long as you don't need this meta data you don't need to call this method.
$statement = $db->prepare("SELECT fld1, fld2 FROM phptech_contact");
$statement->execute();
$stmt->bind_result($fld1, $fld2);
while ($stmt->fetch()) {
echo "$fld1 and $fld2<br />";
}
But I really dislike the mysqli extension. PDO is much cooler ... ;-)
$db = new PDO('...');
$stmt = $db->prepare("SELECT fld1, fld2 FROM phptech_contact");
$stmt->execute();
while ($obj = $stmt->fetchObject()) {
// ...
}
or
$objs = stmt->fetchAll(PDO::FETCH_OBJ);
if you're trying to get the rows from the database, the function you need is mysqli_stmt::fetch(), not mysqli_stmt::fetch_metadata()
You're also missing a few steps. When using prepared statements, you must specify the fields you would like to return instead of using the star wildcard, and then use mysqli_stmt::bind_result() to specify which variables the database fields should be placed in.
If you're more familiar with the original MySQL extension, prepared statements have a different process to use. If your select statement has a parameter (eg., "WHERE value=?") prepared statements are definitely recommended, but for your simple query, mysqli:query() would be sufficient, and not very different from the process of mysql_query()
I believe the problem is that mysqli_stmt::result_metadata() returns a mysqli_result object without any of the actual results — it only holds metadata.
So what you want to do is use $result = $statement->bind_result(...) and then call $result->fetch() repeatedly to get the results.
One of the comments under the bind-result() article shows how to do this for a query like yours, where you don't necessarily know all of the columns being returned.

Categories