/**
   * Evaluate the matches() function to give a Boolean value.
   *
   * @param c The dynamic evaluation context
   * @return the result as a BooleanValue, or null to indicate the empty sequence
   * @throws XPathException on an error
   */
  public Item evaluateItem(XPathContext c) throws XPathException {
    AtomicValue sv0 = (AtomicValue) argument[0].evaluateItem(c);
    if (sv0 == null) {
      sv0 = StringValue.EMPTY_STRING;
    }
    ;

    RegularExpression re = regexp;

    if (re == null) {
      AtomicValue pat = (AtomicValue) argument[1].evaluateItem(c);
      if (pat == null) return null;

      CharSequence flags;
      if (argument.length == 2) {
        flags = "";
      } else {
        AtomicValue sv2 = (AtomicValue) argument[2].evaluateItem(c);
        if (sv2 == null) return null;
        flags = sv2.getStringValueCS();
      }

      try {
        final Platform platform = c.getConfiguration().getPlatform();
        re = platform.compileRegularExpression(pat.getStringValueCS(), true, flags);
      } catch (XPathException err) {
        DynamicError de = new DynamicError(err);
        de.setErrorCode("FORX0002");
        de.setXPathContext(c);
        throw de;
      }
    }
    return BooleanValue.get(re.containsMatch(sv0.getStringValueCS()));
  }
  /**
   * Process this instruction
   *
   * @param context the dynamic context of the transformation
   * @return a TailCall to be executed by the caller, always null for this instruction
   */
  public TailCall processLeavingTail(XPathContext context) throws XPathException {
    Controller controller = context.getController();
    SequenceReceiver out = context.getReceiver();
    int opt = options;
    int ann = annotation;

    // we may need to change the namespace prefix if the one we chose is
    // already in use with a different namespace URI: this is done behind the scenes
    // by the Outputter

    CharSequence value = expandChildren(context);
    if (schemaType != null) {
      // test whether the value actually conforms to the given type
      XPathException err =
          schemaType.validateContent(
              value,
              DummyNamespaceResolver.getInstance(),
              context.getConfiguration().getNameChecker());
      if (err != null) {
        ValidationException verr =
            new ValidationException(
                "Attribute value "
                    + Err.wrap(value, Err.VALUE)
                    + " does not the match the required type "
                    + schemaType.getDescription()
                    + ". "
                    + err.getMessage());
        verr.setErrorCode("XTTE1540");
        verr.setLocator(this);
        throw verr;
      }
    } else if (validationAction == Validation.STRICT || validationAction == Validation.LAX) {
      try {
        ann = controller.getConfiguration().validateAttribute(nameCode, value, validationAction);
      } catch (ValidationException e) {
        DynamicError err = DynamicError.makeDynamicError(e);
        String errorCode = e.getErrorCodeLocalPart();
        if (errorCode == null) {
          errorCode = (validationAction == Validation.STRICT ? "XTTE1510" : "XTTE1515");
        }
        err.setErrorCode(errorCode);
        err.setXPathContext(context);
        err.setLocator(this);
        err.setIsTypeError(true);
        throw err;
      }
    }
    try {
      out.attribute(nameCode, ann, value, locationId, opt);
    } catch (XPathException err) {
      throw dynamicError(this, err, context);
    }

    return null;
  }
  /** Evaluate in a general context */
  public Item evaluateItem(XPathContext c) throws XPathException {
    StringValue sv = (StringValue) argument[0].evaluateItem(c);
    if (sv == null) {
      return StringValue.EMPTY_STRING;
    }

    byte fb = Normalizer.C;
    if (argument.length == 2) {
      String form = argument[1].evaluateAsString(c).trim();
      if (form.equalsIgnoreCase("NFC")) {
        fb = Normalizer.C;
      } else if (form.equalsIgnoreCase("NFD")) {
        fb = Normalizer.D;
      } else if (form.equalsIgnoreCase("NFKC")) {
        fb = Normalizer.KC;
      } else if (form.equalsIgnoreCase("NFKD")) {
        fb = Normalizer.KD;
      } else if (form.equalsIgnoreCase("")) {
        return sv;
      } else {
        String msg = "Normalization form " + form + " is not supported";
        DynamicError err = new DynamicError(msg);
        err.setErrorCode("FOCH0003");
        err.setXPathContext(c);
        err.setLocator(this);
        throw err;
      }
    }

    // fast path for ASCII strings: normalization is a no-op
    boolean allASCII = true;
    CharSequence chars = sv.getStringValueCS();
    if (chars instanceof CompressedWhitespace) {
      return sv;
    }
    for (int i = chars.length() - 1; i >= 0; i--) {
      if (chars.charAt(i) > 127) {
        allASCII = false;
        break;
      }
    }
    if (allASCII) {
      return sv;
    }

    Normalizer norm = new Normalizer(fb);
    CharSequence result = norm.normalize(sv.getStringValueCS());
    return StringValue.makeStringValue(result);
  }
  public Item evaluateItem(XPathContext context) throws XPathException {
    Orphan o = (Orphan) super.evaluateItem(context);
    if (schemaType != null) {
      XPathException err =
          schemaType.validateContent(
              o.getStringValueCS(),
              DummyNamespaceResolver.getInstance(),
              context.getConfiguration().getNameChecker());
      if (err != null) {
        throw new ValidationException(
            "Attribute value "
                + Err.wrap(o.getStringValueCS(), Err.VALUE)
                + " does not the match the required type "
                + schemaType.getDescription()
                + ". "
                + err.getMessage());
      }
      o.setTypeAnnotation(schemaType.getFingerprint());
      if (schemaType.isNamespaceSensitive()) {
        throw new DynamicError(
            "Cannot validate a parentless attribute whose content is namespace-sensitive");
      }
    } else if (validationAction == Validation.STRICT || validationAction == Validation.LAX) {
      try {
        int ann =
            context
                .getController()
                .getConfiguration()
                .validateAttribute(nameCode, o.getStringValueCS(), validationAction);
        o.setTypeAnnotation(ann);
      } catch (ValidationException e) {
        DynamicError err = DynamicError.makeDynamicError(e);
        err.setErrorCode(e.getErrorCodeLocalPart());
        err.setXPathContext(context);
        err.setLocator(this);
        err.setIsTypeError(true);
        throw err;
      }
    }

    return o;
  }
    public void process(XPathContext context) throws XPathException {
      // Prepare the SQL statement (only do this once)

      Controller controller = context.getController();
      Item conn = arguments[CONNECTION].evaluateItem(context);
      if (!(conn instanceof ObjectValue
          && ((ObjectValue) conn).getObject() instanceof Connection)) {
        DynamicError de =
            new DynamicError("Value of connection expression is not a JDBC Connection");
        de.setXPathContext(context);
        throw de;
      }
      Connection connection = (Connection) ((ObjectValue) conn).getObject();

      String dbCol = arguments[COLUMN].evaluateAsString(context);
      String dbTab = arguments[TABLE].evaluateAsString(context);
      String dbWhere = arguments[WHERE].evaluateAsString(context);

      NamePool pool = controller.getNamePool();
      int rowCode = pool.allocate("", "", rowTag);
      int colCode = pool.allocate("", "", colTag);

      PreparedStatement ps = null;
      ResultSet rs = null;
      DynamicError de = null;

      try {
        StringBuffer statement = new StringBuffer();
        statement.append("SELECT " + dbCol + " FROM " + dbTab);
        if (dbWhere != "") {
          statement.append(" WHERE " + dbWhere);
        }
        // System.err.println("-> SQL: " + statement.toString());

        // -- Prepare the SQL statement
        ps = connection.prepareStatement(statement.toString());
        controller.setUserData(this, "sql:statement", ps);

        // -- Execute Statement
        rs = ps.executeQuery();

        // -- Print out Result
        Receiver out = context.getReceiver();
        String result = "";
        int icol = rs.getMetaData().getColumnCount();
        while (rs.next()) { // next row
          // System.out.print("<- SQL : "+ rowStart);
          out.startElement(rowCode, StandardNames.XDT_UNTYPED, locationId, 0);
          for (int col = 1; col <= icol; col++) { // next column
            // Read result from RS only once, because
            // of JDBC-Specifications
            result = rs.getString(col);
            out.startElement(colCode, StandardNames.XDT_UNTYPED, locationId, 0);
            if (result != null) {
              out.characters(result, locationId, options);
            }
            out.endElement();
          }
          // System.out.println(rowEnd);
          out.endElement();
        }
        // rs.close();

        if (!connection.getAutoCommit()) {
          connection.commit();
        }

      } catch (SQLException ex) {
        de = new DynamicError("(SQL) " + ex.getMessage());
        de.setXPathContext(context);
        throw de;
      } finally {
        boolean wasDEThrown = (de != null);
        if (rs != null) {
          try {
            rs.close();
          } catch (SQLException ex) {
            de = new DynamicError("(SQL) " + ex.getMessage());
            de.setXPathContext(context);
          }
        }
        if (ps != null) {
          try {
            ps.close();
          } catch (SQLException ex) {
            de = new DynamicError("(SQL) " + ex.getMessage());
            de.setXPathContext(context);
          }
        }
        if (!wasDEThrown && de != null) {
          throw de; // test so we don't lose the real exception
        }
      }
    }