我有以下代码:
String searchText = "...";
String sqlQuery =
"FROM Studio s " +
"WHERE fts('english', s.companyName, :q) = true";
Query q = JPA.em()
.createQuery(sqlQuery)
.setParameter("q", searchText);
当我将单个单词传递给searchText
时,它可以正常运行:
String searchText = "one";
当我传递两个词时,比如
String searchText = "one two";
我得到了
[PersistenceException:org.hibernate.exception.SQLGrammarException: 无法执行查询]
但是,当我传递带引号的字符串时,它再次起作用:
String searchText = "'one two'";
SetParameter
是否应该设置正确的引号并转义文本?
P.S。 fts
是PostgreSQL方言函数,定义如下:
public class MyPostgreSQLDialect extends PostgreSQLDialect {
public MyPostgreSQLDialect() {
registerFunction("fts", new PostgreSQLFullTextSearchFunction());
}
}
...
public class PostgreSQLFullTextSearchFunction implements SQLFunction {
public String render(@SuppressWarnings("rawtypes") List args, SessionFactoryImplementor factory) {
if (args.size() != 3) {
throw new IllegalArgumentException(
"The function must be passed 3 arguments");
}
String ftsConfig = (String) args.get(0);
String field = (String) args.get(1);
String value = (String) args.get(2);
String fragment = null;
if (ftsConfig == null) {
fragment = "to_tsvector(" + field + ") @@ " + "to_tsquery('"
+ value + "')";
} else {
fragment = "to_tsvector(" + ftsConfig + "::regconfig, " + field + ") @@ "
+ "to_tsquery(" + ftsConfig + ", " + value + ")";
}
return fragment;
}
@Override
public Type getReturnType(Type columnType, Mapping mapping)
throws QueryException {
return new BooleanType();
}
@Override
public boolean hasArguments() {
return true;
}
@Override
public boolean hasParenthesesIfNoArguments() {
return false;
}
@SuppressWarnings("rawtypes")
@Override
public String render(Type arg0, List arg1, SessionFactoryImplementor arg2)
throws QueryException {
return render(arg1, arg2);
}
}
它将查询转换为:
to_tsvector('english'::regconfig, studio0_.companyName) @@ to_tsquery('english', ?)
P.P.S。
PostreSQL日志:
2014-02-11 15:10:39 CET ERROR: syntax error in tsquery: "one two"
2014-02-11 15:10:39 CET STATEMENT: select studio0_.uuid as uuid164_, studio0_.addressScore as addressS2_164_, studio0_.adwordsAktivity as adwordsA3_164_, studio0_.affDiversityScore as affDiver4_164_, studio0_.allSources as allSources164_, studio0_.backgroundImg as backgrou6_164_, studio0_.city as city164_, studio0_.clusterDiversityScore as clusterD8_164_, studio0_.companyName as companyN9_164_, studio0_.companyNameCount as company10_164_, studio0_.companyType as company11_164_, studio0_.completenessScore as complet12_164_, studio0_.contentTags as content13_164_, studio0_.crefoId as crefoId164_, studio0_.decisionMaker1 as decisio15_164_, studio0_.decisionMaker2 as decisio16_164_, studio0_.description as descrip17_164_, studio0_.email as email164_, studio0_.email2 as email19_164_, studio0_.emailCount as emailCount164_, studio0_.fax1 as fax21_164_, studio0_.fax2 as fax22_164_, studio0_.faxImpressum as faxImpr23_164_, studio0_.fbProfileUrl as fbProfi24_164_, studio0_.formOfAddress as formOfA25_164_, studio0_.hasGeoCode as hasGeoCode164_, studio0_.house as house164_, studio0_.imprintDataExtracted as imprint28_164_, studio0_.industry1 as industry29_164_, studio0_.industry2 as industry30_164_, studio0_.internetIq as internetIq164_, studio0_.internetIqCluster as interne32_164_, studio0_.lastActivityDelta as lastAct33_164_, studio0_.lastActivitySource as lastAct34_164_, studio0_.lastActivityTime as lastAct35_164_, studio0_.logoImg as logoImg164_, studio0_.mgUuid as mgUuid164_, studio0_.mgcUuid as mgcUuid164_, studio0_.minCriticalityLevel as minCrit39_164_, studio0_.numCheckins as numChec40_164_, studio0_.numLikes as numLikes164_, studio0_.numLocations as numLoca42_164_, studio0_.numMentions as numMent43_164_, studio0_.numRatings as numRatings164_, studio0_.numSEMKeywords as numSEMK45_164_, studio0_.numVouchersSold as numVouc46_164_, studio0_.phone1 as phone47_164_, studio0_.phone2 as phone48_164_, studio0_.phone3 as phone49_164_, studio0_.phoneImpressum as phoneIm50_164_, studio0_.premiumRecordUrls as premium51_164_, studio0_.premiumRecords as premium52_164_, studio0_.qualityPrediction as quality53_164_, studio0_.rating as rating164_, studio0_.ratingSources as ratingS55_164_, studio0_.reachabilityScore as reachab56_164_, studio0_.sectorNameScore as sectorN57_164_, studio0_.sectorOverlapScore as sectorO58_164_, studio0_.sectorScore as sectorS59_164_, studio0_.socialMedia as socialM60_164_, studio0_.sourcesWithNoAff as sources61_164_, studio0_.starsOverall as starsOv62_164_, studio0_.street as street164_, studio0_.successfulWebsiteLookup as success64_164_, studio0_.targetGroupTags as targetG65_164_, studio0_.teaser as teaser164_, studio0_.totalSrcEntities as totalSr67_164_, studio0_.totalSrcEntitiesWithNoAff as totalSr68_164_, studio0_.totalSummaryScore as totalSu69_164_, studio0_.videoUrl as videoUrl164_, studio0_.voucherUrls as voucher71_164_, studio0_.vouchers as vouchers164_, studio0_.website as website164_, studio0_.website2 as website74_164_, studio0_.website3 as website75_164_, studio0_.websiteAvailability as website76_164_, studio0_.websiteCount as website77_164_, studio0_.zip as zip164_ from studio studio0_ where to_tsvector('german'::regconfig, studio0_.companyName) @@ to_tsquery('german', $1)=true limit $2
答案 0 :(得分:1)
我想出的唯一解决方案是手动转义searchText:
String escapedSearchText = String.format("'%s'", searchText.replace("'", "''"));