The following code in question always logs that the affected_rows was 0. I check my DB, the row updates fine everytime. Why is it 0?
public static function updateNextRunTime($nextRunTime)
{
$mysqli = new mysqli(GDB_HOST, GDB_USERNAME, GDB_PASSWORD, GDB_NAME);
if ($mysqli->connect_errno)
{
throw new Exception('DB Connection Failed. Error Code: ' . $mysqli->connect_errno);
}
$cmd = $mysqli->prepare("UPDATE balanceagent SET NextRunTime = ? WHERE Id = 1");
if (!$cmd)
{
throw new Exception($mysqli->error);
}
$cmd->bind_param('s', $nextRunTime);
$cmd->execute();
$rows = $mysqli->affected_rows;
$cmd->close();
$mysqli->close();
if ($rows != 1)
{
logToFile("Balance Agent Error - Failed to update the next run time! - Affected rows: " . $rows);
}
}
For prepared statements you should be using the mysqli_stmt::affected_rows form :
$cmd->bind_param('s', $nextRunTime);
$cmd->execute();
$rows = $cmd->affected_rows;
Your should check
$cmd->affected_rows;
instead of
$mysqli->affected_rows;
Related
I'm trying to create a system, where my website generates an unique code (current date + 5 random characters) and that code is transferred to a table in my database.
Before function generateNumber() can insert the unique code into the database, it has to check if the code already exist in the database.
If the code doesn't exist, my function works flawlessly. But the problem is when the code can already be found on the database, my website just doesn't do anything (it should just re-run the function).
function generateNumber()
{
global $conn;
$rand = strtoupper(substr(uniqid(sha1(time())),0,5));
$result = date("Ydm") . $rand;
$SQL = $conn->query("SELECT code FROM test WHERE code='$result'");
$c = $SQL->fetch(PDO::FETCH_ASSOC);
if ($c['code'] > 0) { // test if $result is already in the database
generateNumber();
} else {
$sql2 = "INSERT INTO test (code) VALUES (?)";
$stmt2 = $conn->prepare($sql2);
$stmt2->execute([$result]);
return $result;
}
}
try {
$conn = new PDO("sqlite:db"/*, $username, $password*/);
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
echo generateNumber();
}
catch(PDOException $e) {
echo "Error:" . $e->getMessage();
}
$conn = null;
?>
There are no error messages in the console, but I suspect the problem is this part of the code:
if ($c['code'] > 0) { // test if $result is already in the database
generateNumber();
}
Any idea how I can write this function in a better way?
Solution :
if ($c['code'] > 0) { // test if $result is already in the database
// if the code exists in db the function return nothing
// because you are missing a return :
return generateNumber();
}
I have a function that is not acting as I expect it to. Its purpose is to return an array of rows for select queries, or the insert id for Insert queries. For some reason if there is an insert query followed by a select query, the part of the function where it tests whether or not the query was an insert or not fails because inesrt_id still returns the id of the inserted row. I could program around this but I'd really like to understand why it's happening.
My understanding was that if the most recent query is a select, then there should be no insert id. I'm new to mysqli, so maybe the query doesn't really 'end' when I think it does so the new select counts as part of the same query? I can get it to work fine if I recreate the connection on each query but that's not practical. Here's the code for the query function.
public function __construct(){
parent::__construct();
// #mysql_select_db ('public') OR die('Could not select the database: ' . mysql_error() );
$this->connection = new mysqli(DB_HOST, DB_USER, DB_PASS, DB_TABLE, DB_PORT)OR die ('Could not connect to MySQL: ' . mysql_error());
$this->db = $this;
}
public function query_return($querystring){
$response = array();
$this->result_object = $this->connection->query($querystring);
if($this->result_object != FALSE) {
$last_id = $this->connection->insert_id;
if (!empty($last_id)) {
$response = $last_id;
}
else {
while ($row = mysqli_fetch_assoc($this->result_object)) {
array_push($response, $row);
}
}
}
else{
$response = PEAR::raiseError('There was a problem with the query: '. mysql_error());
}
return $response;
}
EDIT: Ok so thanks to the guys below I added an is_object test to the function. I couldn't directly replace the true/false test as I actually use this function for deletions too and I want to know when it fails. I wrapped the insert_id test with the is_object test and things seem to be working now. I guess that an insert_id will be returned for a deletion query if there was a previous insert on the connection but I don't think that will cause problems as those functions only fail if they receive FALSE from the query_return.
I still don't really fathom why mysqli_insert_id would return a value after a select query when the documentation leads me to believe that it shouldn't but at least my code is working. This query_return function is tweaked from 'mysql_' (no 'i') procedural versions of these methods and it worked with those versions so there's something I'm still not understanding. Anyways here's the tweaked function.
private function query_return($querystring){
$response = array();
$this->result_object = $this->connection->query($querystring);
if($this->result_object != FALSE) {
if (!is_object($this->result_object)) {
$last_id = $this->connection->insert_id;
if (!empty($last_id)) {
$response = $last_id;
}
}
else {
while ($row = mysqli_fetch_assoc($this->result_object)) {
array_push($response, $row);
}
}
}
else{
$response = PEAR::raiseError('There was a problem with the query: '. mysql_error());
}
return $response;
}
Looking though the source of PHP its a wrapper to https://dev.mysql.com/doc/refman/5.0/en/mysql-stmt-insert-id.html
This documentation says the followng
LAST_INSERT_ID() (with no argument) returns a BIGINT (64-bit) value representing the first automatically generated value that was
set for an AUTO_INCREMENT column by the most recently executed INSERT
statement to affect such a column
https://dev.mysql.com/doc/refman/5.0/en/information-functions.html#function_last-insert-id
I would suggest changing your if statement to
if (!is_object($this->result_object)) {
this will check if there are any results to retrieve
The PHP documentation should probably be updated to reflect this though, As it stands its obvious behaviour
That's how it works, mysqli_insert_id Still returns a value because it's the same connection. You will need to close and open a new one for it to be set to 0.
I believe the variable is retaining its value from the last call. Try adding a unset($last_id); like below. Let me know if it doesn't work that way. Cheers.
public function __construct(){
parent::__construct();
// #mysql_select_db ('public') OR die('Could not select the database: ' . mysql_error() );
$this->connection = new mysqli(DB_HOST, DB_USER, DB_PASS, DB_TABLE, DB_PORT)OR die ('Could not connect to MySQL: ' . mysql_error());
$this->db = $this;
}
public function query_return($querystring){
$response = array();
$this->result_object = $this->connection->query($querystring);
if($this->result_object != FALSE) {
$last_id = $this->connection->insert_id;
if (!empty($last_id)) {
$response = $last_id;
}
else {
while ($row = mysqli_fetch_assoc($this->result_object)) {
array_push($response, $row);
}
}
unset($last_id); //<--------here
}
else{
$response = PEAR::raiseError('There was a problem with the query: '. mysql_error());
}
return $response;
}
In php I call a procedure in mysql. Now I want to check if a query result == true then set return variable in my php file in true or false if query failed. How can I do that?
This is my php code:
public function DeleteSingleAccount($accountId)
{
$Config = new Config();
$mysqli = $Config->OpenConnection();
mysqli_query($mysqli, "CALL DeleteSingleAccount($accountId)") or die("Query fail: ". mysqli_error());
}
This is my query in mysql for now:
DELETE
FROM table
WHERE accountId = par_AccountId
This code runs correct but I want to set an return parameter when query is true or false.
public function DeleteSingleAccount($accountId)
{
$Config = new Config();
$mysqli = $Config->OpenConnection();
return !! mysqli_query($mysqli, "CALL DeleteSingleAccount(" . intval($accountId) . ")");
}
I added intval() to avoid SQL injection (not needed if you're sure $accountId is always an integer, never null, empty string, user input, etc.)
Think your looking for something like this:
public function DeleteSingleAccount($accountId) {
$Config = new Config();
$mysqli = $Config->OpenConnection();
$result = mysqli_query($mysqli, "CALL DeleteSingleAccount($accountId)") or die("Query fail: ". mysqli_error());
//^Assignment of the query to a variable
if($result && mysqli_num_rows($result) > 0) {
//^Check if query is successfull ^ Check if query has 1 or more rows in it! (You can delete this check if you don't care about how many row's the result has)
echo "The query is successful and have 1 or more rows in it!";
} else {
echo "The query failed or have 0 rows in it!";
}
}
In my db I have some stored procedures.
I want to call the one of them, and according to the results I get from this procedure, i will determine weather to call the second one or not.
As you can see in the isUserValid() method I've used $result->free_results()
but still when calling the other procedure I get: Commands out of sync; you can't run this command now
This is my calling to the db functions:
/**
* Run a new query on the db.
* this will open an close the connection to the db
* #param $query string the query to run
* #param $verifyAccessToken boolean true if user validation is needed before query is executed, false otherwise
* #return bool|mysqli_result the result of the query if any or true or false in a non query
* #throws Exception on connection and query errors
*/
private function queryDb($query,$verifyAccessToken)
{
// if ($this->test)
// echo $query . "<br>";
//create a new mysqli connection
$mysqli = new mysqli($this->DB_HOST, $this->DB_USER, $this->DB_PASS, $this->DB_NAME);
//set the charset for the connection
if (!$mysqli->set_charset("utf8"))
{
$mysqli->close();
throw new Exception ("Error setting UTF 8 DB connection");
}
//check if the connection was ok
if (mysqli_connect_errno())
{
$mysqli->close();
throw new Exception("Error connecting DB");
}
//if verification is needed - verify access token
if ($verifyAccessToken && !$this->isUserValid($mysqli))
{
$mysqli->close();
throw new Exception(ACCESS_TOKEN_INCORRECT);
}
//get results
$result = $mysqli->query($query);
//check if there were now error in query. if so - throw an exception
if (!$result)
{
$mysqlError = $mysqli->error . __LINE__;
//close the connection
$mysqli->close();
throw new Exception ("mySQL Error: " . $mysqlError);
}
//fetch the results into an array
$rows = $result->fetch_all(MYSQLI_BOTH);
//close the connection
$result->close();
$result->free();
$mysqli->close();
//return the results if any
return $rows;
}
/**
* Check if user is valid
* #param $mysqli mysqli connection to db
* #return true if user is valid, false otherwise
*/
function isUserValid($mysqli)
{
//Check if there is a saved access token. if not - throw an exception
if (is_null($this->user) || $this->user->getPicoAccessToken() == null)
throw new Exception(ACCESS_TOKEN_INCORRECT);
//get user details
$facebookId = $this->user->getFacebookId();
$picoAccessToken = $this->user->getPicoAccessToken();
//create verification query
$verificationQuery = "Call isUserValid('$facebookId','$picoAccessToken')";
//execute query
$result = $mysqli->query($verificationQuery);
//if query had error - throw exception
if (!$result)
{
$mysqlError = $mysqli->error . __LINE__;
//close the connection
$mysqli->close();
throw new Exception ("mySQL Error: " . $mysqlError);
}
$rows = $result->fetch_all(MYSQLI_ASSOC);
$rows = $rows[0];
$result->free_result();
//return user valid status
return isset($rows["isUserValid"]) && $rows["isUserValid"] == 1;
}
Every stored procedure returns at least two results
one (or many) actual results
one empty result to tell the client there are no more results.
You have to use mysqli_more_results()/mysqli_next_result() to clean them.
If your procedure returns only one result, or you just don't want any extra results but the first one, you can clean up the results queue with this code snippet:
while($mysqli->more_results())
{
$mysqli->next_result();
if($res = $mysqli->store_result())
{
$res->free();
}
}
The currently accepted answer wont work as-is, i think next_result() should not be called before the first result.
This is an example that does work:
if (!$mysqli->multi_query("CALL p()")) {
echo "CALL failed: (" . $mysqli->errno . ") " . $mysqli->error;
}
do {
if ($res = $mysqli->store_result()) {
printf("---\n");
var_dump($res->fetch_all());
$res->free();
} else {
if ($mysqli->errno) {
echo "Store failed: (" . $mysqli->errno . ") " . $mysqli->error;
}
}
} while ($mysqli->more_results() && $mysqli->next_result());
From the PHP manual http://php.net/manual/en/mysqli.quickstart.stored-procedures.php
re connect database $this->db->reconnect(); // likes in codeigniter
<?php
$id = $_POST["id"];
$id2 = $_POST["id2"];
$db = new mysqli('localhost', '***', '***', '***');
if (mysqli_connect_errno() == 0) {
$sql = "SELECT * FROM chat_message WHERE id > " . $id . " AND id <= " . $id2 . " ORDER BY id";
$result = $db->query($sql);
while ($msg = $result->fetch_object()) {
?>
<div>...</div>
<?php
}
}
$db->close();
?>
I am getting this error:
Call to a member function fetch_object() on a non-object in /var/www/template/loadchat.php on line 11
Line 11:
while ($msg = $result->fetch_object())
Any help? Because I work on this thing since yesterday and I can't find the mistake.
1) Verify if your db table is named like chat_message (maybe it is chat_messages?)
2) Verify if your chat_message.id field exists
3) Verify if your php variables $id and $id2 are integer/float numbers!
$result = $db->query($sql); is returning false. This means that the query failed for some reason.
Quoting the PHP manual for mysqli::query:
Returns FALSE on failure. For successful SELECT, SHOW, DESCRIBE or
EXPLAIN queries mysqli_query() will return a mysqli_result object. For
other successful queries mysqli_query() will return TRUE.
To check for an error you can do:
if (!$db->query($sql)) {
trigger_error('Database error: '. $db->error);
}