protected function compareToSimilarSchema(PhabricatorConfigStorageSchema $expect) { $issues = array(); if ($this->getCollation() != $expect->getCollation()) { $issues[] = self::ISSUE_COLLATION; } return $issues; }
protected function compareToSimilarSchema(PhabricatorConfigStorageSchema $expect) { $issues = array(); if ($this->getAccessDenied()) { $issues[] = self::ISSUE_ACCESSDENIED; } else { if ($this->getCharacterSet() != $expect->getCharacterSet()) { $issues[] = self::ISSUE_CHARSET; } if ($this->getCollation() != $expect->getCollation()) { $issues[] = self::ISSUE_COLLATION; } } return $issues; }
protected function compareToSimilarSchema(PhabricatorConfigStorageSchema $expect) { $issues = array(); if ($this->getColumnNames() !== $expect->getColumnNames()) { $issues[] = self::ISSUE_KEYCOLUMNS; } if ($this->getUnique() !== $expect->getUnique()) { $issues[] = self::ISSUE_UNIQUE; } // A fulltext index can be of any length. if ($this->getIndexType() != 'FULLTEXT') { if ($this->getKeyByteLength() > self::MAX_INNODB_KEY_LENGTH) { $issues[] = self::ISSUE_LONGKEY; } } return $issues; }
private function compareSchemata(PhabricatorConfigStorageSchema $expect = null, PhabricatorConfigStorageSchema $actual = null) { $expect_is_key = $expect instanceof PhabricatorConfigKeySchema; $actual_is_key = $actual instanceof PhabricatorConfigKeySchema; if ($expect_is_key || $actual_is_key) { $missing_issue = PhabricatorConfigStorageSchema::ISSUE_MISSINGKEY; $surplus_issue = PhabricatorConfigStorageSchema::ISSUE_SURPLUSKEY; } else { $missing_issue = PhabricatorConfigStorageSchema::ISSUE_MISSING; $surplus_issue = PhabricatorConfigStorageSchema::ISSUE_SURPLUS; } if (!$expect && !$actual) { throw new Exception(pht('Can not compare two missing schemata!')); } else { if ($expect && !$actual) { $issues = array($missing_issue); } else { if ($actual && !$expect) { $issues = array($surplus_issue); } else { $issues = $actual->compareTo($expect); } } } return $issues; }
private function printErrors(array $errors, $default_return) { if (!$errors) { return $default_return; } $console = PhutilConsole::getConsole(); $table = id(new PhutilConsoleTable())->addColumn('target', array('title' => pht('Target')))->addColumn('error', array('title' => pht('Error'))); $any_surplus = false; $all_surplus = true; $any_access = false; $all_access = true; foreach ($errors as $error) { $pieces = array_select_keys($error, array('database', 'table', 'name')); $pieces = array_filter($pieces); $target = implode('.', $pieces); $name = PhabricatorConfigStorageSchema::getIssueName($error['issue']); $issue = $error['issue']; if ($issue === PhabricatorConfigStorageSchema::ISSUE_SURPLUS) { $any_surplus = true; } else { $all_surplus = false; } if ($issue === PhabricatorConfigStorageSchema::ISSUE_ACCESSDENIED) { $any_access = true; } else { $all_access = false; } $table->addRow(array('target' => $target, 'error' => $name)); } $console->writeOut("\n"); $table->draw(); $console->writeOut("\n"); $message = array(); if ($all_surplus) { $message[] = pht('You have surplus schemata (extra tables or columns which Phabricator ' . 'does not expect). For information on resolving these ' . 'issues, see the "Surplus Schemata" section in the "Managing Storage ' . 'Adjustments" article in the documentation.'); } else { if ($all_access) { $message[] = pht('The user you are connecting to MySQL with does not have the correct ' . 'permissions, and can not access some databases or tables that it ' . 'needs to be able to access. GRANT the user additional permissions.'); } else { $message[] = pht('The schemata have errors (detailed above) which the adjustment ' . 'workflow can not fix.'); if ($any_access) { $message[] = pht('Some of these errors are caused by access control problems. ' . 'The user you are connecting with does not have permission to see ' . 'all of the database or tables that Phabricator uses. You need to ' . 'GRANT the user more permission, or use a different user.'); } if ($any_surplus) { $message[] = pht('Some of these errors are caused by surplus schemata (extra ' . 'tables or columns which Phabricator does not expect). These are ' . 'not serious. For information on resolving these issues, see the ' . '"Surplus Schemata" section in the "Managing Storage Adjustments" ' . 'article in the documentation.'); } $message[] = pht('If you are not developing Phabricator itself, report this issue to ' . 'the upstream.'); $message[] = pht('If you are developing Phabricator, these errors usually indicate ' . 'that your schema specifications do not agree with the schemata your ' . 'code actually builds.'); } } $message = implode("\n\n", $message); if ($all_surplus) { $console->writeOut("**<bg:yellow> %s </bg>**\n\n%s\n", pht('SURPLUS SCHEMATA'), phutil_console_wrap($message)); } else { if ($all_access) { $console->writeOut("**<bg:yellow> %s </bg>**\n\n%s\n", pht('ACCESS DENIED'), phutil_console_wrap($message)); } else { $console->writeOut("**<bg:red> %s </bg>**\n\n%s\n", pht('SCHEMATA ERRORS'), phutil_console_wrap($message)); } } return 2; }
private function buildProperties(array $properties, array $issues) { $view = id(new PHUIPropertyListView())->setUser($this->getRequest()->getUser()); foreach ($properties as $property) { list($key, $value) = $property; $view->addProperty($key, $value); } $status_view = new PHUIStatusListView(); if (!$issues) { $status_view->addItem(id(new PHUIStatusItemView())->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green')->setTarget(pht('No Schema Issues'))); } else { foreach ($issues as $issue) { $note = PhabricatorConfigStorageSchema::getIssueDescription($issue); $status = PhabricatorConfigStorageSchema::getIssueStatus($issue); switch ($status) { case PhabricatorConfigStorageSchema::STATUS_WARN: $icon = PHUIStatusItemView::ICON_WARNING; $color = 'yellow'; break; case PhabricatorConfigStorageSchema::STATUS_FAIL: default: $icon = PHUIStatusItemView::ICON_REJECT; $color = 'red'; break; } $item = id(new PHUIStatusItemView())->setTarget(PhabricatorConfigStorageSchema::getIssueName($issue))->setIcon($icon, $color)->setNote($note); $status_view->addItem($item); } } $view->addProperty(pht('Schema Status'), $status_view); return phutil_tag_div('config-page-property', $view); }
protected function compareToSimilarSchema(PhabricatorConfigStorageSchema $expect) { $issues = array(); $type_unknown = PhabricatorConfigSchemaSpec::DATATYPE_UNKNOWN; if ($expect->getColumnType() == $type_unknown) { $issues[] = self::ISSUE_UNKNOWN; } else { if ($this->getCharacterSet() != $expect->getCharacterSet()) { $issues[] = self::ISSUE_CHARSET; } if ($this->getCollation() != $expect->getCollation()) { $issues[] = self::ISSUE_COLLATION; } if ($this->getColumnType() != $expect->getColumnType()) { $issues[] = self::ISSUE_COLUMNTYPE; } if ($this->getNullable() !== $expect->getNullable()) { $issues[] = self::ISSUE_NULLABLE; } if ($this->getAutoIncrement() !== $expect->getAutoIncrement()) { $issues[] = self::ISSUE_AUTOINCREMENT; } } return $issues; }
public function handleRequest(AphrontRequest $request) { $viewer = $request->getViewer(); $query = $this->buildSchemaQuery(); $actual = $query->loadActualSchema(); $expect = $query->loadExpectedSchema(); $comp = $query->buildComparisonSchema($expect, $actual); $crumbs = $this->buildApplicationCrumbs(); $crumbs->addTextCrumb(pht('Database Issues')); $crumbs->setBorder(true); // Collect all open issues. $issues = array(); foreach ($comp->getDatabases() as $database_name => $database) { foreach ($database->getLocalIssues() as $issue) { $issues[] = array($database_name, null, null, null, $issue); } foreach ($database->getTables() as $table_name => $table) { foreach ($table->getLocalIssues() as $issue) { $issues[] = array($database_name, $table_name, null, null, $issue); } foreach ($table->getColumns() as $column_name => $column) { foreach ($column->getLocalIssues() as $issue) { $issues[] = array($database_name, $table_name, 'column', $column_name, $issue); } } foreach ($table->getKeys() as $key_name => $key) { foreach ($key->getLocalIssues() as $issue) { $issues[] = array($database_name, $table_name, 'key', $key_name, $issue); } } } } // Sort all open issues so that the most severe issues appear first. $order = array(); $counts = array(); foreach ($issues as $key => $issue) { $const = $issue[4]; $status = PhabricatorConfigStorageSchema::getIssueStatus($const); $severity = PhabricatorConfigStorageSchema::getStatusSeverity($status); $order[$key] = sprintf('~%d~%s%s%s', 9 - $severity, $issue[0], $issue[1], $issue[3]); if (empty($counts[$status])) { $counts[$status] = 0; } $counts[$status]++; } asort($order); $issues = array_select_keys($issues, array_keys($order)); // Render the issues. $rows = array(); foreach ($issues as $issue) { $const = $issue[4]; $database_link = phutil_tag('a', array('href' => $this->getApplicationURI('/database/' . $issue[0] . '/')), $issue[0]); $rows[] = array($this->renderIcon(PhabricatorConfigStorageSchema::getIssueStatus($const)), $database_link, $issue[1], $issue[2], $issue[3], PhabricatorConfigStorageSchema::getIssueDescription($const)); } $table = id(new AphrontTableView($rows))->setNoDataString(pht('No databases have any issues.'))->setHeaders(array(null, pht('Database'), pht('Table'), pht('Type'), pht('Column/Key'), pht('Issue')))->setColumnClasses(array(null, null, null, null, null, 'wide')); $errors = array(); if (isset($counts[PhabricatorConfigStorageSchema::STATUS_FAIL])) { $errors[] = pht('Detected %s serious issue(s) with the schemata.', new PhutilNumber($counts[PhabricatorConfigStorageSchema::STATUS_FAIL])); } if (isset($counts[PhabricatorConfigStorageSchema::STATUS_WARN])) { $errors[] = pht('Detected %s warning(s) with the schemata.', new PhutilNumber($counts[PhabricatorConfigStorageSchema::STATUS_WARN])); } $title = pht('Database Issues'); $header = id(new PHUIHeaderView())->setHeader($title)->setProfileHeader(true); $nav = $this->buildSideNavView(); $nav->selectFilter('dbissue/'); $content = id(new PhabricatorConfigPageView())->setHeader($header)->setContent($table); return $this->newPage()->setTitle($title)->setCrumbs($crumbs)->setNavigation($nav)->appendChild($content)->addClass('white-background'); }