Ejemplo n.º 1
0
 public function testEscape()
 {
     Context::setMode('ANSI_QUOTES');
     $this->assertEquals('"test"', Context::escape('test'));
     Context::setMode();
     $this->assertEquals('`test`', Context::escape('test'));
     $this->assertEquals(array('`a`', '`b`'), Context::escape(array('a', 'b')));
 }
Ejemplo n.º 2
0
 /**
  * Parses unknown parts of the query.
  *
  * @return Token
  */
 public function parseUnknown()
 {
     $token = $this->str[$this->last];
     if (Context::isSeparator($token)) {
         return null;
     }
     while (++$this->last < $this->len && !Context::isSeparator($this->str[$this->last])) {
         $token .= $this->str[$this->last];
     }
     --$this->last;
     return new Token($token);
 }
 /**
  * Index action
  *
  * @return void
  */
 public function indexAction()
 {
     PMA_PageSettings::showGroup('TableStructure');
     /**
      * Function implementations for this script
      */
     include_once 'libraries/check_user_privileges.lib.php';
     include_once 'libraries/index.lib.php';
     include_once 'libraries/sql.lib.php';
     include_once 'libraries/bookmark.lib.php';
     $this->response->getHeader()->getScripts()->addFiles(array('tbl_structure.js', 'indexes.js'));
     /**
      * Handle column moving
      */
     if (isset($_REQUEST['move_columns']) && is_array($_REQUEST['move_columns']) && $this->response->isAjax()) {
         $this->moveColumns();
         return;
     }
     /**
      * handle MySQL reserved words columns check
      */
     if (isset($_REQUEST['reserved_word_check'])) {
         if ($GLOBALS['cfg']['ReservedWordDisableWarning'] === false) {
             $columns_names = $_REQUEST['field_name'];
             $reserved_keywords_names = array();
             foreach ($columns_names as $column) {
                 if (SqlParser\Context::isKeyword(trim($column), true)) {
                     $reserved_keywords_names[] = trim($column);
                 }
             }
             if (SqlParser\Context::isKeyword(trim($this->table), true)) {
                 $reserved_keywords_names[] = trim($this->table);
             }
             if (count($reserved_keywords_names) == 0) {
                 $this->response->isSuccess(false);
             }
             $this->response->addJSON('message', sprintf(_ngettext('The name \'%s\' is a MySQL reserved keyword.', 'The names \'%s\' are MySQL reserved keywords.', count($reserved_keywords_names)), implode(',', $reserved_keywords_names)));
         } else {
             $this->response->isSuccess(false);
         }
         return;
     }
     /**
      * A click on Change has been made for one column
      */
     if (isset($_REQUEST['change_column'])) {
         $this->displayHtmlForColumnChange(null, 'tbl_structure.php');
         return;
     }
     /**
      * handle multiple field commands if required
      *
      * submit_mult_*_x comes from IE if <input type="img" ...> is used
      */
     $submit_mult = $this->getMultipleFieldCommandType();
     if (!empty($submit_mult)) {
         if (isset($_REQUEST['selected_fld'])) {
             if ($submit_mult == 'browse') {
                 // browsing the table displaying only selected columns
                 $this->displayTableBrowseForSelectedColumns($GLOBALS['goto'], $GLOBALS['pmaThemeImage']);
             } else {
                 // handle multiple field commands
                 // handle confirmation of deleting multiple columns
                 $action = 'tbl_structure.php';
                 $GLOBALS['selected'] = $_REQUEST['selected_fld'];
                 list($what_ret, $query_type_ret, $is_unset_submit_mult, $mult_btn_ret, $centralColsError) = $this->getDataForSubmitMult($submit_mult, $_REQUEST['selected_fld'], $action);
                 //update the existing variables
                 // todo: refactor mult_submits.inc.php such as
                 // below globals are not needed anymore
                 if (isset($what_ret)) {
                     $GLOBALS['what'] = $what_ret;
                     global $what;
                 }
                 if (isset($query_type_ret)) {
                     $GLOBALS['query_type'] = $query_type_ret;
                     global $query_type;
                 }
                 if ($is_unset_submit_mult) {
                     unset($submit_mult);
                 }
                 if (isset($mult_btn_ret)) {
                     $GLOBALS['mult_btn'] = $mult_btn_ret;
                     global $mult_btn;
                 }
                 include 'libraries/mult_submits.inc.php';
                 /**
                  * if $submit_mult == 'change', execution will have stopped
                  * at this point
                  */
                 if (empty($message)) {
                     $message = PMA_Message::success();
                 }
                 $this->response->addHTML(PMA_Util::getMessage($message, $sql_query));
             }
         } else {
             $this->response->isSuccess(false);
             $this->response->addJSON('message', __('No column selected.'));
         }
     }
     // display secondary level tabs if necessary
     $engine = $this->table_obj->sGetStatusInfo('ENGINE');
     $this->response->addHTML(Template::get('table/secondary_tabs')->render(array('url_params' => array('db' => $this->db, 'table' => $this->table), 'engine' => $engine)));
     $this->response->addHTML('<div id="structure_content">');
     /**
      * Modifications have been submitted -> updates the table
      */
     if (isset($_REQUEST['do_save_data'])) {
         $regenerate = $this->updateColumns();
         if ($regenerate) {
             // This happens when updating failed
             // @todo: do something appropriate
         } else {
             // continue to show the table's structure
             unset($_REQUEST['selected']);
         }
     }
     /**
      * Adding indexes
      */
     if (isset($_REQUEST['add_key'])) {
         //todo: set some variables for sql.php include, to be eliminated
         //after refactoring sql.php
         $db = $this->db;
         $table = $this->table;
         $cfg = $GLOBALS['cfg'];
         $is_superuser = $GLOBALS['dbi']->isSuperuser();
         $pmaThemeImage = $GLOBALS['pmaThemeImage'];
         include 'sql.php';
         $GLOBALS['reload'] = true;
     }
     /**
      * Gets the relation settings
      */
     $cfgRelation = PMA_getRelationsParam();
     /**
      * Runs common work
      */
     // set db, table references, for require_once that follows
     // got to be eliminated in long run
     $db =& $this->db;
     $table =& $this->table;
     include_once 'libraries/tbl_common.inc.php';
     $this->_url_query = $url_query . '&amp;goto=tbl_structure.php&amp;back=tbl_structure.php';
     $url_params['goto'] = 'tbl_structure.php';
     $url_params['back'] = 'tbl_structure.php';
     /**
      * Gets tables information
      */
     include_once 'libraries/tbl_info.inc.php';
     include_once 'libraries/Index.class.php';
     // 2. Gets table keys and retains them
     // @todo should be: $server->db($db)->table($table)->primary()
     $primary = PMA_Index::getPrimary($this->table, $this->db);
     $columns_with_index = $this->dbi->getTable($this->db, $this->table)->getColumnsWithIndex(PMA_Index::UNIQUE | PMA_Index::INDEX | PMA_Index::SPATIAL | PMA_Index::FULLTEXT);
     $columns_with_unique_index = $this->dbi->getTable($this->db, $this->table)->getColumnsWithIndex(PMA_Index::UNIQUE);
     // 3. Get fields
     $fields = (array) $this->dbi->getColumns($this->db, $this->table, null, true);
     // Get more complete field information
     // For now, this is done just for MySQL 4.1.2+ new TIMESTAMP options
     // but later, if the analyser returns more information, it
     // could be executed for any MySQL version and replace
     // the info given by SHOW FULL COLUMNS FROM.
     //
     // We also need this to correctly learn if a TIMESTAMP is NOT NULL, since
     // SHOW FULL COLUMNS or INFORMATION_SCHEMA incorrectly says NULL
     // and SHOW CREATE TABLE says NOT NULL (tested
     // in MySQL 4.0.25 and 5.0.21, http://bugs.mysql.com/20910).
     $show_create_table = $this->table_obj->showCreate();
     $parser = new SqlParser\Parser($show_create_table);
     /**
      * @var CreateStatement $stmt
      */
     $stmt = $parser->statements[0];
     $create_table_fields = SqlParser\Utils\Table::getFields($stmt);
     //display table structure
     $this->response->addHTML($this->displayStructure($cfgRelation, $columns_with_unique_index, $url_params, $primary, $fields, $columns_with_index, $create_table_fields));
     $this->response->addHTML('</div>');
 }
