protected Constraint rewriteConstraint(Constraint constraint) {
   if (constraint instanceof Comparison) {
     Comparison comparison = (Comparison) constraint;
     DynamicOperand left = comparison.getOperand1();
     if (left instanceof PropertyValue) {
       PropertyValue propValue = (PropertyValue) left;
       if ("jcr:path".equals(propValue.getPropertyName())) {
         // Rewrite this constraint as a PATH criteria ...
         NodePath path = new NodePath(propValue.selectorName());
         return new Comparison(path, comparison.operator(), comparison.getOperand2());
       }
       if ("jcr:score".equals(propValue.getPropertyName())) {
         // Rewrite this constraint as a SCORE criteria ...
         FullTextSearchScore score = new FullTextSearchScore(propValue.selectorName());
         return new Comparison(score, comparison.operator(), comparison.getOperand2());
       }
     }
   } else if (constraint instanceof FullTextSearch) {
     FullTextSearch search = (FullTextSearch) constraint;
     if (".".equals(search.getPropertyName())) {
       // JCR-SQL's use of CONTAINS allows a '.' to be used to represent the search is to be
       // performed on all properties of the node(s). However, JCR-SQL2 and our AQM
       // expect a '*' to be used instead ...
       return new FullTextSearch(search.selectorName(), search.fullTextSearchExpression());
     }
   } else if (constraint instanceof And) {
     And and = (And) constraint;
     constraint = new And(rewriteConstraint(and.left()), rewriteConstraint(and.right()));
   } else if (constraint instanceof Or) {
     Or or = (Or) constraint;
     constraint = new Or(rewriteConstraint(or.left()), rewriteConstraint(or.right()));
   }
   return constraint;
 }
  /**
   * Create the constraint evaluator that is used by the {@link SelectComponent} to evaluate the
   * supplied {@link Constraint criteria}.
   *
   * @param types the type system; may not be null
   * @param schemata the schemata; may not be null
   * @param columns the definition of the result columns and the tuples; may not be null
   * @param constraint the criteria that this {@link SelectComponent} is to evaluate
   * @param variables the variables that are to be substituted for the various {@link
   *     BindVariableName} {@link StaticOperand operands}; may not be null
   * @return the constraint evaluator; never null
   */
  protected ConstraintChecker createChecker(
      final TypeSystem types,
      Schemata schemata,
      Columns columns,
      Constraint constraint,
      Map<String, Object> variables) {
    if (constraint instanceof Or) {
      Or orConstraint = (Or) constraint;
      final ConstraintChecker left =
          createChecker(types, schemata, columns, orConstraint.left(), variables);
      final ConstraintChecker right =
          createChecker(types, schemata, columns, orConstraint.right(), variables);
      return new ConstraintChecker() {
        @Override
        public boolean satisfiesConstraints(Object[] tuple) {
          return left.satisfiesConstraints(tuple) || right.satisfiesConstraints(tuple);
        }
      };
    }
    if (constraint instanceof Not) {
      Not notConstraint = (Not) constraint;
      final ConstraintChecker original =
          createChecker(types, schemata, columns, notConstraint.getConstraint(), variables);
      return new ConstraintChecker() {
        @Override
        public boolean satisfiesConstraints(Object[] tuple) {
          return !original.satisfiesConstraints(tuple);
        }
      };
    }
    if (constraint instanceof And) {
      And andConstraint = (And) constraint;
      final ConstraintChecker left =
          createChecker(types, schemata, columns, andConstraint.left(), variables);
      final ConstraintChecker right =
          createChecker(types, schemata, columns, andConstraint.right(), variables);
      return new ConstraintChecker() {
        @Override
        public boolean satisfiesConstraints(Object[] tuple) {
          return left.satisfiesConstraints(tuple) && right.satisfiesConstraints(tuple);
        }
      };
    }
    if (constraint instanceof ChildNode) {
      ChildNode childConstraint = (ChildNode) constraint;
      final int locationIndex = columns.getLocationIndex(childConstraint.selectorName().name());
      final Path parentPath = (Path) types.getPathFactory().create(childConstraint.getParentPath());
      return new ConstraintChecker() {
        @Override
        public boolean satisfiesConstraints(Object[] tuple) {
          Location location = (Location) tuple[locationIndex];
          return location.getPath().getParent().equals(parentPath);
        }
      };
    }
    if (constraint instanceof DescendantNode) {
      DescendantNode descendantNode = (DescendantNode) constraint;
      final int locationIndex = columns.getLocationIndex(descendantNode.selectorName().name());
      final Path ancestorPath =
          (Path) types.getPathFactory().create(descendantNode.getAncestorPath());
      return new ConstraintChecker() {
        @Override
        public boolean satisfiesConstraints(Object[] tuple) {
          Location location = (Location) tuple[locationIndex];
          return location.getPath().isDescendantOf(ancestorPath);
        }
      };
    }
    if (constraint instanceof SameNode) {
      SameNode sameNode = (SameNode) constraint;
      final int locationIndex = columns.getLocationIndex(sameNode.selectorName().name());
      final String path = sameNode.getPath();
      return new ConstraintChecker() {
        @Override
        public boolean satisfiesConstraints(Object[] tuple) {
          Location location = (Location) tuple[locationIndex];
          return location.toString().equals(path);
        }
      };
    }
    if (constraint instanceof PropertyExistence) {
      PropertyExistence propertyExistance = (PropertyExistence) constraint;
      String selectorName = propertyExistance.selectorName().name();
      final String propertyName = propertyExistance.getPropertyName();
      final int columnIndex = columns.getColumnIndexForProperty(selectorName, propertyName);
      return new ConstraintChecker() {
        @Override
        public boolean satisfiesConstraints(Object[] tuple) {
          return tuple[columnIndex] != null;
        }
      };
    }
    if (constraint instanceof FullTextSearch) {
      return new ConstraintChecker() {
        @Override
        public boolean satisfiesConstraints(Object[] tuple) {
          return true;
        }
      };
    }
    if (constraint instanceof Relike) {
      return new ConstraintChecker() {
        @Override
        public boolean satisfiesConstraints(Object[] tuple) {
          return true;
        }
      };
    }
    if (constraint instanceof Comparison) {
      Comparison comparison = (Comparison) constraint;

      // Create the correct dynamic operation ...
      DynamicOperation dynamicOperation =
          createDynamicOperation(types, schemata, columns, comparison.getOperand1());
      Operator operator = comparison.operator();
      StaticOperand staticOperand = comparison.getOperand2();
      return createChecker(types, schemata, columns, dynamicOperation, operator, staticOperand);
    }
    if (constraint instanceof SetCriteria) {
      SetCriteria setCriteria = (SetCriteria) constraint;
      DynamicOperation dynamicOperation =
          createDynamicOperation(types, schemata, columns, setCriteria.leftOperand());
      Operator operator = Operator.EQUAL_TO;
      final List<ConstraintChecker> checkers = new LinkedList<ConstraintChecker>();
      for (StaticOperand setValue : setCriteria.rightOperands()) {
        ConstraintChecker rightChecker =
            createChecker(types, schemata, columns, dynamicOperation, operator, setValue);
        assert rightChecker != null;
        checkers.add(rightChecker);
      }
      if (checkers.isEmpty()) {
        // Nothing will satisfy these constraints ...
        return new ConstraintChecker() {
          @Override
          public boolean satisfiesConstraints(Object[] tuple) {
            return false;
          }
        };
      }
      return new ConstraintChecker() {
        @Override
        public boolean satisfiesConstraints(Object[] tuple) {
          for (ConstraintChecker checker : checkers) {
            if (checker.satisfiesConstraints(tuple)) return true;
          }
          return false;
        }
      };
    }
    assert false;
    return null;
  }