3
abstract class PhabricatorConfigSchemaSpec extends Phobject {
7
private $utf8BinaryCollation;
8
private $utf8SortingCollation;
10
public function setUTF8SortingCollation($utf8_sorting_collation) {
11
$this->utf8SortingCollation = $utf8_sorting_collation;
15
public function getUTF8SortingCollation() {
16
return $this->utf8SortingCollation;
19
public function setUTF8BinaryCollation($utf8_binary_collation) {
20
$this->utf8BinaryCollation = $utf8_binary_collation;
24
public function getUTF8BinaryCollation() {
25
return $this->utf8BinaryCollation;
28
public function setUTF8Charset($utf8_charset) {
29
$this->utf8Charset = $utf8_charset;
33
public function getUTF8Charset() {
34
return $this->utf8Charset;
37
public function setServer(PhabricatorConfigServerSchema $server) {
38
$this->server = $server;
42
public function getServer() {
46
abstract public function buildSchemata();
48
protected function buildLiskObjectSchema(PhabricatorLiskDAO $object) {
49
$this->buildRawSchema(
50
$object->getApplicationName(),
51
$object->getTableName(),
52
$object->getSchemaColumns(),
53
$object->getSchemaKeys());
56
protected function buildRawSchema(
61
$database = $this->getDatabase($database_name);
63
$table = $this->newTable($table_name);
65
foreach ($columns as $name => $type) {
70
$details = $this->getDetailsForDataType($type);
71
list($column_type, $charset, $collation, $nullable, $auto) = $details;
73
$column = $this->newColumn($name)
75
->setColumnType($column_type)
76
->setCharacterSet($charset)
77
->setCollation($collation)
78
->setNullable($nullable)
79
->setAutoIncrement($auto);
81
$table->addColumn($column);
84
foreach ($keys as $key_name => $key_spec) {
85
if ($key_spec === null) {
86
// This is a subclass removing a key which Lisk expects.
90
$key = $this->newKey($key_name)
91
->setColumnNames(idx($key_spec, 'columns', array()));
93
$key->setUnique((bool)idx($key_spec, 'unique'));
94
$key->setIndexType(idx($key_spec, 'type', 'BTREE'));
99
$database->addTable($table);
102
protected function buildEdgeSchemata(PhabricatorLiskDAO $object) {
103
$this->buildRawSchema(
104
$object->getApplicationName(),
105
PhabricatorEdgeConfig::TABLE_NAME_EDGE,
110
'dateCreated' => 'epoch',
116
'columns' => array('src', 'type', 'dst'),
120
'columns' => array('src', 'type', 'dateCreated', 'seq'),
123
'columns' => array('dst', 'type', 'src'),
128
$this->buildRawSchema(
129
$object->getApplicationName(),
130
PhabricatorEdgeConfig::TABLE_NAME_EDGEDATA,
137
'columns' => array('id'),
143
protected function getDatabase($name) {
144
$server = $this->getServer();
146
$database = $server->getDatabase($this->getNamespacedDatabase($name));
148
$database = $this->newDatabase($name);
149
$server->addDatabase($database);
155
protected function newDatabase($name) {
156
return id(new PhabricatorConfigDatabaseSchema())
157
->setName($this->getNamespacedDatabase($name))
158
->setCharacterSet($this->getUTF8Charset())
159
->setCollation($this->getUTF8BinaryCollation());
162
protected function getNamespacedDatabase($name) {
163
$namespace = PhabricatorLiskDAO::getStorageNamespace();
164
return $namespace.'_'.$name;
167
protected function newTable($name) {
168
return id(new PhabricatorConfigTableSchema())
170
->setCollation($this->getUTF8BinaryCollation());
173
protected function newColumn($name) {
174
return id(new PhabricatorConfigColumnSchema())
178
protected function newKey($name) {
179
return id(new PhabricatorConfigKeySchema())
183
private function getDetailsForDataType($data_type) {
189
// If the type ends with "?", make the column nullable.
191
if (preg_match('/\?$/', $data_type)) {
193
$data_type = substr($data_type, 0, -1);
196
// NOTE: MySQL allows fragments like "VARCHAR(32) CHARACTER SET binary",
197
// but just interprets that to mean "VARBINARY(32)". The fragment is
198
// totally disallowed in a MODIFY statement vs a CREATE TABLE statement.
200
$is_binary = ($this->getUTF8Charset() == 'binary');
202
if (preg_match('/^(fulltext|sort|text)(\d+)?\z/', $data_type, $matches)) {
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.
207
static $valid_types = array(
229
if (empty($valid_types[$data_type])) {
230
throw new Exception(pht('Unknown column type "%s"!', $data_type));
234
$size = idx($matches, 2);
238
$column_type = 'varbinary('.$size.')';
240
$column_type = 'longblob';
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.
249
if ($type == 'fulltext') {
250
$column_type = 'longtext';
252
$collation = 'utf8_general_ci';
256
$column_type = 'varchar('.$size.')';
258
$column_type = 'longtext';
260
$charset = $this->getUTF8Charset();
261
if ($type == 'sort' || $type == 'fulltext') {
262
$collation = $this->getUTF8SortingCollation();
264
$collation = $this->getUTF8BinaryCollation();
268
switch ($data_type) {
270
$column_type = 'int(10) unsigned';
274
$column_type = 'bigint(20) unsigned';
280
$column_type = 'int(10) unsigned';
283
$column_type = 'int(10)';
287
$column_type = 'bigint(20) unsigned';
290
$column_type = 'bigint(20)';
294
$column_type = 'varbinary(64)';
297
$column_type = 'binary(64)';
300
$column_type = 'binary(40)';
303
$column_type = 'binary(32)';
306
$column_type = 'binary(20)';
309
$column_type = 'binary(12)';
312
$column_type = 'binary(4)';
315
$column_type = 'longblob';
318
$column_type = 'tinyint(1)';
321
$column_type = 'double';
324
$column_type = 'date';
327
$column_type = pht('<unknown>');
328
$charset = pht('<unknown>');
329
$collation = pht('<unknown>');
334
return array($column_type, $charset, $collation, $nullable, $auto);