PostgresGrammar.php 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802
  1. <?php
  2. namespace Illuminate\Database\Schema\Grammars;
  3. use RuntimeException;
  4. use Illuminate\Support\Fluent;
  5. use Illuminate\Database\Schema\Blueprint;
  6. class PostgresGrammar extends Grammar
  7. {
  8. /**
  9. * If this Grammar supports schema changes wrapped in a transaction.
  10. *
  11. * @var bool
  12. */
  13. protected $transactions = true;
  14. /**
  15. * The possible column modifiers.
  16. *
  17. * @var array
  18. */
  19. protected $modifiers = ['Increment', 'Nullable', 'Default'];
  20. /**
  21. * The columns available as serials.
  22. *
  23. * @var array
  24. */
  25. protected $serials = ['bigInteger', 'integer', 'mediumInteger', 'smallInteger', 'tinyInteger'];
  26. /**
  27. * Compile the query to determine if a table exists.
  28. *
  29. * @return string
  30. */
  31. public function compileTableExists()
  32. {
  33. return 'select * from information_schema.tables where table_schema = ? and table_name = ?';
  34. }
  35. /**
  36. * Compile the query to determine the list of columns.
  37. *
  38. * @return string
  39. */
  40. public function compileColumnListing()
  41. {
  42. return 'select column_name from information_schema.columns where table_schema = ? and table_name = ?';
  43. }
  44. /**
  45. * Compile a create table command.
  46. *
  47. * @param \Illuminate\Database\Schema\Blueprint $blueprint
  48. * @param \Illuminate\Support\Fluent $command
  49. * @return string
  50. */
  51. public function compileCreate(Blueprint $blueprint, Fluent $command)
  52. {
  53. return sprintf('%s table %s (%s)',
  54. $blueprint->temporary ? 'create temporary' : 'create',
  55. $this->wrapTable($blueprint),
  56. implode(', ', $this->getColumns($blueprint))
  57. );
  58. }
  59. /**
  60. * Compile a column addition command.
  61. *
  62. * @param \Illuminate\Database\Schema\Blueprint $blueprint
  63. * @param \Illuminate\Support\Fluent $command
  64. * @return string
  65. */
  66. public function compileAdd(Blueprint $blueprint, Fluent $command)
  67. {
  68. return sprintf('alter table %s %s',
  69. $this->wrapTable($blueprint),
  70. implode(', ', $this->prefixArray('add column', $this->getColumns($blueprint)))
  71. );
  72. }
  73. /**
  74. * Compile a primary key command.
  75. *
  76. * @param \Illuminate\Database\Schema\Blueprint $blueprint
  77. * @param \Illuminate\Support\Fluent $command
  78. * @return string
  79. */
  80. public function compilePrimary(Blueprint $blueprint, Fluent $command)
  81. {
  82. $columns = $this->columnize($command->columns);
  83. return 'alter table '.$this->wrapTable($blueprint)." add primary key ({$columns})";
  84. }
  85. /**
  86. * Compile a unique key command.
  87. *
  88. * @param \Illuminate\Database\Schema\Blueprint $blueprint
  89. * @param \Illuminate\Support\Fluent $command
  90. * @return string
  91. */
  92. public function compileUnique(Blueprint $blueprint, Fluent $command)
  93. {
  94. return sprintf('alter table %s add constraint %s unique (%s)',
  95. $this->wrapTable($blueprint),
  96. $this->wrap($command->index),
  97. $this->columnize($command->columns)
  98. );
  99. }
  100. /**
  101. * Compile a plain index key command.
  102. *
  103. * @param \Illuminate\Database\Schema\Blueprint $blueprint
  104. * @param \Illuminate\Support\Fluent $command
  105. * @return string
  106. */
  107. public function compileIndex(Blueprint $blueprint, Fluent $command)
  108. {
  109. return sprintf('create index %s on %s%s (%s)',
  110. $this->wrap($command->index),
  111. $this->wrapTable($blueprint),
  112. $command->algorithm ? ' using '.$command->algorithm : '',
  113. $this->columnize($command->columns)
  114. );
  115. }
  116. /**
  117. * Compile a spatial index key command.
  118. *
  119. * @param \Illuminate\Database\Schema\Blueprint $blueprint
  120. * @param \Illuminate\Support\Fluent $command
  121. * @return string
  122. */
  123. public function compileSpatialIndex(Blueprint $blueprint, Fluent $command)
  124. {
  125. $command->algorithm = 'gist';
  126. return $this->compileIndex($blueprint, $command);
  127. }
  128. /**
  129. * Compile a foreign key command.
  130. *
  131. * @param \Illuminate\Database\Schema\Blueprint $blueprint
  132. * @param \Illuminate\Support\Fluent $command
  133. * @return string
  134. */
  135. public function compileForeign(Blueprint $blueprint, Fluent $command)
  136. {
  137. $sql = parent::compileForeign($blueprint, $command);
  138. if (! is_null($command->deferrable)) {
  139. $sql .= $command->deferrable ? ' deferrable' : ' not deferrable';
  140. }
  141. if ($command->deferrable && ! is_null($command->initiallyImmediate)) {
  142. $sql .= $command->initiallyImmediate ? ' initially immediate' : ' initially deferred';
  143. }
  144. return $sql;
  145. }
  146. /**
  147. * Compile a drop table command.
  148. *
  149. * @param \Illuminate\Database\Schema\Blueprint $blueprint
  150. * @param \Illuminate\Support\Fluent $command
  151. * @return string
  152. */
  153. public function compileDrop(Blueprint $blueprint, Fluent $command)
  154. {
  155. return 'drop table '.$this->wrapTable($blueprint);
  156. }
  157. /**
  158. * Compile a drop table (if exists) command.
  159. *
  160. * @param \Illuminate\Database\Schema\Blueprint $blueprint
  161. * @param \Illuminate\Support\Fluent $command
  162. * @return string
  163. */
  164. public function compileDropIfExists(Blueprint $blueprint, Fluent $command)
  165. {
  166. return 'drop table if exists '.$this->wrapTable($blueprint);
  167. }
  168. /**
  169. * Compile the SQL needed to drop all tables.
  170. *
  171. * @param string $tables
  172. * @return string
  173. */
  174. public function compileDropAllTables($tables)
  175. {
  176. return 'drop table "'.implode('","', $tables).'" cascade';
  177. }
  178. /**
  179. * Compile the SQL needed to retrieve all table names.
  180. *
  181. * @param string $schema
  182. * @return string
  183. */
  184. public function compileGetAllTables($schema)
  185. {
  186. return "select tablename from pg_catalog.pg_tables where schemaname = '{$schema}'";
  187. }
  188. /**
  189. * Compile a drop column command.
  190. *
  191. * @param \Illuminate\Database\Schema\Blueprint $blueprint
  192. * @param \Illuminate\Support\Fluent $command
  193. * @return string
  194. */
  195. public function compileDropColumn(Blueprint $blueprint, Fluent $command)
  196. {
  197. $columns = $this->prefixArray('drop column', $this->wrapArray($command->columns));
  198. return 'alter table '.$this->wrapTable($blueprint).' '.implode(', ', $columns);
  199. }
  200. /**
  201. * Compile a drop primary key command.
  202. *
  203. * @param \Illuminate\Database\Schema\Blueprint $blueprint
  204. * @param \Illuminate\Support\Fluent $command
  205. * @return string
  206. */
  207. public function compileDropPrimary(Blueprint $blueprint, Fluent $command)
  208. {
  209. $index = $this->wrap("{$blueprint->getTable()}_pkey");
  210. return 'alter table '.$this->wrapTable($blueprint)." drop constraint {$index}";
  211. }
  212. /**
  213. * Compile a drop unique key command.
  214. *
  215. * @param \Illuminate\Database\Schema\Blueprint $blueprint
  216. * @param \Illuminate\Support\Fluent $command
  217. * @return string
  218. */
  219. public function compileDropUnique(Blueprint $blueprint, Fluent $command)
  220. {
  221. $index = $this->wrap($command->index);
  222. return "alter table {$this->wrapTable($blueprint)} drop constraint {$index}";
  223. }
  224. /**
  225. * Compile a drop index command.
  226. *
  227. * @param \Illuminate\Database\Schema\Blueprint $blueprint
  228. * @param \Illuminate\Support\Fluent $command
  229. * @return string
  230. */
  231. public function compileDropIndex(Blueprint $blueprint, Fluent $command)
  232. {
  233. return "drop index {$this->wrap($command->index)}";
  234. }
  235. /**
  236. * Compile a drop spatial index command.
  237. *
  238. * @param \Illuminate\Database\Schema\Blueprint $blueprint
  239. * @param \Illuminate\Support\Fluent $command
  240. * @return string
  241. */
  242. public function compileDropSpatialIndex(Blueprint $blueprint, Fluent $command)
  243. {
  244. return $this->compileDropIndex($blueprint, $command);
  245. }
  246. /**
  247. * Compile a drop foreign key command.
  248. *
  249. * @param \Illuminate\Database\Schema\Blueprint $blueprint
  250. * @param \Illuminate\Support\Fluent $command
  251. * @return string
  252. */
  253. public function compileDropForeign(Blueprint $blueprint, Fluent $command)
  254. {
  255. $index = $this->wrap($command->index);
  256. return "alter table {$this->wrapTable($blueprint)} drop constraint {$index}";
  257. }
  258. /**
  259. * Compile a rename table command.
  260. *
  261. * @param \Illuminate\Database\Schema\Blueprint $blueprint
  262. * @param \Illuminate\Support\Fluent $command
  263. * @return string
  264. */
  265. public function compileRename(Blueprint $blueprint, Fluent $command)
  266. {
  267. $from = $this->wrapTable($blueprint);
  268. return "alter table {$from} rename to ".$this->wrapTable($command->to);
  269. }
  270. /**
  271. * Compile the command to enable foreign key constraints.
  272. *
  273. * @return string
  274. */
  275. public function compileEnableForeignKeyConstraints()
  276. {
  277. return 'SET CONSTRAINTS ALL IMMEDIATE;';
  278. }
  279. /**
  280. * Compile the command to disable foreign key constraints.
  281. *
  282. * @return string
  283. */
  284. public function compileDisableForeignKeyConstraints()
  285. {
  286. return 'SET CONSTRAINTS ALL DEFERRED;';
  287. }
  288. /**
  289. * Create the column definition for a char type.
  290. *
  291. * @param \Illuminate\Support\Fluent $column
  292. * @return string
  293. */
  294. protected function typeChar(Fluent $column)
  295. {
  296. return "char({$column->length})";
  297. }
  298. /**
  299. * Create the column definition for a string type.
  300. *
  301. * @param \Illuminate\Support\Fluent $column
  302. * @return string
  303. */
  304. protected function typeString(Fluent $column)
  305. {
  306. return "varchar({$column->length})";
  307. }
  308. /**
  309. * Create the column definition for a text type.
  310. *
  311. * @param \Illuminate\Support\Fluent $column
  312. * @return string
  313. */
  314. protected function typeText(Fluent $column)
  315. {
  316. return 'text';
  317. }
  318. /**
  319. * Create the column definition for a medium text type.
  320. *
  321. * @param \Illuminate\Support\Fluent $column
  322. * @return string
  323. */
  324. protected function typeMediumText(Fluent $column)
  325. {
  326. return 'text';
  327. }
  328. /**
  329. * Create the column definition for a long text type.
  330. *
  331. * @param \Illuminate\Support\Fluent $column
  332. * @return string
  333. */
  334. protected function typeLongText(Fluent $column)
  335. {
  336. return 'text';
  337. }
  338. /**
  339. * Create the column definition for an integer type.
  340. *
  341. * @param \Illuminate\Support\Fluent $column
  342. * @return string
  343. */
  344. protected function typeInteger(Fluent $column)
  345. {
  346. return $column->autoIncrement ? 'serial' : 'integer';
  347. }
  348. /**
  349. * Create the column definition for a big integer type.
  350. *
  351. * @param \Illuminate\Support\Fluent $column
  352. * @return string
  353. */
  354. protected function typeBigInteger(Fluent $column)
  355. {
  356. return $column->autoIncrement ? 'bigserial' : 'bigint';
  357. }
  358. /**
  359. * Create the column definition for a medium integer type.
  360. *
  361. * @param \Illuminate\Support\Fluent $column
  362. * @return string
  363. */
  364. protected function typeMediumInteger(Fluent $column)
  365. {
  366. return $column->autoIncrement ? 'serial' : 'integer';
  367. }
  368. /**
  369. * Create the column definition for a tiny integer type.
  370. *
  371. * @param \Illuminate\Support\Fluent $column
  372. * @return string
  373. */
  374. protected function typeTinyInteger(Fluent $column)
  375. {
  376. return $column->autoIncrement ? 'smallserial' : 'smallint';
  377. }
  378. /**
  379. * Create the column definition for a small integer type.
  380. *
  381. * @param \Illuminate\Support\Fluent $column
  382. * @return string
  383. */
  384. protected function typeSmallInteger(Fluent $column)
  385. {
  386. return $column->autoIncrement ? 'smallserial' : 'smallint';
  387. }
  388. /**
  389. * Create the column definition for a float type.
  390. *
  391. * @param \Illuminate\Support\Fluent $column
  392. * @return string
  393. */
  394. protected function typeFloat(Fluent $column)
  395. {
  396. return $this->typeDouble($column);
  397. }
  398. /**
  399. * Create the column definition for a double type.
  400. *
  401. * @param \Illuminate\Support\Fluent $column
  402. * @return string
  403. */
  404. protected function typeDouble(Fluent $column)
  405. {
  406. return 'double precision';
  407. }
  408. /**
  409. * Create the column definition for a real type.
  410. *
  411. * @param \Illuminate\Support\Fluent $column
  412. * @return string
  413. */
  414. protected function typeReal(Fluent $column)
  415. {
  416. return 'real';
  417. }
  418. /**
  419. * Create the column definition for a decimal type.
  420. *
  421. * @param \Illuminate\Support\Fluent $column
  422. * @return string
  423. */
  424. protected function typeDecimal(Fluent $column)
  425. {
  426. return "decimal({$column->total}, {$column->places})";
  427. }
  428. /**
  429. * Create the column definition for a boolean type.
  430. *
  431. * @param \Illuminate\Support\Fluent $column
  432. * @return string
  433. */
  434. protected function typeBoolean(Fluent $column)
  435. {
  436. return 'boolean';
  437. }
  438. /**
  439. * Create the column definition for an enum type.
  440. *
  441. * @param \Illuminate\Support\Fluent $column
  442. * @return string
  443. */
  444. protected function typeEnum(Fluent $column)
  445. {
  446. $allowed = array_map(function ($a) {
  447. return "'{$a}'";
  448. }, $column->allowed);
  449. return "varchar(255) check (\"{$column->name}\" in (".implode(', ', $allowed).'))';
  450. }
  451. /**
  452. * Create the column definition for a json type.
  453. *
  454. * @param \Illuminate\Support\Fluent $column
  455. * @return string
  456. */
  457. protected function typeJson(Fluent $column)
  458. {
  459. return 'json';
  460. }
  461. /**
  462. * Create the column definition for a jsonb type.
  463. *
  464. * @param \Illuminate\Support\Fluent $column
  465. * @return string
  466. */
  467. protected function typeJsonb(Fluent $column)
  468. {
  469. return 'jsonb';
  470. }
  471. /**
  472. * Create the column definition for a date type.
  473. *
  474. * @param \Illuminate\Support\Fluent $column
  475. * @return string
  476. */
  477. protected function typeDate(Fluent $column)
  478. {
  479. return 'date';
  480. }
  481. /**
  482. * Create the column definition for a date-time type.
  483. *
  484. * @param \Illuminate\Support\Fluent $column
  485. * @return string
  486. */
  487. protected function typeDateTime(Fluent $column)
  488. {
  489. return "timestamp($column->precision) without time zone";
  490. }
  491. /**
  492. * Create the column definition for a date-time (with time zone) type.
  493. *
  494. * @param \Illuminate\Support\Fluent $column
  495. * @return string
  496. */
  497. protected function typeDateTimeTz(Fluent $column)
  498. {
  499. return "timestamp($column->precision) with time zone";
  500. }
  501. /**
  502. * Create the column definition for a time type.
  503. *
  504. * @param \Illuminate\Support\Fluent $column
  505. * @return string
  506. */
  507. protected function typeTime(Fluent $column)
  508. {
  509. return "time($column->precision) without time zone";
  510. }
  511. /**
  512. * Create the column definition for a time (with time zone) type.
  513. *
  514. * @param \Illuminate\Support\Fluent $column
  515. * @return string
  516. */
  517. protected function typeTimeTz(Fluent $column)
  518. {
  519. return "time($column->precision) with time zone";
  520. }
  521. /**
  522. * Create the column definition for a timestamp type.
  523. *
  524. * @param \Illuminate\Support\Fluent $column
  525. * @return string
  526. */
  527. protected function typeTimestamp(Fluent $column)
  528. {
  529. $columnType = "timestamp($column->precision) without time zone";
  530. return $column->useCurrent ? "$columnType default CURRENT_TIMESTAMP" : $columnType;
  531. }
  532. /**
  533. * Create the column definition for a timestamp (with time zone) type.
  534. *
  535. * @param \Illuminate\Support\Fluent $column
  536. * @return string
  537. */
  538. protected function typeTimestampTz(Fluent $column)
  539. {
  540. $columnType = "timestamp($column->precision) with time zone";
  541. return $column->useCurrent ? "$columnType default CURRENT_TIMESTAMP" : $columnType;
  542. }
  543. /**
  544. * Create the column definition for a year type.
  545. *
  546. * @param \Illuminate\Support\Fluent $column
  547. * @return string
  548. */
  549. protected function typeYear(Fluent $column)
  550. {
  551. return $this->typeInteger($column);
  552. }
  553. /**
  554. * Create the column definition for a binary type.
  555. *
  556. * @param \Illuminate\Support\Fluent $column
  557. * @return string
  558. */
  559. protected function typeBinary(Fluent $column)
  560. {
  561. return 'bytea';
  562. }
  563. /**
  564. * Create the column definition for a uuid type.
  565. *
  566. * @param \Illuminate\Support\Fluent $column
  567. * @return string
  568. */
  569. protected function typeUuid(Fluent $column)
  570. {
  571. return 'uuid';
  572. }
  573. /**
  574. * Create the column definition for an IP address type.
  575. *
  576. * @param \Illuminate\Support\Fluent $column
  577. * @return string
  578. */
  579. protected function typeIpAddress(Fluent $column)
  580. {
  581. return 'inet';
  582. }
  583. /**
  584. * Create the column definition for a MAC address type.
  585. *
  586. * @param \Illuminate\Support\Fluent $column
  587. * @return string
  588. */
  589. protected function typeMacAddress(Fluent $column)
  590. {
  591. return 'macaddr';
  592. }
  593. /**
  594. * Create the column definition for a spatial Geometry type.
  595. *
  596. * @param \Illuminate\Support\Fluent $column
  597. * @throws \RuntimeException
  598. */
  599. protected function typeGeometry(Fluent $column)
  600. {
  601. throw new RuntimeException('The database driver in use does not support the Geometry spatial column type.');
  602. }
  603. /**
  604. * Create the column definition for a spatial Point type.
  605. *
  606. * @param \Illuminate\Support\Fluent $column
  607. * @return string
  608. */
  609. protected function typePoint(Fluent $column)
  610. {
  611. return $this->formatPostGisType('point');
  612. }
  613. /**
  614. * Create the column definition for a spatial LineString type.
  615. *
  616. * @param \Illuminate\Support\Fluent $column
  617. * @return string
  618. */
  619. protected function typeLineString(Fluent $column)
  620. {
  621. return $this->formatPostGisType('linestring');
  622. }
  623. /**
  624. * Create the column definition for a spatial Polygon type.
  625. *
  626. * @param \Illuminate\Support\Fluent $column
  627. * @return string
  628. */
  629. protected function typePolygon(Fluent $column)
  630. {
  631. return $this->formatPostGisType('polygon');
  632. }
  633. /**
  634. * Create the column definition for a spatial GeometryCollection type.
  635. *
  636. * @param \Illuminate\Support\Fluent $column
  637. * @return string
  638. */
  639. protected function typeGeometryCollection(Fluent $column)
  640. {
  641. return $this->formatPostGisType('geometrycollection');
  642. }
  643. /**
  644. * Create the column definition for a spatial MultiPoint type.
  645. *
  646. * @param \Illuminate\Support\Fluent $column
  647. * @return string
  648. */
  649. protected function typeMultiPoint(Fluent $column)
  650. {
  651. return $this->formatPostGisType('multipoint');
  652. }
  653. /**
  654. * Create the column definition for a spatial MultiLineString type.
  655. *
  656. * @param \Illuminate\Support\Fluent $column
  657. * @return string
  658. */
  659. public function typeMultiLineString(Fluent $column)
  660. {
  661. return $this->formatPostGisType('multilinestring');
  662. }
  663. /**
  664. * Create the column definition for a spatial MultiPolygon type.
  665. *
  666. * @param \Illuminate\Support\Fluent $column
  667. * @return string
  668. */
  669. protected function typeMultiPolygon(Fluent $column)
  670. {
  671. return $this->formatPostGisType('multipolygon');
  672. }
  673. /**
  674. * Format the column definition for a PostGIS spatial type.
  675. *
  676. * @param string $type
  677. * @return string
  678. */
  679. private function formatPostGisType(string $type)
  680. {
  681. return "geography($type, 4326)";
  682. }
  683. /**
  684. * Get the SQL for a nullable column modifier.
  685. *
  686. * @param \Illuminate\Database\Schema\Blueprint $blueprint
  687. * @param \Illuminate\Support\Fluent $column
  688. * @return string|null
  689. */
  690. protected function modifyNullable(Blueprint $blueprint, Fluent $column)
  691. {
  692. return $column->nullable ? ' null' : ' not null';
  693. }
  694. /**
  695. * Get the SQL for a default column modifier.
  696. *
  697. * @param \Illuminate\Database\Schema\Blueprint $blueprint
  698. * @param \Illuminate\Support\Fluent $column
  699. * @return string|null
  700. */
  701. protected function modifyDefault(Blueprint $blueprint, Fluent $column)
  702. {
  703. if (! is_null($column->default)) {
  704. return ' default '.$this->getDefaultValue($column->default);
  705. }
  706. }
  707. /**
  708. * Get the SQL for an auto-increment column modifier.
  709. *
  710. * @param \Illuminate\Database\Schema\Blueprint $blueprint
  711. * @param \Illuminate\Support\Fluent $column
  712. * @return string|null
  713. */
  714. protected function modifyIncrement(Blueprint $blueprint, Fluent $column)
  715. {
  716. if (in_array($column->type, $this->serials) && $column->autoIncrement) {
  717. return ' primary key';
  718. }
  719. }
  720. }