Skip to content

Commit d67b7f0

Browse files
author
epriestley
committedOct 2, 2014
Correct column mutations for old versions of MySQL
Summary: Ref T1191. Although I fixed some of the mutations earlier (in D10598), I missed the column mutations under old versions of MySQL. In particular, this isn't valid: - `ALTER TABLE ... MODIFY columnName VARCHAR(64) COLLATE binary` Issue the permitted version of this instead, which is: - `ALTER TABLE ... MODIFY columnName VARBINARY(64)` Also fixed an issue where a clean schema had the wrong nullability for a column in the draft table. Force it to the expected nullability. The other trick here is around the one column with a FULLTEXT index on it, which needs a little massaging. Test Plan: - Forced my local install to return `false` for utf8mb4 support. - Did a clean adjust into `binary` columns. - Poked around, added emoji to things. - Reverted the fake check and did a clean adjust into `utf8mb4` columns. - Emoji survived. Reviewers: btrahan Reviewed By: btrahan Subscribers: fabe, epriestley Maniphest Tasks: T1191 Differential Revision: https://secure.phabricator.com/D10627
1 parent e333017 commit d67b7f0

File tree

3 files changed

+134
-153
lines changed

3 files changed

+134
-153
lines changed
 
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
ALTER TABLE {$NAMESPACE}_draft.draft
2+
MODIFY metadata LONGTEXT NOT NULL;

‎src/applications/config/schema/PhabricatorConfigSchemaSpec.php

