setParameter()没有设置正确的引号

时间:2014-02-10 14:01:55

标签: hibernate postgresql jpa

我有以下代码:

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

1 个答案:

答案 0 :(得分:1)

我想出的唯一解决方案是手动转义searchText:

String escapedSearchText = String.format("'%s'", searchText.replace("'", "''"));