Ejemplo n.º 4
0
 /**
  * Get all column names which are MySQL reserved words
  *
  * @return array
  * @access public
  */
 public function getReservedColumnNames()
 {
     $columns = $this->getColumns(false);
     $return = array();
     foreach ($columns as $column) {
         $temp = explode('.', $column);
         $column_name = $temp[2];
         if (Context::isKeyword($column_name, true)) {
             $return[] = $column_name;
         }
     }
     return $return;
 }
Ejemplo n.º 5
0
 /**
  * @param Key   $component The component to be built.
  * @param array $options   Parameters for building.
  *
  * @return string
  */
 public static function build($component, array $options = array())
 {
     $ret = $component->type . ' ';
     if (!empty($component->name)) {
         $ret .= Context::escape($component->name) . ' ';
     }
     $columns = array();
     foreach ($component->columns as $column) {
         $tmp = Context::escape($column['name']);
         if (isset($column['length'])) {
             $tmp .= '(' . $column['length'] . ')';
         }
         $columns[] = $tmp;
     }
     $ret .= '(' . implode(',', $columns) . ') ' . $component->options;
     return trim($ret);
 }
Ejemplo n.º 6
0
 /**
  * Index action
  *
  * @return void
  */
 public function indexAction()
 {
     PageSettings::showGroup('TableStructure');
     /**
      * Function implementations for this script
      */
     include_once 'libraries/check_user_privileges.lib.php';
     include_once 'libraries/index.lib.php';
     include_once 'libraries/sql.lib.php';
     $this->response->getHeader()->getScripts()->addFiles(array('tbl_structure.js', 'indexes.js'));
     /**
      * Handle column moving
      */
     if (isset($_REQUEST['move_columns']) && is_array($_REQUEST['move_columns']) && $this->response->isAjax()) {
         $this->moveColumns();
         return;
     }
     /**
      * handle MySQL reserved words columns check
      */
     if (isset($_REQUEST['reserved_word_check'])) {
         if ($GLOBALS['cfg']['ReservedWordDisableWarning'] === false) {
             $columns_names = $_REQUEST['field_name'];
             $reserved_keywords_names = array();
             foreach ($columns_names as $column) {
                 if (SqlParser\Context::isKeyword(trim($column), true)) {
                     $reserved_keywords_names[] = trim($column);
                 }
             }
             if (SqlParser\Context::isKeyword(trim($this->table), true)) {
                 $reserved_keywords_names[] = trim($this->table);
             }
             if (count($reserved_keywords_names) == 0) {
                 $this->response->setRequestStatus(false);
             }
             $this->response->addJSON('message', sprintf(_ngettext('The name \'%s\' is a MySQL reserved keyword.', 'The names \'%s\' are MySQL reserved keywords.', count($reserved_keywords_names)), implode(',', $reserved_keywords_names)));
         } else {
             $this->response->setRequestStatus(false);
         }
         return;
     }
     /**
      * A click on Change has been made for one column
      */
     if (isset($_REQUEST['change_column'])) {
         $this->displayHtmlForColumnChange(null, 'tbl_structure.php');
         return;
     }
     /**
      * Adding or editing partitioning of the table
      */
     if (isset($_REQUEST['edit_partitioning']) && !isset($_REQUEST['save_partitioning'])) {
         $this->displayHtmlForPartitionChange();
         return;
     }
     /**
      * handle multiple field commands if required
      *
      * submit_mult_*_x comes from IE if <input type="img" ...> is used
      */
     $submit_mult = $this->getMultipleFieldCommandType();
     if (!empty($submit_mult)) {
         if (isset($_REQUEST['selected_fld'])) {
             if ($submit_mult == 'browse') {
                 // browsing the table displaying only selected columns
                 $this->displayTableBrowseForSelectedColumns($GLOBALS['goto'], $GLOBALS['pmaThemeImage']);
             } else {
                 // handle multiple field commands
                 // handle confirmation of deleting multiple columns
                 $action = 'tbl_structure.php';
                 $GLOBALS['selected'] = $_REQUEST['selected_fld'];
                 list($what_ret, $query_type_ret, $is_unset_submit_mult, $mult_btn_ret, $centralColsError) = $this->getDataForSubmitMult($submit_mult, $_REQUEST['selected_fld'], $action);
                 //update the existing variables
                 // todo: refactor mult_submits.inc.php such as
                 // below globals are not needed anymore
                 if (isset($what_ret)) {
                     $GLOBALS['what'] = $what_ret;
                     global $what;
                 }
                 if (isset($query_type_ret)) {
                     $GLOBALS['query_type'] = $query_type_ret;
                     global $query_type;
                 }
                 if ($is_unset_submit_mult) {
                     unset($submit_mult);
                 }
                 if (isset($mult_btn_ret)) {
                     $GLOBALS['mult_btn'] = $mult_btn_ret;
                     global $mult_btn;
                 }
                 include 'libraries/mult_submits.inc.php';
                 /**
                  * if $submit_mult == 'change', execution will have stopped
                  * at this point
                  */
                 if (empty($message)) {
                     $message = Message::success();
                 }
                 $this->response->addHTML(Util::getMessage($message, $sql_query));
             }
         } else {
             $this->response->setRequestStatus(false);
             $this->response->addJSON('message', __('No column selected.'));
         }
     }
     // display secondary level tabs if necessary
     $engine = $this->table_obj->getStatusInfo('ENGINE');
     $this->response->addHTML(Template::get('table/secondary_tabs')->render(array('url_params' => array('db' => $this->db, 'table' => $this->table), 'engine' => $engine)));
     $this->response->addHTML('<div id="structure_content">');
     /**
      * Modifications have been submitted -> updates the table
      */
     if (isset($_REQUEST['do_save_data'])) {
         $regenerate = $this->updateColumns();
         if ($regenerate) {
             // This happens when updating failed
             // @todo: do something appropriate
         } else {
             // continue to show the table's structure
             unset($_REQUEST['selected']);
         }
     }
     /**
      * Modifications to the partitioning have been submitted -> updates the table
      */
     if (isset($_REQUEST['save_partitioning'])) {
         $this->updatePartitioning();
     }
     /**
      * Adding indexes
      */
     if (isset($_REQUEST['add_key']) || isset($_REQUEST['partition_maintenance'])) {
         //todo: set some variables for sql.php include, to be eliminated
         //after refactoring sql.php
         $db = $this->db;
         $table = $this->table;
         $cfg = $GLOBALS['cfg'];
         $is_superuser = $GLOBALS['dbi']->isSuperuser();
         $pmaThemeImage = $GLOBALS['pmaThemeImage'];
         include 'sql.php';
         $GLOBALS['reload'] = true;
     }
     /**
      * Gets the relation settings
      */
     $cfgRelation = PMA_getRelationsParam();
     /**
      * Runs common work
      */
     // set db, table references, for require_once that follows
     // got to be eliminated in long run
     $db =& $this->db;
     $table =& $this->table;
     include_once 'libraries/tbl_common.inc.php';
     $this->_db_is_system_schema = $db_is_system_schema;
     $this->_url_query = $url_query . '&amp;goto=tbl_structure.php&amp;back=tbl_structure.php';
     $url_params = array('goto' => 'tbl_structure.php', 'back' => 'tbl_structure.php');
     /**
      * Gets tables information
      */
     include_once 'libraries/tbl_info.inc.php';
     // 2. Gets table keys and retains them
     // @todo should be: $server->db($db)->table($table)->primary()
     $primary = Index::getPrimary($this->table, $this->db);
     $columns_with_index = $this->dbi->getTable($this->db, $this->table)->getColumnsWithIndex(Index::UNIQUE | Index::INDEX | Index::SPATIAL | Index::FULLTEXT);
     $columns_with_unique_index = $this->dbi->getTable($this->db, $this->table)->getColumnsWithIndex(Index::UNIQUE);
     // 3. Get fields
     $fields = (array) $this->dbi->getColumns($this->db, $this->table, null, true);
     //display table structure
     $this->response->addHTML($this->displayStructure($cfgRelation, $columns_with_unique_index, $url_params, $primary, $fields, $columns_with_index));
     $this->response->addHTML('</div>');
 }
