Reputation: 11820
My code currently uses mysqli::query
and checks mysqli::$warning_count
. When trying to insert text into an integer column, 0
gets inserted and a warning is generated. However, I'm just starting to learn prepared statements and for the same query, no warning is generated.
Here's an excerpt from my code:
$db_err_msg = 'Database Error: Failed to update profile';
$sql = "UPDATE tblProfiles SET intBookId = ? WHERE lngProfileId = ?";
$stmt = $mysqli->prepare($sql) or output_error($db_err_msg);
$book = 'CA';
$id = 10773;
$stmt->bind_param('ii', $book, $id) or output_error($db_err_msg);
$stmt->execute() or output_error($db_err_msg);
echo '$stmt->affected_rows is ', $stmt->affected_rows, "\n";
if ($mysqli->warning_count) {
$warnings = $stmt->get_warnings();
do {
trigger_error('Database Warning (' . $warnings->errno . '): '
. $warnings->message, E_USER_WARNING);
} while ( $warnings->next() );
}
else {
echo 'no warnings', "\n";
}
which produces the following output:
$stmt->affected_rows is 1
no warnings
Note that the intBookId
column has a TINYINT
data type. The same query generates a warning when using mysqli::query
, but not when using prepared statements.
Enabling strict mode does not help. It will turn the warning into an error when using mysqli::query
, but when using prepared statements the column is silently updated with a 0
;
For the record, my application already does extensive validation before it gets to this point. But I wanted this extra validation as way to catch anything I might miss by mistake.
Note: It's beyond the scope of the current project to switch to PDO.
Why is this happening with MySQLi prepared statements? Is this expected behaviour?
Upvotes: 0
Views: 151
Reputation: 11820
Though it may not be immediately obvious, it is expected behaviour.
Because of this line of code:
$stmt->bind_param('ii', $book, $id) or output_error($db_err_msg);
PHP is casting the value to an integer before sending it to MySQL. MySQL receives the value 0
which is a valid value for the column and no warning is generated.
If you don't want PHP to do this, then you need to send it as a string. Like so:
$stmt->bind_param('si', $book, $id) or output_error($db_err_msg);
MySQL will receive the string 'CA' and generate a warning about it being an incorrect integer value.
Note: By sending everything as a string, MySQL will have to do a little more processing to convert the strings to integers, but it was already doing that anyway when the whole query was sent as a string using mysqli::query.
Note: A related problem occurs when using integers that are greater than PHP_INT_MAX
. If you think an integer value will surpass that maximum (which is platform-dependent and only 2147483647 on 32-bit platforms) and precision is important, it's safer to send it as a string.
Upvotes: 1