1 16 package org.outerj.daisy.query.model; 17 18 import org.outerj.daisy.query.QueryContext; 19 import org.outerj.daisy.repository.query.QueryException; 20 import org.outerj.daisy.repository.query.EvaluationContext; 21 import org.outerj.daisy.repository.Document; 22 import org.outerj.daisy.repository.Version; 23 24 import java.util.regex.Pattern ; 25 import java.util.regex.Matcher ; 26 import java.sql.PreparedStatement ; 27 import java.sql.SQLException ; 28 29 public class Like extends AbstractPredicateExpr { 30 private final ValueExpr valueExpr; 31 private final Literal literal; 32 private final boolean not; 33 private Pattern likePattern; 34 35 public Like(boolean not, ValueExpr valueExpr, Literal literal) { 36 this.valueExpr = valueExpr; 37 this.literal = literal; 38 this.not = not; 39 } 40 41 public void prepare(QueryContext context) throws QueryException { 42 valueExpr.prepare(context); 43 if (valueExpr.isSymbolicIdentifier()) 44 throw new QueryException("A symbolic identifier cannot be used with LIKE"); 45 46 if (valueExpr.getValueType() != QValueType.STRING && valueExpr.getValueType() != QValueType.UNDEFINED) { 47 throw new QueryException("LIKE can only be used for strings."); 48 } 49 } 50 51 public boolean evaluate(Document document, Version version, EvaluationContext evaluationContext) throws QueryException { 52 Object value = valueExpr.evaluate(QValueType.STRING, document, version, evaluationContext); 53 if (value instanceof Object []) { 54 Object [] values = (Object [])value; 56 for (int i = 0; i < values.length; i++) { 57 if (evaluate(values[i])) 58 return true; 59 } 60 return false; 61 } else { 62 return evaluate(value); 63 } 64 } 65 66 private boolean evaluate(Object value) throws QueryException { 67 compileLikePattern(); 68 Matcher matcher = likePattern.matcher((String )value); 69 boolean matches = matcher.matches(); 70 return not? !matches :matches; 71 } 72 73 public Tristate appliesTo(Document document) throws QueryException { 74 if (valueExpr.canTestAppliesTo()) { 75 boolean result = evaluate(valueExpr.evaluate(QValueType.STRING, document, null, new EvaluationContext())); 76 return result ? Tristate.YES : Tristate.NO; 77 } else { 78 return Tristate.MAYBE; 79 } 80 } 81 82 86 private void compileLikePattern() throws QueryException { 87 if (likePattern != null) 88 return; 89 90 String likeExpr = (String )literal.evaluate(QValueType.STRING); 91 StringBuffer pattern = new StringBuffer ((likeExpr.length() * 4) + 10); 92 93 boolean inEscape = false; 94 for (int i = 0; i < likeExpr.length(); i++) { 95 char c = likeExpr.charAt(i); 96 switch (c) { 97 case '%': 98 if (inEscape) { 99 inEscape = false; 100 pattern.append('%'); 101 } else { 102 pattern.append(".*"); 103 } 104 break; 105 case '_': 106 if (inEscape) { 107 inEscape = false; 108 pattern.append('_'); 109 } else { 110 pattern.append('.'); 111 } 112 break; 113 case '\\': 114 inEscape = true; 116 break; 117 default: 118 char ch1 = Character.forDigit((c >> 4) & 0xF, 16); 119 char ch2 = Character.forDigit(c & 0xF, 16); 120 pattern.append('\\').append('u').append('0').append('0').append(ch1).append(ch2); 121 break; 122 } 123 } 124 likePattern = Pattern.compile(pattern.toString()); 125 } 126 127 public AclConditionViolation isAclAllowed() { 128 return valueExpr.isAclAllowed(); 129 } 130 131 public void generateSql(StringBuffer sql, SqlGenerationContext context) throws QueryException { 132 sql.append(" ("); 133 String preCond = valueExpr.getSqlPreConditions(context); 134 if (preCond != null) 135 sql.append(preCond).append(" AND "); 136 valueExpr.generateSqlValueExpr(sql, context); 137 if (not) 138 sql.append(" NOT LIKE "); 139 else 140 sql.append(" LIKE "); 141 sql.append(" ?) "); 142 } 143 144 public int bindSql(PreparedStatement stmt, int bindPos, EvaluationContext evaluationContext) throws SQLException , QueryException { 145 bindPos = valueExpr.bindPreConditions(stmt, bindPos); 146 bindPos = valueExpr.bindValueExpr(stmt, bindPos, QValueType.STRING, evaluationContext); 147 bindPos = literal.bindValueExpr(stmt, bindPos, QValueType.STRING, evaluationContext); 148 return bindPos; 149 } 150 } 151 | Popular Tags |