Ejemplo n.º 7
0
 /**
  * @param Reference $component The component to be built.
  * @param array     $options   Parameters for building.
  *
  * @return string
  */
 public static function build($component, array $options = array())
 {
     return trim(Context::escape($component->table) . ' (' . implode(', ', Context::escape($component->columns)) . ') ' . $component->options);
 }
Ejemplo n.º 8
0
 /**
  * @param CreateDefinition|CreateDefinition[] $component The component to be built.
  * @param array                               $options   Parameters for building.
  *
  * @return string
  */
 public static function build($component, array $options = array())
 {
     if (is_array($component)) {
         return "(\n  " . implode(",\n  ", $component) . "\n)";
     } else {
         $tmp = '';
         if ($component->isConstraint) {
             $tmp .= 'CONSTRAINT ';
         }
         if (isset($component->name) && $component->name !== '') {
             $tmp .= Context::escape($component->name) . ' ';
         }
         if (!empty($component->type)) {
             $tmp .= DataType::build($component->type, array('lowercase' => true)) . ' ';
         }
         if (!empty($component->key)) {
             $tmp .= $component->key . ' ';
         }
         if (!empty($component->references)) {
             $tmp .= 'REFERENCES ' . $component->references . ' ';
         }
         $tmp .= $component->options;
         return trim($tmp);
     }
 }
Ejemplo n.º 9
0
 /**
  * @param Key $component The component to be built.
  *
  * @return string
  */
 public static function build($component)
 {
     $ret = $component->type . ' ';
     if (!empty($component->name)) {
         $ret .= Context::escape($component->name) . ' ';
     }
     $ret .= '(' . implode(',', Context::escape($component->columns)) . ')';
     $ret .= OptionsArray::build($component->options);
     return trim($ret);
 }
Ejemplo n.º 10
0
 /**
  * replaces db/table/column names with their aliases
  *
  * @param string $sql_query SQL query in which aliases are to be substituted
  * @param array  $aliases   Alias information for db/table/column
  * @param string $db        the database name
  * @param string $table     the tablename
  * @param string &$flag     the flag denoting whether any replacement was done
  *
  * @return string query replaced with aliases
  */
 public function replaceWithAliases($sql_query, $aliases, $db, $table = '', &$flag = null)
 {
     $flag = false;
     /**
      * The parser of this query.
      *
      * @var Parser $parser
      */
     $parser = new Parser($sql_query);
     if (empty($parser->statements[0])) {
         return $sql_query;
     }
     /**
      * The statement that represents the query.
      *
      * @var CreateStatement $statement
      */
     $statement = $parser->statements[0];
     /**
      * Old database name.
      *
      * @var string $old_database
      */
     $old_database = $db;
     // Replacing aliases in `CREATE TABLE` statement.
     if ($statement->options->has('TABLE')) {
         // Extracting the name of the old database and table from the
         // statement to make sure the parameters are corect.
         if (!empty($statement->name->database)) {
             $old_database = $statement->name->database;
         }
         /**
          * Old table name.
          *
          * @var string $old_table
          */
         $old_table = $statement->name->table;
         // Finding the aliased database name.
         // The database might be empty so we have to add a few checks.
         $new_database = null;
         if (!empty($statement->name->database)) {
             $new_database = $statement->name->database;
             if (!empty($aliases[$old_database]['alias'])) {
                 $new_database = $aliases[$old_database]['alias'];
             }
         }
         // Finding the aliases table name.
         $new_table = $old_table;
         if (!empty($aliases[$old_database]['tables'][$old_table]['alias'])) {
             $new_table = $aliases[$old_database]['tables'][$old_table]['alias'];
         }
         // Replacing new values.
         if ($statement->name->database !== $new_database || $statement->name->table !== $new_table) {
             $statement->name->database = $new_database;
             $statement->name->table = $new_table;
             $statement->name->expr = null;
             // Force rebuild.
             $flag = true;
         }
         foreach ($statement->fields as $field) {
             // Column name.
             if (!empty($field->type)) {
                 if (!empty($aliases[$old_database]['tables'][$old_table]['columns'][$field->name])) {
                     $field->name = $aliases[$old_database]['tables'][$old_table]['columns'][$field->name];
                     $flag = true;
                 }
             }
             // Key's columns.
             if (!empty($field->key)) {
                 foreach ($field->key->columns as $key => $column) {
                     if (!empty($aliases[$old_database]['tables'][$old_table]['columns'][$column['name']])) {
                         $field->key->columns[$key]['name'] = $aliases[$old_database]['tables'][$old_table]['columns'][$column['name']];
                         $flag = true;
                     }
                 }
             }
             // References.
             if (!empty($field->references)) {
                 $ref_table = $field->references->table->table;
                 // Replacing table.
                 if (!empty($aliases[$old_database]['tables'][$ref_table]['alias'])) {
                     $field->references->table->table = $aliases[$old_database]['tables'][$ref_table]['alias'];
                     $field->references->table->expr = null;
                     $flag = true;
                 }
                 // Replacing column names.
                 foreach ($field->references->columns as $key => $column) {
                     if (!empty($aliases[$old_database]['tables'][$ref_table]['columns'][$column])) {
                         $field->references->columns[$key] = $aliases[$old_database]['tables'][$ref_table]['columns'][$column];
                         $flag = true;
                     }
                 }
             }
         }
     } elseif ($statement->options->has('TRIGGER')) {
         // Extracting the name of the old database and table from the
         // statement to make sure the parameters are corect.
         if (!empty($statement->table->database)) {
             $old_database = $statement->table->database;
         }
         /**
          * Old table name.
          *
          * @var string $old_table
          */
         $old_table = $statement->table->table;
         if (!empty($aliases[$old_database]['tables'][$old_table]['alias'])) {
             $statement->table->table = $aliases[$old_database]['tables'][$old_table]['alias'];
             $statement->table->expr = null;
             // Force rebuild.
             $flag = true;
         }
     }
     if ($statement->options->has('TRIGGER') || $statement->options->has('PROCEDURE') || $statement->options->has('FUNCTION') || $statement->options->has('VIEW')) {
         // Repalcing the body.
         for ($i = 0, $count = count($statement->body); $i < $count; ++$i) {
             /**
              * Token parsed at this moment.
              *
              * @var Token $token
              */
             $token = $statement->body[$i];
             // Replacing only symbols (that are not variables) and unknown
             // identifiers.
             if ($token->type === Token::TYPE_SYMBOL && !($token->flags & Token::FLAG_SYMBOL_VARIABLE) || ($token->type === Token::TYPE_KEYWORD && !($token->flags & Token::FLAG_KEYWORD_RESERVED) || $token->type === Token::TYPE_NONE)) {
                 $alias = $this->getAlias($aliases, $token->value);
                 if (!empty($alias)) {
                     // Replacing the token.
                     $token->token = Context::escape($alias);
                     $flag = true;
                 }
             }
         }
     }
     return $statement->build();
 }
 /**
  * @param ParameterDefinition[] $component The component to be built.
  *
  * @return string
  */
 public static function build($component)
 {
     $ret = array();
     foreach ($component as $c) {
         $tmp = '';
         if (!empty($c->inOut)) {
             $tmp .= $c->inOut . ' ';
         }
         $ret[] = trim($tmp . Context::escape($c->name) . ' ' . DataType::build($c->type));
     }
     return '(' . implode(', ', $ret) . ')';
 }
