1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-11-10 00:42:41 +01:00

Tighten query compiler rules around spaces inside and after operators

Summary:
Ref T13509. Since `title:- cat` is now ambiguous, forbid spaces after operators.

Also, forbid spaces inside operators, although this has no effect today.

Test Plan: Added unit tests, ran unit tests.

Maniphest Tasks: T13509

Differential Revision: https://secure.phabricator.com/D21109
This commit is contained in:
epriestley 2020-04-14 09:28:38 -07:00
parent 8fa8d0e648
commit 143f86d60b
2 changed files with 73 additions and 10 deletions

View file

@ -172,8 +172,10 @@ final class PhutilSearchQueryCompiler
}
if ($mode == 'operator') {
if (preg_match('/^\s\z/u', $character)) {
continue;
if (!$current_operator) {
if (preg_match('/^\s\z/u', $character)) {
continue;
}
}
if (preg_match('/^'.$operator_characters.'\z/', $character)) {
@ -337,6 +339,7 @@ final class PhutilSearchQueryCompiler
'operator' => $operator,
'quoted' => $is_quoted,
'value' => $value,
'raw' => $this->getDisplayToken($token),
);
if ($enable_functions) {
@ -355,16 +358,58 @@ final class PhutilSearchQueryCompiler
$result['function'] = $function;
if ($result['quoted']) {
$last_function = null;
} else {
$is_sticky = !$result['quoted'];
switch ($operator) {
case self::OPERATOR_ABSENT:
case self::OPERATOR_PRESENT:
$is_sticky = false;
break;
}
if ($is_sticky) {
$last_function = $function;
} else {
$last_function = null;
}
}
$results[] = $result;
}
if ($enable_functions) {
// If any function is required to be "absent", there must be no other
// terms which make assertions about it.
$present_tokens = array();
$absent_tokens = array();
foreach ($results as $result) {
$function = $result['function'];
if ($result['operator'] === self::OPERATOR_ABSENT) {
$absent_tokens[$function][] = $result;
} else {
$present_tokens[$function][] = $result;
}
}
foreach ($absent_tokens as $function => $tokens) {
$absent_token = head($tokens);
if (empty($present_tokens[$function])) {
continue;
}
$present_token = head($present_tokens[$function]);
throw new PhutilSearchQueryCompilerSyntaxException(
pht(
'Query field must be absent ("%s") and present ("%s"). This '.
'is impossible, so the query is not valid.',
$absent_token['raw'],
$present_token['raw']));
}
}
return $results;
}

View file

@ -10,10 +10,6 @@ final class PhutilSearchQueryCompilerTestCase
'cat -dog' => '+"cat" -"dog"',
'cat-dog' => '+"cat-dog"',
// If there are spaces after an operator, the operator applies to the
// next search term.
'cat - dog' => '+"cat" -"dog"',
// Double quotes serve as delimiters even if there is no whitespace
// between terms.
'"cat"dog' => '+"cat" +"dog"',
@ -40,9 +36,16 @@ final class PhutilSearchQueryCompilerTestCase
// Trailing whitespace should be discarded.
'a b ' => '+"a" +"b"',
// Functions must have search text.
// Tokens must have search text.
'""' => false,
'-' => false,
// Previously, we permitted spaces to appear inside or after operators.
// Now that "title:-" is now a valid construction meaning "title is
// absent", this had to be tightened. We want "title:- duck" to mean
// "title is absent, and any other field matches 'duck'".
'cat - dog' => false,
);
$this->assertCompileQueries($tests);
@ -171,6 +174,21 @@ final class PhutilSearchQueryCompilerTestCase
array('title', $op_and, 'x'),
array(null, $op_and, 'y'),
),
// The "present" and "absent" functions are not sticky.
'title:~ x' => array(
array('title', $op_present, null),
array(null, $op_and, 'x'),
),
'title:- x' => array(
array('title', $op_absent, null),
array(null, $op_and, 'x'),
),
// These queries require a field be both present and absent, which is
// impossible.
'title:- title:x' => false,
'title:- title:~' => false,
);
$this->assertCompileFunctionQueries($function_tests);