Differential D10598 Diff 25471 src/infrastructure/storage/management/workflow/PhabricatorStorageManagementAdjustWorkflow.php
Changeset View
Changeset View
Standalone View
Standalone View
src/infrastructure/storage/management/workflow/PhabricatorStorageManagementAdjustWorkflow.php
Show First 20 Lines • Show All 121 Lines • ▼ Show 20 Lines | private function adjustSchemata() { | ||||
$console->writeOut( | $console->writeOut( | ||||
"%s\n", | "%s\n", | ||||
pht('Fixing schema issues...')); | pht('Fixing schema issues...')); | ||||
$api = $this->getAPI(); | $api = $this->getAPI(); | ||||
$conn = $api->getConn(null); | $conn = $api->getConn(null); | ||||
$failed = array(); | |||||
$bar = id(new PhutilConsoleProgressBar()) | $bar = id(new PhutilConsoleProgressBar()) | ||||
->setTotal(count($adjustments)); | ->setTotal(count($adjustments)); | ||||
foreach ($adjustments as $adjust) { | foreach ($adjustments as $adjust) { | ||||
try { | |||||
switch ($adjust['kind']) { | switch ($adjust['kind']) { | ||||
case 'database': | case 'database': | ||||
queryfx( | queryfx( | ||||
$conn, | $conn, | ||||
'ALTER DATABASE %T CHARACTER SET = %s COLLATE = %s', | 'ALTER DATABASE %T CHARACTER SET = %s COLLATE = %s', | ||||
$adjust['database'], | $adjust['database'], | ||||
$adjust['charset'], | $adjust['charset'], | ||||
$adjust['collation']); | $adjust['collation']); | ||||
break; | break; | ||||
case 'table': | case 'table': | ||||
queryfx( | queryfx( | ||||
$conn, | $conn, | ||||
'ALTER TABLE %T.%T COLLATE = %s', | 'ALTER TABLE %T.%T COLLATE = %s', | ||||
$adjust['database'], | $adjust['database'], | ||||
$adjust['table'], | $adjust['table'], | ||||
$adjust['collation']); | $adjust['collation']); | ||||
break; | break; | ||||
case 'column': | |||||
$parts = array(); | |||||
if ($adjust['charset']) { | |||||
$parts[] = qsprintf( | |||||
$conn, | |||||
'CHARACTER SET %Q COLLATE %Q', | |||||
$adjust['charset'], | |||||
$adjust['collation']); | |||||
} | |||||
queryfx( | |||||
$conn, | |||||
'ALTER TABLE %T.%T MODIFY %T %Q %Q %Q', | |||||
$adjust['database'], | |||||
$adjust['table'], | |||||
$adjust['name'], | |||||
$adjust['type'], | |||||
implode(' ', $parts), | |||||
$adjust['nullable'] ? 'NULL' : 'NOT NULL'); | |||||
break; | |||||
default: | default: | ||||
throw new Exception( | throw new Exception( | ||||
pht('Unknown schema adjustment kind "%s"!', $adjust['kind'])); | pht('Unknown schema adjustment kind "%s"!', $adjust['kind'])); | ||||
} | } | ||||
} catch (AphrontQueryException $ex) { | |||||
$failed[] = array($adjust, $ex); | |||||
} | |||||
$bar->update(1); | $bar->update(1); | ||||
} | } | ||||
$bar->done(); | $bar->done(); | ||||
if (!$failed) { | |||||
$console->writeOut( | $console->writeOut( | ||||
"%s\n", | "%s\n", | ||||
pht('Completed fixing all schema issues.')); | pht('Completed fixing all schema issues.')); | ||||
return; | |||||
} | |||||
$table = id(new PhutilConsoleTable()) | |||||
->addColumn('target', array('title' => pht('Target'))) | |||||
->addColumn('error', array('title' => pht('Error'))); | |||||
foreach ($failed as $failure) { | |||||
list($adjust, $ex) = $failure; | |||||
$pieces = array_select_keys($adjust, array('database', 'table', 'naeme')); | |||||
$pieces = array_filter($pieces); | |||||
$target = implode('.', $pieces); | |||||
$table->addRow( | |||||
array( | |||||
'target' => $target, | |||||
'error' => $ex->getMessage(), | |||||
)); | |||||
} | |||||
$console->writeOut("\n"); | |||||
$table->draw(); | |||||
$console->writeOut( | |||||
"\n%s\n", | |||||
pht('Failed to make some schema adjustments, detailed above.')); | |||||
return 1; | |||||
} | } | ||||
private function findAdjustments() { | private function findAdjustments() { | ||||
list($comp, $expect, $actual) = $this->loadSchemata(); | list($comp, $expect, $actual) = $this->loadSchemata(); | ||||
$issue_charset = PhabricatorConfigStorageSchema::ISSUE_CHARSET; | $issue_charset = PhabricatorConfigStorageSchema::ISSUE_CHARSET; | ||||
$issue_collation = PhabricatorConfigStorageSchema::ISSUE_COLLATION; | $issue_collation = PhabricatorConfigStorageSchema::ISSUE_COLLATION; | ||||
$issue_columntype = PhabricatorConfigStorageSchema::ISSUE_COLUMNTYPE; | |||||
$adjustments = array(); | $adjustments = array(); | ||||
foreach ($comp->getDatabases() as $database_name => $database) { | foreach ($comp->getDatabases() as $database_name => $database) { | ||||
$expect_database = $expect->getDatabase($database_name); | $expect_database = $expect->getDatabase($database_name); | ||||
$actual_database = $actual->getDatabase($database_name); | $actual_database = $actual->getDatabase($database_name); | ||||
if (!$expect_database || !$actual_database) { | if (!$expect_database || !$actual_database) { | ||||
// If there's a real issue here, skip this stuff. | // If there's a real issue here, skip this stuff. | ||||
Show All 35 Lines | foreach ($comp->getDatabases() as $database_name => $database) { | ||||
$adjustments[] = array( | $adjustments[] = array( | ||||
'kind' => 'table', | 'kind' => 'table', | ||||
'database' => $database_name, | 'database' => $database_name, | ||||
'table' => $table_name, | 'table' => $table_name, | ||||
'issues' => $issues, | 'issues' => $issues, | ||||
'collation' => $expect_table->getCollation(), | 'collation' => $expect_table->getCollation(), | ||||
); | ); | ||||
} | } | ||||
foreach ($table->getColumns() as $column_name => $column) { | |||||
$expect_column = $expect_table->getColumn($column_name); | |||||
$actual_column = $actual_table->getColumn($column_name); | |||||
if (!$expect_column || !$actual_column) { | |||||
continue; | |||||
} | |||||
$issues = array(); | |||||
if ($column->hasIssue($issue_collation)) { | |||||
$issues[] = $issue_collation; | |||||
} | |||||
if ($column->hasIssue($issue_charset)) { | |||||
$issues[] = $issue_charset; | |||||
} | |||||
if ($column->hasIssue($issue_columntype)) { | |||||
$issues[] = $issue_columntype; | |||||
} | |||||
if ($issues) { | |||||
if ($expect_column->getCharacterSet() === null) { | |||||
// For non-text columns, we won't be specifying a collation or | |||||
// character set. | |||||
$charset = null; | |||||
$collation = null; | |||||
} else { | |||||
$charset = $expect_column->getCharacterSet(); | |||||
$collation = $expect_column->getCollation(); | |||||
} | |||||
$adjustments[] = array( | |||||
'kind' => 'column', | |||||
'database' => $database_name, | |||||
'table' => $table_name, | |||||
'name' => $column_name, | |||||
'issues' => $issues, | |||||
'collation' => $collation, | |||||
'charset' => $charset, | |||||
'type' => $expect_column->getColumnType(), | |||||
// NOTE: We don't adjust column nullability because it is | |||||
// dangerous, so always use the current nullability. | |||||
'nullable' => $actual_column->getNullable(), | |||||
); | |||||
} | |||||
} | |||||
} | } | ||||
} | } | ||||
return $adjustments; | return $adjustments; | ||||
} | } | ||||
} | } |