Ejemplo n.º 12
0
 /**
  * @param Reference $component The component to be built.
  *
  * @return string
  */
 public static function build($component)
 {
     return trim(Context::escape($component->table) . ' (' . implode(', ', Context::escape($component->columns)) . ') ' . OptionsArray::build($component->options));
 }
Ejemplo n.º 13
0
 /**
  * @expectedException Exception
  * @expectedExceptionMessage Specified context ("\SqlParser\Contexts\ContextFoo") doesn't exist.
  */
 public function testLoadError()
 {
     Context::load('Foo');
 }
Ejemplo n.º 14
0
 /**
  * Extracts a statement from the buffer.
  *
  * @param bool $end Whether the end of the buffer was reached.
  *
  * @return string
  */
 public function extract($end = false)
 {
     /**
      * The last parsed position.
      *
      * This is statically defined because it is not used outside anywhere
      * outside this method and there is probably a (minor) performance
      * improvement to it.
      *
      * @var int
      */
     static $i = 0;
     if (empty($this->query)) {
         return false;
     }
     /**
      * The length of the buffer.
      * @var int $len
      */
     $len = strlen($this->query);
     /**
      * The last index of the string that is going to be parsed.
      *
      * There must be a few characters left in the buffer so the parser can
      * avoid confusing some symbols that may have multiple meanings.
      *
      * For example, if the buffer ends in `-` that may be an operator or the
      * beginning of a comment.
      *
      * Another example if the buffer ends in `DELIMITE`. The parser is going
      * to require a few more characters because that may be a part of the
      * `DELIMITER` keyword or just a column named `DELIMITE`.
      *
      * Those extra characters are required only if there is more data
      * expected (the end of the buffer was not reached).
      *
      * @var int $loopLen
      */
     $loopLen = $end ? $len : $len - 16;
     for (; $i < $loopLen; ++$i) {
         /*
          * Handling special parses statuses.
          */
         if ($this->status === static::STATUS_STRING_SINGLE_QUOTES) {
             // Single-quoted strings like 'foo'.
             if ($this->query[$i - 1] != '\\' && $this->query[$i] === '\'') {
                 $this->status = 0;
             }
             $this->current .= $this->query[$i];
             continue;
         } elseif ($this->status === static::STATUS_STRING_DOUBLE_QUOTES) {
             // Double-quoted strings like "bar".
             if ($this->query[$i - 1] != '\\' && $this->query[$i] === '"') {
                 $this->status = 0;
             }
             $this->current .= $this->query[$i];
             continue;
         } elseif ($this->status === static::STATUS_STRING_BACKTICK) {
             if ($this->query[$i] === '`') {
                 $this->status = 0;
             }
             $this->current .= $this->query[$i];
             continue;
         } elseif ($this->status === static::STATUS_COMMENT_BASH || $this->status === static::STATUS_COMMENT_SQL) {
             // Bash-like (#) or SQL-like (-- ) comments end in new line.
             if ($this->query[$i] === "\n") {
                 $this->status = 0;
             }
             continue;
         } elseif ($this->status === static::STATUS_COMMENT_C) {
             // C-like comments end in */.
             if ($this->query[$i - 1] === '*' && $this->query[$i] === '/') {
                 $this->status = 0;
             }
             continue;
         }
         /*
          * Checking if a string started.
          */
         if ($this->query[$i] === '\'') {
             $this->status = static::STATUS_STRING_SINGLE_QUOTES;
             $this->current .= $this->query[$i];
             continue;
         } elseif ($this->query[$i] === '"') {
             $this->status = static::STATUS_STRING_DOUBLE_QUOTES;
             $this->current .= $this->query[$i];
             continue;
         } elseif ($this->query[$i] === '`') {
             $this->status = static::STATUS_STRING_BACKTICK;
             $this->current .= $this->query[$i];
             continue;
         }
         /*
          * Checking if a comment started.
          */
         if ($this->query[$i] === '#') {
             $this->status = static::STATUS_COMMENT_BASH;
             continue;
         } elseif ($i + 2 < $len && $this->query[$i] === '-' && $this->query[$i + 1] === '-' && Context::isWhitespace($this->query[$i + 2])) {
             $this->status = static::STATUS_COMMENT_SQL;
             continue;
         } elseif ($i + 2 < $len && $this->query[$i] === '/' && $this->query[$i + 1] === '*' && $this->query[$i + 2] !== '!') {
             $this->status = static::STATUS_COMMENT_C;
             continue;
         }
         /*
          * Handling `DELIMITER` statement.
          *
          * The code below basically checks for
          *     `strtoupper(substr($this->query, $i, 9)) === 'DELIMITER'`
          *
          * This optimization makes the code about 3 times faster.
          */
         if ($i + 9 < $len && ($this->query[$i] === 'D' || $this->query[$i] === 'd') && ($this->query[$i + 1] === 'E' || $this->query[$i + 1] === 'e') && ($this->query[$i + 2] === 'L' || $this->query[$i + 2] === 'l') && ($this->query[$i + 3] === 'I' || $this->query[$i + 3] === 'i') && ($this->query[$i + 4] === 'M' || $this->query[$i + 4] === 'm') && ($this->query[$i + 5] === 'I' || $this->query[$i + 5] === 'i') && ($this->query[$i + 6] === 'T' || $this->query[$i + 6] === 't') && ($this->query[$i + 7] === 'E' || $this->query[$i + 7] === 'e') && ($this->query[$i + 8] === 'R' || $this->query[$i + 8] === 'r') && Context::isWhitespace($this->query[$i + 9])) {
             // Saving the current index to be able to revert any parsing
             // done in this block.
             $iBak = $i;
             $i += 9;
             // Skipping `DELIMITER`.
             // Skipping whitespaces.
             while ($i < $len && Context::isWhitespace($this->query[$i])) {
                 ++$i;
             }
             // Parsing the delimiter.
             $delimiter = '';
             while ($i < $len && !Context::isWhitespace($this->query[$i])) {
                 $delimiter .= $this->query[$i++];
             }
             // Checking if the delimiter definition ended.
             if ($delimiter != '' && ($i < $len && Context::isWhitespace($this->query[$i]) || $i === $len && $end)) {
                 // Saving the delimiter.
                 $this->setDelimiter($delimiter);
                 // Whether this statement should be returned or not.
                 $ret = '';
                 if (!empty($this->options['parse_delimiter'])) {
                     // Appending the `DELIMITER` statement that was just
                     // found to the current statement.
                     $ret = trim($this->current . ' ' . substr($this->query, $iBak, $i - $iBak));
                 }
                 // Removing the statement that was just extracted from the
                 // query.
                 $this->query = substr($this->query, $i);
                 $i = 0;
                 // Resetting the current statement.
                 $this->current = '';
                 return $ret;
             }
             // Incomplete statement. Reverting
             $i = $iBak;
             return false;
         }
         /*
          * Checking if the current statement finished.
          *
          * The first letter of the delimiter is being checked as an
          * optimization. This code is almost as fast as the one above.
          *
          * There is no point in checking if two strings match if not even
          * the first letter matches.
          */
         if ($this->query[$i] === $this->delimiter[0] && ($this->delimiterLen === 1 || substr($this->query, $i, $this->delimiterLen) === $this->delimiter)) {
             // Saving the statement that just ended.
             $ret = $this->current;
             // If needed, adds a delimiter at the end of the statement.
             if (!empty($this->options['add_delimiter'])) {
                 $ret .= $this->delimiter;
             }
             // Removing the statement that was just extracted from the
             // query.
             $this->query = substr($this->query, $i + $this->delimiterLen);
             $i = 0;
             // Resetting the current statement.
             $this->current = '';
             // Returning the statement.
             return trim($ret);
         }
         /*
          * Appending current character to current statement.
          */
         $this->current .= $this->query[$i];
     }
     if ($end && $i === $len) {
         // If the end of the buffer was reached, the buffer is emptied and
         // the current statement that was extracted is returned.
         $ret = $this->current;
         // Emptying the buffer.
         $this->query = '';
         $i = 0;
         // Resetting the current statement.
         $this->current = '';
         // Returning the statement.
         return trim($ret);
     }
     return '';
 }
 /**
  * @param ParameterDefinition[] $component The component to be built.
  * @param array                 $options   Parameters for building.
  *
  * @return string
  */
 public static function build($component, array $options = array())
 {
     if (is_array($component)) {
         return '(' . implode(', ', $component) . ')';
     } else {
         $tmp = '';
         if (!empty($component->inOut)) {
             $tmp .= $component->inOut . ' ';
         }
         return trim($tmp . Context::escape($component->name) . ' ' . $component->type);
     }
 }
