/**
   * This is the guts of the Execution-time logic for DROP ROLE.
   *
   * @see org.apache.derby.iapi.sql.execute.ConstantAction#executeConstantAction
   */
  public void executeConstantAction(Activation activation) throws StandardException {
    LanguageConnectionContext lcc = activation.getLanguageConnectionContext();
    DataDictionary dd = lcc.getDataDictionary();
    TransactionController tc = lcc.getTransactionExecute();

    /*
     ** Inform the data dictionary that we are about to write to it.
     ** There are several calls to data dictionary "get" methods here
     ** that might be done in "read" mode in the data dictionary, but
     ** it seemed safer to do this whole operation in "write" mode.
     **
     ** We tell the data dictionary we're done writing at the end of
     ** the transaction.
     */
    dd.startWriting(lcc);

    RoleGrantDescriptor rdDef = dd.getRoleDefinitionDescriptor(roleName);

    if (rdDef == null) {
      throw StandardException.newException(SQLState.ROLE_INVALID_SPECIFICATION, roleName);
    }

    // When a role is dropped, for every role in its grantee closure, we
    // call the REVOKE_ROLE action. It is used to invalidate dependent
    // objects (constraints, triggers and views).  Note that until
    // DERBY-1632 is fixed, we risk dropping objects not really dependent
    // on this role, but one some other role just because it inherits from
    // this one. See also RevokeRoleConstantAction.
    RoleClosureIterator rci =
        dd.createRoleClosureIterator(activation.getTransactionController(), roleName, false);

    String role;
    while ((role = rci.next()) != null) {
      RoleGrantDescriptor r = dd.getRoleDefinitionDescriptor(role);

      dd.getDependencyManager().invalidateFor(r, DependencyManager.REVOKE_ROLE, lcc);
    }

    rdDef.drop(lcc);

    /*
     * We dropped a role, now drop all dependents:
     * - role grants to this role
     * - grants of this role to other roles or users
     * - privilege grants to this role
     */

    dd.dropRoleGrantsByGrantee(roleName, tc);
    dd.dropRoleGrantsByName(roleName, tc);
    dd.dropAllPermsByGrantee(roleName, tc);
  }
  public String next() throws StandardException {
    if (initial) {
      // Optimization so we don't compute the closure for the current
      // role if unnecessary (when next is only called once).
      initial = false;
      seenSoFar.put(root, null);

      return root;

    } else if (graph == null) {
      // We get here the second time next is called.
      graph = dd.getRoleGrantGraph(tc, inverse);
      List outArcs = (List) graph.get(root);
      if (outArcs != null) {
        currNodeIter = outArcs.iterator();
      }
    }

    RoleGrantDescriptor result = null;

    while (result == null) {
      while (currNodeIter.hasNext()) {
        RoleGrantDescriptor r = (RoleGrantDescriptor) currNodeIter.next();

        if (seenSoFar.containsKey(inverse ? r.getRoleName() : r.getGrantee())) {
          continue;
        } else {
          lifo.add(r);
          result = r;
          break;
        }
      }

      if (result == null) {
        // not more candidates located outgoing from the
        // latest found node, pick another and continue
        RoleGrantDescriptor newNode = null;

        currNodeIter = null;

        while (lifo.size() > 0 && currNodeIter == null) {

          newNode = (RoleGrantDescriptor) lifo.remove(lifo.size() - 1);

          // In the example (see interface doc), the
          // iterator of outgoing arcs for f (grant inverse)
          // would contain {e,c,d}.
          List outArcs = (List) graph.get(inverse ? newNode.getRoleName() : newNode.getGrantee());

          if (outArcs != null) {
            currNodeIter = outArcs.iterator();
          } // else: leaf node, pop next candidate, if any
        }

        if (currNodeIter == null) {
          // candidate stack is empty, done
          currNodeIter = null;
          break;
        }
      }
    }

    if (result != null) {
      String role = inverse ? result.getRoleName() : result.getGrantee();
      seenSoFar.put(role, null);
      return role;
    } else {
      return null;
    }
  }