/**
  * Parses GRANT and REVOKE commands
  *
  * @param database database
  * @param command REVOKE command
  *
  */
 public static function parse($database, $command)
 {
     $command = sql_parser::remove_last_semicolon($command);
     if (preg_match(self::PATTERN_GRANT_REVOKE, $command, $matches) > 0) {
         if (count($matches) != 5) {
             throw new exception("GRANT/REVOKE definition preg exploded into " . count($matches) . ", panic!");
         }
         $action = strtoupper($matches[1]);
         switch ($action) {
             case 'GRANT':
             case 'REVOKE':
                 break;
             default:
                 throw new exception("permission action " . $action . " is unknown, panic!");
                 break;
         }
         $operations = preg_split("/[\\,\\s]+/", $matches[2], -1, PREG_SPLIT_NO_EMPTY);
         if (!is_array($operations)) {
             $permission = array($operations);
         }
         for ($i = 0; $i < count($operations); $i++) {
             $operations[$i] = strtoupper($operations[$i]);
             switch ($operations[$i]) {
                 case 'ALL':
                 case 'SELECT':
                 case 'INSERT':
                 case 'UPDATE':
                 case 'DELETE':
                 case 'USAGE':
                 case 'REFERENCES':
                 case 'TRIGGER':
                     break;
                 default:
                     var_dump($operations);
                     throw new exception("the operation " . $operations[$i] . " is unknown, panic!");
                     break;
             }
         }
         $object = $matches[3];
         $chunks = preg_split("/[\\s]+/", $object, -1, PREG_SPLIT_NO_EMPTY);
         if (count($chunks) == 1) {
             // if there is no white space separating this bit
             // then let postgresql decide what it is when the grant is run
             $object_type = '';
             $object_name = $chunks[0];
         } else {
             if (count($chunks) == 2) {
                 // SEQUENCE schema.table_table_id_seq
                 // TABLE schema.table
                 $object_type = $chunks[0];
                 $object_name = $chunks[1];
                 // if it's a schema, don't try to explode / default the schema prefix
                 if (strcasecmp($object_type, 'SCHEMA') == 0) {
                     $schema =& dbx::get_schema($database, $object_name);
                 } else {
                     $object_name = sql_parser::get_schema_name($object_name, $database) . '.' . sql_parser::get_object_name($object_name);
                     $schema =& dbx::get_schema($database, sql_parser::get_schema_name($object_name, $database));
                 }
                 if ($schema == null) {
                     throw new exception("Failed to find schema for grant/revoke: " . sql_parser::get_schema_name($object_name, $database));
                 }
             } else {
                 throw new exception("object definition exploded into " . count($chunks) . " chunks, panic!");
             }
         }
         $role = $matches[4];
         // find the node_object, swtich'd on $object_type
         // based on http://www.postgresql.org/docs/8.4/static/sql-grant.html
         // empty object_type should be considered a TABLE GRANT/REVOKE
         if (strlen($object_type) == 0) {
             $object_type = 'TABLE';
         }
         /*
         var_dump($command);
         var_dump(sql_parser::get_schema_name($object_name, $database));
         var_dump(sql_parser::get_object_name($object_name));
         /**/
         switch (strtoupper($object_type)) {
             case 'SCHEMA':
                 $node_object =& dbx::get_schema($database, $object_name);
                 break;
             case 'SEQUENCE':
                 $node_schema =& dbx::get_schema($database, sql_parser::get_schema_name($object_name, $database));
                 $node_object =& dbx::get_sequence($node_schema, sql_parser::get_object_name($object_name));
                 break;
             case 'TABLE':
                 $node_schema =& dbx::get_schema($database, sql_parser::get_schema_name($object_name, $database));
                 $node_object =& dbx::get_table($node_schema, sql_parser::get_object_name($object_name));
                 break;
             default:
                 throw new exception("unknown object_type " . $object_type . " encountered, panic!");
                 break;
         }
         dbx::set_permission($node_object, $action, $operations, $role);
     } else {
         throw new exception("Cannot parse command: " . $command);
     }
 }