private ImmutableSetMultimap<String, String> parsePermissions(
     @Nullable String database, Ini.Section rolesSection, Ini.Section groupsSection) {
   ImmutableSetMultimap.Builder<String, String> resultBuilder = ImmutableSetMultimap.builder();
   Multimap<String, String> roleNameToPrivilegeMap = HashMultimap.create();
   List<? extends RoleValidator> validators =
       Lists.newArrayList(
           new ServersAllIsInvalid(),
           new DatabaseMustMatch(),
           new DatabaseRequiredInRole(),
           new ServerNameMustMatch(serverName));
   for (Map.Entry<String, String> entry : rolesSection.entrySet()) {
     String roleName = Strings.nullToEmpty(entry.getKey()).trim();
     String roleValue = Strings.nullToEmpty(entry.getValue()).trim();
     boolean invalidConfiguration = false;
     if (roleName.isEmpty()) {
       LOGGER.warn("Empty role name encountered in {}", resourcePath);
       invalidConfiguration = true;
     }
     if (roleValue.isEmpty()) {
       LOGGER.warn("Empty role value encountered in {}", resourcePath);
       invalidConfiguration = true;
     }
     if (roleNameToPrivilegeMap.containsKey(roleName)) {
       LOGGER.warn("Role {} defined twice in {}", roleName, resourcePath);
     }
     Set<String> roles = PermissionUtils.toPermissionStrings(roleValue);
     if (!invalidConfiguration && roles != null) {
       for (String role : roles) {
         for (RoleValidator validator : validators) {
           validator.validate(database, role.trim());
         }
       }
       roleNameToPrivilegeMap.putAll(roleName, roles);
     }
   }
   Splitter roleSplitter = ROLE_SPLITTER.omitEmptyStrings().trimResults();
   for (Map.Entry<String, String> entry : groupsSection.entrySet()) {
     String groupName = Strings.nullToEmpty(entry.getKey()).trim();
     String groupPrivileges = Strings.nullToEmpty(entry.getValue()).trim();
     Collection<String> resolvedGroupPrivileges = Sets.newHashSet();
     for (String roleName : roleSplitter.split(groupPrivileges)) {
       if (roleNameToPrivilegeMap.containsKey(roleName)) {
         resolvedGroupPrivileges.addAll(roleNameToPrivilegeMap.get(roleName));
       } else {
         LOGGER.warn(
             "Role {} for group {} does not exist in privileges section in {}",
             new Object[] {roleName, groupName, resourcePath});
       }
     }
     resultBuilder.putAll(groupName, resolvedGroupPrivileges);
   }
   return resultBuilder.build();
 }
  private static void addPrivilege(String roleName, String privileges, Statement statement)
      throws IOException, SQLException {
    String serverName = null, dbName = null, tableName = null, uriPath = null, columnName = null;
    String action = "ALL"; // AccessConstants.ALL;
    for (String privilege : ROLE_SPLITTER.split(privileges)) {
      for (String section : AUTHORIZABLE_SPLITTER.split(privilege)) {
        // action is not an authorizeable
        if (!section.toLowerCase().startsWith(PRIVILEGE_PREFIX)) {
          DBModelAuthorizable dbAuthorizable = DBModelAuthorizables.from(section);
          if (dbAuthorizable == null) {
            throw new IOException("Unknown Auth type " + section);
          }

          if (DBModelAuthorizable.AuthorizableType.Server.equals(dbAuthorizable.getAuthzType())) {
            serverName = dbAuthorizable.getName();
          } else if (DBModelAuthorizable.AuthorizableType.Db.equals(
              dbAuthorizable.getAuthzType())) {
            dbName = dbAuthorizable.getName();
          } else if (DBModelAuthorizable.AuthorizableType.Table.equals(
              dbAuthorizable.getAuthzType())) {
            tableName = dbAuthorizable.getName();
          } else if (DBModelAuthorizable.AuthorizableType.Column.equals(
              dbAuthorizable.getAuthzType())) {
            columnName = dbAuthorizable.getName();
          } else if (DBModelAuthorizable.AuthorizableType.URI.equals(
              dbAuthorizable.getAuthzType())) {
            uriPath = dbAuthorizable.getName();
          } else {
            throw new IOException(
                "Unsupported auth type "
                    + dbAuthorizable.getName()
                    + " : "
                    + dbAuthorizable.getTypeName());
          }
        } else {
          action =
              DBModelAction.valueOf(
                      StringUtils.removePrefix(section, PRIVILEGE_PREFIX).toUpperCase())
                  .toString();
        }
      }

      LOGGER.info("addPrivilege");
      if (columnName != null) {
        statement.execute("CREATE DATABASE IF NOT EXISTS " + dbName);
        statement.execute("USE " + dbName);
        String sql =
            "GRANT "
                + action
                + " ( "
                + columnName
                + " ) ON TABLE "
                + tableName
                + " TO ROLE "
                + roleName;
        LOGGER.info("Granting column level privilege: database = " + dbName + ", sql = " + sql);
        statement.execute(sql);
      } else if (tableName != null) {
        statement.execute("CREATE DATABASE IF NOT EXISTS " + dbName);
        statement.execute("USE " + dbName);
        String sql = "GRANT " + action + " ON TABLE " + tableName + " TO ROLE " + roleName;
        LOGGER.info("Granting table level privilege:  database = " + dbName + ", sql = " + sql);
        statement.execute(sql);
      } else if (dbName != null) {
        String sql = "GRANT " + action + " ON DATABASE " + dbName + " TO ROLE " + roleName;
        LOGGER.info("Granting db level privilege: " + sql);
        statement.execute(sql);
      } else if (uriPath != null) {
        String sql = "GRANT " + action + " ON URI '" + uriPath + "' TO ROLE " + roleName;
        LOGGER.info("Granting uri level privilege: " + sql);
        statement.execute(sql); // ALL?
      } else if (serverName != null) {
        String sql = "GRANT ALL ON SERVER " + serverName + " TO ROLE " + roleName;
        LOGGER.info("Granting server level privilege: " + sql);
        statement.execute(sql);
      }
    }
  }