1 package net.sf.saxon.expr; 2 import net.sf.saxon.functions.*; 3 import net.sf.saxon.om.Item; 4 import net.sf.saxon.sort.AtomicComparer; 5 import net.sf.saxon.sort.CodepointCollator; 6 import net.sf.saxon.trans.DynamicError; 7 import net.sf.saxon.trans.StaticError; 8 import net.sf.saxon.trans.XPathException; 9 import net.sf.saxon.type.AtomicType; 10 import net.sf.saxon.type.ItemType; 11 import net.sf.saxon.type.Type; 12 import net.sf.saxon.value.*; 13 14 import java.util.Comparator ; 15 16 21 22 public final class ValueComparison extends BinaryExpression { 23 24 private AtomicComparer comparer; 25 26 32 33 public ValueComparison(Expression p1, int op, Expression p2) { 34 super(p1, op, p2); 35 } 36 37 40 41 public Expression typeCheck(StaticContext env, ItemType contextItemType) throws XPathException { 42 43 operand0 = operand0.typeCheck(env, contextItemType); 44 if (operand0 instanceof EmptySequence) { 45 return operand0; 46 } 47 operand1 = operand1.typeCheck(env, contextItemType); 48 if (operand1 instanceof EmptySequence) { 49 return operand1; 50 } 51 52 final SequenceType optionalAtomic = SequenceType.OPTIONAL_ATOMIC; 53 54 RoleLocator role0 = new RoleLocator(RoleLocator.BINARY_EXPR, Token.tokens[operator], 0, null); 55 role0.setSourceLocator(this); 56 operand0 = TypeChecker.staticTypeCheck(operand0, optionalAtomic, false, role0, env); 57 58 RoleLocator role1 = new RoleLocator(RoleLocator.BINARY_EXPR, Token.tokens[operator], 1, null); 59 role1.setSourceLocator(this); 60 operand1 = TypeChecker.staticTypeCheck(operand1, optionalAtomic, false, role1, env); 61 62 AtomicType t1 = operand0.getItemType().getAtomizedItemType(); 63 AtomicType t2 = operand1.getItemType().getAtomizedItemType(); 64 65 int p1 = t1.getPrimitiveType(); 66 if (p1 == Type.UNTYPED_ATOMIC) { 67 p1 = Type.STRING; 68 } 69 int p2 = t2.getPrimitiveType(); 70 if (p2 == Type.UNTYPED_ATOMIC) { 71 p2 = Type.STRING; 72 } 73 74 if (!Type.isComparable(p1, p2)) { 75 boolean opt0 = Cardinality.allowsZero(operand0.getCardinality()); 76 boolean opt1 = Cardinality.allowsZero(operand1.getCardinality()); 77 if (opt0 || opt1) { 78 82 String which = null; 83 if (opt0) which = "the first operand is"; 84 if (opt1) which = "the second operand is"; 85 if (opt0 && opt1) which = "one or both operands are"; 86 env.issueWarning( 87 "Comparison of " + t1.toString(env.getNamePool()) + (opt0?"?":"") + " to " + t2.toString(env.getNamePool()) + 88 (opt1?"?":"") + " will fail unless " + which + " empty", this); 89 90 } else { 91 StaticError err = 92 new StaticError("Cannot compare " + t1.toString(env.getNamePool()) + 93 " to " + t2.toString(env.getNamePool())); 94 err.setIsTypeError(true); 95 err.setErrorCode("XPTY0004"); 96 throw err; 97 } 98 } 99 if (!(operator == Token.FEQ || operator == Token.FNE)) { 100 if (!Type.isOrdered(p1)) { 101 StaticError err = new StaticError( 102 "Type " + t1.toString(env.getNamePool()) + " is not an ordered type"); 103 err.setErrorCode("XPTY0004"); 104 err.setIsTypeError(true); 105 throw err; 106 } 107 if (!Type.isOrdered(p2)) { 108 StaticError err = new StaticError( 109 "Type " + t2.toString(env.getNamePool()) + " is not an ordered type"); 110 err.setErrorCode("XPTY0004"); 111 err.setIsTypeError(true); 112 throw err; 113 } 114 } 115 116 Comparator comp = env.getCollation(env.getDefaultCollationName()); 117 if (comp==null) comp = CodepointCollator.getInstance(); 118 comparer = new AtomicComparer(comp, env.getConfiguration()); 119 return this; 120 } 121 122 139 140 public Expression optimize(Optimizer opt, StaticContext env, ItemType contextItemType) throws XPathException { 141 142 operand0 = operand0.optimize(opt, env, contextItemType); 143 operand1 = operand1.optimize(opt, env, contextItemType); 144 146 if (Aggregate.isCountFunction(operand0) && 147 operand1 instanceof AtomicValue) { 148 if (isZero(operand1)) { 149 if (operator == Token.FEQ || operator == Token.FLE ) { 150 FunctionCall fn = SystemFunction.makeSystemFunction("empty", 1, env.getNamePool()); 152 Expression[] args = new Expression[1]; 153 args[0] = ((FunctionCall)operand0).argument[0]; 154 fn.setArguments(args); 155 return fn; 156 } else if (operator == Token.FNE || operator == Token.FGT) { 157 FunctionCall fn = SystemFunction.makeSystemFunction("exists", 1, env.getNamePool()); 159 Expression[] args = new Expression[1]; 160 args[0] = ExpressionTool.unsorted(opt, ((FunctionCall)operand0).argument[0], false); 161 fn.setArguments(args); 162 return fn; 163 } else if (operator == Token.FGE) { 164 return BooleanValue.TRUE; 166 } else { return BooleanValue.FALSE; 169 } 170 } else if (operand1 instanceof IntegerValue && 171 (operator == Token.FGT || operator == Token.FGE) ) { 172 long val = ((IntegerValue)operand1).longValue(); 175 if (operator == Token.FGT) { 176 val++; 177 } 178 FunctionCall fn = SystemFunction.makeSystemFunction("exists", 1, env.getNamePool()); 179 Expression[] args = new Expression[1]; 180 FilterExpression filter = 181 new FilterExpression(((FunctionCall)operand0).argument[0], 182 new IntegerValue(val), env); 183 args[0] = filter; 184 fn.setArguments(args); 185 return fn; 186 } 187 } 188 189 191 if (Aggregate.isCountFunction(operand1) && isZero(operand0)) { 192 Expression s = 193 new ValueComparison(operand1, Token.inverse(operator), operand0).typeCheck(env, contextItemType); 194 return s.optimize(opt, env, contextItemType); 196 } 197 198 200 if ((operand0 instanceof StringLength) && 201 (((StringLength)operand0).getNumberOfArguments()==1) && isZero(operand1)) { 202 ((StringLength)operand0).setShortcut(); 203 } 204 205 207 if ((operand1 instanceof StringLength) && 208 (((StringLength)operand1).getNumberOfArguments()==1) && isZero(operand0)) { 209 ((StringLength)operand1).setShortcut(); 210 } 211 212 214 if ((operand0 instanceof Position) && (operand1 instanceof Last)) { 215 switch (operator) { 216 case Token.FEQ: 217 case Token.FGE: 218 return new IsLastExpression(true); 219 case Token.FNE: 220 case Token.FLT: 221 return new IsLastExpression(false); 222 case Token.FGT: 223 return BooleanValue.FALSE; 224 case Token.FLE: 225 return BooleanValue.TRUE; 226 } 227 } 228 if ((operand0 instanceof Last) && (operand1 instanceof Position)) { 229 switch (operator) { 230 case Token.FEQ: 231 case Token.FLE: 232 return new IsLastExpression(true); 233 case Token.FNE: 234 case Token.FGT: 235 return new IsLastExpression(false); 236 case Token.FLT: 237 return BooleanValue.FALSE; 238 case Token.FGE: 239 return BooleanValue.TRUE; 240 } 241 } 242 243 245 if (operand0 instanceof Position) { 246 boolean isInteger = (operand1 instanceof IntegerValue); 247 int pos = 0; 248 if (isInteger) { 249 pos = (int)((IntegerValue)operand1).longValue(); 250 if (pos < 0) { 251 pos = 0; 252 } 253 } 254 switch (operator) { 255 case Token.FEQ: 256 return new PositionRange(operand1, operand1); 257 case Token.FGE: 258 return new PositionRange(operand1, null); 259 case Token.FNE: 260 if (isInteger && pos==1) { 261 return new PositionRange(2, Integer.MAX_VALUE); 262 } else { 263 break; 264 } 265 case Token.FLT: 266 if (isInteger) { 267 return new PositionRange(1, pos-1); 268 } else { 269 break; 270 } 271 case Token.FGT: 272 if (isInteger) { 273 return new PositionRange(pos+1, Integer.MAX_VALUE); 274 } else { 275 break; 276 } 277 case Token.FLE: 278 if (isInteger) { 279 return new PositionRange(1, pos); 280 } else { 281 break; 282 } 283 } 284 } 285 286 if (operand1 instanceof Position) { 287 int pos = 0; 288 boolean isInteger = (operand0 instanceof IntegerValue); 289 if (isInteger) { 290 pos = (int)((IntegerValue)operand0).longValue(); 291 if (pos < 0) { 292 pos = 0; 293 } 294 } 295 296 switch (operator) { 297 case Token.FEQ: 298 return new PositionRange(operand0, operand0); 299 case Token.FLE: 300 return new PositionRange(operand0, null); 301 case Token.FNE: 302 if (isInteger && pos==1) { 303 return new PositionRange(2, Integer.MAX_VALUE); 304 } else { 305 break; 306 } 307 case Token.FGT: 308 if (isInteger) { 309 return new PositionRange(1, pos - 1); 310 } else { 311 break; 312 } 313 case Token.FLT: 314 if (isInteger) { 315 return new PositionRange(pos + 1, Integer.MAX_VALUE); 316 } else { 317 break; 318 } 319 case Token.FGE: 320 if (isInteger) { 321 return new PositionRange(1, pos); 322 } else { 323 break; 324 } 325 } 326 } 327 328 333 if (NamePart.isGenerateIdFunction(operand0) && NamePart.isGenerateIdFunction(operand1)) { 334 FunctionCall f0 = (FunctionCall)operand0; 335 FunctionCall f1 = (FunctionCall)operand1; 336 if (!Cardinality.allowsMany(f0.argument[0].getCardinality()) && 337 !Cardinality.allowsMany(f1.argument[0].getCardinality()) && 338 (operator == Token.FEQ) ) { 339 IdentityComparison id = 340 new IdentityComparison ( 341 f0.argument[0], 342 Token.IS, 343 f1.argument[0] ); 344 id.setGenerateIdEmulation(true); 345 return id.simplify(env).typeCheck(env, contextItemType).optimize(opt, env, contextItemType); 346 } 347 } 348 349 351 if ((operand0 instanceof Value) && (operand1 instanceof Value)) { 352 return (AtomicValue)evaluateItem(null); 353 } 354 355 return this; 356 } 357 358 359 362 363 private static boolean isZero(Expression exp) { 364 try { 365 if (!(exp instanceof AtomicValue)) return false; 366 if (exp instanceof IntegerValue) { 367 return ((IntegerValue)exp).longValue()==0; 368 } 369 if (exp instanceof BigIntegerValue) { 370 return ((BigIntegerValue)exp).compareTo(BigIntegerValue.ZERO) == 0; 371 } 372 373 Value val = ((AtomicValue)exp).convert(Type.INTEGER, null); 374 return isZero(val); 375 } catch (XPathException err) { 376 return false; 377 } 378 } 379 380 385 386 public boolean effectiveBooleanValue(XPathContext context) throws XPathException { 387 try { 388 AtomicValue v1 = ((AtomicValue)operand0.evaluateItem(context)); 389 if (v1==null) return false; 390 if (v1 instanceof UntypedAtomicValue) { 391 v1 = v1.convert(Type.STRING, context); 392 } 393 AtomicValue v2 = ((AtomicValue)operand1.evaluateItem(context)); 394 if (v2==null) return false; 395 if (v2 instanceof UntypedAtomicValue) { 396 v2 = v2.convert(Type.STRING, context); 397 } 398 return compare(v1, operator, v2, comparer); 399 } catch (DynamicError e) { 400 if (e.getXPathContext() == null) { 402 e.setXPathContext(context); 403 } 404 if (e.getLocator() == null) { 405 e.setLocator(this); 406 } 407 throw e; 408 } 409 } 410 411 420 421 static boolean compare(AtomicValue v1, int op, AtomicValue v2, 422 AtomicComparer collator) 423 throws DynamicError { 424 if (v1 instanceof NumericValue && ((NumericValue)v1).isNaN()) { 425 return false; 426 } 427 if (v2 instanceof NumericValue && ((NumericValue)v2).isNaN()) { 428 return false; 429 } 430 try { 431 switch (op) { 432 case Token.FEQ: 433 return collator.comparesEqual(v1, v2); 434 case Token.FNE: 435 return !collator.comparesEqual(v1, v2); 436 case Token.FGT: 437 return collator.compare(v1, v2) > 0; 438 case Token.FLT: 439 return collator.compare(v1, v2) < 0; 440 case Token.FGE: 441 return collator.compare(v1, v2) >= 0; 442 case Token.FLE: 443 return collator.compare(v1, v2) <= 0; 444 default: 445 throw new UnsupportedOperationException ("Unknown operator " + op); 446 } 447 } catch (ClassCastException err) { 448 DynamicError e2 = new DynamicError ( 449 "Cannot compare " + v1.getItemType() + " to " + v2.getItemType()); 450 e2.setErrorCode("XPTY0004"); 451 e2.setIsTypeError(true); 452 throw e2; 453 } 454 } 455 456 462 463 public Item evaluateItem(XPathContext context) throws XPathException { 464 try { 465 AtomicValue v1 = (AtomicValue)operand0.evaluateItem(context); 466 if (v1==null) return null; 467 if (v1 instanceof UntypedAtomicValue) { 468 v1 = v1.convert(Type.STRING, context); 469 } 470 AtomicValue v2 = (AtomicValue)operand1.evaluateItem(context); 471 if (v2==null) return null; 472 if (v2 instanceof UntypedAtomicValue) { 473 v2 = v2.convert(Type.STRING, context); 474 } 475 return BooleanValue.get(compare(v1, operator, v2, comparer)); 476 } catch (DynamicError e) { 477 if (e.getXPathContext() == null) { 479 e.setXPathContext(context); 480 } 481 if (e.getLocator() == null) { 482 e.setLocator(this); 483 } 484 throw e; 485 } 486 } 487 488 489 493 494 public ItemType getItemType() { 495 return Type.BOOLEAN_TYPE; 496 } 497 498 } 499 500 | Popular Tags |