Hi.
When not logged (anonymous) or logged with a no superuser the fulltext operator "contains none of these words" is not working.
This issue might be related only with postgresql database and maybe it is related with patch #7 of the issue #2127001.
The bug is a true mistery!!! Honestly speaking I can't find an explanation for the PHP behavior.
Below a small part of the file service.inc where the bug is at.
The echo commands were used to debug only and they dont exist in the file!
----
if ($skip_count || $results['result count']) {
echo "first echo
";
echo $db_query;
echo "
";
if ($query->getOption('search_api_facets')) {
$results['search_api_facets'] = $this->getFacets($query, clone $db_query);
}
echo "second echo
";
echo $db_query;
echo "
";
---
CASE1
--------
Ok, with both "echo blocks" I get the following result.
The sql is correct and I get my search completed!
first echo
SELECT DISTINCT t.item_id AS item_id, :score AS score FROM {search_api_db_idx_acervo} t LEFT OUTER JOIN {search_api_db_idx_acervo_search_api_access_node} t_2 ON t.item_id = t_2.item_id WHERE (t.item_id NOT IN (SELECT t.item_id AS item_id FROM (SELECT t.item_id AS item_id FROM {search_api_db_idx_acervo_title} t WHERE (word = :db_condition_placeholder_0) UNION ALL SELECT t.item_id AS item_id FROM {search_api_db_idx_acervo_field_acv_ref_cus} t WHERE (word = :db_condition_placeholder_1) UNION ALL SELECT t.item_id AS item_id FROM {search_api_db_idx_acervo_field_acv_autor_name} t WHERE (word = :db_condition_placeholder_2) UNION ALL SELECT t.item_id AS item_id FROM {search_api_db_idx_acervo_field_acv_tipo_name} t WHERE (word = :db_condition_placeholder_3) UNION ALL SELECT t.item_id AS item_id FROM {search_api_db_idx_acervo_field_acv_local_name} t WHERE (word = :db_condition_placeholder_4) UNION ALL SELECT t.item_id AS item_id FROM {search_api_db_idx_acervo_field_acv_editora_name} t WHERE (word = :db_condition_placeholder_5) UNION ALL SELECT t.item_id AS item_id FROM {search_api_db_idx_acervo_field_acv_obs_value} t WHERE (word = :db_condition_placeholder_6) UNION ALL SELECT t.item_id AS item_id FROM {search_api_db_idx_acervo_field_acv_origem_name} t WHERE (word = :db_condition_placeholder_7) UNION ALL SELECT t.item_id AS item_id FROM {search_api_db_idx_acervo_field_acv_assunto_name} t WHERE (word = :db_condition_placeholder_8) UNION ALL SELECT t.item_id AS item_id FROM {search_api_db_idx_acervo_field_acv_disponibilidade_name} t WHERE (word = :db_condition_placeholder_9) UNION ALL SELECT t.item_id AS item_id FROM {search_api_db_idx_acervo_field_acv_reproducao_name} t WHERE (word = :db_condition_placeholder_10) ) t)) AND( (t.status = :db_condition_placeholder_11) AND( (t_2.value = :db_condition_placeholder_12) OR (t_2.value = :db_condition_placeholder_13) OR (t_2.value = :db_condition_placeholder_14) OR (t_2.value = :db_condition_placeholder_15) ))
second echo
SELECT DISTINCT t.item_id AS item_id, :score AS score FROM {search_api_db_idx_acervo} t LEFT OUTER JOIN {search_api_db_idx_acervo_search_api_access_node} t_2 ON t.item_id = t_2.item_id WHERE (t.item_id NOT IN (SELECT t.item_id AS item_id FROM (SELECT t.item_id AS item_id FROM {search_api_db_idx_acervo_title} t WHERE (word = :db_condition_placeholder_0) UNION ALL SELECT t.item_id AS item_id FROM {search_api_db_idx_acervo_field_acv_ref_cus} t WHERE (word = :db_condition_placeholder_1) UNION ALL SELECT t.item_id AS item_id FROM {search_api_db_idx_acervo_field_acv_autor_name} t WHERE (word = :db_condition_placeholder_2) UNION ALL SELECT t.item_id AS item_id FROM {search_api_db_idx_acervo_field_acv_tipo_name} t WHERE (word = :db_condition_placeholder_3) UNION ALL SELECT t.item_id AS item_id FROM {search_api_db_idx_acervo_field_acv_local_name} t WHERE (word = :db_condition_placeholder_4) UNION ALL SELECT t.item_id AS item_id FROM {search_api_db_idx_acervo_field_acv_editora_name} t WHERE (word = :db_condition_placeholder_5) UNION ALL SELECT t.item_id AS item_id FROM {search_api_db_idx_acervo_field_acv_obs_value} t WHERE (word = :db_condition_placeholder_6) UNION ALL SELECT t.item_id AS item_id FROM {search_api_db_idx_acervo_field_acv_origem_name} t WHERE (word = :db_condition_placeholder_7) UNION ALL SELECT t.item_id AS item_id FROM {search_api_db_idx_acervo_field_acv_assunto_name} t WHERE (word = :db_condition_placeholder_8) UNION ALL SELECT t.item_id AS item_id FROM {search_api_db_idx_acervo_field_acv_disponibilidade_name} t WHERE (word = :db_condition_placeholder_9) UNION ALL SELECT t.item_id AS item_id FROM {search_api_db_idx_acervo_field_acv_reproducao_name} t WHERE (word = :db_condition_placeholder_10) ) t)) AND( (t.status = :db_condition_placeholder_11) AND( (t_2.value = :db_condition_placeholder_12) OR (t_2.value = :db_condition_placeholder_13) OR (t_2.value = :db_condition_placeholder_14) OR (t_2.value = :db_condition_placeholder_15) ))
CASE2
--------
Ok, if I comment all the three commands from the first echo block and keep only the second echo block I get the following result.
The sql is incorrect and it is using the term defined for the fulltext filter to compare with the field "status" resulting SQLSTATE[22P02].
second echo
SELECT DISTINCT t.item_id AS item_id, :score AS score FROM {search_api_db_idx_acervo} t LEFT OUTER JOIN {search_api_db_idx_acervo_search_api_access_node} t_2 ON t.item_id = t_2.item_id WHERE (t.item_id NOT IN (SELECT t.item_id AS item_id FROM (SELECT t.item_id AS item_id FROM {search_api_db_idx_acervo_title} t WHERE (word = :db_condition_placeholder_0) UNION ALL SELECT t.item_id AS item_id FROM {search_api_db_idx_acervo_field_acv_ref_cus} t WHERE (word = :db_condition_placeholder_1) UNION ALL SELECT t.item_id AS item_id FROM {search_api_db_idx_acervo_field_acv_autor_name} t WHERE (word = :db_condition_placeholder_2) UNION ALL SELECT t.item_id AS item_id FROM {search_api_db_idx_acervo_field_acv_tipo_name} t WHERE (word = :db_condition_placeholder_3) UNION ALL SELECT t.item_id AS item_id FROM {search_api_db_idx_acervo_field_acv_local_name} t WHERE (word = :db_condition_placeholder_4) UNION ALL SELECT t.item_id AS item_id FROM {search_api_db_idx_acervo_field_acv_editora_name} t WHERE (word = :db_condition_placeholder_5) UNION ALL SELECT t.item_id AS item_id FROM {search_api_db_idx_acervo_field_acv_obs_value} t WHERE (word = :db_condition_placeholder_6) UNION ALL SELECT t.item_id AS item_id FROM {search_api_db_idx_acervo_field_acv_origem_name} t WHERE (word = :db_condition_placeholder_7) UNION ALL SELECT t.item_id AS item_id FROM {search_api_db_idx_acervo_field_acv_assunto_name} t WHERE (word = :db_condition_placeholder_8) UNION ALL SELECT t.item_id AS item_id FROM {search_api_db_idx_acervo_field_acv_disponibilidade_name} t WHERE (word = :db_condition_placeholder_9) UNION ALL SELECT t.item_id AS item_id FROM {search_api_db_idx_acervo_field_acv_reproducao_name} t WHERE (word = :db_condition_placeholder_10) ) t)) AND( (t.status = :db_condition_placeholder_0) AND( (t_2.value = :db_condition_placeholder_1) OR (t_2.value = :db_condition_placeholder_2) OR (t_2.value = :db_condition_placeholder_3) OR (t_2.value = :db_condition_placeholder_4) ))
Conclusion
--------------
Honestly speaking I can't have a clear conclusion.
I can not explain why there is a bug in the code below
...
if ($skip_count || $results['result count']) {
if ($query->getOption('search_api_facets')) {
$results['search_api_facets'] = $this->getFacets($query, clone $db_query);
}
...
that stop to happen when I do:
...
if ($skip_count || $results['result count']) {
echo $db_query;
if ($query->getOption('search_api_facets')) {
$results['search_api_facets'] = $this->getFacets($query, clone $db_query);
}
...
In another words: why an "echo" in the variable would avoid the bug to happen?
I believe there is something wrong in:
....
if ($query->getOption('search_api_facets')) {
$results['search_api_facets'] = $this->getFacets($query, clone $db_query);
....
But I can't imagine what could be happening.
Regards,
Gilsberty
P.S.: the devel module gave me the same results...
1- using "dpq($db_query);" before the point where the bug is happening will fix it!
2 -using "dpq($db_query);" after the same point will not fix it!
Comment | File | Size | Author |
---|---|---|---|
#66 | 2142107-66--fix_select_query_clone.patch | 923 bytes | emanaton |
#58 | 2142107-58--fix_select_query_cloning.patch | 2.88 KB | drunken monkey |
#58 | 2142107-58--fix_select_query_cloning--tests_only.patch | 1.96 KB | drunken monkey |
Comments
Comment #1
gilsbert CreditAttribution: gilsbert commentedComment #2
gilsbert CreditAttribution: gilsbert commentedComment #3
drunken monkeyThanks a lot for debugging so thoroughly, this is a huge help!
However, I can't really say I understand the problem either. I know that outputting the query like this triggers it to be compiled internally (see
SelectQuery::__toString()
). Otherwise, it would only get compiled when executed. It seems that this earlier compiling fixes some bug that otherwise occurs later on. It's probably related to being cloned when computing the facets. (To test, could you maybe comment the$this->getFacets(…)
line and see if the query is correct then?)My theory would be that the
__clone()
implementation is not completely correct and some changes to the cloned query are in fact reflected back to the original one. By compiling the query before cloning it, this is somehow prevented (through internal caching of the arguments, or whatever).In any case, this is almost definitely a core bug of some sorts. Outputting the query shouldn't have any effect, a cloned query should also not interact with the original, and since we are definitely not setting the fulltext key as a status filter, there seems to be a bug there as well.
First off, are you using the latest version of Drupal core (dev would be ideal)? There were bugs like this before (see, e.g., #1792380: DatabaseCondition not cloning SelectQuery value object (documentation followup)) but I thought those were all fixed.
In case this is really a problem in the latest version, I'm moving this to the core issue queue now. Maybe someone can help there. (The problem might be DBMS-specific, I guess (mostly since no-one else has complained so far), so I'm using "postgresql db driver" as the component instead of "database system". If it is a general bug, feel free to move it. Also, instead of closing please move back to the "Search API Database Search" project if the issue is incorrect and there is no bug.)
Comment #4
drunken monkeyOops, wrong version.
Comment #5
gilsbert CreditAttribution: gilsbert commentedHi Drunken.
I made the test you asked and with the line "$results['search_api_facets'] = $this->getFacets($query, clone $db_query);" commented the issue is gone. We found the exact line with the issue!
I'm using the version 7.24. If there is a patch I can try it out but right now I can't use the dev version of the drupal core.
If I understood what you explained I believe you have found a good explanation. The clone operation might have a bug restricted to postgresql database. The bug is avoided when the query is compiled just like what happened using the echo over the variable.
Ouch... what a crazy thing!
I did other test:
...
$db_query2 = $db_query;
$results['search_api_facets'] = $this->getFacets($query, clone $db_query2);
...
Same behavior. No matter which variable is passed the clone is changing its content.
By the way in the last test both variables ($db_query and $db_query2) were changed. If this was already expected please forgive my ignorance.
What do you tnink about raising the priority of this issue to major?
Regards,
Gilsberty
Comment #6
drunken monkeyDrupal 7.24 is good enough, I'd say, it would just have been a problem if it was 7.10 or something similarly old. A quick
git diff
furthermore shows that there are no (non-comment) changes to the database system at all in dev compared to 7.24, so we can be fairly sure that the problem will be in both dev and 7.24.I wouldn't call it ignorance, but yes, it was expected. This is because in PHP 5, objects are always handled by reference. That's why we have to explicitly clone it when passing it into the
getFacets()
method.Normally, the clone operation should be implemented (using the
__clone()
magic method) in a way that also clones all objects that are referenced by the cloned object, so that the two copies are really independent. (See the PHP manual.) This doesn't seem to be the case here, which leads to the problem.I'm always a bit hesitant to do that. I'd say, let's just wait for any Postgres or DB maintainer to read this and let them decide. (If this doesn't happen for a few days, we can still raise the priority.)
Comment #7
gilsbert CreditAttribution: gilsbert commentedHi drunken!
After a deserved vacation I'm back.
This issue is getting more importance... I believe there is a second related issue: https://drupal.org/node/1349080 that depends on this one.
Thats why I'm raising the priority.
What else can we do to get a few attention?
Regards,
Gilsberty
Comment #8
gilsbert CreditAttribution: gilsbert commentedHi.
The issue https://drupal.org/node/1349080 is almost fixed so it is not related with this one.
I updated Drupal core to 7.26 and the reported issue with complex queries is not fixed yet.
Maybe we can contact someone able to help us... I'm not very confident that this post hit them.
Regards,
Gilsberty
Comment #9
drunken monkeyI know, it's (nearly) always the same thing when reporting Drupal core bugs, especially for niche functionality (which most bugs are, of course, so long after 7.0). It's frustrating.
The best thing you could do is probably to go into the #drupal IRC channel and ask around there, whether anyone has encountered the problem, has some idea or would look at it for you.
If that fails, however, you're probably left to either fix it yourself or pay someone to do it – and even then it might need a fair amount of IRC campaigning to get the patch reviewed and committed.
In any case, good luck! Sorry I can't be of more help to you here.
Comment #10
gilsbert CreditAttribution: gilsbert commentedOkie dokie.
I'm trying contact by IRC.
If I get answers I will update this post.
Regards,
Gilsberty
Comment #11
Crell CreditAttribution: Crell commentedPinging one of the Postgres maintainers...
Comment #12
Damien Tournoud CreditAttribution: Damien Tournoud commentedThis cannot be PostgreSQL specific. Nobody has complained about it on MySQL because the engine silently cast column types (so a comparison between
status
that is a number and the parameter that is a string would not trigger an error).Comment #13
gilsbert CreditAttribution: gilsbert commentedHi.
I agree with Damien but I can't confirm it because I dont have a mysql database to use with Drupal.
Drunken or someone else: may you please check it and confirm if this issue is happening over mysql too?
Regards,
Gilsberty
Comment #14
Damien Tournoud CreditAttribution: Damien Tournoud commentedThere are at least two (partially related issues here):
SelectQuery::__clone
doesn't clone the sub-query tables at allSelectQuery::__clone
doesn't callQuery::__clone
, so as a consequence its "placeholder generator id" doesn't get resetAlso, none of the other query types actually implement
__clone
, even if all of them have at least a WHERE condition that should be cloned. Of course, nobody bumped into this yet because cloning those is way less useful.Comment #15
jhodgdonAnother issue reported recently that is possibly a duplicate of this issue:
#2233605: Search query getting confused about which values go with which conditions
I marked the other as "related" because I wasn't sure if it was a duplicate or not? There is a clone happening in that query as well.
Comment #16
drunken monkeyTo hopefully move this forward finally: the attached patch works for me, fixing, e.g., #2299385: Search results not shown in view using several terms and facet filter .
Comment #17
St_B CreditAttribution: St_B commentedYour patch works !
Comment #18
gilsbert CreditAttribution: gilsbert commentedHi.
I tested drupal core 7.31 without the patch and the issue is gone.
Do we need the patch for 7.31 or is it already applied?
Regards,
Gilsberty
Comment #19
St_B CreditAttribution: St_B commentedHi, I have tested only with 7.28. We are going to update the core, I'll tell you the result.
Comment #20
St_B CreditAttribution: St_B commentedFor me it is not solved without the patch after updating the core to 7.31
Comment #21
gilsbert CreditAttribution: gilsbert commentedOk, I will retest as soon as possible.
Comment #22
drunken monkey@ gilsbert: It's definitely not been applied, and I wouldn't know a reason why it should now be fixed. Please re-test!
Also, if the problem is fixed with this patch, could someone set it to "Reviewed & tested by the community"?
Comment #23
St_B CreditAttribution: St_B commentedComment #24
gilsbert CreditAttribution: gilsbert commentedHi Drunken.
I'm sorry for taking so long to give you an answer.
Crazy days: new home, new job.... thanks God I still have the same wife! ;-)
I repeated the tests.
I confirm that the issue is gone since Drupal 7.31 but I have new information.
I did not save the old versions of search_api and search_api_db.
So what made this issue vanish for me?
I believe the new versions of search_api and/or search_api_db are making different sql statements and this new scenario is not triggering the specific situation.
I can confirm search_api 7.x-1.13 and search_api_db 7.x-1.4 dont trigger the issue.
I got this conclusion because the sql statements are slightly different from the old versions.
If you can point me a link with search_api_db version that triggers this situation I will retest.
Regards,
Gilsberty
Comment #25
St_B CreditAttribution: St_B commentedHi,
Here we also use search API 7.X-1.13 et Database search 7.x-1.4 and have this issue. We also use Biblio search API (which allows to search in special fields created by Biblio module), but I don't think this is the problem because we had the same problem on another drupal without Biblio module.
Regards
Stéphanie
Comment #26
gilsbert CreditAttribution: gilsbert commentedHi, good morning!
May it be related with PHP version? We are using 5.4.20 here.
Is it possible to pass a module (features) that will allow me to test the exact situation you have?
I'm deeply interested on investigate and help to fix this issue once for all.
Regards,
Gilsberty
Comment #27
drunken monkey@ gilsbert: You can find old releases of modules under "View all Releases" on the project page.
For Search API
For Search API DB
It's of course possible that some change there could lead to that issue not being triggered in your setup anymore.
Comment #30
David_Rothstein CreditAttribution: David_Rothstein commentedLooks like a testbot fluke.
Comment #33
David_Rothstein CreditAttribution: David_Rothstein commentedTestbot fluke.
Comment #36
David_Rothstein CreditAttribution: David_Rothstein commentedTestbot fluke.
Comment #38
David_Rothstein CreditAttribution: David_Rothstein commentedTook a look at this, and actually, doesn't this need to go into Drupal 8 first?
The code in this method for Drupal 8 is the exact same as the code in Drupal 7, so I would assume the same bug exists there.
Comment #40
Kristi Wachter CreditAttribution: Kristi Wachter as a volunteer commentedJust another report that the patch in #16 fixed the issue for me on a site running Drupal 7.43 with Search API 7.x-1.18 and Facet API 7.x-1.5.
This is a very hard-to-troubleshoot bug, and it would be great if we could get the fix committed to both Drupal 7 and Drupal 8 soon.
Thanks!
Comment #41
flocondetoileAnd another report that patch #16 fixed the issue with Search API 7.x-1.18 and Facet API 7.x-1.5 too. Thanks.
Comment #43
agerard CreditAttribution: agerard commentedAnd another report - patch #16 fixed the issue with Search API 7.x-1.20 and Facet API 7.x-1.5. Thanks much!
Comment #44
drunken monkeyHere is the same patch for Drupal 8 (8.2 and 8.3 should both work).
Comment #45
daffie CreditAttribution: daffie commentedThis needs test(s) to make sure that the problem is fixed and will stay fixed.
Comment #48
candelas CreditAttribution: candelas as a volunteer commentedThanks @drunken monkey :)
Patch in #16 works perfect. I was getting nuts with this :)
Comment #50
brickhauser CreditAttribution: brickhauser commented@ drunken monkey, your patch works great! You're a lifesaver #16
Comment #51
drunken monkeyTa-da.
Comment #54
giorgio79 CreditAttribution: giorgio79 commentedI am happy to confirm that #16 solved #2842853: Strange behaviour of tokenized fields for me! Thank you @drunken-monkey. You are the best, and still going strong in Drupal :)
Comment #55
wla_g CreditAttribution: wla_g as a volunteer commentedComment #56
TwoDTo add some context, @wla_g was my mentee today and worked on testing/reviewing this as he's got personal experience battling this bug for years on his D7 sites. He knew the fix works very well in production and it looks like a clean solution. To ensure it still applies cleanly and the D8 tests are correct we ran them again locally and verified the same fix is needed there.
Thanks to @wla_g for making me confident in mentoring my first sprint!
Comment #57
mondrakewe can use
$this->connection->select('test', 't');
here now.EDIT - also a couple of lines below.
Comment #58
drunken monkeyA dubious reason to hold up a bug fix that’s been needed for five years, but alright.
Please just review again and set back to RTBC!
Comment #59
mondrakeBack to RTBC.
Comment #60
mondrakeComment #64
catchFixed these on commit:
This should be 'Tests that...'.
Missing a period on the end.
Committed/pushed to 8.7.x and cherry-picked to 8.6.x. Thanks!
7.x issue here: #3000191: Complex cloned query dependent on __toString() call.
Comment #66
emanaton CreditAttribution: emanaton commentedHere's a re-roll of patch #16 for drupal 7.80.
I'm having the same issue, and this patch fixes it. My current applicable module versions are:
* search_api: 7.x-1.28
* search_api_db: 7.x-1.8
* facetapi: 7.x-1.6
Comment #69
quietone CreditAttribution: quietone at PreviousNext commentedClosed #1808624: SelectQuery __clone method does not recompute the Query uniqueIdentifier while other QueryPlaceholderInterface does as a duplicate, adding credit.