Update: Please see below; I have removed all abstraction and created a plain PHP script but still get the same error. Please see 'ANOTHER update' below for more information...
Original Post: I have a query which has been correctly formed through a database abstraction layer. The query is the following:
SELECT 5c9_dpd_users.id, 5c9_dpd_users.username, 5c9_dpd_users.cms_usergroup_id,
5c9_dpd_usergroups_cms.usergroup_name, 5c9_dpd_users.email FROM 5c9_dpd_users LEFT JOIN
5c9_dpd_usergroups_cms ON 5c9_dpd_usergroups_cms.id = 5c9_dpd_users.cm开发者_JS百科s_usergroup_id
ORDER BY username asc
If I generate the same query but run it as a prepared statement which parameterises the second operand of the WHERE clause as below, I get incorrect results. I am certain that the statement itself is correct and that I am running the MySQLi prep. statement functions in the right order. The prepared statement query is below:
SELECT 5c9_dpd_users.id, 5c9_dpd_users.username, 5c9_dpd_users.cms_usergroup_id,
5c9_dpd_usergroups_cms.usergroup_name, 5c9_dpd_users.email FROM 5c9_dpd_users LEFT JOIN
5c9_dpd_usergroups_cms ON 5c9_dpd_usergroups_cms.id = ? ORDER BY username asc
This query seems to convert the 5c9_dpd_users.cms_usergroup_id
that is parameterized to simply '5', since running the query retrieves the right columns from the SELECT
clause but returns the same usergroup_name
for all results - this usergroup name matches the usergroup name for the result that has a 5c9_dpd_usergroups_cms.id
of 5
.
I am binding parameters dynamically (call_user_func_array()
). In this instance, I tell it to bind the ?
parameter as an i
. I thought perhaps this made it convert the 5c9_dpd_users.cms_usergroup_id
to a 5
for some reason, but I have tried all three other data types (s
,b
and d
) with no luck.
NB: I have used my database abstraction layer without problem many times, although this IS the first instance in which it has run a join (it has only been recently developed). To reiterate, the query returns the correct result through PHP and the MySQL console if it is not parameterized, but if given a ?
through the PHP prepared statement functions, the results are incorrect, as described above.
If anyone could help, I would greatly appreciate it. I've been up all night googling for help on this matter, and I can't find any similar instance documented anywhere. Thank you.
Edit (provides PHP code):
$stmt->select_prep(array('users.id', 'users.username', 'users.cms_usergroup_id', 'usergroups_cms.usergroup_name', 'users.email'), array('users'));
$stmt->left_join_prep('usergroups_cms');
$stmt->on_prep('usergroups_cms.id', '=', 'users.cms_usergroup_id', 'i');
$stmt->order($column, $asc_desc);
$stmt->execute_prep();
The query is now executed, and all I have to do is call $stmt->fetch_prep(), a wrapping method that basically retrieves a result set. The query that this client code generates was given above as the second - the parameterized - query I gave as an example.
I printed out some debugging code in my $stmt->execute_prep() method and the parameter that gets bound to the query appears correctly as:
Array
(
[0] => i
[1] => 5c9_dpd_users.cms_usergroup_id
)
This means it is binding one parameter (key 1) as an int (key 0). I have also tried binding it as a string, double and blob, to no effect.
ANOTHER Update:
I created a test script to completely remove my database abstraction layer, and the results are the same: no cms usergroup name is returned. Here is the script:
<?php
$mysqli = new mysqli('localhost', 'root', '', 'frame');
$q = "SELECT ac9_dpd_users.id, ac9_dpd_users.username, ac9_dpd_users.cms_usergroup_id,
ac9_dpd_usergroups_cms.usergroup_name, ac9_dpd_users.email
FROM ac9_dpd_users
LEFT JOIN ac9_dpd_usergroups_cms
ON ac9_dpd_usergroups_cms.id = ?
ORDER BY username asc";
$stmt = $mysqli->prepare($q);
$stmt->bind_param('i', $param);
$param = 'ac9_dpd_users.cms_usergroup_id';
$stmt->execute();
$stmt->bind_result($a, $b, $c, $d, $e);
while ($stmt->fetch()) {
echo "id: $a <br>un: $b <br>id: $c <br>cms name: $d <br>email: $e<br><br>";
}
$stmt->close();
unset($mysqli);
?>
Output:
id: 7
un: ADD
id: 1
cms name:
email: test@test.com
id: 1
un: New User
id: 2
cms name:
email: test@test.com
etc
Maybe I'm just a bit picky but I wouldn't start a table/field name with a digit. Use a letter or surround these weird names with backtick (`
). It should work.
Edit (according to your question changes)
Some spot of your edited script sound alerting to me:
...
ON ac9_dpd_usergroups_cms.id = ?
...
$stmt->bind_param('i', $param);
$param = 'ac9_dpd_users.cms_usergroup_id';
As reported into the php manual, mysqli::prepare accepts parameters into where clause and does not permit to change the columns name of the query.
Furthermore doing a integer bind of a string should convert the value to a number before inserting it into the prepared query and your $params should be converted to 0.
Issue a sqlstate statement to check what is going with the query just after your execute:
...
$stmt->execute();
$sqlError = $stmt->sqlstate();
if($sqlError != '00000') die($sqlError);
...
A possible solution:
<?php
$mysqli = new mysqli('localhost', 'root', '', 'frame');
$q = "SELECT ac9_dpd_users.id, ac9_dpd_users.username, ac9_dpd_users.cms_usergroup_id,
ac9_dpd_usergroups_cms.usergroup_name, ac9_dpd_users.email
FROM ac9_dpd_users
LEFT JOIN ac9_dpd_usergroups_cms
ON ac9_dpd_usergroups_cms.id = ac9_dpd_users.cms_usergroup_id
ORDER BY username asc";
$stmt = $mysqli->prepare($q);
$stmt->execute();
$stmt->bind_result($a, $b, $c, $d, $e);
while ($stmt->fetch()) {
echo "id: $a <br>un: $b <br>id: $c <br>cms name: $d <br>email: $e<br><br>";
}
$stmt->close();
unset($mysqli);
?>
精彩评论