diff --git a/shared/sqlitesearch.cpp b/shared/sqlitesearch.cpp index a779f2e..dbd59fc 100644 --- a/shared/sqlitesearch.cpp +++ b/shared/sqlitesearch.cpp @@ -66,6 +66,28 @@ QString SqliteSearch::createSortSql(const QVector sortConditions) return ""; } +QString SqliteSearch::escapeFtsArgument(QString ftsArg) +{ + QString result; + QRegularExpression extractor(R"#("([^"]*)"|([^\s]+))#"); + QRegularExpressionMatchIterator i = extractor.globalMatch(ftsArg); + while(i.hasNext()) + { + QRegularExpressionMatch m = i.next(); + QString value = m.captured(1); + if(value.isEmpty()) + { + value = m.captured(2); + } + else + { + value = "\"\"" + value + "\"\""; + } + result += "\"" + value + "\" "; + } + return result; +} + QPair> createNonArgPair(QString key) { return {" " + key + " ", QVector()}; @@ -117,7 +139,7 @@ QPair> SqliteSearch::createSql(const Token &token) { return {" content.id IN (SELECT fts.ROWID FROM fts WHERE fts.content MATCH ? ORDER BY " "rank) ", - {value}}; + {escapeFtsArgument(value)}}; } throw LooqsGeneralException("Unknown token passed (should not happen)"); } @@ -145,7 +167,7 @@ QSqlQuery SqliteSearch::makeSqlQuery(const LooqsQuery &query) ftsAlreadyJoined = true; } whereSql += " fts.content MATCH ? "; - bindValues.append(token.value); + bindValues.append(escapeFtsArgument(token.value)); } else { diff --git a/shared/sqlitesearch.h b/shared/sqlitesearch.h index ea2f70c..3acdd09 100644 --- a/shared/sqlitesearch.h +++ b/shared/sqlitesearch.h @@ -18,6 +18,7 @@ class SqliteSearch QString fieldToColumn(QueryField field); QPair> createSql(const Token &token); QString createSortSql(const QVector sortConditions); + QString escapeFtsArgument(QString ftsArg); }; #endif // SQLITESEARCH_H