Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix EZP-27416: Error 500 on search when trying to search space or single quote #2029

Conversation

adamwojs
Copy link
Member

@adamwojs adamwojs commented Jun 20, 2017

JIRA: https://jira.ez.no/browse/EZP-27416

Description

This PR provide patch to incorrect generated SQL in Legacy Search Engine when user is trying to search a query that contains only a word separators characters e.g single quote character.

Steps to reproduce

  1. Setup Legacy Search Engine
  2. In Platform UI go to Content > Content structure > Search
  3. Try to search: ' (single quote)
  4. Backend will return "Internal server error" with the following description:
The expression ' OR ' expected at least 1 argument but none provided.

TODO

  • Patch
  • Tests

@adamwojs adamwojs changed the base branch from master to 6.7 June 20, 2017 20:13
@andrerom
Copy link
Contributor

Will you also reuse $wordIdSubquery below? ;)

@adamwojs
Copy link
Member Author

@andrerom Fixed :-)


$wordIdSubquery = $this->getWordIdSubquery($subSelect, $criterion->value);
if ($wordIdSubquery === null) {
return $query->expr->neq(1, 1);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is still not compatible with declared return type, and I think it's require few words of comment .

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is still not compatible with declared return type, and I think it's require few words of comment .

I looked over returned values in other criterions and I actually think that @return in getWordIdSubquery PhpDoc is just wrong - it should be @return string because all methods of the eZ\Publish\Core\Persistence\Database\Expression interface return string as well.

@adamwojs
Copy link
Member Author

Updated with PostgreSQL compatible version.

@adamwojs adamwojs changed the title [WIP] Fix EZP-27416: Error 500 on search when trying to search space or single quote Fix EZP-27416: Error 500 on search when trying to search space or single quote Jun 21, 2017
@alongosz
Copy link
Member

I gave it a little bit of thought and I think we should consider two separate cases here, applied on SQL Search layer, so not affecting other search engines:

  1. In eZ\Publish\Core\Search\Legacy\Content\Handler::findContent at the beginning we should check empty value:
if (trim($query->query->value) === '') {
    return new SearchResult(['time' => 0, 'totalCount' => 0]);
}

because search for an empty value should always return 0 count in 0 time (other SearchResult fields already have proper default values). Note on 0 time - it will be accurate with respect to current code if the above block gets placed as described, at the beginning of findContent

  1. When we get empty-ish value, e.g. containing quotes, we actually should throw API InvalidArgumentException (instead of returning null in getWordIdSubquery). Meaning: when tokenizer returns empty result - something went wrong, because we already checked one of the expected states in point 1. ^
    This exception is already hinted on findContent PhpDoc and is AFAIR close to what @adamwojs suggested when we initially discussed this :-)

WDYT @andrerom ?

Copy link
Member

@alongosz alongosz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some minor comments below:

array('searchQuery' => ''),
array('searchQuery' => '\''),
array('searchQuery' => ' '),
);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick: please use short array syntax.

*
* @dataProvider getFullTextQueriesWithoutWords
*/
public function testFullTextOnQueryWithoutWords($searchQuery)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please hint also @param in PhpDoc