+131-152
Original file line numberDiff line numberDiff line change
@@ -197,159 +197,138 @@ private function getDetailsForDataType($data_type) {
197197
// but just interprets that to mean "VARBINARY(32)". The fragment is
198198
// totally disallowed in a MODIFY statement vs a CREATE TABLE statement.
199199

200-
switch ($data_type) {
201-
case 'auto':
202-
$column_type = 'int(10) unsigned';
203-
$auto = true;
204-
break;
205-
case 'auto64':
206-
$column_type = 'bigint(20) unsigned';
207-
$auto = true;
208-
break;
209-
case 'id':
210-
case 'epoch':
211-
case 'uint32':
212-
$column_type = 'int(10) unsigned';
213-
break;
214-
case 'sint32':
215-
$column_type = 'int(10)';
216-
break;
217-
case 'id64':
218-
case 'uint64':
219-
$column_type = 'bigint(20) unsigned';
220-
break;
221-
case 'sint64':
222-
$column_type = 'bigint(20)';
223-
break;
224-
case 'phid':
225-
case 'policy';
226-
$column_type = 'varbinary(64)';
227-
break;
228-
case 'bytes64':
229-
$column_type = 'binary(64)';
230-
break;
231-
case 'bytes40':
232-
$column_type = 'binary(40)';
233-
break;
234-
case 'bytes32':
235-
$column_type = 'binary(32)';
236-
break;
237-
case 'bytes20':
238-
$column_type = 'binary(20)';
239-
break;
240-
case 'bytes12':
241-
$column_type = 'binary(12)';
242-
break;
243-
case 'bytes4':
244-
$column_type = 'binary(4)';
245-
break;
246-
case 'bytes':
247-
$column_type = 'longblob';
248-
break;
249-
case 'sort255':
250-
$column_type = 'varchar(255)';
251-
$charset = $this->getUTF8Charset();
252-
$collation = $this->getUTF8SortingCollation();
253-
break;
254-
case 'sort128':
255-
$column_type = 'varchar(128)';
256-
$charset = $this->getUTF8Charset();
257-
$collation = $this->getUTF8SortingCollation();
258-
break;
259-
case 'sort64':
260-
$column_type = 'varchar(64)';
261-
$charset = $this->getUTF8Charset();
262-
$collation = $this->getUTF8SortingCollation();
263-
break;
264-
case 'sort32':
265-
$column_type = 'varchar(32)';
266-
$charset = $this->getUTF8Charset();
267-
$collation = $this->getUTF8SortingCollation();
268-
break;
269-
case 'sort':
270-
$column_type = 'longtext';
271-
$charset = $this->getUTF8Charset();
272-
$collation = $this->getUTF8SortingCollation();
273-
break;
274-
case 'text255':
275-
$column_type = 'varchar(255)';
276-
$charset = $this->getUTF8Charset();
277-
$collation = $this->getUTF8BinaryCollation();
278-
break;
279-
case 'text160':
280-
$column_type = 'varchar(160)';
281-
$charset = $this->getUTF8Charset();
282-
$collation = $this->getUTF8BinaryCollation();
283-
break;
284-
case 'text128':
285-
$column_type = 'varchar(128)';
286-
$charset = $this->getUTF8Charset();
287-
$collation = $this->getUTF8BinaryCollation();
288-
break;
289-
case 'text80':
290-
$column_type = 'varchar(80)';
291-
$charset = $this->getUTF8Charset();
292-
$collation = $this->getUTF8BinaryCollation();
293-
break;
294-
case 'text64':
295-
$column_type = 'varchar(64)';
296-
$charset = $this->getUTF8Charset();
297-
$collation = $this->getUTF8BinaryCollation();
298-
break;
299-
case 'text40':
300-
$column_type = 'varchar(40)';
301-
$charset = $this->getUTF8Charset();
302-
$collation = $this->getUTF8BinaryCollation();
303-
break;
304-
case 'text32':
305-
$column_type = 'varchar(32)';
306-
$charset = $this->getUTF8Charset();
307-
$collation = $this->getUTF8BinaryCollation();
308-
break;
309-
case 'text20':
310-
$column_type = 'varchar(20)';
311-
$charset = $this->getUTF8Charset();
312-
$collation = $this->getUTF8BinaryCollation();
313-
break;
314-
case 'text16':
315-
$column_type = 'varchar(16)';
316-
$charset = $this->getUTF8Charset();
317-
$collation = $this->getUTF8BinaryCollation();
318-
break;
319-
case 'text12':
320-
$column_type = 'varchar(12)';
321-
$charset = $this->getUTF8Charset();
322-
$collation = $this->getUTF8BinaryCollation();
323-
break;
324-
case 'text8':
325-
$column_type = 'varchar(8)';
326-
$charset = $this->getUTF8Charset();
327-
$collation = $this->getUTF8BinaryCollation();
328-
break;
329-
case 'text4':
330-
$column_type = 'varchar(4)';
331-
$charset = $this->getUTF8Charset();
332-
$collation = $this->getUTF8BinaryCollation();
333-
break;
334-
case 'text':
335-
$column_type = 'longtext';
200+
$is_binary = ($this->getUTF8Charset() == 'binary');
201+
$matches = null;
202+
if (preg_match('/^(fulltext|sort|text)(\d+)?\z/', $data_type, $matches)) {
203+
204+
// Limit the permitted column lengths under the theory that it would
205+
// be nice to eventually reduce this to a small set of standard lengths.
206+
207+
static $valid_types = array(
208+
'text255' => true,
209+
'text160' => true,
210+
'text128' => true,
211+
'text80' => true,
212+
'text64' => true,
213+
'text40' => true,
214+
'text32' => true,
215+
'text20' => true,
216+
'text16' => true,
217+
'text12' => true,
218+
'text8' => true,
219+
'text4' => true,
220+
'text' => true,
221+
'sort255' => true,
222+
'sort128' => true,
223+
'sort64' => true,
224+
'sort32' => true,
225+
'sort' => true,
226+
'fulltext' => true,
227+
);
228+
229+
if (empty($valid_types[$data_type])) {
230+
throw new Exception(pht('Unknown column type "%s"!', $data_type));
231+
}
232+
233+
$type = $matches[1];
234+
$size = idx($matches, 2);
235+
236+
if ($is_binary) {
237+
if ($size) {
238+
$column_type = 'varbinary('.$size.')';
239+
} else {
240+
$column_type = 'longblob';
241+
}
242+
243+
// MySQL (at least, under MyISAM) refuses to create a FULLTEXT index
244+
// on a LONGBLOB column. We'd also lose case insensitivity in search.
245+
// Force this column to utf8 collation. This will truncate results with
246+
// 4-byte UTF characters in their text, but work reasonably in the
247+
// majority of cases.
248+
249+
if ($type == 'fulltext') {
250+
$column_type = 'longtext';
251+
$charset = 'utf8';
252+
$collation = 'utf8_general_ci';
253+
}
254+
} else {
255+
if ($size) {
256+
$column_type = 'varchar('.$size.')';
257+
} else {
258+
$column_type = 'longtext';
259+
}
336260
$charset = $this->getUTF8Charset();
337-
$collation = $this->getUTF8BinaryCollation();
338-
break;
339-
case 'bool':
340-
$column_type = 'tinyint(1)';
341-
break;
342-
case 'double':
343-
$column_type = 'double';
344-
break;
345-
case 'date':
346-
$column_type = 'date';
347-
break;
348-
default:
349-
$column_type = pht('<unknown>');
350-
$charset = pht('<unknown>');
351-
$collation = pht('<unknown>');
352-
break;
261+
if ($type == 'sort' || $type == 'fulltext') {
262+
$collation = $this->getUTF8SortingCollation();
263+
} else {
264+
$collation = $this->getUTF8BinaryCollation();
265+
}
266+
}
267+
} else {
268+
switch ($data_type) {
269+
case 'auto':
270+
$column_type = 'int(10) unsigned';
271+
$auto = true;
272+
break;
273+
case 'auto64':
274+
$column_type = 'bigint(20) unsigned';
275+
$auto = true;
276+
break;
277+
case 'id':
278+
case 'epoch':
279+
case 'uint32':
280+
$column_type = 'int(10) unsigned';
281+
break;
282+
case 'sint32':
283+
$column_type = 'int(10)';
284+
break;
285+
case 'id64':
286+
case 'uint64':
287+
$column_type = 'bigint(20) unsigned';
288+
break;
289+
case 'sint64':
290+
$column_type = 'bigint(20)';
291+
break;
292+
case 'phid':
293+
case 'policy';
294+
$column_type = 'varbinary(64)';
295+
break;
296+
case 'bytes64':
297+
$column_type = 'binary(64)';
298+
break;
299+
case 'bytes40':
300+
$column_type = 'binary(40)';
301+
break;
302+
case 'bytes32':
303+
$column_type = 'binary(32)';
304+
break;
305+
case 'bytes20':
306+
$column_type = 'binary(20)';
307+
break;
308+
case 'bytes12':
309+
$column_type = 'binary(12)';
310+
break;
311+
case 'bytes4':
312+
$column_type = 'binary(4)';
313+
break;
314+
case 'bytes':
315+
$column_type = 'longblob';
316+
break;
317+
case 'bool':
318+
$column_type = 'tinyint(1)';
319+
break;
320+
case 'double':
321+
$column_type = 'double';
322+
break;
323+
case 'date':
324+
$column_type = 'date';
325+
break;
326+
default:
327+
$column_type = pht('<unknown>');
328+
$charset = pht('<unknown>');
329+
$collation = pht('<unknown>');
330+
break;
331+
}
353332
}
354333

355334
return array($column_type, $charset, $collation, $nullable, $auto);

‎src/applications/search/storage/document/PhabricatorSearchDocumentField.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ public function getConfiguration() {
1515
'phidType' => 'text4',
1616
'field' => 'text4',
1717
'auxPHID' => 'phid?',
18-
'corpus' => 'sort?',
18+
'corpus' => 'fulltext?',
1919
),
2020
self::CONFIG_KEY_SCHEMA => array(
2121
'key_phid' => null,

0 commit comments

Comments
 (0)
Failed to load comments.