1 19 package org.apache.cayenne.access.jdbc; 20 21 import java.math.BigDecimal ; 22 import java.util.ArrayList ; 23 import java.util.Iterator ; 24 import java.util.List ; 25 import java.util.Map ; 26 27 import org.apache.cayenne.ObjectId; 28 import org.apache.cayenne.Persistent; 29 import org.apache.cayenne.ejbql.EJBQLBaseVisitor; 30 import org.apache.cayenne.ejbql.EJBQLException; 31 import org.apache.cayenne.ejbql.EJBQLExpression; 32 import org.apache.cayenne.ejbql.parser.EJBQLPath; 33 import org.apache.cayenne.ejbql.parser.EJBQLPositionalInputParameter; 34 35 39 class EJBQLConditionTranslator extends EJBQLBaseVisitor { 40 41 private EJBQLTranslationContext context; 42 43 private List multiColumnOperands; 44 45 EJBQLConditionTranslator(EJBQLTranslationContext context) { 46 this.context = context; 47 } 48 49 void addMultiColumnOperand(EJBQLMultiColumnOperand operand) { 50 if (multiColumnOperands == null) { 51 multiColumnOperands = new ArrayList (2); 52 } 53 54 multiColumnOperands.add(operand); 55 } 56 57 public boolean visitAnd(EJBQLExpression expression, int finishedChildIndex) { 58 afterChild(expression, " AND", finishedChildIndex); 59 return true; 60 } 61 62 public boolean visitBetween(EJBQLExpression expression, int finishedChildIndex) { 63 switch (finishedChildIndex) { 64 case 0: 65 if (expression.isNegated()) { 66 context.append(" NOT"); 67 } 68 context.append(" BETWEEN"); 69 break; 70 case 1: 71 context.append(" AND"); 72 break; 73 } 74 75 return true; 76 } 77 78 public boolean visitOr(EJBQLExpression expression, int finishedChildIndex) { 79 afterChild(expression, " OR", finishedChildIndex); 80 return true; 81 } 82 83 public boolean visitEquals(EJBQLExpression expression, int finishedChildIndex) { 84 switch (finishedChildIndex) { 85 case 0: 86 context.append(" ="); 87 break; 88 case 1: 89 if (multiColumnOperands != null) { 92 93 if (multiColumnOperands.size() != 2) { 94 throw new EJBQLException( 95 "Invalid multi-column equals expression. Expected 2 multi-column operands, got " 96 + multiColumnOperands.size()); 97 } 98 99 context.trim(2); 100 101 EJBQLMultiColumnOperand lhs = (EJBQLMultiColumnOperand) multiColumnOperands 102 .get(0); 103 EJBQLMultiColumnOperand rhs = (EJBQLMultiColumnOperand) multiColumnOperands 104 .get(1); 105 106 Iterator it = lhs.getKeys().iterator(); 107 while (it.hasNext()) { 108 Object key = it.next(); 109 110 lhs.appendValue(key); 111 context.append(" ="); 112 rhs.appendValue(key); 113 114 if (it.hasNext()) { 115 context.append(" AND"); 116 } 117 } 118 119 multiColumnOperands = null; 120 } 121 122 break; 123 } 124 125 return true; 126 } 127 128 public boolean visitNamedInputParameter(EJBQLExpression expression) { 129 String parameter = context.bindNamedParameter(expression.getText()); 130 processParameter(parameter); 131 return true; 132 } 133 134 public boolean visitNot(EJBQLExpression expression) { 135 context.append(" NOT"); 136 return true; 137 } 138 139 public boolean visitNotEquals(EJBQLExpression expression, int finishedChildIndex) { 140 switch (finishedChildIndex) { 141 case 0: 142 context.append(" <>"); 143 break; 144 case 1: 145 if (multiColumnOperands != null) { 148 149 if (multiColumnOperands.size() != 2) { 150 throw new EJBQLException( 151 "Invalid multi-column equals expression. Expected 2 multi-column operands, got " 152 + multiColumnOperands.size()); 153 } 154 155 context.trim(3); 156 157 EJBQLMultiColumnOperand lhs = (EJBQLMultiColumnOperand) multiColumnOperands 158 .get(0); 159 EJBQLMultiColumnOperand rhs = (EJBQLMultiColumnOperand) multiColumnOperands 160 .get(1); 161 162 Iterator it = lhs.getKeys().iterator(); 163 while (it.hasNext()) { 164 Object key = it.next(); 165 166 lhs.appendValue(key); 167 context.append(" <>"); 168 rhs.appendValue(key); 169 170 if (it.hasNext()) { 171 context.append(" OR"); 172 } 173 } 174 175 multiColumnOperands = null; 176 } 177 178 break; 179 } 180 return true; 181 } 182 183 public boolean visitGreaterThan(EJBQLExpression expression, int finishedChildIndex) { 184 if (finishedChildIndex == 0) { 185 context.append(" >"); 186 } 187 188 return true; 189 } 190 191 public boolean visitGreaterOrEqual(EJBQLExpression expression, int finishedChildIndex) { 192 if (finishedChildIndex == 0) { 193 context.append(" >="); 194 } 195 196 return true; 197 } 198 199 public boolean visitLessOrEqual(EJBQLExpression expression, int finishedChildIndex) { 200 if (finishedChildIndex == 0) { 201 context.append(" <="); 202 } 203 204 return true; 205 } 206 207 public boolean visitLessThan(EJBQLExpression expression, int finishedChildIndex) { 208 if (finishedChildIndex == 0) { 209 context.append(" <"); 210 } 211 212 return true; 213 } 214 215 public boolean visitLike(EJBQLExpression expression, int finishedChildIndex) { 216 if (finishedChildIndex == 0) { 217 if (expression.isNegated()) { 218 context.append(" NOT"); 219 } 220 context.append(" LIKE"); 221 } 222 223 return true; 224 } 225 226 protected void afterChild(EJBQLExpression e, String text, int childIndex) { 227 if (childIndex >= 0) { 228 if (childIndex + 1 < e.getChildrenCount()) { 229 context.append(text); 230 } 231 } 232 } 233 234 public boolean visitPath(EJBQLPath expression, int finishedChildIndex) { 235 236 expression.visit(new EJBQLPathTranslator(context) { 237 238 protected void appendMultiColumnPath(EJBQLMultiColumnOperand operand) { 239 EJBQLConditionTranslator.this.addMultiColumnOperand(operand); 240 } 241 }); 242 return false; 243 } 244 245 public boolean visitIntegerLiteral(EJBQLExpression expression) { 246 if (expression.getText() == null) { 247 context.append("null"); 248 } 249 else { 250 Object value; 251 252 try { 253 value = new Integer (expression.getText()); 254 } 255 catch (NumberFormatException nfex) { 256 throw new EJBQLException("Invalid integer: " + expression.getText()); 257 } 258 259 String var = context.bindParameter(value); 260 context.append(" #bind($").append(var).append(" 'INTEGER')"); 261 } 262 return true; 263 } 264 265 public boolean visitDecimalLiteral(EJBQLExpression expression) { 266 if (expression.getText() == null) { 267 context.append("null"); 268 } 269 else { 270 Object value; 271 272 try { 273 value = new BigDecimal (expression.getText()); 274 } 275 catch (NumberFormatException nfex) { 276 throw new EJBQLException("Invalid decimal: " + expression.getText()); 277 } 278 279 String var = context.bindParameter(value); 280 context.append(" #bind($").append(var).append(" 'DECIMAL')"); 281 } 282 return true; 283 } 284 285 public boolean visitPatternValue(EJBQLExpression expression) { 286 return true; 288 } 289 290 public boolean visitIsNull(EJBQLExpression expression, int finishedChildIndex) { 291 if (finishedChildIndex == 0) { 292 context.append(expression.isNegated() ? " IS NOT NULL" : " IS NULL"); 293 } 294 295 return true; 296 } 297 298 public boolean visitPositionalInputParameter(EJBQLPositionalInputParameter expression) { 299 300 String parameter = context.bindPositionalParameter(expression.getPosition()); 301 processParameter(parameter); 302 return true; 303 } 304 305 public boolean visitStringLiteral(EJBQLExpression expression) { 306 if (expression.getText() == null) { 307 context.append("null"); 308 } 309 else { 310 context.append(" #bind(").append(expression.getText()).append(" 'VARCHAR')"); 313 } 314 return true; 315 } 316 317 private void processParameter(String boundName) { 318 Object object = context.getBoundParameter(boundName); 319 320 Map map = null; 321 if (object instanceof Persistent) { 322 map = ((Persistent) object).getObjectId().getIdSnapshot(); 323 } 324 else if (object instanceof ObjectId) { 325 map = ((ObjectId) object).getIdSnapshot(); 326 } 327 else if (object instanceof Map ) { 328 map = (Map ) object; 329 } 330 331 if (map != null) { 332 if (map.size() == 1) { 333 context.rebindParameter(boundName, map.values().iterator().next()); 334 } 335 else { 336 addMultiColumnOperand(EJBQLMultiColumnOperand.getObjectOperand( 337 context, 338 map)); 339 return; 340 } 341 } 342 343 if (object != null) { 344 context.append(" #bind($").append(boundName).append(")"); 345 } 346 else { 347 352 context.append(" #bind($").append(boundName).append(" 'VARCHAR')"); 355 } 356 } 357 } 358 | Popular Tags |