/**
  * Parses CREATE TRIGGER command.
  *
  * @param database database
  * @param command CREATE TRIGGER command
  *
  * @throws ParserException Thrown if problem occured while parsing the
  *         command.
  */
 public static function parse($database, $command)
 {
     if (preg_match(self::PATTERN, trim($command), $matches) > 0) {
         $trigger_name = trim($matches[1]);
         $when = $matches[2];
         $events = array();
         if (strlen($matches[3]) > 0) {
             $events[] = $matches[3];
         }
         if (strlen($matches[4]) > 0) {
             $events[] = $matches[4];
         }
         if (strlen($matches[5]) > 0) {
             $events[] = $matches[5];
         }
         $table_name = trim($matches[6]);
         $fireOn = $matches[7];
         $procedure = $matches[8];
         $node_schema =& dbx::get_schema($database, sql_parser::get_schema_name($table_name, $database));
         $node_table =& dbx::get_table($node_schema, sql_parser::get_object_name($table_name));
         if ($node_table == null) {
             throw new exception("Failed to find trigger table " . $trigger->get_table_name());
         }
         $node_trigger =& dbx::get_table_trigger($node_schema, $node_table, $trigger_name, true);
         dbx::set_attribute($node_trigger, 'when', strcasecmp('BEFORE', $when) == 0 ? 'BEFORE' : 'AFTER');
         dbx::set_attribute($node_trigger, 'forEach', strcasecmp('ROW', $when) == 0 ? 'ROW' : 'STATEMENT');
         dbx::set_attribute($node_trigger, 'function', trim($procedure));
         dbx::set_attribute($node_trigger, 'event', implode(', ', $events));
     } else {
         throw new exception("Cannot parse command: " . $command);
     }
 }
 /**
  * Parses CREATE TYPE command.
  *
  * @param database database
  * @param command CREATE TYPE command
  */
 public static function parse($database, $command)
 {
     $line = $command;
     //  CREATE PROCEDURAL LANGUAGE plpgsql;
     //  CREATE [ PROCEDURAL ] LANGUAGE name
     //  CREATE [ TRUSTED ] [ PROCEDURAL ] LANGUAGE name
     //    HANDLER call_handler [ VALIDATOR valfunction ]
     if (preg_match(self::PATTERN_CREATE_LANGUAGE, $line, $matches) > 0) {
         // simplify parsing by killing last semicolon
         $line = sql_parser::remove_last_semicolon($line);
         // break up the command by whitespace
         $chunks = preg_split('/[\\s]+/', $line, -1, PREG_SPLIT_NO_EMPTY);
         // shift the LANGUAGE keyword off
         array_shift($chunks);
         // shift the language name off
         $language_name = array_shift($chunks);
         // create language entry
         $language =& dbx::get_language($database, $language_name, true);
         // grab the language modifiers
         while (strcasecmp('LANGUAGE', $chunks[0]) != 0) {
             if (strcasecmp('CREATE', $chunks[0]) == 0) {
                 // expected first CREATE lead doesn't modify anything
             } else {
                 if (strcasecmp('TRUSTED', $chunks[0]) == 0) {
                     dbx::set_attribute($language, 'trusted', $chunks[0]);
                 } else {
                     if (strcasecmp('PROCEDURAL', $chunks[0]) == 0) {
                         dbx::set_attribute($language, 'procedural', $chunks[0]);
                     } else {
                         throw new exception("unknown CREATE LANGUAGE modifier: " . $chunks[0]);
                     }
                 }
             }
             // shift the lead chunk off now that it has been interpreted
             array_shift($chunks);
         }
         // if there are chunks left, figure out what optional parameteres they are and save them in the language object
         // make sure it's not the trailing ;, we don't care
         while (count($chunks) > 0 && trim(implode(' ', $chunks)) != ';') {
             if (strcasecmp('HANDLER', $chunks[0]) == 0) {
                 dbx::set_attribute($language, 'handler', $chunks[1]);
             } else {
                 if (strcasecmp('VALIDATOR', $chunks[0]) == 0) {
                     dbx::set_attribute($language, 'validator', $chunks[1]);
                 } else {
                     throw new exception("unknown CREATE LANGUAGE callback: " . $chunks[0]);
                 }
             }
             // shift the lead chunk and its value off now that it has been interpreted
             array_shift($chunks);
             array_shift($chunks);
         }
     } else {
         throw new exception("Cannot parse command: " . $line);
     }
 }
 /**
  * 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_CONFIG_PARAMETER, $command, $matches) > 0) {
         if (count($matches) != 3) {
             var_dump($matches);
             throw new exception("Database configuration parameter call preg exploded into " . count($matches) . ", panic!");
         }
         // just do what the call does push around the name -> value
         $configuration_parameter =& dbx::get_configuration_parameter($database, $matches[1], true);
         dbx::set_attribute($configuration_parameter, 'value', $matches[2]);
     } else {
         throw new exception("Cannot parse command: " . $command);
     }
 }
 /**
  * Parses ALTER SCHEMA command.
  *
  * @param database database
  * @param command ALTER SCHEMA command
  *
  */
 public static function parse($database, $command)
 {
     if (preg_match(self::PATTERN_OWNER, $command, $matches) > 0) {
         $line = $command;
         $schema_name = trim($matches[1]);
         $owner_name = trim($matches[2]);
         $schema =& dbx::get_schema($database, $schema_name);
         if ($schema == null) {
             throw new exception("failed to find schema " . $schema_name . " for alter owner statement");
         }
         dbx::set_attribute($schema, 'owner', $owner_name);
     } else {
         throw new exception("Cannot parse command: " . $command);
     }
 }
 /**
  * Parses ALTER LANGUAGE command.
  *
  * @param database database
  * @param command ALTER LANGUAGE command
  *
  */
 public static function parse($database, $command)
 {
     if (preg_match(self::PATTERN, $command, $matches) > 0) {
         $line = $command;
         $language_name = trim($matches[1]);
         $owner_name = trim($matches[2]);
         $language =& dbx::get_language($database, $language_name);
         if ($language == null) {
             throw new exception("Language " . $language_name . " not found. Is the create for it missing or after the ALTER LANGUAGE statement ?");
         }
         dbx::set_attribute($language, 'owner', $owner_name);
     } else {
         throw new exception("Cannot parse command: " . $command);
     }
 }
 /**
  * Parses CREATE SCHEMA command.
  *
  * @param database database
  * @param command CREATE SCHEMA command
  */
 public static function parse($database, $command)
 {
     if (preg_match(self::PATTERN_CREATE_SCHEMA, $command, $matches) > 0) {
         $node_schema = dbx::get_schema($database, $matches[1], true);
         if (isset($matches[2])) {
             dbx::set_attribute($node_schema, 'authorization', $matches[2]);
         }
     } else {
         if (preg_match(self::PATTERN_CREATE_SCHEMA_AUTHORIZATION, $command, $matches) > 0) {
             $node_schema = dbx::get_schema($database, $matches[1], true);
             dbx::set_attribute($node_schema, 'authorization', $node_schema['name']);
         } else {
             throw new exception("Cannot parse command: " . $command);
         }
     }
 }
 public static function set_permission($node_object, $action, $operations, $role)
 {
     if (!is_object($node_object)) {
         throw new exception("node_object is not an object, something is wrong, trace calling stack");
     }
     $action = strtolower($action);
     // see @TODO below, this xpath may need generalized if it is implemented
     $nodes = $node_object->xpath($action . "[@role='" . $role . "']");
     if (count($nodes) == 0) {
         // no $action for $object not found
         $node_permission = $node_object->addChild($action);
         dbx::set_attribute($node_permission, 'role', $role);
         dbx::set_attribute($node_permission, 'operation', implode(', ', $operations));
     }
     //@TODO: compare to existing $node_object grants with has_permission()?
     //@TODO: maybe return NOP if node_object already has role operation right defined?
 }
 /**
  * Parses CREATE INDEX command.
  *
  * @param database database
  * @param command CREATE INDEX command
  */
 public static function parse($database, $command)
 {
     if (preg_match(self::CREATE_PATTERN, trim($command), $matches) > 0) {
         $unique_value = strlen(trim($matches[1])) > 0 ? 'true' : 'false';
         $index_name = $matches[2];
         $table_name = $matches[3];
         $using = trim($matches[4]);
         if ($index_name == null || $table_name == null || $using == null) {
             throw new exception("Cannot parse command: " . $command);
         }
         $node_schema =& dbx::get_schema($database, sql_parser::get_schema_name(trim($table_name), $database));
         $node_table =& dbx::get_table($node_schema, sql_parser::get_object_name(trim($table_name)));
         if ($node_table == null) {
             throw new exception("Failed to find table: " . $table_name);
         }
         $node_index =& dbx::create_table_index($node_table, $index_name);
         dbx::set_attribute($node_index, 'using', $using);
         dbx::set_attribute($node_index, 'unique', $unique_value);
     } else {
         throw new exception("Cannot parse command: " . $command);
     }
 }
 /**
  * Save declaration information to the node_function
  *
  * @param functionName name of the function
  * @param arguments string containing arguments part of function
  *        declaration
  */
 public static function set_declaration(&$node_schema, &$node_function, $arguments)
 {
     if (strlen(trim($arguments)) == 0) {
         // no arguments to set for the function
     } else {
         $arguement_parts = explode(',', trim($arguments));
         $args = array();
         foreach ($arguement_parts as $part) {
             $chunks = preg_split("/[\\s]+/", $part, -1, PREG_SPLIT_NO_EMPTY);
             // per http://www.postgresql.org/docs/8.4/static/sql-createfunction.html
             // IN is default
             $direction = 'IN';
             $name = '';
             // if the first chunk is in or out, push it off as the direction
             if (strcasecmp($chunks[0], 'IN') == 0 || strcasecmp($chunks[0], 'OUT') == 0) {
                 $direction = strtoupper(array_shift($chunks));
             }
             // only 1 remaining chunk, and no match to known types, cry about it
             if (count($chunks) < 2 && preg_match(dbsteward::PATTERN_KNOWN_TYPES, implode(' ', $chunks)) == 0) {
                 throw new exception("unknown type encountered: " . implode(' ', $chunks));
             }
             // if the remainder is not a known type, push it off as the parameter name
             if (preg_match(dbsteward::PATTERN_KNOWN_TYPES, implode(' ', $chunks)) == 0) {
                 $name = array_shift($chunks);
             }
             // whatever is left is the type of the parameter
             $type = implode(' ', $chunks);
             // is reformed type in the known type list?
             if (preg_match(dbsteward::PATTERN_KNOWN_TYPES, $type) == 0) {
                 throw new exception("unknown type inferred: " . implode(' ', $chunks));
             }
             $function_parameter =& dbx::get_function_parameter($node_function, $name, true);
             dbx::set_attribute($function_parameter, 'direction', $direction);
             dbx::set_attribute($function_parameter, 'type', $type);
         }
     }
     return self::get_declaration($node_schema, $node_function);
 }
 /**
  * Parses ALTER FUNCTION command.
  *
  * @param database database
  * @param command ALTER FUNCTION command
  *
  */
 public static function parse($database, $command)
 {
     if (preg_match(self::PATTERN_OWNER, $command, $matches) > 0) {
         $line = $command;
         $function_name = trim($matches[1]);
         // make all functionName's fully qualified
         // default_schema will make set search path induced schemas come through correctly
         $function_name = sql_parser::get_schema_name($function_name, $database) . '.' . sql_parser::get_object_name($function_name);
         $arguments = $matches[2];
         $owner_name = trim($matches[3]);
         $node_schema = dbx::get_schema($database, sql_parser::get_schema_name($function_name, $database));
         if ($node_schema == null) {
             throw new exception("Failed to find function schema for " . $function_name);
         }
         $node_function = dbx::get_function($node_schema, sql_parser::get_object_name($function_name));
         if ($node_function == null) {
             throw new exception("Failed to find function " . $function_name . " in schema " . $node_schema['name']);
         }
         dbx::set_attribute($node_function, 'owner', $owner_name);
     } else {
         throw new exception("Cannot parse command: " . $command);
     }
 }
 /**
  * Parses definitions that are present after column definition is
  * closed with ')'.
  *
  * @param type type being parsed
  * @param commands commands being processed
  *
  * @return true if the command was the last command for CREATE TYPE,
  *         otherwise false
  */
 private static function parse_post_columns(&$type, $commands)
 {
     $line = $commands;
     if (preg_match(self::PATTERN_WITH_OIDS, $line, $matches) > 0) {
         dbx::set_attribute($node_table, 'withOIDS', 'true');
         $line = sql_parser::removeSubString($line, "WITH OIDS");
     } else {
         if (preg_match(self::PATTERN_WITHOUT_OIDS, $line, $matches) > 0) {
             dbx::set_attribute($node_table, 'withOIDS', 'false');
             $line = sql_parser::removeSubString($line, "WITHOUT OIDS");
         }
     }
     return $line;
 }
 /**
  * Parses all rows in CREATE TABLE command.
  *
  * @param $node_schema   schema table belongs to
  * @param $node_table    table being parsed
  * @param $command  command without 'CREATE TABLE ... (' string
  */
 private static function parse_rows(&$node_schema, &$node_table, $command)
 {
     $line = $command;
     $post_columns = false;
     while (strlen($line) > 0) {
         $command_end = sql_parser::get_command_end($line, 0);
         $subCommand = trim(substr($line, 0, $command_end));
         if ($post_columns) {
             $line = self::parse_post_columns($node_table, $subCommand);
             break;
         } else {
             if (substr($line, $command_end, 1) == ')') {
                 $post_columns = true;
             }
         }
         // look for modifier tokens and act accordingly
         $tokens = preg_split("/[\\s]+/", $subCommand, -1, PREG_SPLIT_NO_EMPTY);
         // start at 2, first is always name, second is always type
         for ($i = 2; $i < count($tokens); $i++) {
             if (strcasecmp($tokens[$i], 'UNIQUE') == 0) {
                 // CREATE TABLE test_table (
                 //   test_table_id varchar(64) PRIMARY KEY,
                 //   test_table_col_c varchar(100) UNIQUE NOT NULL
                 // );
                 // NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "test_table_pkey" for table "test_table"
                 // NOTICE:  CREATE TABLE / UNIQUE will create implicit index "test_table_test_table_col_c_key" for table "test_table"
                 dbsteward::debug("NOTICE:  CREATE TABLE with UNIQUE column attribute -- creating implicit index \"" . pgsql8_index::index_name(sql_parser::get_object_name($node_table->get_name()), sql_parser::get_object_name($tokens[0]), 'key') . "\" for table \"" . $node_schema->get_name() . '.' . $node_table->get_name() . "\"");
                 $node_index =& dbx::create_table_index($node_table, pgsql8_index::index_name(sql_parser::get_object_name($node_table['name']), sql_parser::get_object_name($tokens[0]), 'key'));
                 dbx::set_attribute($node_index, 'unique', 'true');
                 dbx::set_attribute($node_index, 'using', 'btree');
                 $node_index->addChild('indexDimension', sql_parser::get_object_name($tokens[0]))->addAttribute('name', $tokens[0] . '_unq');
                 // make sure we don't process this token again
                 unset($tokens[$i]);
                 $tokens = array_merge($tokens);
                 $i--;
                 continue;
             }
             // @TODO: other cases?
             // other cases is how you would fix pgsql8_column::parse_definition() throwing 'column definition parse fail' exceptions
         }
         $subCommand = implode(' ', $tokens);
         self::parse_column_defs($node_schema, $node_table, $subCommand);
         $line = $command_end >= strlen($line) ? "" : substr($line, $command_end + 1);
     }
     $line = trim($line);
     if (strlen($line) > 0) {
         throw new exception("Cannot parse CREATE TABLE '" . $node_table['name'] . "' - do not know how to parse '" . $line . "'");
     }
 }
 /**
  * Parses all rows in ALTER TABLE command.
  *
  * @param table table being parsed
  * @param commands commands
  *
  * @throws ParserException Thrown if problem occured while parsing DDL.
  */
 private static function parse_rows(&$db_doc, &$node_schema, &$node_table, $commands)
 {
     $line = $commands;
     $subCommand = null;
     while (strlen($line) > 0) {
         $commandEnd = sql_parser::get_command_end($line, 0);
         $subCommand = trim(substr($line, 0, $commandEnd));
         $line = $commandEnd >= strlen($line) ? "" : substr($line, $commandEnd + 1);
         if (strlen($subCommand) > 0) {
             if (preg_match(self::PATTERN_ADD_CONSTRAINT_FOREIGN_KEY, $subCommand, $matches) > 0) {
                 $column_name = trim($matches[3]);
                 $constraint_name = trim($matches[1]);
                 $node_constraint = pgsql8_constraint::get_table_constraint($db_doc, $node_table, $constraint_name, true);
                 dbx::set_attribute($node_constraint, 'definition', trim($matches[2]));
                 $subCommand = "";
             }
         }
         if (preg_match(self::PATTERN_ADD_CONSTRAINT, $subCommand, $matches) > 0) {
             $constraint_name = trim($matches[1]);
             $node_constraint = pgsql8_constraint::get_table_constraint($db_doc, $node_table, $constraint_name, true);
             dbx::set_attribute($node_constraint, 'definition', trim($matches[2]));
             $subCommand = "";
         }
         if (strlen($subCommand) > 0) {
             if (preg_match(self::PATTERN_ADD_PRIMARY_KEY, $subCommand, $matches) > 0) {
                 $definition = trim($matches[1]);
                 $column_name = trim($matches[2]);
                 $constraint_name = $node_table['name'] . '_pkey';
                 dbx::set_attribute($node_table, 'primaryKey', $column_name);
                 $subCommand = "";
             }
         }
         if (strlen($subCommand) > 0) {
             if (preg_match(self::PATTERN_ADD_FOREIGN_KEY, $subCommand, $matches) > 0) {
                 $column_name = trim($matches[2]);
                 $constraint_name = pgsql8::identifier_name($node_schema['name'], $node_table['name'], $column_name, '_fkey');
                 $node_constraint = pgsql8_constraint::get_table_constraint($db_doc, $node_table, $constraint_name, true);
                 dbx::set_attribute($node_constraint, 'definition', trim($matches[1]));
                 $subCommand = "";
             }
         }
         if (strlen($subCommand) > 0) {
             if (preg_match(self::PATTERN_SET_DEFAULT, $subCommand, $matches) > 0) {
                 $column_name = trim($matches[1]);
                 $default_value = trim($matches[2]);
                 if ($node_table->contains_column($column_name)) {
                     $node_column =& dbx::get_column($node_table, $column_name);
                     dbx::set_attribute($node_column, 'default', $default_value);
                 } else {
                     throw new exception("Cannot find column '" . $column_name . " 'in table '" . $node_table['name'] . "'");
                 }
                 $subCommand = "";
             }
         }
         if (preg_match(self::PATTERN_ALTER_COLUMN_STATISTICS, $subCommand, $matches) > 0) {
             $column_name = trim($matches[2]);
             $value = trim($matches[3]);
             $node_column =& dbx::get_column($node_table, $column_name);
             dbx::set_attribute($node_column, 'statistics', $value);
             $subCommand = "";
         }
         if (preg_match(self::PATTERN_CLUSTER_ON, $subCommand, $matches) > 0) {
             $indexName = trim($matches[1]);
             dbx::set_attribute($node_column, 'clusterIndexName', $indexName);
             $subCommand = "";
         }
         if (strlen($subCommand) > 0) {
             if (preg_match(self::PATTERN_TRIGGER, $subCommand, $matches) > 0) {
                 $triggerName = trim($matches[2]);
                 throw new exception("@TODO: do something with ALTER TABLE ... ENABLE / DISABLE trigger statements");
                 $subCommand = "";
             }
         }
         if (strlen($subCommand) > 0) {
             throw new exception("Don't know how to parse: " . $subCommand);
         }
     }
 }
 /**
  * Parses CREATE FUNCTION and CREATE OR REPLACE FUNCTION command.
  *
  * @param database database
  * @param command CREATE FUNCTION command
  */
 public static function parse($database, $command)
 {
     if (preg_match(self::PATTERN, trim($command), $matches) > 0) {
         $function_name = trim($matches[1]);
         // make all functionName's fully qualified
         // default_schema will make set search path induced schemas come through correctly
         $function_name = sql_parser::get_schema_name($function_name, $database) . '.' . sql_parser::get_object_name($function_name);
         $arguments = $matches[2];
         $node_schema = dbx::get_schema($database, sql_parser::get_schema_name($function_name, $database));
         if ($node_schema == null) {
             throw new exception("Failed to find function schema for " . $function_name);
         }
         $node_function = dbx::get_function($node_schema, sql_parser::get_object_name($function_name), null, true);
         //@TODO: this may be a problem when there is more than one prototype for a function
         $function_declaration = pgsql8_function::set_declaration($node_schema, $node_function, $arguments);
         // check remaining definition for function modifiers by chopping of function declaration
         $function_close_position = stripos($command, ')');
         $function_modifiers = str_replace("\n", ' ', substr($command, $function_close_position + 1));
         // kill extra whitespace by regex match
         $function_modifiers = preg_replace("/\\s+/", " ", $function_modifiers);
         // kill trailing semicolon
         $function_modifiers = trim($function_modifiers);
         if (substr($function_modifiers, -1) == ';') {
             $function_modifiers = trim(substr($function_modifiers, 0, -1));
         }
         $function_modifiers = ' ' . $function_modifiers . ' ';
         // AS token (definition) token
         // AS $_$ BEGIN DO STUFF END $_$
         if (($as_pos = stripos($function_modifiers, ' AS ')) !== false) {
             $end_as_token_pos = strpos($function_modifiers, ' ', $as_pos + 4);
             $as_token = substr($function_modifiers, $as_pos + 4, $end_as_token_pos - ($as_pos + 4));
             $definition_start = strpos($function_modifiers, $as_token, $as_pos) + strlen($as_token);
             $definition_end = strpos($function_modifiers, $as_token, $definition_start + strlen($as_token));
             $definition = substr($function_modifiers, $definition_start, $definition_end - $definition_start);
             $definition = trim($definition);
             pgsql8_function::set_definition($node_function, $definition);
             // cut out what we just found
             $function_modifiers = substr($function_modifiers, 0, $as_pos) . ' ' . substr($function_modifiers, $definition_end + strlen($as_token));
         }
         // now that the AS <token> (definition) <token> section is gone, parsing is simpler:
         // RETURNS (type)
         if (preg_match(self::PATTERN_RETURNS, $function_modifiers, $matches) > 0) {
             dbx::set_attribute($node_function, 'returns', trim($matches[1]));
         }
         // LANGUAGE (languagename)
         if (preg_match(self::PATTERN_LANGUAGE, $function_modifiers, $matches) > 0) {
             dbx::set_attribute($node_function, 'language', trim($matches[1]));
         }
         // check for IMMUTABLE | STABLE | VOLATILE modifiers
         if (preg_match('/.*\\s+IMMUTABLE\\s+.*/i', $function_modifiers, $matches) > 0) {
             dbx::set_attribute($node_function, 'cachePolicy', 'IMMUTABLE');
         }
         if (preg_match('/.*\\s+STABLE\\s+.*/i', $function_modifiers, $matches) > 0) {
             dbx::set_attribute($node_function, 'cachePolicy', 'STABLE');
         }
         if (preg_match('/.*\\s+VOLATILE\\s+.*/i', $function_modifiers, $matches) > 0) {
             dbx::set_attribute($node_function, 'cachePolicy', 'VOLATILE');
         }
         // check for SECURITY DEFINER modifier
         if (preg_match('/.*\\s+SECURITY DEFINER\\s+.*/i', $function_modifiers, $matches) > 0) {
             dbx::set_attribute($node_function, 'securityDefiner', 'true');
         }
     } else {
         throw new exception("Cannot parse command: " . $command);
     }
 }
 /**
  * Parses definition of the column
  *
  * @param definition definition of the column
  */
 public static function parse_definition(&$node_schema, &$node_table, &$node_column, $definition)
 {
     $type = $definition;
     if (preg_match(self::PATTERN_NOT_NULL, $type, $matches) > 0) {
         $type = trim($matches[1]);
         dbx::set_attribute($node_column, 'null', 'false');
     } else {
         if (preg_match(self::PATTERN_NULL, $type, $matches) > 0 && preg_match(self::PATTERN_DEFAULT_NULL, $type) == 0) {
             // PATTERN_NULL match only if it is not a trailing DEFAULT NULL
             // as that is not a null designation just a default designation
             $type = trim($matches[1]);
             dbx::set_attribute($node_column, 'null', 'true');
         }
     }
     if (preg_match(self::PATTERN_DEFAULT, $type, $matches) > 0) {
         $type = trim($matches[1]);
         dbx::set_attribute($node_column, 'default', trim($matches[2]));
     }
     // post-parsing sanity checks
     if (preg_match('/[\\s]+/', $type) > 0) {
         // type contains whitespace
         // split the type and look for bad tokens
         $bad_keywords = array('DEFAULT', 'UNIQUE');
         $tokens = preg_split("/[\\s]+/", $type, -1, PREG_SPLIT_NO_EMPTY);
         foreach ($tokens as $token) {
             foreach ($bad_keywords as $bad_keyword) {
                 if (strcasecmp($token, $bad_keyword) == 0) {
                     var_dump($definition);
                     throw new exception($node_column['name'] . " column definition parse fail: type '" . $type . "' still contains '" . $bad_keyword . "' keyword -- look at callers for mis-handling of definition parameter");
                 }
             }
         }
     }
     dbx::set_attribute($node_column, 'type', $type);
     // for serial and bigserials, create the accompanying sequence that powers the serial
     if (preg_match(pgsql8::PATTERN_TABLE_LINKED_TYPES, $type) > 0) {
         $sequence_name = pgsql8::identifier_name($node_schema['name'], $node_table['name'], $node_column['name'], '_seq');
         $node_sequence =& dbx::get_sequence($node_schema, $sequence_name, true);
         dbx::set_attribute($node_sequence, 'owner', $node_table['owner']);
         dbx::set_attribute($node_sequence, 'start', '1');
         dbx::set_attribute($node_sequence, 'min', '1');
         dbx::set_attribute($node_sequence, 'inc', '1');
         dbx::set_attribute($node_sequence, 'cycle', 'false');
     }
 }
 /**
  * Processes START WITH instruction.
  *
  * @param sequence sequence
  * @param command command
  *
  * @return command without START WITH instruction
  */
 private static function processstart_with(&$node_sequence, $command)
 {
     $line = $command;
     if (preg_match(self::PATTERN_START_WITH, $line, $matches) > 0) {
         dbx::set_attribute($node_sequence, 'start', trim($matches[1]));
         $line = preg_replace(self::PATTERN_START_WITH, '', $line);
     }
     return $line;
 }