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
        }
      }
    }
  /** Enumerate the results of the expression */
  public SequenceIterator iterate(XPathContext context) throws XPathException {

    Controller controller = context.getController();

    Item arg2;
    try {
      arg2 = argument[2].evaluateItem(context);
    } catch (XPathException e) {
      if ("XPDY0002".equals(e.getErrorCodeLocalPart())) {
        dynamicError(
            "Cannot call the key() function when there is no context item", "XTDE1270", context);
        return null;
      } else if ("XPDY0050".equals(e.getErrorCodeLocalPart())) {
        dynamicError(
            "In the key() function,"
                + " the node supplied in the third argument (or the context node if absent)"
                + " must be in a tree whose root is a document node",
            "XTDE1270",
            context);
        return null;
      } else if ("XPTY0020".equals(e.getErrorCodeLocalPart())) {
        dynamicError(
            "Cannot call the key() function when the context item is an atomic value",
            "XTDE1270",
            context);
        return null;
      }
      throw e;
    }

    NodeInfo origin = (NodeInfo) arg2;
    NodeInfo root = origin.getRoot();
    if (root.getNodeKind() != Type.DOCUMENT) {
      dynamicError(
          "In the key() function,"
              + " the node supplied in the third argument (or the context node if absent)"
              + " must be in a tree whose root is a document node",
          "XTDE1270",
          context);
      return null;
    }
    DocumentInfo doc = (DocumentInfo) root;

    int fprint = keyFingerprint;
    if (fprint == -1) {
      String givenkeyname = argument[0].evaluateItem(context).getStringValue();
      try {
        fprint =
            controller
                    .getNamePool()
                    .allocateLexicalQName(
                        givenkeyname,
                        false,
                        nsContext,
                        controller.getConfiguration().getNameChecker())
                & NamePool.FP_MASK;
      } catch (XPathException err) {
        dynamicError("Invalid key name: " + err.getMessage(), "XTDE1260", context);
      }
      if (fprint == -1) {
        dynamicError("Key '" + givenkeyname + "' has not been defined", "XTDE1260", context);
        return null;
      }
    }

    //        if (internal) {
    //            System.err.println("Using key " + fprint + " on doc " + doc);
    //        }

    // If the second argument is a singleton, we evaluate the function
    // directly; otherwise we recurse to evaluate it once for each Item
    // in the sequence.

    Expression expression = argument[1];
    SequenceIterator allResults;
    if (Cardinality.allowsMany(expression.getCardinality())) {
      final XPathContext keyContext = context;
      final DocumentInfo document = doc;
      final KeyManager keyManager = controller.getKeyManager();
      MappingFunction map =
          new MappingFunction() {
            // Map a value to the sequence of nodes having that value as a key value
            public Object map(Item item) throws XPathException {
              return keyManager.selectByKey(
                  keyFingerprint, document, (AtomicValue) item, keyContext);
            }
          };

      SequenceIterator keys = argument[1].iterate(context);
      SequenceIterator allValues = new MappingIterator(keys, map);
      allResults = new DocumentOrderIterator(allValues, LocalOrderComparer.getInstance());
    } else {
      try {
        AtomicValue keyValue = (AtomicValue) argument[1].evaluateItem(context);
        if (keyValue == null) {
          return EmptyIterator.getInstance();
        }
        KeyManager keyManager = controller.getKeyManager();
        allResults = keyManager.selectByKey(fprint, doc, keyValue, context);
      } catch (XPathException e) {
        if (e.getLocator() == null) {
          e.setLocator(this);
        }
        throw e;
      }
    }
    if (origin == doc) {
      return allResults;
    }
    SubtreeFilter filter = new SubtreeFilter();
    filter.origin = origin;
    return new ItemMappingIterator(allResults, filter);
  }