No Code Attached Yet
avatar pioada
pioada
21 Oct 2021

Steps to reproduce the issue

Prepared Statements. Bind value for IN clause, eg.:
$array_of_ids = array(1,2,3,4);
$array_of_ids = ArrayHelper::toInteger($array_of_ids);
$array_of_ids = $db->q($array_of_ids);
$ids = implode(',', $array_of_ids);
...
->where($db->qn('id') .' IN (:ids)')
...
->bind(':ids', $ids, ParameterType::STRING)

Expected result

Return data for all IDs.

Actual result

Returns data only for first ID.

System information (as much as possible)

Apache, MySQL, Joomla! 4

Additional comments

Probably $ids string in quoted somewhere on binding / execution.

avatar pioada pioada - open - 21 Oct 2021
avatar pioada pioada - change - 21 Oct 2021
Labels Removed: ?
avatar joomla-cms-bot joomla-cms-bot - change - 21 Oct 2021
Labels Added: No Code Attached Yet
avatar joomla-cms-bot joomla-cms-bot - labeled - 21 Oct 2021
avatar joomdonation
joomdonation - comment - 21 Oct 2021

Your code could be replaced with the below one line of code:

->whereIn($db->quoteName('id'), $array_of_ids);
avatar richard67
richard67 - comment - 21 Oct 2021

@pioada Just 2 questions: Why do you quote the IDs and use the string type? Are they stored as string in database? Otherwise if your code shall work with both database drivers MySQLi and MySQL (PDO), or even with PostgreSQL, you should use the integer type. And why do you use ArrayHelper::toInteger? Isn't it already an array of integers?

Besides that, as @joomdonation correctly pointed out you can use whereIn with the array directly.

Another way would be to do it like here: https://github.com/joomla/joomla-cms/blob/4.0-dev/libraries/src/MVC/Model/AdminModel.php#L1478

->where($db->quoteName('id') . ' IN (' . implode(',', $query->bindArray(array_values($array_of_ids))) . ')'

(The array_values is only needed if the array elements are not indexed by 0,1, 2, ..., e.g. if an element has been removed from the array so it besomes an associated list.)

So or so I think you see your mistake: You should use either bindArray or whereIn (which also binds as array).

avatar richard67
richard67 - comment - 21 Oct 2021

P.S.: The short named aliases q and qn should not be used anymore in J4, They still work, but they are deprecated. You should use quote and quoteName.

avatar richard67
richard67 - comment - 21 Oct 2021

P.P.S.: Let us know if our comments helped you to solve your issue so we can close it here, or close it yourself. Thanks in advance.

avatar pioada
pioada - comment - 21 Oct 2021

@richard67 Data comes from form, should be integers but it can be anything. You're right, quoting is unnecessary.
whereIn and where + bindArray works fine. In AdminModel.php#L1478 look few lines up or down. There is code like:
$where[] = $db->quoteName('key') . ' = :oldKey';
$query->bind(':oldKey', $oldKey);
This is what I try to use / do.
Meybe my first example is too simple and therefore confusing.
Extended example:
...
->where($db->qn('id') .' IN (:ids)'),
->where($db->qn('some_col') .' = :some_value')
...
foreach ($somethings as $something) {
->bind(':ids', $ids, ParameterType::STRING), <- string because I don't see a better type
->bind(':some_col', $some_value, ParameterType::INTEGER)
->execute();
}
:some_col + $some_value always works fine.
But when I try to do the same with IN clause it return only row for first ID. So if first ID is 1 then it will return row with id=1 but when first id is eg 4 then it return row for id=4. Should return all rows like it do for whereIn or where + bindArray.

I got same result when quote $ids in "standard" IN, eg:
$ids = implode(',', $ids);
->where($db->qn('id') .' IN ('. $ids .')')
I tlooks like ids given in ->bind(':ids', $ids, ParameterType::STRING) are quoted somewhere on bind or execute. But i dont know where exactly and i dont see way to prevent quoting.

BTW: Thanks for info about q / qn depreciation.


This comment was created with the J!Tracker Application at issues.joomla.org/tracker/joomla-cms/35870.

avatar richard67
richard67 - comment - 21 Oct 2021

@pioada You still don't get that you can't use bind for an array, like you are trying to do with your ->bind(':ids', $ids, ParameterType::STRING). You have to use whereIn or where + bindArray. What I don't get is why you bind it again and again in your foreach loop which doesn't change the IDs array.

Anyway I do not see a bug here, so please check again and consider to close that issue and if necessary ask for further support in the support forum.

Thanks in advance.

avatar pioada
pioada - comment - 22 Oct 2021
avatar richard67
richard67 - comment - 22 Oct 2021

@pioada But you notice that in the example you linked above the $id is a single value from an array as being used in the foreach loop, so it is one string value, while in all your previous examples and in the description of this issue, you tried to bind an array as string.

avatar pioada
pioada - comment - 22 Oct 2021

Summary. It can be whereIn, where + bindArray.
This code will work as well:
$keys = array(':id1',':id2',':id3',':id4');
$values = array(1,4,3,4);
...
->where($db->quoteName('field_id') .' IN ('. implode(',', $keys) .')')
...
->bind($keys, $values, ParameterType::INTEGER)

Got everything i needed. Thanks. Closing.


This comment was created with the J!Tracker Application at issues.joomla.org/tracker/joomla-cms/35870.

avatar richard67 richard67 - change - 22 Oct 2021
Status New Closed
Closed_Date 0000-00-00 00:00:00 2021-10-22 07:27:20
Closed_By richard67
avatar richard67 richard67 - close - 22 Oct 2021

Add a Comment

Login with GitHub to post a comment