From 25e62cda03a43ded9f95830021aa1ff8e077997b Mon Sep 17 00:00:00 2001 From: Lukas Kahwe Smith Date: Wed, 11 Jun 2014 18:18:56 +0200 Subject: [PATCH] handle escaping fulltext search literal when converting from/to QOM/SQL2 --- CHANGELOG.md | 5 ++ .../Util/QOM/BaseQomToSqlQueryConverter.php | 5 +- src/PHPCR/Util/QOM/BaseSqlGenerator.php | 20 ++++++++ .../Util/QOM/Sql2ToQomQueryConverter.php | 48 +++++++++++++++++++ 4 files changed, 75 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fae711c..4965020 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,11 @@ Changelog ========= +1.1.1 +----- + +* **2014-06-11**: handle escaping fulltext search literal when converting from/to QOM/SQL2 + 1.1.0 ----- diff --git a/src/PHPCR/Util/QOM/BaseQomToSqlQueryConverter.php b/src/PHPCR/Util/QOM/BaseQomToSqlQueryConverter.php index b7eec17..6e55318 100644 --- a/src/PHPCR/Util/QOM/BaseQomToSqlQueryConverter.php +++ b/src/PHPCR/Util/QOM/BaseQomToSqlQueryConverter.php @@ -171,9 +171,8 @@ protected function convertFullTextSearchExpression($expr) if ($expr instanceof QOM\BindVariableValueInterface) { return $this->convertBindVariable($expr); } - if ($expr instanceof QOM\LiteralInterface) { - return $this->convertLiteral($expr); - } + + $expr = $this->generator->evalFullText($expr); return "'$expr'"; } diff --git a/src/PHPCR/Util/QOM/BaseSqlGenerator.php b/src/PHPCR/Util/QOM/BaseSqlGenerator.php index 54f219d..1cbb392 100644 --- a/src/PHPCR/Util/QOM/BaseSqlGenerator.php +++ b/src/PHPCR/Util/QOM/BaseSqlGenerator.php @@ -217,6 +217,26 @@ public function evalBindVariable($var) return '$' . $var; } + /** + * Escape the illegal characters for inclusion in a fulltext statement. Escape Character is \\. + * + * @param string $string + * + * @return string Escaped String + * + * @see http://jackrabbit.apache.org/api/1.4/org/apache/jackrabbit/util/Text.html #escapeIllegalJcrChars + */ + public function evalFullText($string) + { + $illegalCharacters = array( + '!' => '\\!', '(' => '\\(', ':' => '\\:', '^' => '\\^', + '[' => '\\[', ']' => '\\]', '{' => '\\{', '}' => '\\}', + '\"' => '\\\"', '?' => '\\?', "'" => "''", + ); + + return strtr($string, $illegalCharacters); + } + /** * Literal ::= CastLiteral | UncastLiteral * diff --git a/src/PHPCR/Util/QOM/Sql2ToQomQueryConverter.php b/src/PHPCR/Util/QOM/Sql2ToQomQueryConverter.php index 3d485b5..be59a0d 100644 --- a/src/PHPCR/Util/QOM/Sql2ToQomQueryConverter.php +++ b/src/PHPCR/Util/QOM/Sql2ToQomQueryConverter.php @@ -811,6 +811,7 @@ protected function parseLiteral() } $token = substr($token, 1, -1); $token = str_replace('\\'.$quoteString, $quoteString, $token); + $token = str_replace("''", "'", $token); if (preg_match('/^\d{4}-\d{2}-\d{2}( \d{2}:\d{2}:\d+)?$/', $token)) { if (preg_match('/^\d{4}-\d{2}-\d{2}$/', $token)) { $token.= ' 00:00:00'; @@ -828,6 +829,53 @@ protected function parseLiteral() return $this->factory->literal($token); } + /** + * 6.7.34 Fulltext Literal + * Parse an SQL2 literal value + * + * @return LiteralInterface + */ + protected function parseFulltextLiteral() + { + $token = $this->scanner->fetchNextToken(); + if ($this->scanner->tokenIs($token, 'CAST')) { + return $this->parseCastLiteral($token); + } + + $quoteString = false; + if (substr($token, 0, 1) === '\'') { + $quoteString = "'"; + } elseif (substr($token, 0, 1) === '"') { + $quoteString = '"'; + } + + if ($quoteString) { + while (substr($token, -1) !== $quoteString) { + $nextToken = $this->scanner->fetchNextToken(); + if ('' === $nextToken) { + break; + } + $token .= $this->scanner->getPreviousDelimiter(); + $token .= $nextToken; + } + + if (substr($token, -1) !== $quoteString) { + throw new InvalidQueryException("Syntax error: unterminated quoted string $token in '{$this->sql2}'"); + } + $token = substr($token, 1, -1); + $token = str_replace('\\'.$quoteString, $quoteString, $token); + $illegalCharacters = array( + '\\!' => '!', '\\(' => '(', '\\:' => ':', '\\^' => '^', + '\\[' => '[', '\\]' => ']', '\\{' => '{', '\\}' => '}', + '\\\"' => '\"', '\\?' => '?', "''" => "'", + ); + + $token = strtr($token, $illegalCharacters); + + } + + return $this->factory->literal($token); + } /** * 6.7.37 Ordering */