Ejemplo n.º 16
0
 public function testisSeparator()
 {
     $this->assertTrue(Context::isSeparator('+'));
     $this->assertTrue(Context::isSeparator('.'));
     $this->assertFalse(Context::isSeparator('1'));
     $this->assertFalse(Context::isSeparator('E'));
     $this->assertFalse(Context::isSeparator('_'));
 }
Ejemplo n.º 17
0
 /**
  * @param FieldDefinition|FieldDefinition[] $component The component to be built.
  *
  * @return string
  */
 public static function build($component)
 {
     if (is_array($component)) {
         $ret = array();
         foreach ($component as $c) {
             $ret[] = static::build($c);
         }
         return "(\n" . implode(",\n", $ret) . "\n)";
     } else {
         $tmp = '';
         if ($component->isConstraint) {
             $tmp .= 'CONSTRAINT ';
         }
         if (!empty($component->name)) {
             $tmp .= Context::escape($component->name) . ' ';
         }
         if (!empty($component->type)) {
             $tmp .= DataType::build($component->type) . ' ';
         }
         if (!empty($component->key)) {
             $tmp .= Key::build($component->key) . ' ';
         }
         if (!empty($component->references)) {
             $tmp .= 'REFERENCES ' . Reference::build($component->references) . ' ';
         }
         $tmp .= OptionsArray::build($component->options);
         return trim($tmp);
     }
 }
Ejemplo n.º 18
0
    /**
     * Adds backquotes on both sides of a database, table or field name.
     * in compatibility mode
     *
     * example:
     * <code>
     * echo backquoteCompat('owner`s db'); // `owner``s db`
     *
     * </code>
     *
     * @param mixed   $a_name        the database, table or field name to
     *                               "backquote" or array of it
     * @param string  $compatibility string compatibility mode (used by dump
     *                               functions)
     * @param boolean $do_it         a flag to bypass this function (used by dump
     *                               functions)
     *
     * @return mixed the "backquoted" database, table or field name
     *
     * @access  public
     */
    public static function backquoteCompat(
        $a_name,
        $compatibility = 'MSSQL',
        $do_it = true
    ) {
        if (is_array($a_name)) {
            foreach ($a_name as &$data) {
                $data = self::backquoteCompat($data, $compatibility, $do_it);
            }
            return $a_name;
        }

        if (! $do_it) {
            if (!Context::isKeyword($a_name)) {
                return $a_name;
            }
        }

        // @todo add more compatibility cases (ORACLE for example)
        switch ($compatibility) {
        case 'MSSQL':
            $quote = '"';
            break;
        default:
            $quote = "`";
            break;
        }

        // '0' is also empty for php :-(
        if (strlen($a_name) > 0 && $a_name !== '*') {
            return $quote . $a_name . $quote;
        } else {
            return $a_name;
        }
    } // end of the 'backquoteCompat()' function
Ejemplo n.º 19
0
 /**
  * @param Expression $component The component to be built.
  *
  * @return string
  */
 public static function build($component)
 {
     if (!empty($component->expr)) {
         $ret = $component->expr;
     } else {
         $fields = array();
         if (!empty($component->database)) {
             $fields[] = $component->database;
         }
         if (!empty($component->table)) {
             $fields[] = $component->table;
         }
         if (!empty($component->column)) {
             $fields[] = $component->column;
         }
         $ret = implode('.', Context::escape($fields));
     }
     if (!empty($component->alias)) {
         $ret .= ' AS ' . Context::escape($component->alias);
     }
     return $ret;
 }