$contentService->publishVersion(
$contentService->createContent(
$contentCreateStruct,
array($locationService->newLocationCreateStruct(2))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick: please use short array syntax.

$query = new Query(
array(
'query' => new Criterion\FullText($searchQuery),
)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick: please use short array syntax.


$wordIdSubquery = $this->getWordIdSubquery($subSelect, $criterion->value);
if ($wordIdSubquery === null) {
return $query->expr->neq(1, 1);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is still not compatible with declared return type, and I think it's require few words of comment .

I looked over returned values in other criterions and I actually think that @return in getWordIdSubquery PhpDoc is just wrong - it should be @return string because all methods of the eZ\Publish\Core\Persistence\Database\Expression interface return string as well.

@ezsystems ezsystems deleted a comment from ezrobot Jun 21, 2017
@adamwojs
Copy link
Member Author

adamwojs commented Aug 3, 2017

@andrerom WDYT about @alongosz idea? IMHO is a cleaner solution than generating a query that always returns an empty result set.

@andrerom
Copy link
Contributor

andrerom commented Aug 3, 2017

@adamwojs I kind of likes part of the proposal, but I had and have doubts about hardcoding logic about full text in the handler, as value can be anything here right?

@alongosz
Copy link
Member

alongosz commented Aug 4, 2017

I had and have doubts about hardcoding logic about full text in the handler, as value can be anything here right?

@adamwojs: @andrerom has a good point here, I looked at this from the FullText Criterion perspective, not the whole scope of all possible Criterions - my mistake.

To determine if the value is correct should be a responsibility of eZ\Publish\Core\Search\Legacy\Content\Common\Gateway\CriterionHandler\FullText::handle.
While I'd prefer in case of empty value to get 0 count result, due do the way query expression is processed and built we cannot do it without a major refactoring.
In this case I'd go with InvalidArgumentException also for "pure" empty value ''.

@andrerom can we expect from API consumer not to allow such queries or be prepared for this exception?
If not, then the last thing, I could think of, we could do to solve this is to introduce our own exception thrown from FullText::handle and caught/handled in \eZ\Publish\Core\Search\Legacy\Content\Gateway\DoctrineDatabase::find or even in getResultCount by returning 0 result count.

@andrerom
Copy link
Contributor

andrerom commented Aug 4, 2017

If not, then the last thing

I was thinking in similar way, adding exception that we handle internally, however how do we then tell UI to tell the user the query was invalid and this is why there is empty result?

@alongosz
Copy link
Member

alongosz commented Aug 4, 2017

I was thinking in similar way, adding exception that we handle internally, however how do we then tell UI to tell the user the query was invalid and this is why there is empty result?

True. So I'd say the only one valid solution is to throw InvalidArgumentException for empty values as well. SearchService::findContent hints it, so my previous concern about API consumer expectations seems to be resolved.

@adamwojs adamwojs force-pushed the fix-EZP-27416-500_on_search_when_trying_to_search_space_or_single_quote branch from 57d1ddc to 39d37e8 Compare August 8, 2017 09:37
@adamwojs
Copy link
Member Author

adamwojs commented Aug 8, 2017

I've updated PR according to our consensus about solution

@adamwojs adamwojs force-pushed the fix-EZP-27416-500_on_search_when_trying_to_search_space_or_single_quote branch from 39d37e8 to 6d864c9 Compare August 8, 2017 09:42
@adamwojs adamwojs force-pushed the fix-EZP-27416-500_on_search_when_trying_to_search_space_or_single_quote branch from 6d864c9 to c1c11a6 Compare August 8, 2017 10:38
@ezsystems ezsystems deleted a comment from ezrobot Aug 8, 2017
@ezsystems ezsystems deleted a comment from ezrobot Aug 8, 2017
*/
protected function getWordIdSubquery(SelectQuery $query, $string)
{
$subQuery = $query->subSelect();
$tokens = $this->tokenizeString(
$this->processor->transform($string, $this->configuration['commands'])
);

if (empty($tokens)) {
throw new InvalidArgumentException('string', 'Search query does not contains any searchable token');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should rather be something that actually is 1. concrete enoug so devs know what is wrong, 2. user friendly enough so user knows what he did wrong.

Unsure, but something like :
Search query does not contain a valid FullText search string

Would also be great if we can create a new exception that extends InvalidArgumentException, so UI code can detect it better in case they want to provide a better user feedback then this.

@@ -178,14 +178,21 @@ protected function getWordExpression(SelectQuery $query, $token)
* @param \eZ\Publish\Core\Persistence\Database\SelectQuery $query
* @param string $string
*
* @return \eZ\Publish\Core\Persistence\Database\SelectQuery
* @return \eZ\Publish\Core\Persistence\Database\SelectQuery|null
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

when does it return null? On exceptions nothing is returned at all ;)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

*Also note that handle() should add phpdoc that it uses getWordIdSubquery so the throw part gets reflected there to.

Copy link
Contributor

@andrerom andrerom left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Think this is better, some nitpicks added

@@ -0,0 +1,21 @@
<?php

namespace eZ\Publish\Core\Search\Common\Exception;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure about namespace, but for me is too specific for \eZ\Publish\Core\Base\Exceptions and too generic for concrete search engine impl.

/**
* Exception thrown FullText search string is invalid.
*/
class InvalidFullTextSearchString extends InvalidArgumentException
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe InvalidFullTextQuery will be better a name ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd say either keep it as is or InvalidFullTextSearchQuery.

Side thing: if we intend for external bundle to be able to catch it (and thus refer to it), shouldn't it be a part of API, not Core? Or maybe SPI to avoid cluttering API namespace? POV @andrerom?

…t contain valid token in Legacy Search Engine
@adamwojs
Copy link
Member Author

Closing PR as obsolete. eZ Platform 2.5 has reached EOM, so please reopen PR in ezsystems/ezplatform-kernel (bug fixes) or ibexa/core (features/improvements) if issue is still valid for v3.3 / v4.x and you are willing to work on it.

@adamwojs adamwojs closed this Apr 19, 2022
@adamwojs adamwojs deleted the fix-EZP-27416-500_on_search_when_trying_to_search_space_or_single_quote branch April 19, 2022 14:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
3 participants