@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Allow `bin/storage adjust` to make key changes

Summary:
Ref T1191. These are a bit tricky because keys can interact with column changes, so basically we do three phases:

1. Nuke all bad keys.
2. Make all column (and database/table) changes.
3. Fix all nuked keys.

Test Plan: Ran migration locally. See note for remaining issues.

Reviewers: btrahan

Reviewed By: btrahan

Subscribers: epriestley

Maniphest Tasks: T1191

Differential Revision: https://secure.phabricator.com/D10599

+135 -42
+135 -42
src/infrastructure/storage/management/workflow/PhabricatorStorageManagementAdjustWorkflow.php
··· 129 129 130 130 $failed = array(); 131 131 132 + // We make changes in three phases: 133 + // 134 + // Phase 0: Drop all keys which we're going to adjust. This prevents them 135 + // from interfering with column changes. 136 + // 137 + // Phase 1: Apply all database, table, and column changes. 138 + // 139 + // Phase 2: Restore adjusted keys. 140 + $phases = 3; 141 + 132 142 $bar = id(new PhutilConsoleProgressBar()) 133 - ->setTotal(count($adjustments)); 134 - foreach ($adjustments as $adjust) { 135 - try { 136 - switch ($adjust['kind']) { 137 - case 'database': 138 - queryfx( 139 - $conn, 140 - 'ALTER DATABASE %T CHARACTER SET = %s COLLATE = %s', 141 - $adjust['database'], 142 - $adjust['charset'], 143 - $adjust['collation']); 144 - break; 145 - case 'table': 146 - queryfx( 147 - $conn, 148 - 'ALTER TABLE %T.%T COLLATE = %s', 149 - $adjust['database'], 150 - $adjust['table'], 151 - $adjust['collation']); 152 - break; 153 - case 'column': 154 - $parts = array(); 155 - if ($adjust['charset']) { 156 - $parts[] = qsprintf( 143 + ->setTotal(count($adjustments) * $phases); 144 + 145 + for ($phase = 0; $phase < $phases; $phase++) { 146 + foreach ($adjustments as $adjust) { 147 + try { 148 + switch ($adjust['kind']) { 149 + case 'database': 150 + if ($phase != 1) { 151 + break; 152 + } 153 + queryfx( 157 154 $conn, 158 - 'CHARACTER SET %Q COLLATE %Q', 155 + 'ALTER DATABASE %T CHARACTER SET = %s COLLATE = %s', 156 + $adjust['database'], 159 157 $adjust['charset'], 160 158 $adjust['collation']); 161 - } 159 + break; 160 + case 'table': 161 + if ($phase != 1) { 162 + break; 163 + } 164 + queryfx( 165 + $conn, 166 + 'ALTER TABLE %T.%T COLLATE = %s', 167 + $adjust['database'], 168 + $adjust['table'], 169 + $adjust['collation']); 170 + break; 171 + case 'column': 172 + if ($phase != 1) { 173 + break; 174 + } 175 + $parts = array(); 176 + if ($adjust['charset']) { 177 + $parts[] = qsprintf( 178 + $conn, 179 + 'CHARACTER SET %Q COLLATE %Q', 180 + $adjust['charset'], 181 + $adjust['collation']); 182 + } 162 183 163 - queryfx( 164 - $conn, 165 - 'ALTER TABLE %T.%T MODIFY %T %Q %Q %Q', 166 - $adjust['database'], 167 - $adjust['table'], 168 - $adjust['name'], 169 - $adjust['type'], 170 - implode(' ', $parts), 171 - $adjust['nullable'] ? 'NULL' : 'NOT NULL'); 184 + queryfx( 185 + $conn, 186 + 'ALTER TABLE %T.%T MODIFY %T %Q %Q %Q', 187 + $adjust['database'], 188 + $adjust['table'], 189 + $adjust['name'], 190 + $adjust['type'], 191 + implode(' ', $parts), 192 + $adjust['nullable'] ? 'NULL' : 'NOT NULL'); 193 + 194 + break; 195 + case 'key': 196 + if (($phase == 0) && $adjust['exists']) { 197 + queryfx( 198 + $conn, 199 + 'ALTER TABLE %T.%T DROP KEY %T', 200 + $adjust['database'], 201 + $adjust['table'], 202 + $adjust['name']); 203 + } 172 204 173 - break; 174 - default: 175 - throw new Exception( 176 - pht('Unknown schema adjustment kind "%s"!', $adjust['kind'])); 205 + if (($phase == 2) && $adjust['keep']) { 206 + queryfx( 207 + $conn, 208 + 'ALTER TABLE %T.%T ADD %Q KEY %T (%Q)', 209 + $adjust['database'], 210 + $adjust['table'], 211 + $adjust['unique'] ? 'UNIQUE' : '/* NONUNIQUE */', 212 + $adjust['name'], 213 + implode(', ', $adjust['columns'])); 214 + } 215 + break; 216 + default: 217 + throw new Exception( 218 + pht('Unknown schema adjustment kind "%s"!', $adjust['kind'])); 219 + } 220 + } catch (AphrontQueryException $ex) { 221 + $failed[] = array($adjust, $ex); 177 222 } 178 - } catch (AphrontQueryException $ex) { 179 - $failed[] = array($adjust, $ex); 223 + $bar->update(1); 180 224 } 181 - $bar->update(1); 182 225 } 183 226 $bar->done(); 184 227 ··· 222 265 $issue_charset = PhabricatorConfigStorageSchema::ISSUE_CHARSET; 223 266 $issue_collation = PhabricatorConfigStorageSchema::ISSUE_COLLATION; 224 267 $issue_columntype = PhabricatorConfigStorageSchema::ISSUE_COLUMNTYPE; 268 + $issue_surpluskey = PhabricatorConfigStorageSchema::ISSUE_SURPLUSKEY; 269 + $issue_missingkey = PhabricatorConfigStorageSchema::ISSUE_MISSINGKEY; 270 + $issue_columns = PhabricatorConfigStorageSchema::ISSUE_KEYCOLUMNS; 271 + $issue_unique = PhabricatorConfigStorageSchema::ISSUE_UNIQUE; 272 + 225 273 226 274 $adjustments = array(); 227 275 foreach ($comp->getDatabases() as $database_name => $database) { ··· 319 367 // dangerous, so always use the current nullability. 320 368 'nullable' => $actual_column->getNullable(), 321 369 ); 370 + } 371 + } 372 + 373 + foreach ($table->getKeys() as $key_name => $key) { 374 + $expect_key = $expect_table->getKey($key_name); 375 + $actual_key = $actual_table->getKey($key_name); 376 + 377 + $issues = array(); 378 + $keep_key = true; 379 + if ($key->hasIssue($issue_surpluskey)) { 380 + $issues[] = $issue_surpluskey; 381 + $keep_key = false; 382 + } 383 + 384 + if ($key->hasIssue($issue_missingkey)) { 385 + $issues[] = $issue_missingkey; 386 + } 387 + 388 + if ($key->hasIssue($issue_columns)) { 389 + $issues[] = $issue_columns; 390 + } 391 + 392 + if ($key->hasIssue($issue_unique)) { 393 + $issues[] = $issue_unique; 394 + } 395 + 396 + if ($issues) { 397 + $adjustment = array( 398 + 'kind' => 'key', 399 + 'database' => $database_name, 400 + 'table' => $table_name, 401 + 'name' => $key_name, 402 + 'issues' => $issues, 403 + 'exists' => (bool)$actual_key, 404 + 'keep' => $keep_key, 405 + ); 406 + 407 + if ($keep_key) { 408 + $adjustment += array( 409 + 'columns' => $expect_key->getColumnNames(), 410 + 'unique' => $expect_key->getUnique(), 411 + ); 412 + } 413 + 414 + $adjustments[] = $adjustment; 322 415 } 323 416 } 324 417 }