mirror of
https://we.phorge.it/source/phorge.git
synced 2024-12-22 05:20:56 +01:00
Allow bin/storage adjust
to correct column types and collations
Summary: Ref T1191. Allow `bin/storage adjust` to modify columns. - Although `CREATE TABLE ... colname VARCHAR(64) CHARACTER SET BINARY` works fine, it's actually a trick. Adjust the binary columns for this. Test Plan: See comment. Reviewers: btrahan Reviewed By: btrahan Subscribers: epriestley Maniphest Tasks: T6130, T6128, T6135, T6137, T6138, T6149, T6151, T1191 Differential Revision: https://secure.phabricator.com/D10598
This commit is contained in:
parent
f7ee2c7467
commit
22ee8432d2
2 changed files with 138 additions and 44 deletions
|
@ -230,6 +230,10 @@ abstract class PhabricatorConfigSchemaSpec extends Phobject {
|
|||
$data_type = substr($data_type, 0, -1);
|
||||
}
|
||||
|
||||
// NOTE: MySQL allows fragments like "VARCHAR(32) CHARACTER SET binary",
|
||||
// but just interprets that to mean "VARBINARY(32)". The fragment is
|
||||
// totally disallowed in a MODIFY statement vs a CREATE TABLE statement.
|
||||
|
||||
switch ($data_type) {
|
||||
case 'id':
|
||||
case 'epoch':
|
||||
|
@ -248,39 +252,25 @@ abstract class PhabricatorConfigSchemaSpec extends Phobject {
|
|||
break;
|
||||
case 'phid':
|
||||
case 'policy';
|
||||
$column_type = 'varchar(64)';
|
||||
$charset = 'binary';
|
||||
$collation = 'binary';
|
||||
$column_type = 'varbinary(64)';
|
||||
break;
|
||||
case 'bytes64':
|
||||
$column_type = 'char(64)';
|
||||
$charset = 'binary';
|
||||
$collation = 'binary';
|
||||
$column_type = 'binary(64)';
|
||||
break;
|
||||
case 'bytes40':
|
||||
$column_type = 'char(40)';
|
||||
$charset = 'binary';
|
||||
$collation = 'binary';
|
||||
$column_type = 'binary(40)';
|
||||
break;
|
||||
case 'bytes32':
|
||||
$column_type = 'char(32)';
|
||||
$charset = 'binary';
|
||||
$collation = 'binary';
|
||||
$column_type = 'binary(32)';
|
||||
break;
|
||||
case 'bytes20':
|
||||
$column_type = 'char(20)';
|
||||
$charset = 'binary';
|
||||
$collation = 'binary';
|
||||
$column_type = 'binary(20)';
|
||||
break;
|
||||
case 'bytes12':
|
||||
$column_type = 'char(12)';
|
||||
$charset = 'binary';
|
||||
$collation = 'binary';
|
||||
$column_type = 'binary(12)';
|
||||
break;
|
||||
case 'bytes4':
|
||||
$column_type = 'char(4)';
|
||||
$charset = 'binary';
|
||||
$collation = 'binary';
|
||||
$column_type = 'binary(4)';
|
||||
break;
|
||||
case 'bytes':
|
||||
$column_type = 'longblob';
|
||||
|
|
|
@ -127,9 +127,12 @@ final class PhabricatorStorageManagementAdjustWorkflow
|
|||
$api = $this->getAPI();
|
||||
$conn = $api->getConn(null);
|
||||
|
||||
$failed = array();
|
||||
|
||||
$bar = id(new PhutilConsoleProgressBar())
|
||||
->setTotal(count($adjustments));
|
||||
foreach ($adjustments as $adjust) {
|
||||
try {
|
||||
switch ($adjust['kind']) {
|
||||
case 'database':
|
||||
queryfx(
|
||||
|
@ -147,18 +150,70 @@ final class PhabricatorStorageManagementAdjustWorkflow
|
|||
$adjust['table'],
|
||||
$adjust['collation']);
|
||||
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:
|
||||
throw new Exception(
|
||||
pht('Unknown schema adjustment kind "%s"!', $adjust['kind']));
|
||||
}
|
||||
|
||||
} catch (AphrontQueryException $ex) {
|
||||
$failed[] = array($adjust, $ex);
|
||||
}
|
||||
$bar->update(1);
|
||||
}
|
||||
$bar->done();
|
||||
|
||||
if (!$failed) {
|
||||
$console->writeOut(
|
||||
"%s\n",
|
||||
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() {
|
||||
|
@ -166,6 +221,7 @@ final class PhabricatorStorageManagementAdjustWorkflow
|
|||
|
||||
$issue_charset = PhabricatorConfigStorageSchema::ISSUE_CHARSET;
|
||||
$issue_collation = PhabricatorConfigStorageSchema::ISSUE_COLLATION;
|
||||
$issue_columntype = PhabricatorConfigStorageSchema::ISSUE_COLUMNTYPE;
|
||||
|
||||
$adjustments = array();
|
||||
foreach ($comp->getDatabases() as $database_name => $database) {
|
||||
|
@ -217,6 +273,54 @@ final class PhabricatorStorageManagementAdjustWorkflow
|
|||
'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(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue