[ Index ] |
PHP Cross Reference of Phabricator |
[Summary view] [Print] [Text view]
1 <?php 2 3 abstract class PhabricatorConfigSchemaSpec extends Phobject { 4 5 private $server; 6 private $utf8Charset; 7 private $utf8BinaryCollation; 8 private $utf8SortingCollation; 9 10 const DATATYPE_UNKNOWN = '<unknown>'; 11 12 public function setUTF8SortingCollation($utf8_sorting_collation) { 13 $this->utf8SortingCollation = $utf8_sorting_collation; 14 return $this; 15 } 16 17 public function getUTF8SortingCollation() { 18 return $this->utf8SortingCollation; 19 } 20 21 public function setUTF8BinaryCollation($utf8_binary_collation) { 22 $this->utf8BinaryCollation = $utf8_binary_collation; 23 return $this; 24 } 25 26 public function getUTF8BinaryCollation() { 27 return $this->utf8BinaryCollation; 28 } 29 30 public function setUTF8Charset($utf8_charset) { 31 $this->utf8Charset = $utf8_charset; 32 return $this; 33 } 34 35 public function getUTF8Charset() { 36 return $this->utf8Charset; 37 } 38 39 public function setServer(PhabricatorConfigServerSchema $server) { 40 $this->server = $server; 41 return $this; 42 } 43 44 public function getServer() { 45 return $this->server; 46 } 47 48 abstract public function buildSchemata(); 49 50 protected function buildLiskObjectSchema(PhabricatorLiskDAO $object) { 51 $this->buildRawSchema( 52 $object->getApplicationName(), 53 $object->getTableName(), 54 $object->getSchemaColumns(), 55 $object->getSchemaKeys()); 56 } 57 58 protected function buildRawSchema( 59 $database_name, 60 $table_name, 61 array $columns, 62 array $keys) { 63 $database = $this->getDatabase($database_name); 64 65 $table = $this->newTable($table_name); 66 67 foreach ($columns as $name => $type) { 68 if ($type === null) { 69 continue; 70 } 71 72 $details = $this->getDetailsForDataType($type); 73 list($column_type, $charset, $collation, $nullable, $auto) = $details; 74 75 $column = $this->newColumn($name) 76 ->setDataType($type) 77 ->setColumnType($column_type) 78 ->setCharacterSet($charset) 79 ->setCollation($collation) 80 ->setNullable($nullable) 81 ->setAutoIncrement($auto); 82 83 $table->addColumn($column); 84 } 85 86 foreach ($keys as $key_name => $key_spec) { 87 if ($key_spec === null) { 88 // This is a subclass removing a key which Lisk expects. 89 continue; 90 } 91 92 $key = $this->newKey($key_name) 93 ->setColumnNames(idx($key_spec, 'columns', array())); 94 95 $key->setUnique((bool)idx($key_spec, 'unique')); 96 $key->setIndexType(idx($key_spec, 'type', 'BTREE')); 97 98 $table->addKey($key); 99 } 100 101 $database->addTable($table); 102 } 103 104 protected function buildEdgeSchemata(PhabricatorLiskDAO $object) { 105 $this->buildRawSchema( 106 $object->getApplicationName(), 107 PhabricatorEdgeConfig::TABLE_NAME_EDGE, 108 array( 109 'src' => 'phid', 110 'type' => 'uint32', 111 'dst' => 'phid', 112 'dateCreated' => 'epoch', 113 'seq' => 'uint32', 114 'dataID' => 'id?', 115 ), 116 array( 117 'PRIMARY' => array( 118 'columns' => array('src', 'type', 'dst'), 119 'unique' => true, 120 ), 121 'src' => array( 122 'columns' => array('src', 'type', 'dateCreated', 'seq'), 123 ), 124 'key_dst' => array( 125 'columns' => array('dst', 'type', 'src'), 126 'unique' => true, 127 ), 128 )); 129 130 $this->buildRawSchema( 131 $object->getApplicationName(), 132 PhabricatorEdgeConfig::TABLE_NAME_EDGEDATA, 133 array( 134 'id' => 'auto', 135 'data' => 'text', 136 ), 137 array( 138 'PRIMARY' => array( 139 'columns' => array('id'), 140 'unique' => true, 141 ), 142 )); 143 } 144 145 protected function getDatabase($name) { 146 $server = $this->getServer(); 147 148 $database = $server->getDatabase($this->getNamespacedDatabase($name)); 149 if (!$database) { 150 $database = $this->newDatabase($name); 151 $server->addDatabase($database); 152 } 153 154 return $database; 155 } 156 157 protected function newDatabase($name) { 158 return id(new PhabricatorConfigDatabaseSchema()) 159 ->setName($this->getNamespacedDatabase($name)) 160 ->setCharacterSet($this->getUTF8Charset()) 161 ->setCollation($this->getUTF8BinaryCollation()); 162 } 163 164 protected function getNamespacedDatabase($name) { 165 $namespace = PhabricatorLiskDAO::getStorageNamespace(); 166 return $namespace.'_'.$name; 167 } 168 169 protected function newTable($name) { 170 return id(new PhabricatorConfigTableSchema()) 171 ->setName($name) 172 ->setCollation($this->getUTF8BinaryCollation()); 173 } 174 175 protected function newColumn($name) { 176 return id(new PhabricatorConfigColumnSchema()) 177 ->setName($name); 178 } 179 180 protected function newKey($name) { 181 return id(new PhabricatorConfigKeySchema()) 182 ->setName($name); 183 } 184 185 private function getDetailsForDataType($data_type) { 186 $column_type = null; 187 $charset = null; 188 $collation = null; 189 $auto = false; 190 191 // If the type ends with "?", make the column nullable. 192 $nullable = false; 193 if (preg_match('/\?$/', $data_type)) { 194 $nullable = true; 195 $data_type = substr($data_type, 0, -1); 196 } 197 198 // NOTE: MySQL allows fragments like "VARCHAR(32) CHARACTER SET binary", 199 // but just interprets that to mean "VARBINARY(32)". The fragment is 200 // totally disallowed in a MODIFY statement vs a CREATE TABLE statement. 201 202 $is_binary = ($this->getUTF8Charset() == 'binary'); 203 $matches = null; 204 if (preg_match('/^(fulltext|sort|text)(\d+)?\z/', $data_type, $matches)) { 205 206 // Limit the permitted column lengths under the theory that it would 207 // be nice to eventually reduce this to a small set of standard lengths. 208 209 static $valid_types = array( 210 'text255' => true, 211 'text160' => true, 212 'text128' => true, 213 'text80' => true, 214 'text64' => true, 215 'text40' => true, 216 'text32' => true, 217 'text20' => true, 218 'text16' => true, 219 'text12' => true, 220 'text8' => true, 221 'text4' => true, 222 'text' => true, 223 'sort255' => true, 224 'sort128' => true, 225 'sort64' => true, 226 'sort32' => true, 227 'sort' => true, 228 'fulltext' => true, 229 ); 230 231 if (empty($valid_types[$data_type])) { 232 throw new Exception(pht('Unknown column type "%s"!', $data_type)); 233 } 234 235 $type = $matches[1]; 236 $size = idx($matches, 2); 237 238 if ($is_binary) { 239 if ($size) { 240 $column_type = 'varbinary('.$size.')'; 241 } else { 242 $column_type = 'longblob'; 243 } 244 245 // MySQL (at least, under MyISAM) refuses to create a FULLTEXT index 246 // on a LONGBLOB column. We'd also lose case insensitivity in search. 247 // Force this column to utf8 collation. This will truncate results with 248 // 4-byte UTF characters in their text, but work reasonably in the 249 // majority of cases. 250 251 if ($type == 'fulltext') { 252 $column_type = 'longtext'; 253 $charset = 'utf8'; 254 $collation = 'utf8_general_ci'; 255 } 256 } else { 257 if ($size) { 258 $column_type = 'varchar('.$size.')'; 259 } else { 260 $column_type = 'longtext'; 261 } 262 $charset = $this->getUTF8Charset(); 263 if ($type == 'sort' || $type == 'fulltext') { 264 $collation = $this->getUTF8SortingCollation(); 265 } else { 266 $collation = $this->getUTF8BinaryCollation(); 267 } 268 } 269 } else { 270 switch ($data_type) { 271 case 'auto': 272 $column_type = 'int(10) unsigned'; 273 $auto = true; 274 break; 275 case 'auto64': 276 $column_type = 'bigint(20) unsigned'; 277 $auto = true; 278 break; 279 case 'id': 280 case 'epoch': 281 case 'uint32': 282 $column_type = 'int(10) unsigned'; 283 break; 284 case 'sint32': 285 $column_type = 'int(10)'; 286 break; 287 case 'id64': 288 case 'uint64': 289 $column_type = 'bigint(20) unsigned'; 290 break; 291 case 'sint64': 292 $column_type = 'bigint(20)'; 293 break; 294 case 'phid': 295 case 'policy'; 296 $column_type = 'varbinary(64)'; 297 break; 298 case 'bytes64': 299 $column_type = 'binary(64)'; 300 break; 301 case 'bytes40': 302 $column_type = 'binary(40)'; 303 break; 304 case 'bytes32': 305 $column_type = 'binary(32)'; 306 break; 307 case 'bytes20': 308 $column_type = 'binary(20)'; 309 break; 310 case 'bytes12': 311 $column_type = 'binary(12)'; 312 break; 313 case 'bytes4': 314 $column_type = 'binary(4)'; 315 break; 316 case 'bytes': 317 $column_type = 'longblob'; 318 break; 319 case 'bool': 320 $column_type = 'tinyint(1)'; 321 break; 322 case 'double': 323 $column_type = 'double'; 324 break; 325 case 'date': 326 $column_type = 'date'; 327 break; 328 default: 329 $column_type = self::DATATYPE_UNKNOWN; 330 $charset = self::DATATYPE_UNKNOWN; 331 $collation = self::DATATYPE_UNKNOWN; 332 break; 333 } 334 } 335 336 return array($column_type, $charset, $collation, $nullable, $auto); 337 } 338 339 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Sun Nov 30 09:20:46 2014 | Cross-referenced by PHPXref 0.7.1 |