MySqlGrammar.php 39 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342
  1. <?php
  2. namespace Illuminate\Database\Schema\Grammars;
  3. use Illuminate\Database\Connection;
  4. use Illuminate\Database\Query\Expression;
  5. use Illuminate\Database\Schema\Blueprint;
  6. use Illuminate\Database\Schema\ColumnDefinition;
  7. use Illuminate\Support\Fluent;
  8. use RuntimeException;
  9. class MySqlGrammar extends Grammar
  10. {
  11. /**
  12. * The possible column modifiers.
  13. *
  14. * @var string[]
  15. */
  16. protected $modifiers = [
  17. 'Unsigned', 'Charset', 'Collate', 'VirtualAs', 'StoredAs', 'Nullable',
  18. 'Default', 'OnUpdate', 'Invisible', 'Increment', 'Comment', 'After', 'First',
  19. ];
  20. /**
  21. * The possible column serials.
  22. *
  23. * @var string[]
  24. */
  25. protected $serials = ['bigInteger', 'integer', 'mediumInteger', 'smallInteger', 'tinyInteger'];
  26. /**
  27. * The commands to be executed outside of create or alter command.
  28. *
  29. * @var string[]
  30. */
  31. protected $fluentCommands = ['AutoIncrementStartingValues'];
  32. /**
  33. * Compile a create database command.
  34. *
  35. * @param string $name
  36. * @param \Illuminate\Database\Connection $connection
  37. * @return string
  38. */
  39. public function compileCreateDatabase($name, $connection)
  40. {
  41. $charset = $connection->getConfig('charset');
  42. $collation = $connection->getConfig('collation');
  43. if (! $charset || ! $collation) {
  44. return sprintf(
  45. 'create database %s',
  46. $this->wrapValue($name),
  47. );
  48. }
  49. return sprintf(
  50. 'create database %s default character set %s default collate %s',
  51. $this->wrapValue($name),
  52. $this->wrapValue($charset),
  53. $this->wrapValue($collation),
  54. );
  55. }
  56. /**
  57. * Compile a drop database if exists command.
  58. *
  59. * @param string $name
  60. * @return string
  61. */
  62. public function compileDropDatabaseIfExists($name)
  63. {
  64. return sprintf(
  65. 'drop database if exists %s',
  66. $this->wrapValue($name)
  67. );
  68. }
  69. /**
  70. * Compile the query to determine the tables.
  71. *
  72. * @param string $database
  73. * @return string
  74. */
  75. public function compileTables($database)
  76. {
  77. return sprintf(
  78. 'select table_name as `name`, (data_length + index_length) as `size`, '
  79. .'table_comment as `comment`, engine as `engine`, table_collation as `collation` '
  80. ."from information_schema.tables where table_schema = %s and table_type in ('BASE TABLE', 'SYSTEM VERSIONED') "
  81. .'order by table_name',
  82. $this->quoteString($database)
  83. );
  84. }
  85. /**
  86. * Compile the query to determine the views.
  87. *
  88. * @param string $database
  89. * @return string
  90. */
  91. public function compileViews($database)
  92. {
  93. return sprintf(
  94. 'select table_name as `name`, view_definition as `definition` '
  95. .'from information_schema.views where table_schema = %s '
  96. .'order by table_name',
  97. $this->quoteString($database)
  98. );
  99. }
  100. /**
  101. * Compile the query to determine the columns.
  102. *
  103. * @param string $database
  104. * @param string $table
  105. * @return string
  106. */
  107. public function compileColumns($database, $table)
  108. {
  109. return sprintf(
  110. 'select column_name as `name`, data_type as `type_name`, column_type as `type`, '
  111. .'collation_name as `collation`, is_nullable as `nullable`, '
  112. .'column_default as `default`, column_comment as `comment`, '
  113. .'generation_expression as `expression`, extra as `extra` '
  114. .'from information_schema.columns where table_schema = %s and table_name = %s '
  115. .'order by ordinal_position asc',
  116. $this->quoteString($database),
  117. $this->quoteString($table)
  118. );
  119. }
  120. /**
  121. * Compile the query to determine the indexes.
  122. *
  123. * @param string $database
  124. * @param string $table
  125. * @return string
  126. */
  127. public function compileIndexes($database, $table)
  128. {
  129. return sprintf(
  130. 'select index_name as `name`, group_concat(column_name order by seq_in_index) as `columns`, '
  131. .'index_type as `type`, not non_unique as `unique` '
  132. .'from information_schema.statistics where table_schema = %s and table_name = %s '
  133. .'group by index_name, index_type, non_unique',
  134. $this->quoteString($database),
  135. $this->quoteString($table)
  136. );
  137. }
  138. /**
  139. * Compile the query to determine the foreign keys.
  140. *
  141. * @param string $database
  142. * @param string $table
  143. * @return string
  144. */
  145. public function compileForeignKeys($database, $table)
  146. {
  147. return sprintf(
  148. 'select kc.constraint_name as `name`, '
  149. .'group_concat(kc.column_name order by kc.ordinal_position) as `columns`, '
  150. .'kc.referenced_table_schema as `foreign_schema`, '
  151. .'kc.referenced_table_name as `foreign_table`, '
  152. .'group_concat(kc.referenced_column_name order by kc.ordinal_position) as `foreign_columns`, '
  153. .'rc.update_rule as `on_update`, '
  154. .'rc.delete_rule as `on_delete` '
  155. .'from information_schema.key_column_usage kc join information_schema.referential_constraints rc '
  156. .'on kc.constraint_schema = rc.constraint_schema and kc.constraint_name = rc.constraint_name '
  157. .'where kc.table_schema = %s and kc.table_name = %s and kc.referenced_table_name is not null '
  158. .'group by kc.constraint_name, kc.referenced_table_schema, kc.referenced_table_name, rc.update_rule, rc.delete_rule',
  159. $this->quoteString($database),
  160. $this->quoteString($table)
  161. );
  162. }
  163. /**
  164. * Compile a create table command.
  165. *
  166. * @param \Illuminate\Database\Schema\Blueprint $blueprint
  167. * @param \Illuminate\Support\Fluent $command
  168. * @param \Illuminate\Database\Connection $connection
  169. * @return string
  170. */
  171. public function compileCreate(Blueprint $blueprint, Fluent $command, Connection $connection)
  172. {
  173. $sql = $this->compileCreateTable(
  174. $blueprint, $command, $connection
  175. );
  176. // Once we have the primary SQL, we can add the encoding option to the SQL for
  177. // the table. Then, we can check if a storage engine has been supplied for
  178. // the table. If so, we will add the engine declaration to the SQL query.
  179. $sql = $this->compileCreateEncoding(
  180. $sql, $connection, $blueprint
  181. );
  182. // Finally, we will append the engine configuration onto this SQL statement as
  183. // the final thing we do before returning this finished SQL. Once this gets
  184. // added the query will be ready to execute against the real connections.
  185. return $this->compileCreateEngine($sql, $connection, $blueprint);
  186. }
  187. /**
  188. * Create the main create table clause.
  189. *
  190. * @param \Illuminate\Database\Schema\Blueprint $blueprint
  191. * @param \Illuminate\Support\Fluent $command
  192. * @param \Illuminate\Database\Connection $connection
  193. * @return string
  194. */
  195. protected function compileCreateTable($blueprint, $command, $connection)
  196. {
  197. $tableStructure = $this->getColumns($blueprint);
  198. if ($primaryKey = $this->getCommandByName($blueprint, 'primary')) {
  199. $tableStructure[] = sprintf(
  200. 'primary key %s(%s)',
  201. $primaryKey->algorithm ? 'using '.$primaryKey->algorithm : '',
  202. $this->columnize($primaryKey->columns)
  203. );
  204. $primaryKey->shouldBeSkipped = true;
  205. }
  206. return sprintf('%s table %s (%s)',
  207. $blueprint->temporary ? 'create temporary' : 'create',
  208. $this->wrapTable($blueprint),
  209. implode(', ', $tableStructure)
  210. );
  211. }
  212. /**
  213. * Append the character set specifications to a command.
  214. *
  215. * @param string $sql
  216. * @param \Illuminate\Database\Connection $connection
  217. * @param \Illuminate\Database\Schema\Blueprint $blueprint
  218. * @return string
  219. */
  220. protected function compileCreateEncoding($sql, Connection $connection, Blueprint $blueprint)
  221. {
  222. // First we will set the character set if one has been set on either the create
  223. // blueprint itself or on the root configuration for the connection that the
  224. // table is being created on. We will add these to the create table query.
  225. if (isset($blueprint->charset)) {
  226. $sql .= ' default character set '.$blueprint->charset;
  227. } elseif (! is_null($charset = $connection->getConfig('charset'))) {
  228. $sql .= ' default character set '.$charset;
  229. }
  230. // Next we will add the collation to the create table statement if one has been
  231. // added to either this create table blueprint or the configuration for this
  232. // connection that the query is targeting. We'll add it to this SQL query.
  233. if (isset($blueprint->collation)) {
  234. $sql .= " collate '{$blueprint->collation}'";
  235. } elseif (! is_null($collation = $connection->getConfig('collation'))) {
  236. $sql .= " collate '{$collation}'";
  237. }
  238. return $sql;
  239. }
  240. /**
  241. * Append the engine specifications to a command.
  242. *
  243. * @param string $sql
  244. * @param \Illuminate\Database\Connection $connection
  245. * @param \Illuminate\Database\Schema\Blueprint $blueprint
  246. * @return string
  247. */
  248. protected function compileCreateEngine($sql, Connection $connection, Blueprint $blueprint)
  249. {
  250. if (isset($blueprint->engine)) {
  251. return $sql.' engine = '.$blueprint->engine;
  252. } elseif (! is_null($engine = $connection->getConfig('engine'))) {
  253. return $sql.' engine = '.$engine;
  254. }
  255. return $sql;
  256. }
  257. /**
  258. * Compile an add column command.
  259. *
  260. * @param \Illuminate\Database\Schema\Blueprint $blueprint
  261. * @param \Illuminate\Support\Fluent $command
  262. * @return string
  263. */
  264. public function compileAdd(Blueprint $blueprint, Fluent $command)
  265. {
  266. $columns = $this->prefixArray('add', $this->getColumns($blueprint));
  267. return 'alter table '.$this->wrapTable($blueprint).' '.implode(', ', $columns);
  268. }
  269. /**
  270. * Compile the auto-incrementing column starting values.
  271. *
  272. * @param \Illuminate\Database\Schema\Blueprint $blueprint
  273. * @param \Illuminate\Support\Fluent $command
  274. * @return string
  275. */
  276. public function compileAutoIncrementStartingValues(Blueprint $blueprint, Fluent $command)
  277. {
  278. if ($command->column->autoIncrement
  279. && $value = $command->column->get('startingValue', $command->column->get('from'))) {
  280. return 'alter table '.$this->wrapTable($blueprint).' auto_increment = '.$value;
  281. }
  282. }
  283. /**
  284. * Compile a rename column command.
  285. *
  286. * @param \Illuminate\Database\Schema\Blueprint $blueprint
  287. * @param \Illuminate\Support\Fluent $command
  288. * @param \Illuminate\Database\Connection $connection
  289. * @return array|string
  290. */
  291. public function compileRenameColumn(Blueprint $blueprint, Fluent $command, Connection $connection)
  292. {
  293. $version = $connection->getServerVersion();
  294. if (($connection->isMaria() && version_compare($version, '10.5.2', '<')) ||
  295. (! $connection->isMaria() && version_compare($version, '8.0.3', '<'))) {
  296. return $this->compileLegacyRenameColumn($blueprint, $command, $connection);
  297. }
  298. return parent::compileRenameColumn($blueprint, $command, $connection);
  299. }
  300. /**
  301. * Compile a rename column command for legacy versions of MySQL.
  302. *
  303. * @param \Illuminate\Database\Schema\Blueprint $blueprint
  304. * @param \Illuminate\Support\Fluent $command
  305. * @param \Illuminate\Database\Connection $connection
  306. * @return string
  307. */
  308. protected function compileLegacyRenameColumn(Blueprint $blueprint, Fluent $command, Connection $connection)
  309. {
  310. $column = collect($connection->getSchemaBuilder()->getColumns($blueprint->getTable()))
  311. ->firstWhere('name', $command->from);
  312. $modifiers = $this->addModifiers($column['type'], $blueprint, new ColumnDefinition([
  313. 'change' => true,
  314. 'type' => match ($column['type_name']) {
  315. 'bigint' => 'bigInteger',
  316. 'int' => 'integer',
  317. 'mediumint' => 'mediumInteger',
  318. 'smallint' => 'smallInteger',
  319. 'tinyint' => 'tinyInteger',
  320. default => $column['type_name'],
  321. },
  322. 'nullable' => $column['nullable'],
  323. 'default' => $column['default'] && (str_starts_with(strtolower($column['default']), 'current_timestamp') || $column['default'] === 'NULL')
  324. ? new Expression($column['default'])
  325. : $column['default'],
  326. 'autoIncrement' => $column['auto_increment'],
  327. 'collation' => $column['collation'],
  328. 'comment' => $column['comment'],
  329. 'virtualAs' => ! is_null($column['generation']) && $column['generation']['type'] === 'virtual'
  330. ? $column['generation']['expression'] : null,
  331. 'storedAs' => ! is_null($column['generation']) && $column['generation']['type'] === 'stored'
  332. ? $column['generation']['expression'] : null,
  333. ]));
  334. return sprintf('alter table %s change %s %s %s',
  335. $this->wrapTable($blueprint),
  336. $this->wrap($command->from),
  337. $this->wrap($command->to),
  338. $modifiers
  339. );
  340. }
  341. /**
  342. * Compile a change column command into a series of SQL statements.
  343. *
  344. * @param \Illuminate\Database\Schema\Blueprint $blueprint
  345. * @param \Illuminate\Support\Fluent $command
  346. * @param \Illuminate\Database\Connection $connection
  347. * @return array|string
  348. *
  349. * @throws \RuntimeException
  350. */
  351. public function compileChange(Blueprint $blueprint, Fluent $command, Connection $connection)
  352. {
  353. $columns = [];
  354. foreach ($blueprint->getChangedColumns() as $column) {
  355. $sql = sprintf('%s %s%s %s',
  356. is_null($column->renameTo) ? 'modify' : 'change',
  357. $this->wrap($column),
  358. is_null($column->renameTo) ? '' : ' '.$this->wrap($column->renameTo),
  359. $this->getType($column)
  360. );
  361. $columns[] = $this->addModifiers($sql, $blueprint, $column);
  362. }
  363. return 'alter table '.$this->wrapTable($blueprint).' '.implode(', ', $columns);
  364. }
  365. /**
  366. * Compile a primary key command.
  367. *
  368. * @param \Illuminate\Database\Schema\Blueprint $blueprint
  369. * @param \Illuminate\Support\Fluent $command
  370. * @return string
  371. */
  372. public function compilePrimary(Blueprint $blueprint, Fluent $command)
  373. {
  374. return sprintf('alter table %s add primary key %s(%s)',
  375. $this->wrapTable($blueprint),
  376. $command->algorithm ? 'using '.$command->algorithm : '',
  377. $this->columnize($command->columns)
  378. );
  379. }
  380. /**
  381. * Compile a unique key command.
  382. *
  383. * @param \Illuminate\Database\Schema\Blueprint $blueprint
  384. * @param \Illuminate\Support\Fluent $command
  385. * @return string
  386. */
  387. public function compileUnique(Blueprint $blueprint, Fluent $command)
  388. {
  389. return $this->compileKey($blueprint, $command, 'unique');
  390. }
  391. /**
  392. * Compile a plain index key command.
  393. *
  394. * @param \Illuminate\Database\Schema\Blueprint $blueprint
  395. * @param \Illuminate\Support\Fluent $command
  396. * @return string
  397. */
  398. public function compileIndex(Blueprint $blueprint, Fluent $command)
  399. {
  400. return $this->compileKey($blueprint, $command, 'index');
  401. }
  402. /**
  403. * Compile a fulltext index key command.
  404. *
  405. * @param \Illuminate\Database\Schema\Blueprint $blueprint
  406. * @param \Illuminate\Support\Fluent $command
  407. * @return string
  408. */
  409. public function compileFullText(Blueprint $blueprint, Fluent $command)
  410. {
  411. return $this->compileKey($blueprint, $command, 'fulltext');
  412. }
  413. /**
  414. * Compile a spatial index key command.
  415. *
  416. * @param \Illuminate\Database\Schema\Blueprint $blueprint
  417. * @param \Illuminate\Support\Fluent $command
  418. * @return string
  419. */
  420. public function compileSpatialIndex(Blueprint $blueprint, Fluent $command)
  421. {
  422. return $this->compileKey($blueprint, $command, 'spatial index');
  423. }
  424. /**
  425. * Compile an index creation command.
  426. *
  427. * @param \Illuminate\Database\Schema\Blueprint $blueprint
  428. * @param \Illuminate\Support\Fluent $command
  429. * @param string $type
  430. * @return string
  431. */
  432. protected function compileKey(Blueprint $blueprint, Fluent $command, $type)
  433. {
  434. return sprintf('alter table %s add %s %s%s(%s)',
  435. $this->wrapTable($blueprint),
  436. $type,
  437. $this->wrap($command->index),
  438. $command->algorithm ? ' using '.$command->algorithm : '',
  439. $this->columnize($command->columns)
  440. );
  441. }
  442. /**
  443. * Compile a drop table command.
  444. *
  445. * @param \Illuminate\Database\Schema\Blueprint $blueprint
  446. * @param \Illuminate\Support\Fluent $command
  447. * @return string
  448. */
  449. public function compileDrop(Blueprint $blueprint, Fluent $command)
  450. {
  451. return 'drop table '.$this->wrapTable($blueprint);
  452. }
  453. /**
  454. * Compile a drop table (if exists) command.
  455. *
  456. * @param \Illuminate\Database\Schema\Blueprint $blueprint
  457. * @param \Illuminate\Support\Fluent $command
  458. * @return string
  459. */
  460. public function compileDropIfExists(Blueprint $blueprint, Fluent $command)
  461. {
  462. return 'drop table if exists '.$this->wrapTable($blueprint);
  463. }
  464. /**
  465. * Compile a drop column command.
  466. *
  467. * @param \Illuminate\Database\Schema\Blueprint $blueprint
  468. * @param \Illuminate\Support\Fluent $command
  469. * @return string
  470. */
  471. public function compileDropColumn(Blueprint $blueprint, Fluent $command)
  472. {
  473. $columns = $this->prefixArray('drop', $this->wrapArray($command->columns));
  474. return 'alter table '.$this->wrapTable($blueprint).' '.implode(', ', $columns);
  475. }
  476. /**
  477. * Compile a drop primary key command.
  478. *
  479. * @param \Illuminate\Database\Schema\Blueprint $blueprint
  480. * @param \Illuminate\Support\Fluent $command
  481. * @return string
  482. */
  483. public function compileDropPrimary(Blueprint $blueprint, Fluent $command)
  484. {
  485. return 'alter table '.$this->wrapTable($blueprint).' drop primary key';
  486. }
  487. /**
  488. * Compile a drop unique key command.
  489. *
  490. * @param \Illuminate\Database\Schema\Blueprint $blueprint
  491. * @param \Illuminate\Support\Fluent $command
  492. * @return string
  493. */
  494. public function compileDropUnique(Blueprint $blueprint, Fluent $command)
  495. {
  496. $index = $this->wrap($command->index);
  497. return "alter table {$this->wrapTable($blueprint)} drop index {$index}";
  498. }
  499. /**
  500. * Compile a drop index command.
  501. *
  502. * @param \Illuminate\Database\Schema\Blueprint $blueprint
  503. * @param \Illuminate\Support\Fluent $command
  504. * @return string
  505. */
  506. public function compileDropIndex(Blueprint $blueprint, Fluent $command)
  507. {
  508. $index = $this->wrap($command->index);
  509. return "alter table {$this->wrapTable($blueprint)} drop index {$index}";
  510. }
  511. /**
  512. * Compile a drop fulltext index command.
  513. *
  514. * @param \Illuminate\Database\Schema\Blueprint $blueprint
  515. * @param \Illuminate\Support\Fluent $command
  516. * @return string
  517. */
  518. public function compileDropFullText(Blueprint $blueprint, Fluent $command)
  519. {
  520. return $this->compileDropIndex($blueprint, $command);
  521. }
  522. /**
  523. * Compile a drop spatial index command.
  524. *
  525. * @param \Illuminate\Database\Schema\Blueprint $blueprint
  526. * @param \Illuminate\Support\Fluent $command
  527. * @return string
  528. */
  529. public function compileDropSpatialIndex(Blueprint $blueprint, Fluent $command)
  530. {
  531. return $this->compileDropIndex($blueprint, $command);
  532. }
  533. /**
  534. * Compile a drop foreign key command.
  535. *
  536. * @param \Illuminate\Database\Schema\Blueprint $blueprint
  537. * @param \Illuminate\Support\Fluent $command
  538. * @return string
  539. */
  540. public function compileDropForeign(Blueprint $blueprint, Fluent $command)
  541. {
  542. $index = $this->wrap($command->index);
  543. return "alter table {$this->wrapTable($blueprint)} drop foreign key {$index}";
  544. }
  545. /**
  546. * Compile a rename table command.
  547. *
  548. * @param \Illuminate\Database\Schema\Blueprint $blueprint
  549. * @param \Illuminate\Support\Fluent $command
  550. * @return string
  551. */
  552. public function compileRename(Blueprint $blueprint, Fluent $command)
  553. {
  554. $from = $this->wrapTable($blueprint);
  555. return "rename table {$from} to ".$this->wrapTable($command->to);
  556. }
  557. /**
  558. * Compile a rename index command.
  559. *
  560. * @param \Illuminate\Database\Schema\Blueprint $blueprint
  561. * @param \Illuminate\Support\Fluent $command
  562. * @return string
  563. */
  564. public function compileRenameIndex(Blueprint $blueprint, Fluent $command)
  565. {
  566. return sprintf('alter table %s rename index %s to %s',
  567. $this->wrapTable($blueprint),
  568. $this->wrap($command->from),
  569. $this->wrap($command->to)
  570. );
  571. }
  572. /**
  573. * Compile the SQL needed to drop all tables.
  574. *
  575. * @param array $tables
  576. * @return string
  577. */
  578. public function compileDropAllTables($tables)
  579. {
  580. return 'drop table '.implode(',', $this->wrapArray($tables));
  581. }
  582. /**
  583. * Compile the SQL needed to drop all views.
  584. *
  585. * @param array $views
  586. * @return string
  587. */
  588. public function compileDropAllViews($views)
  589. {
  590. return 'drop view '.implode(',', $this->wrapArray($views));
  591. }
  592. /**
  593. * Compile the command to enable foreign key constraints.
  594. *
  595. * @return string
  596. */
  597. public function compileEnableForeignKeyConstraints()
  598. {
  599. return 'SET FOREIGN_KEY_CHECKS=1;';
  600. }
  601. /**
  602. * Compile the command to disable foreign key constraints.
  603. *
  604. * @return string
  605. */
  606. public function compileDisableForeignKeyConstraints()
  607. {
  608. return 'SET FOREIGN_KEY_CHECKS=0;';
  609. }
  610. /**
  611. * Compile a table comment command.
  612. *
  613. * @param \Illuminate\Database\Schema\Blueprint $blueprint
  614. * @param \Illuminate\Support\Fluent $command
  615. * @return string
  616. */
  617. public function compileTableComment(Blueprint $blueprint, Fluent $command)
  618. {
  619. return sprintf('alter table %s comment = %s',
  620. $this->wrapTable($blueprint),
  621. "'".str_replace("'", "''", $command->comment)."'"
  622. );
  623. }
  624. /**
  625. * Create the column definition for a char type.
  626. *
  627. * @param \Illuminate\Support\Fluent $column
  628. * @return string
  629. */
  630. protected function typeChar(Fluent $column)
  631. {
  632. return "char({$column->length})";
  633. }
  634. /**
  635. * Create the column definition for a string type.
  636. *
  637. * @param \Illuminate\Support\Fluent $column
  638. * @return string
  639. */
  640. protected function typeString(Fluent $column)
  641. {
  642. return "varchar({$column->length})";
  643. }
  644. /**
  645. * Create the column definition for a tiny text type.
  646. *
  647. * @param \Illuminate\Support\Fluent $column
  648. * @return string
  649. */
  650. protected function typeTinyText(Fluent $column)
  651. {
  652. return 'tinytext';
  653. }
  654. /**
  655. * Create the column definition for a text type.
  656. *
  657. * @param \Illuminate\Support\Fluent $column
  658. * @return string
  659. */
  660. protected function typeText(Fluent $column)
  661. {
  662. return 'text';
  663. }
  664. /**
  665. * Create the column definition for a medium text type.
  666. *
  667. * @param \Illuminate\Support\Fluent $column
  668. * @return string
  669. */
  670. protected function typeMediumText(Fluent $column)
  671. {
  672. return 'mediumtext';
  673. }
  674. /**
  675. * Create the column definition for a long text type.
  676. *
  677. * @param \Illuminate\Support\Fluent $column
  678. * @return string
  679. */
  680. protected function typeLongText(Fluent $column)
  681. {
  682. return 'longtext';
  683. }
  684. /**
  685. * Create the column definition for a big integer type.
  686. *
  687. * @param \Illuminate\Support\Fluent $column
  688. * @return string
  689. */
  690. protected function typeBigInteger(Fluent $column)
  691. {
  692. return 'bigint';
  693. }
  694. /**
  695. * Create the column definition for an integer type.
  696. *
  697. * @param \Illuminate\Support\Fluent $column
  698. * @return string
  699. */
  700. protected function typeInteger(Fluent $column)
  701. {
  702. return 'int';
  703. }
  704. /**
  705. * Create the column definition for a medium integer type.
  706. *
  707. * @param \Illuminate\Support\Fluent $column
  708. * @return string
  709. */
  710. protected function typeMediumInteger(Fluent $column)
  711. {
  712. return 'mediumint';
  713. }
  714. /**
  715. * Create the column definition for a tiny integer type.
  716. *
  717. * @param \Illuminate\Support\Fluent $column
  718. * @return string
  719. */
  720. protected function typeTinyInteger(Fluent $column)
  721. {
  722. return 'tinyint';
  723. }
  724. /**
  725. * Create the column definition for a small integer type.
  726. *
  727. * @param \Illuminate\Support\Fluent $column
  728. * @return string
  729. */
  730. protected function typeSmallInteger(Fluent $column)
  731. {
  732. return 'smallint';
  733. }
  734. /**
  735. * Create the column definition for a float type.
  736. *
  737. * @param \Illuminate\Support\Fluent $column
  738. * @return string
  739. */
  740. protected function typeFloat(Fluent $column)
  741. {
  742. if ($column->precision) {
  743. return "float({$column->precision})";
  744. }
  745. return 'float';
  746. }
  747. /**
  748. * Create the column definition for a double type.
  749. *
  750. * @param \Illuminate\Support\Fluent $column
  751. * @return string
  752. */
  753. protected function typeDouble(Fluent $column)
  754. {
  755. return 'double';
  756. }
  757. /**
  758. * Create the column definition for a decimal type.
  759. *
  760. * @param \Illuminate\Support\Fluent $column
  761. * @return string
  762. */
  763. protected function typeDecimal(Fluent $column)
  764. {
  765. return "decimal({$column->total}, {$column->places})";
  766. }
  767. /**
  768. * Create the column definition for a boolean type.
  769. *
  770. * @param \Illuminate\Support\Fluent $column
  771. * @return string
  772. */
  773. protected function typeBoolean(Fluent $column)
  774. {
  775. return 'tinyint(1)';
  776. }
  777. /**
  778. * Create the column definition for an enumeration type.
  779. *
  780. * @param \Illuminate\Support\Fluent $column
  781. * @return string
  782. */
  783. protected function typeEnum(Fluent $column)
  784. {
  785. return sprintf('enum(%s)', $this->quoteString($column->allowed));
  786. }
  787. /**
  788. * Create the column definition for a set enumeration type.
  789. *
  790. * @param \Illuminate\Support\Fluent $column
  791. * @return string
  792. */
  793. protected function typeSet(Fluent $column)
  794. {
  795. return sprintf('set(%s)', $this->quoteString($column->allowed));
  796. }
  797. /**
  798. * Create the column definition for a json type.
  799. *
  800. * @param \Illuminate\Support\Fluent $column
  801. * @return string
  802. */
  803. protected function typeJson(Fluent $column)
  804. {
  805. return 'json';
  806. }
  807. /**
  808. * Create the column definition for a jsonb type.
  809. *
  810. * @param \Illuminate\Support\Fluent $column
  811. * @return string
  812. */
  813. protected function typeJsonb(Fluent $column)
  814. {
  815. return 'json';
  816. }
  817. /**
  818. * Create the column definition for a date type.
  819. *
  820. * @param \Illuminate\Support\Fluent $column
  821. * @return string
  822. */
  823. protected function typeDate(Fluent $column)
  824. {
  825. return 'date';
  826. }
  827. /**
  828. * Create the column definition for a date-time type.
  829. *
  830. * @param \Illuminate\Support\Fluent $column
  831. * @return string
  832. */
  833. protected function typeDateTime(Fluent $column)
  834. {
  835. $current = $column->precision ? "CURRENT_TIMESTAMP($column->precision)" : 'CURRENT_TIMESTAMP';
  836. if ($column->useCurrent) {
  837. $column->default(new Expression($current));
  838. }
  839. if ($column->useCurrentOnUpdate) {
  840. $column->onUpdate(new Expression($current));
  841. }
  842. return $column->precision ? "datetime($column->precision)" : 'datetime';
  843. }
  844. /**
  845. * Create the column definition for a date-time (with time zone) type.
  846. *
  847. * @param \Illuminate\Support\Fluent $column
  848. * @return string
  849. */
  850. protected function typeDateTimeTz(Fluent $column)
  851. {
  852. return $this->typeDateTime($column);
  853. }
  854. /**
  855. * Create the column definition for a time type.
  856. *
  857. * @param \Illuminate\Support\Fluent $column
  858. * @return string
  859. */
  860. protected function typeTime(Fluent $column)
  861. {
  862. return $column->precision ? "time($column->precision)" : 'time';
  863. }
  864. /**
  865. * Create the column definition for a time (with time zone) type.
  866. *
  867. * @param \Illuminate\Support\Fluent $column
  868. * @return string
  869. */
  870. protected function typeTimeTz(Fluent $column)
  871. {
  872. return $this->typeTime($column);
  873. }
  874. /**
  875. * Create the column definition for a timestamp type.
  876. *
  877. * @param \Illuminate\Support\Fluent $column
  878. * @return string
  879. */
  880. protected function typeTimestamp(Fluent $column)
  881. {
  882. $current = $column->precision ? "CURRENT_TIMESTAMP($column->precision)" : 'CURRENT_TIMESTAMP';
  883. if ($column->useCurrent) {
  884. $column->default(new Expression($current));
  885. }
  886. if ($column->useCurrentOnUpdate) {
  887. $column->onUpdate(new Expression($current));
  888. }
  889. return $column->precision ? "timestamp($column->precision)" : 'timestamp';
  890. }
  891. /**
  892. * Create the column definition for a timestamp (with time zone) type.
  893. *
  894. * @param \Illuminate\Support\Fluent $column
  895. * @return string
  896. */
  897. protected function typeTimestampTz(Fluent $column)
  898. {
  899. return $this->typeTimestamp($column);
  900. }
  901. /**
  902. * Create the column definition for a year type.
  903. *
  904. * @param \Illuminate\Support\Fluent $column
  905. * @return string
  906. */
  907. protected function typeYear(Fluent $column)
  908. {
  909. return 'year';
  910. }
  911. /**
  912. * Create the column definition for a binary type.
  913. *
  914. * @param \Illuminate\Support\Fluent $column
  915. * @return string
  916. */
  917. protected function typeBinary(Fluent $column)
  918. {
  919. if ($column->length) {
  920. return $column->fixed ? "binary({$column->length})" : "varbinary({$column->length})";
  921. }
  922. return 'blob';
  923. }
  924. /**
  925. * Create the column definition for a uuid type.
  926. *
  927. * @param \Illuminate\Support\Fluent $column
  928. * @return string
  929. */
  930. protected function typeUuid(Fluent $column)
  931. {
  932. return 'char(36)';
  933. }
  934. /**
  935. * Create the column definition for an IP address type.
  936. *
  937. * @param \Illuminate\Support\Fluent $column
  938. * @return string
  939. */
  940. protected function typeIpAddress(Fluent $column)
  941. {
  942. return 'varchar(45)';
  943. }
  944. /**
  945. * Create the column definition for a MAC address type.
  946. *
  947. * @param \Illuminate\Support\Fluent $column
  948. * @return string
  949. */
  950. protected function typeMacAddress(Fluent $column)
  951. {
  952. return 'varchar(17)';
  953. }
  954. /**
  955. * Create the column definition for a spatial Geometry type.
  956. *
  957. * @param \Illuminate\Support\Fluent $column
  958. * @return string
  959. */
  960. protected function typeGeometry(Fluent $column)
  961. {
  962. $subtype = $column->subtype ? strtolower($column->subtype) : null;
  963. if (! in_array($subtype, ['point', 'linestring', 'polygon', 'geometrycollection', 'multipoint', 'multilinestring', 'multipolygon'])) {
  964. $subtype = null;
  965. }
  966. return sprintf('%s%s',
  967. $subtype ?? 'geometry',
  968. match (true) {
  969. $column->srid && $this->connection?->isMaria() => ' ref_system_id='.$column->srid,
  970. (bool) $column->srid => ' srid '.$column->srid,
  971. default => '',
  972. }
  973. );
  974. }
  975. /**
  976. * Create the column definition for a spatial Geography type.
  977. *
  978. * @param \Illuminate\Support\Fluent $column
  979. * @return string
  980. */
  981. protected function typeGeography(Fluent $column)
  982. {
  983. return $this->typeGeometry($column);
  984. }
  985. /**
  986. * Create the column definition for a generated, computed column type.
  987. *
  988. * @param \Illuminate\Support\Fluent $column
  989. * @return void
  990. *
  991. * @throws \RuntimeException
  992. */
  993. protected function typeComputed(Fluent $column)
  994. {
  995. throw new RuntimeException('This database driver requires a type, see the virtualAs / storedAs modifiers.');
  996. }
  997. /**
  998. * Get the SQL for a generated virtual column modifier.
  999. *
  1000. * @param \Illuminate\Database\Schema\Blueprint $blueprint
  1001. * @param \Illuminate\Support\Fluent $column
  1002. * @return string|null
  1003. */
  1004. protected function modifyVirtualAs(Blueprint $blueprint, Fluent $column)
  1005. {
  1006. if (! is_null($virtualAs = $column->virtualAsJson)) {
  1007. if ($this->isJsonSelector($virtualAs)) {
  1008. $virtualAs = $this->wrapJsonSelector($virtualAs);
  1009. }
  1010. return " as ({$virtualAs})";
  1011. }
  1012. if (! is_null($virtualAs = $column->virtualAs)) {
  1013. return " as ({$this->getValue($virtualAs)})";
  1014. }
  1015. }
  1016. /**
  1017. * Get the SQL for a generated stored column modifier.
  1018. *
  1019. * @param \Illuminate\Database\Schema\Blueprint $blueprint
  1020. * @param \Illuminate\Support\Fluent $column
  1021. * @return string|null
  1022. */
  1023. protected function modifyStoredAs(Blueprint $blueprint, Fluent $column)
  1024. {
  1025. if (! is_null($storedAs = $column->storedAsJson)) {
  1026. if ($this->isJsonSelector($storedAs)) {
  1027. $storedAs = $this->wrapJsonSelector($storedAs);
  1028. }
  1029. return " as ({$storedAs}) stored";
  1030. }
  1031. if (! is_null($storedAs = $column->storedAs)) {
  1032. return " as ({$this->getValue($storedAs)}) stored";
  1033. }
  1034. }
  1035. /**
  1036. * Get the SQL for an unsigned column modifier.
  1037. *
  1038. * @param \Illuminate\Database\Schema\Blueprint $blueprint
  1039. * @param \Illuminate\Support\Fluent $column
  1040. * @return string|null
  1041. */
  1042. protected function modifyUnsigned(Blueprint $blueprint, Fluent $column)
  1043. {
  1044. if ($column->unsigned) {
  1045. return ' unsigned';
  1046. }
  1047. }
  1048. /**
  1049. * Get the SQL for a character set column modifier.
  1050. *
  1051. * @param \Illuminate\Database\Schema\Blueprint $blueprint
  1052. * @param \Illuminate\Support\Fluent $column
  1053. * @return string|null
  1054. */
  1055. protected function modifyCharset(Blueprint $blueprint, Fluent $column)
  1056. {
  1057. if (! is_null($column->charset)) {
  1058. return ' character set '.$column->charset;
  1059. }
  1060. }
  1061. /**
  1062. * Get the SQL for a collation column modifier.
  1063. *
  1064. * @param \Illuminate\Database\Schema\Blueprint $blueprint
  1065. * @param \Illuminate\Support\Fluent $column
  1066. * @return string|null
  1067. */
  1068. protected function modifyCollate(Blueprint $blueprint, Fluent $column)
  1069. {
  1070. if (! is_null($column->collation)) {
  1071. return " collate '{$column->collation}'";
  1072. }
  1073. }
  1074. /**
  1075. * Get the SQL for a nullable column modifier.
  1076. *
  1077. * @param \Illuminate\Database\Schema\Blueprint $blueprint
  1078. * @param \Illuminate\Support\Fluent $column
  1079. * @return string|null
  1080. */
  1081. protected function modifyNullable(Blueprint $blueprint, Fluent $column)
  1082. {
  1083. if (is_null($column->virtualAs) &&
  1084. is_null($column->virtualAsJson) &&
  1085. is_null($column->storedAs) &&
  1086. is_null($column->storedAsJson)) {
  1087. return $column->nullable ? ' null' : ' not null';
  1088. }
  1089. if ($column->nullable === false) {
  1090. return ' not null';
  1091. }
  1092. }
  1093. /**
  1094. * Get the SQL for an invisible column modifier.
  1095. *
  1096. * @param \Illuminate\Database\Schema\Blueprint $blueprint
  1097. * @param \Illuminate\Support\Fluent $column
  1098. * @return string|null
  1099. */
  1100. protected function modifyInvisible(Blueprint $blueprint, Fluent $column)
  1101. {
  1102. if (! is_null($column->invisible)) {
  1103. return ' invisible';
  1104. }
  1105. }
  1106. /**
  1107. * Get the SQL for a default column modifier.
  1108. *
  1109. * @param \Illuminate\Database\Schema\Blueprint $blueprint
  1110. * @param \Illuminate\Support\Fluent $column
  1111. * @return string|null
  1112. */
  1113. protected function modifyDefault(Blueprint $blueprint, Fluent $column)
  1114. {
  1115. if (! is_null($column->default)) {
  1116. return ' default '.$this->getDefaultValue($column->default);
  1117. }
  1118. }
  1119. /**
  1120. * Get the SQL for an "on update" column modifier.
  1121. *
  1122. * @param \Illuminate\Database\Schema\Blueprint $blueprint
  1123. * @param \Illuminate\Support\Fluent $column
  1124. * @return string|null
  1125. */
  1126. protected function modifyOnUpdate(Blueprint $blueprint, Fluent $column)
  1127. {
  1128. if (! is_null($column->onUpdate)) {
  1129. return ' on update '.$this->getValue($column->onUpdate);
  1130. }
  1131. }
  1132. /**
  1133. * Get the SQL for an auto-increment column modifier.
  1134. *
  1135. * @param \Illuminate\Database\Schema\Blueprint $blueprint
  1136. * @param \Illuminate\Support\Fluent $column
  1137. * @return string|null
  1138. */
  1139. protected function modifyIncrement(Blueprint $blueprint, Fluent $column)
  1140. {
  1141. if (in_array($column->type, $this->serials) && $column->autoIncrement) {
  1142. return $this->hasCommand($blueprint, 'primary') || ($column->change && ! $column->primary)
  1143. ? ' auto_increment'
  1144. : ' auto_increment primary key';
  1145. }
  1146. }
  1147. /**
  1148. * Get the SQL for a "first" column modifier.
  1149. *
  1150. * @param \Illuminate\Database\Schema\Blueprint $blueprint
  1151. * @param \Illuminate\Support\Fluent $column
  1152. * @return string|null
  1153. */
  1154. protected function modifyFirst(Blueprint $blueprint, Fluent $column)
  1155. {
  1156. if (! is_null($column->first)) {
  1157. return ' first';
  1158. }
  1159. }
  1160. /**
  1161. * Get the SQL for an "after" column modifier.
  1162. *
  1163. * @param \Illuminate\Database\Schema\Blueprint $blueprint
  1164. * @param \Illuminate\Support\Fluent $column
  1165. * @return string|null
  1166. */
  1167. protected function modifyAfter(Blueprint $blueprint, Fluent $column)
  1168. {
  1169. if (! is_null($column->after)) {
  1170. return ' after '.$this->wrap($column->after);
  1171. }
  1172. }
  1173. /**
  1174. * Get the SQL for a "comment" column modifier.
  1175. *
  1176. * @param \Illuminate\Database\Schema\Blueprint $blueprint
  1177. * @param \Illuminate\Support\Fluent $column
  1178. * @return string|null
  1179. */
  1180. protected function modifyComment(Blueprint $blueprint, Fluent $column)
  1181. {
  1182. if (! is_null($column->comment)) {
  1183. return " comment '".addslashes($column->comment)."'";
  1184. }
  1185. }
  1186. /**
  1187. * Wrap a single string in keyword identifiers.
  1188. *
  1189. * @param string $value
  1190. * @return string
  1191. */
  1192. protected function wrapValue($value)
  1193. {
  1194. if ($value !== '*') {
  1195. return '`'.str_replace('`', '``', $value).'`';
  1196. }
  1197. return $value;
  1198. }
  1199. /**
  1200. * Wrap the given JSON selector.
  1201. *
  1202. * @param string $value
  1203. * @return string
  1204. */
  1205. protected function wrapJsonSelector($value)
  1206. {
  1207. [$field, $path] = $this->wrapJsonFieldAndPath($value);
  1208. return 'json_unquote(json_extract('.$field.$path.'))';
  1209. }
  1210. }