Ejemplo n.º 20
0
 /**
  * @param Expression|Expression[] $component The component to be built.
  * @param array                   $options   Parameters for building.
  *
  * @return string
  */
 public static function build($component, array $options = array())
 {
     if (is_array($component)) {
         return implode($component, ', ');
     } else {
         if ($component->expr !== '' && !is_null($component->expr)) {
             $ret = $component->expr;
         } else {
             $fields = array();
             if (isset($component->database) && $component->database !== '') {
                 $fields[] = $component->database;
             }
             if (isset($component->table) && $component->table !== '') {
                 $fields[] = $component->table;
             }
             if (isset($component->column) && $component->column !== '') {
                 $fields[] = $component->column;
             }
             $ret = implode('.', Context::escape($fields));
         }
         if (!empty($component->alias)) {
             $ret .= ' AS ' . Context::escape($component->alias);
         }
         return $ret;
     }
 }
 /**
  * Index action
  *
  * @return void
  */
 public function indexAction()
 {
     // Database structure
     if ($this->_type == 'db') {
         // Add/Remove favorite tables using Ajax request.
         if ($GLOBALS['is_ajax_request'] && !empty($_REQUEST['favorite_table'])) {
             $this->addRemoveFavoriteTables();
             return;
         }
         $this->response->getHeader()->getScripts()->addFiles(array('db_structure.js', 'tbl_change.js', 'jquery/jquery-ui-timepicker-addon.js'));
         // Drops/deletes/etc. multiple tables if required
         if (!empty($_POST['submit_mult']) && isset($_POST['selected_tbl']) || isset($_POST['mult_btn'])) {
             $action = 'db_structure.php';
             $err_url = 'db_structure.php' . PMA_URL_getCommon(array('db' => $this->_db));
             // see bug #2794840; in this case, code path is:
             // db_structure.php -> libraries/mult_submits.inc.php -> sql.php
             // -> db_structure.php and if we got an error on the multi submit,
             // we must display it here and not call again mult_submits.inc.php
             if (!isset($_POST['error']) || false === $_POST['error']) {
                 include 'libraries/mult_submits.inc.php';
             }
             if (empty($_POST['message'])) {
                 $_POST['message'] = PMA_Message::success();
             }
         }
         $this->_url_query .= '&amp;goto=db_structure.php';
         // Gets the database structure
         $sub_part = '_structure';
         // If there is an Ajax request for real row count of a table.
         if ($GLOBALS['is_ajax_request'] && isset($_REQUEST['real_row_count']) && $_REQUEST['real_row_count'] == true) {
             $this->handleRealRowCountRequestAction();
             return;
         }
         if (!PMA_DRIZZLE) {
             include_once 'libraries/replication.inc.php';
         } else {
             $GLOBALS['replication_info']['slave']['status'] = false;
         }
         PMA_PageSettings::showGroup('DbStructure');
         $db_collation = PMA_getDbCollation($this->_db);
         $titles = PMA_Util::buildActionTitles();
         // 1. No tables
         if ($this->_num_tables == 0) {
             $this->response->addHTML(PMA_message::notice(__('No tables found in database.')));
             if (empty($db_is_system_schema)) {
                 $this->response->addHTML(PMA_getHtmlForCreateTable($this->_db));
             }
             return;
         }
         // else
         // 2. Shows table information
         /**
          * Displays the tables list
          */
         $this->response->addHTML('<div id="tableslistcontainer">');
         $_url_params = array('pos' => $this->_pos, 'db' => $this->_db);
         // Add the sort options if they exists
         if (isset($_REQUEST['sort'])) {
             $_url_params['sort'] = $_REQUEST['sort'];
         }
         if (isset($_REQUEST['sort_order'])) {
             $_url_params['sort_order'] = $_REQUEST['sort_order'];
         }
         $this->response->addHTML(PMA_Util::getListNavigator($this->_total_num_tables, $this->_pos, $_url_params, 'db_structure.php', 'frame_content', $GLOBALS['cfg']['MaxTableList']));
         // table form
         $this->response->addHTML(Template::get('structure/table_header')->render(array('db' => $this->_db, 'db_is_system_schema' => $this->_db_is_system_schema, 'replication' => $GLOBALS['replication_info']['slave']['status'])));
         $i = $sum_entries = 0;
         $overhead_check = '';
         $create_time_all = '';
         $update_time_all = '';
         $check_time_all = '';
         $num_columns = $GLOBALS['cfg']['PropertiesNumColumns'] > 1 ? ceil($this->_num_tables / $GLOBALS['cfg']['PropertiesNumColumns']) + 1 : 0;
         $row_count = 0;
         $sum_size = (double) 0;
         $overhead_size = (double) 0;
         $hidden_fields = array();
         $odd_row = true;
         $overall_approx_rows = false;
         // Instance of PMA_RecentFavoriteTable class.
         $fav_instance = PMA_RecentFavoriteTable::getInstance('favorite');
         foreach ($this->_tables as $keyname => $current_table) {
             // Get valid statistics whatever is the table type
             $drop_query = '';
             $drop_message = '';
             $already_favorite = false;
             $overhead = '';
             $table_is_view = false;
             $table_encoded = urlencode($current_table['TABLE_NAME']);
             // Sets parameters for links
             $tbl_url_query = $this->_url_query . '&amp;table=' . $table_encoded;
             // do not list the previous table's size info for a view
             list($current_table, $formatted_size, $unit, $formatted_overhead, $overhead_unit, $overhead_size, $table_is_view, $sum_size) = $this->getStuffForEngineTypeTable($current_table, $this->_db_is_system_schema, $this->_is_show_stats, $sum_size, $overhead_size);
             if (!$this->dbi->getTable($this->_db, $current_table['TABLE_NAME'])->isMerge()) {
                 $sum_entries += $current_table['TABLE_ROWS'];
             }
             if (isset($current_table['Collation'])) {
                 $collation = '<dfn title="' . PMA_getCollationDescr($current_table['Collation']) . '">' . $current_table['Collation'] . '</dfn>';
             } else {
                 $collation = '---';
             }
             if ($this->_is_show_stats) {
                 if ($formatted_overhead != '') {
                     $overhead = '<a href="tbl_structure.php' . $tbl_url_query . '#showusage">' . '<span>' . $formatted_overhead . '</span>&nbsp;' . '<span class="unit">' . $overhead_unit . '</span>' . '</a>' . "\n";
                     $overhead_check .= "markAllRows('row_tbl_" . ($i + 1) . "');";
                 } else {
                     $overhead = '-';
                 }
             }
             // end if
             $showtable = $this->dbi->getTable($this->_db, $current_table['TABLE_NAME'])->sGetStatusInfo(null, true);
             if ($GLOBALS['cfg']['ShowDbStructureCreation']) {
                 $create_time = isset($showtable['Create_time']) ? $showtable['Create_time'] : '';
                 if ($create_time && (!$create_time_all || $create_time < $create_time_all)) {
                     $create_time_all = $create_time;
                 }
             }
             if ($GLOBALS['cfg']['ShowDbStructureLastUpdate']) {
                 // $showtable might already be set from ShowDbStructureCreation,
                 // see above
                 $update_time = isset($showtable['Update_time']) ? $showtable['Update_time'] : '';
                 if ($update_time && (!$update_time_all || $update_time < $update_time_all)) {
                     $update_time_all = $update_time;
                 }
             }
             if ($GLOBALS['cfg']['ShowDbStructureLastCheck']) {
                 // $showtable might already be set from ShowDbStructureCreation,
                 // see above
                 $check_time = isset($showtable['Check_time']) ? $showtable['Check_time'] : '';
                 if ($check_time && (!$check_time_all || $check_time < $check_time_all)) {
                     $check_time_all = $check_time;
                 }
             }
             $alias = htmlspecialchars(!empty($tooltip_aliasname) && isset($tooltip_aliasname[$current_table['TABLE_NAME']]) ? $tooltip_aliasname[$current_table['TABLE_NAME']] : $current_table['TABLE_NAME']);
             $alias = str_replace(' ', '&nbsp;', $alias);
             $truename = htmlspecialchars(!empty($tooltip_truename) && isset($tooltip_truename[$current_table['TABLE_NAME']]) ? $tooltip_truename[$current_table['TABLE_NAME']] : $current_table['TABLE_NAME']);
             $truename = str_replace(' ', '&nbsp;', $truename);
             $i++;
             $row_count++;
             if ($table_is_view) {
                 $hidden_fields[] = '<input type="hidden" name="views[]" value="' . htmlspecialchars($current_table['TABLE_NAME']) . '" />';
             }
             /*
              * Always activate links for Browse, Search and Empty, even if
              * the icons are greyed, because
              * 1. for views, we don't know the number of rows at this point
              * 2. for tables, another source could have populated them since the
              *    page was generated
              *
              * I could have used the PHP ternary conditional operator but I find
              * the code easier to read without this operator.
              */
             $may_have_rows = $current_table['TABLE_ROWS'] > 0 || $table_is_view;
             $browse_table = Template::get('structure/browse_table')->render(array('tbl_url_query' => $tbl_url_query, 'title' => $may_have_rows ? $titles['Browse'] : $titles['NoBrowse']));
             $search_table = Template::get('structure/search_table')->render(array('tbl_url_query' => $tbl_url_query, 'title' => $may_have_rows ? $titles['Search'] : $titles['NoSearch']));
             $browse_table_label = Template::get('structure/browse_table_label')->render(array('tbl_url_query' => $tbl_url_query, 'title' => htmlspecialchars($current_table['TABLE_COMMENT']), 'truename' => $truename));
             $empty_table = '';
             if (!$this->_db_is_system_schema) {
                 $empty_table = '&nbsp;';
                 if (!$table_is_view) {
                     $empty_table = Template::get('structure/empty_table')->render(array('tbl_url_query' => $tbl_url_query, 'sql_query' => urlencode('TRUNCATE ' . PMA_Util::backquote($current_table['TABLE_NAME'])), 'message_to_show' => urlencode(sprintf(__('Table %s has been emptied.'), htmlspecialchars($current_table['TABLE_NAME']))), 'title' => $may_have_rows ? $titles['Empty'] : $titles['NoEmpty']));
                 }
                 $drop_query = sprintf('DROP %s %s', $table_is_view || $current_table['ENGINE'] == null ? 'VIEW' : 'TABLE', PMA_Util::backquote($current_table['TABLE_NAME']));
                 $drop_message = sprintf($table_is_view || $current_table['ENGINE'] == null ? __('View %s has been dropped.') : __('Table %s has been dropped.'), str_replace(' ', '&nbsp;', htmlspecialchars($current_table['TABLE_NAME'])));
             }
             $tracking_icon = '';
             if (PMA_Tracker::isActive()) {
                 $is_tracked = PMA_Tracker::isTracked($GLOBALS["db"], $truename);
                 if ($is_tracked || PMA_Tracker::getVersion($GLOBALS["db"], $truename) > 0) {
                     $tracking_icon = Template::get('structure/tracking_icon')->render(array('url_query' => $this->_url_query, 'truename' => $truename, 'is_tracked' => $is_tracked));
                 }
             }
             if ($num_columns > 0 && $this->_num_tables > $num_columns && $row_count % $num_columns == 0) {
                 $row_count = 1;
                 $odd_row = true;
                 $this->response->addHTML('</tr></tbody></table>');
                 $this->response->addHTML(Template::get('structure/table_header')->render(array('db_is_system_schema' => false, 'replication' => $GLOBALS['replication_info']['slave']['status'])));
             }
             $do = $ignored = false;
             $server_slave_status = $GLOBALS['replication_info']['slave']['status'];
             include_once 'libraries/replication.inc.php';
             if ($server_slave_status) {
                 $nbServSlaveDoDb = count($GLOBALS['replication_info']['slave']['Do_DB']);
                 $nbServSlaveIgnoreDb = count($GLOBALS['replication_info']['slave']['Ignore_DB']);
                 $searchDoDBInTruename = array_search($truename, $GLOBALS['replication_info']['slave']['Do_DB']);
                 $searchDoDBInDB = array_search($this->_db, $GLOBALS['replication_info']['slave']['Do_DB']);
                 $do = strlen($searchDoDBInTruename) > 0 || strlen($searchDoDBInDB) > 0 || $nbServSlaveDoDb == 1 && $nbServSlaveIgnoreDb == 1 || $this->hasTable($GLOBALS['replication_info']['slave']['Wild_Do_Table'], $truename);
                 $searchDb = array_search($this->_db, $GLOBALS['replication_info']['slave']['Ignore_DB']);
                 $searchTable = array_search($truename, $GLOBALS['replication_info']['slave']['Ignore_Table']);
                 $ignored = strlen($searchTable) > 0 || strlen($searchDb) > 0 || $this->hasTable($GLOBALS['replication_info']['slave']['Wild_Ignore_Table'], $truename);
             }
             // Handle favorite table list. ----START----
             $already_favorite = $this->checkFavoriteTable($current_table['TABLE_NAME']);
             if (isset($_REQUEST['remove_favorite'])) {
                 if ($already_favorite) {
                     // If already in favorite list, remove it.
                     $favorite_table = $_REQUEST['favorite_table'];
                     $fav_instance->remove($this->_db, $favorite_table);
                 }
             }
             if (isset($_REQUEST['add_favorite'])) {
                 if (!$already_favorite) {
                     // Otherwise add to favorite list.
                     $favorite_table = $_REQUEST['favorite_table'];
                     $fav_instance->add($this->_db, $favorite_table);
                 }
             }
             // Handle favorite table list. ----ENDS----
             $show_superscript = '';
             // there is a null value in the ENGINE
             // - when the table needs to be repaired, or
             // - when it's a view
             //  so ensure that we'll display "in use" below for a table
             //  that needs to be repaired
             $approx_rows = false;
             if (isset($current_table['TABLE_ROWS']) && ($current_table['ENGINE'] != null || $table_is_view)) {
                 // InnoDB table: we did not get an accurate row count
                 $approx_rows = !$table_is_view && $current_table['ENGINE'] == 'InnoDB' && !$current_table['COUNTED'];
                 // Drizzle views use FunctionEngine, and the only place where
                 // they are available are I_S and D_D schemas, where we do exact
                 // counting
                 if ($table_is_view && $current_table['TABLE_ROWS'] >= $GLOBALS['cfg']['MaxExactCountViews'] && $current_table['ENGINE'] != 'FunctionEngine') {
                     $approx_rows = true;
                     $show_superscript = PMA_Util::showHint(PMA_sanitize(sprintf(__('This view has at least this number of ' . 'rows. Please refer to %sdocumentation%s.'), '[doc@cfg_MaxExactCountViews]', '[/doc]')));
                 }
             }
             $this->response->addHTML(Template::get('structure/structure_table_row')->render(array('db' => $this->_db, 'curr' => $i, 'odd_row' => $odd_row, 'table_is_view' => $table_is_view, 'current_table' => $current_table, 'browse_table_label' => $browse_table_label, 'tracking_icon' => $tracking_icon, 'server_slave_status' => $GLOBALS['replication_info']['slave']['status'], 'browse_table' => $browse_table, 'tbl_url_query' => $tbl_url_query, 'search_table' => $search_table, 'db_is_system_schema' => $this->_db_is_system_schema, 'titles' => $titles, 'empty_table' => $empty_table, 'drop_query' => $drop_query, 'drop_message' => $drop_message, 'collation' => $collation, 'formatted_size' => $formatted_size, 'unit' => $unit, 'overhead' => $overhead, 'create_time' => isset($create_time) ? $create_time : '', 'update_time' => isset($update_time) ? $update_time : '', 'check_time' => isset($check_time) ? $check_time : '', 'is_show_stats' => $this->_is_show_stats, 'ignored' => $ignored, 'do' => $do, 'colspan_for_structure' => $GLOBALS['colspan_for_structure'], 'approx_rows' => $approx_rows, 'show_superscript' => $show_superscript, 'already_favorite' => $this->checkFavoriteTable($current_table['TABLE_NAME']))));
             $odd_row = !$odd_row;
             $overall_approx_rows = $overall_approx_rows || $approx_rows;
         }
         // end foreach
         // Show Summary
         $this->response->addHTML('</tbody>');
         $this->response->addHTML(Template::get('structure/body_for_table_summary')->render(array('num_tables' => $this->_num_tables, 'server_slave_status' => $GLOBALS['replication_info']['slave']['status'], 'db_is_system_schema' => $this->_db_is_system_schema, 'sum_entries' => $sum_entries, 'db_collation' => $db_collation, 'is_show_stats' => $this->_is_show_stats, 'sum_size' => $sum_size, 'overhead_size' => $overhead_size, 'create_time_all' => $create_time_all, 'update_time_all' => $update_time_all, 'check_time_all' => $check_time_all, 'approx_rows' => $overall_approx_rows)));
         $this->response->addHTML('</table>');
         //check all
         $this->response->addHTML(Template::get('structure/check_all_tables')->render(array('pmaThemeImage' => $GLOBALS['pmaThemeImage'], 'text_dir' => $GLOBALS['text_dir'], 'overhead_check' => $overhead_check, 'db_is_system_schema' => $this->_db_is_system_schema, 'hidden_fields' => $hidden_fields)));
         $this->response->addHTML('</form>');
         //end of form
         // display again the table list navigator
         $this->response->addHTML(PMA_Util::getListNavigator($this->_total_num_tables, $this->_pos, $_url_params, 'db_structure.php', 'frame_content', $GLOBALS['cfg']['MaxTableList']));
         $this->response->addHTML('</div><hr />');
         /**
          * Work on the database
          */
         /* DATABASE WORK */
         /* Printable view of a table */
         $this->response->addHTML(Template::get('structure/print_view_data_dictionary_link')->render(array('url_query' => $this->_url_query)));
         if (empty($db_is_system_schema)) {
             $this->response->addHTML(PMA_getHtmlForCreateTable($this->_db));
         }
     } elseif ($this->_type == 'table') {
         // Table structure
         PMA_PageSettings::showGroup('TableStructure');
         /**
          * Function implementations for this script
          */
         require_once 'libraries/check_user_privileges.lib.php';
         require_once 'libraries/index.lib.php';
         require_once 'libraries/sql.lib.php';
         require_once 'libraries/bookmark.lib.php';
         $this->response->getHeader()->getScripts()->addFiles(array('tbl_structure.js', 'indexes.js'));
         /**
          * Handle column moving
          */
         if (isset($_REQUEST['move_columns']) && is_array($_REQUEST['move_columns']) && $this->response->isAjax()) {
             $this->moveColumns();
             return;
         }
         /**
          * handle MySQL reserved words columns check
          */
         if (isset($_REQUEST['reserved_word_check'])) {
             if ($GLOBALS['cfg']['ReservedWordDisableWarning'] === false) {
                 $columns_names = $_REQUEST['field_name'];
                 $reserved_keywords_names = array();
                 foreach ($columns_names as $column) {
                     if (SqlParser\Context::isKeyword(trim($column), true)) {
                         $reserved_keywords_names[] = trim($column);
                     }
                 }
                 if (SqlParser\Context::isKeyword(trim($this->_table), true)) {
                     $reserved_keywords_names[] = trim($this->_table);
                 }
                 if (count($reserved_keywords_names) == 0) {
                     $this->response->isSuccess(false);
                 }
                 $this->response->addJSON('message', sprintf(_ngettext('The name \'%s\' is a MySQL reserved keyword.', 'The names \'%s\' are MySQL reserved keywords.', count($reserved_keywords_names)), implode(',', $reserved_keywords_names)));
             } else {
                 $this->response->isSuccess(false);
             }
             return;
         }
         /**
          * A click on Change has been made for one column
          */
         if (isset($_REQUEST['change_column'])) {
             $this->displayHtmlForColumnChange(null, 'tbl_structure.php');
             return;
         }
         /**
          * handle multiple field commands if required
          *
          * submit_mult_*_x comes from IE if <input type="img" ...> is used
          */
         $submit_mult = $this->getMultipleFieldCommandType();
         if (!empty($submit_mult)) {
             if (isset($_REQUEST['selected_fld'])) {
                 if ($submit_mult == 'browse') {
                     // browsing the table displaying only selected columns
                     $this->displayTableBrowseForSelectedColumns($GLOBALS['goto'], $GLOBALS['pmaThemeImage']);
                 } else {
                     // handle multiple field commands
                     // handle confirmation of deleting multiple columns
                     $action = 'tbl_structure.php';
                     $GLOBALS['selected'] = $_REQUEST['selected_fld'];
                     list($what_ret, $query_type_ret, $is_unset_submit_mult, $mult_btn_ret, $centralColsError) = $this->getDataForSubmitMult($submit_mult, $_REQUEST['selected_fld'], $action);
                     //update the existing variables
                     // todo: refactor mult_submits.inc.php such as
                     // below globals are not needed anymore
                     if (isset($what_ret)) {
                         $GLOBALS['what'] = $what_ret;
                         global $what;
                     }
                     if (isset($query_type_ret)) {
                         $GLOBALS['query_type'] = $query_type_ret;
                         global $query_type;
                     }
                     if ($is_unset_submit_mult) {
                         unset($submit_mult);
                     }
                     if (isset($mult_btn_ret)) {
                         $GLOBALS['mult_btn'] = $mult_btn_ret;
                         global $mult_btn;
                     }
                     include 'libraries/mult_submits.inc.php';
                     /**
                      * if $submit_mult == 'change', execution will have stopped
                      * at this point
                      */
                     if (empty($message)) {
                         $message = PMA_Message::success();
                     }
                     $this->response->addHTML(PMA_Util::getMessage($message, $sql_query));
                 }
             } else {
                 $this->response->isSuccess(false);
                 $this->response->addJSON('message', __('No column selected.'));
             }
         }
         // display secondary level tabs if necessary
         $engine = $this->_table_obj->sGetStatusInfo('ENGINE');
         $this->response->addHTML(Template::get('structure/secondary_tabs')->render(array('url_params' => array('db' => $this->_db, 'table' => $this->_table), 'engine' => $engine)));
         $this->response->addHTML('<div id="structure_content">');
         /**
          * Modifications have been submitted -> updates the table
          */
         if (isset($_REQUEST['do_save_data'])) {
             $regenerate = $this->updateColumns();
             if ($regenerate) {
                 // This happens when updating failed
                 // @todo: do something appropriate
             } else {
                 // continue to show the table's structure
                 unset($_REQUEST['selected']);
             }
         }
         /**
          * Adding indexes
          */
         if (isset($_REQUEST['add_key'])) {
             //todo: set some variables for sql.php include, to be eliminated
             //after refactoring sql.php
             $db = $this->_db;
             $table = $this->_table;
             $cfg = $GLOBALS['cfg'];
             $is_superuser = $GLOBALS['dbi']->isSuperuser();
             $pmaThemeImage = $GLOBALS['pmaThemeImage'];
             include 'sql.php';
             $GLOBALS['reload'] = true;
         }
         /**
          * Gets the relation settings
          */
         $cfgRelation = PMA_getRelationsParam();
         /**
          * Runs common work
          */
         // set db, table references, for require_once that follows
         // got to be eliminated in long run
         $db =& $this->_db;
         $table =& $this->_table;
         require_once 'libraries/tbl_common.inc.php';
         $this->_url_query = $url_query . '&amp;goto=tbl_structure.php&amp;back=tbl_structure.php';
         $url_params['goto'] = 'tbl_structure.php';
         $url_params['back'] = 'tbl_structure.php';
         /**
          * Gets tables information
          */
         require_once 'libraries/tbl_info.inc.php';
         require_once 'libraries/Index.class.php';
         // 2. Gets table keys and retains them
         // @todo should be: $server->db($db)->table($table)->primary()
         $primary = PMA_Index::getPrimary($this->_table, $this->_db);
         $columns_with_index = $this->dbi->getTable($this->_db, $this->_table)->getColumnsWithIndex(PMA_Index::UNIQUE | PMA_Index::INDEX | PMA_Index::SPATIAL | PMA_Index::FULLTEXT);
         $columns_with_unique_index = $this->dbi->getTable($this->_db, $this->_table)->getColumnsWithIndex(PMA_Index::UNIQUE);
         // 3. Get fields
         $fields = (array) $this->dbi->getColumns($this->_db, $this->_table, null, true);
         // Get more complete field information
         // For now, this is done just for MySQL 4.1.2+ new TIMESTAMP options
         // but later, if the analyser returns more information, it
         // could be executed for any MySQL version and replace
         // the info given by SHOW FULL COLUMNS FROM.
         //
         // We also need this to correctly learn if a TIMESTAMP is NOT NULL, since
         // SHOW FULL COLUMNS or INFORMATION_SCHEMA incorrectly says NULL
         // and SHOW CREATE TABLE says NOT NULL (tested
         // in MySQL 4.0.25 and 5.0.21, http://bugs.mysql.com/20910).
         $show_create_table = $this->_table_obj->showCreate();
         $parser = new SqlParser\Parser($show_create_table);
         /**
          * @var CreateStatement $stmt
          */
         $stmt = $parser->statements[0];
         $create_table_fields = SqlParser\Utils\Table::getFields($stmt);
         //display table structure
         $this->response->addHTML($this->displayStructure($cfgRelation, $columns_with_unique_index, $url_params, $primary, $fields, $columns_with_index, $create_table_fields));
         $this->response->addHTML('</div>');
     }
 }