SQLiteGrammar.php 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. <?php
  2. namespace Illuminate\Database\Query\Grammars;
  3. use Illuminate\Support\Arr;
  4. use Illuminate\Support\Str;
  5. use Illuminate\Database\Query\Builder;
  6. class SQLiteGrammar extends Grammar
  7. {
  8. /**
  9. * The components that make up a select clause.
  10. *
  11. * @var array
  12. */
  13. protected $selectComponents = [
  14. 'aggregate',
  15. 'columns',
  16. 'from',
  17. 'joins',
  18. 'wheres',
  19. 'groups',
  20. 'havings',
  21. 'orders',
  22. 'limit',
  23. 'offset',
  24. 'lock',
  25. ];
  26. /**
  27. * All of the available clause operators.
  28. *
  29. * @var array
  30. */
  31. protected $operators = [
  32. '=', '<', '>', '<=', '>=', '<>', '!=',
  33. 'like', 'not like', 'ilike',
  34. '&', '|', '<<', '>>',
  35. ];
  36. /**
  37. * Compile a select query into SQL.
  38. *
  39. * @param \Illuminate\Database\Query\Builder $query
  40. * @return string
  41. */
  42. public function compileSelect(Builder $query)
  43. {
  44. if ($query->unions && $query->aggregate) {
  45. return $this->compileUnionAggregate($query);
  46. }
  47. $sql = parent::compileSelect($query);
  48. if ($query->unions) {
  49. $sql = 'select * from ('.$sql.') '.$this->compileUnions($query);
  50. }
  51. return $sql;
  52. }
  53. /**
  54. * Compile a single union statement.
  55. *
  56. * @param array $union
  57. * @return string
  58. */
  59. protected function compileUnion(array $union)
  60. {
  61. $conjunction = $union['all'] ? ' union all ' : ' union ';
  62. return $conjunction.'select * from ('.$union['query']->toSql().')';
  63. }
  64. /**
  65. * Compile a "where date" clause.
  66. *
  67. * @param \Illuminate\Database\Query\Builder $query
  68. * @param array $where
  69. * @return string
  70. */
  71. protected function whereDate(Builder $query, $where)
  72. {
  73. return $this->dateBasedWhere('%Y-%m-%d', $query, $where);
  74. }
  75. /**
  76. * Compile a "where day" clause.
  77. *
  78. * @param \Illuminate\Database\Query\Builder $query
  79. * @param array $where
  80. * @return string
  81. */
  82. protected function whereDay(Builder $query, $where)
  83. {
  84. return $this->dateBasedWhere('%d', $query, $where);
  85. }
  86. /**
  87. * Compile a "where month" clause.
  88. *
  89. * @param \Illuminate\Database\Query\Builder $query
  90. * @param array $where
  91. * @return string
  92. */
  93. protected function whereMonth(Builder $query, $where)
  94. {
  95. return $this->dateBasedWhere('%m', $query, $where);
  96. }
  97. /**
  98. * Compile a "where year" clause.
  99. *
  100. * @param \Illuminate\Database\Query\Builder $query
  101. * @param array $where
  102. * @return string
  103. */
  104. protected function whereYear(Builder $query, $where)
  105. {
  106. return $this->dateBasedWhere('%Y', $query, $where);
  107. }
  108. /**
  109. * Compile a "where time" clause.
  110. *
  111. * @param \Illuminate\Database\Query\Builder $query
  112. * @param array $where
  113. * @return string
  114. */
  115. protected function whereTime(Builder $query, $where)
  116. {
  117. return $this->dateBasedWhere('%H:%M:%S', $query, $where);
  118. }
  119. /**
  120. * Compile a date based where clause.
  121. *
  122. * @param string $type
  123. * @param \Illuminate\Database\Query\Builder $query
  124. * @param array $where
  125. * @return string
  126. */
  127. protected function dateBasedWhere($type, Builder $query, $where)
  128. {
  129. $value = $this->parameter($where['value']);
  130. return "strftime('{$type}', {$this->wrap($where['column'])}) {$where['operator']} cast({$value} as text)";
  131. }
  132. /**
  133. * Compile a "JSON length" statement into SQL.
  134. *
  135. * @param string $column
  136. * @param string $operator
  137. * @param string $value
  138. * @return string
  139. */
  140. protected function compileJsonLength($column, $operator, $value)
  141. {
  142. [$field, $path] = $this->wrapJsonFieldAndPath($column);
  143. return 'json_array_length('.$field.$path.') '.$operator.' '.$value;
  144. }
  145. /**
  146. * Compile an insert statement into SQL.
  147. *
  148. * @param \Illuminate\Database\Query\Builder $query
  149. * @param array $values
  150. * @return string
  151. */
  152. public function compileInsert(Builder $query, array $values)
  153. {
  154. $table = $this->wrapTable($query->from);
  155. return empty($values)
  156. ? "insert into {$table} DEFAULT VALUES"
  157. : parent::compileInsert($query, $values);
  158. }
  159. /**
  160. * Compile an insert ignore statement into SQL.
  161. *
  162. * @param \Illuminate\Database\Query\Builder $query
  163. * @param array $values
  164. * @return string
  165. */
  166. public function compileInsertOrIgnore(Builder $query, array $values)
  167. {
  168. return Str::replaceFirst('insert', 'insert or ignore', $this->compileInsert($query, $values));
  169. }
  170. /**
  171. * Compile an update statement into SQL.
  172. *
  173. * @param \Illuminate\Database\Query\Builder $query
  174. * @param array $values
  175. * @return string
  176. */
  177. public function compileUpdate(Builder $query, $values)
  178. {
  179. $table = $this->wrapTable($query->from);
  180. $columns = collect($values)->map(function ($value, $key) {
  181. return $this->wrap(Str::after($key, '.')).' = '.$this->parameter($value);
  182. })->implode(', ');
  183. if (isset($query->joins) || isset($query->limit)) {
  184. return $this->compileUpdateWithJoinsOrLimit($query, $columns);
  185. }
  186. return trim("update {$table} set {$columns} {$this->compileWheres($query)}");
  187. }
  188. /**
  189. * Compile an update statement with joins or limit into SQL.
  190. *
  191. * @param \Illuminate\Database\Query\Builder $query
  192. * @param string $columns
  193. * @return string
  194. */
  195. protected function compileUpdateWithJoinsOrLimit(Builder $query, $columns)
  196. {
  197. $segments = preg_split('/\s+as\s+/i', $query->from);
  198. $alias = $segments[1] ?? $segments[0];
  199. $selectSql = parent::compileSelect($query->select($alias.'.rowid'));
  200. return "update {$this->wrapTable($query->from)} set {$columns} where {$this->wrap('rowid')} in ({$selectSql})";
  201. }
  202. /**
  203. * Prepare the bindings for an update statement.
  204. *
  205. * @param array $bindings
  206. * @param array $values
  207. * @return array
  208. */
  209. public function prepareBindingsForUpdate(array $bindings, array $values)
  210. {
  211. $cleanBindings = Arr::except($bindings, 'select');
  212. return array_values(
  213. array_merge($values, Arr::flatten($cleanBindings))
  214. );
  215. }
  216. /**
  217. * Compile a delete statement into SQL.
  218. *
  219. * @param \Illuminate\Database\Query\Builder $query
  220. * @return string
  221. */
  222. public function compileDelete(Builder $query)
  223. {
  224. if (isset($query->joins) || isset($query->limit)) {
  225. return $this->compileDeleteWithJoinsOrLimit($query);
  226. }
  227. $wheres = is_array($query->wheres) ? $this->compileWheres($query) : '';
  228. return trim("delete from {$this->wrapTable($query->from)} $wheres");
  229. }
  230. /**
  231. * Compile a delete statement with joins or limit into SQL.
  232. *
  233. * @param \Illuminate\Database\Query\Builder $query
  234. * @return string
  235. */
  236. protected function compileDeleteWithJoinsOrLimit(Builder $query)
  237. {
  238. $segments = preg_split('/\s+as\s+/i', $query->from);
  239. $alias = $segments[1] ?? $segments[0];
  240. $selectSql = parent::compileSelect($query->select($alias.'.rowid'));
  241. return "delete from {$this->wrapTable($query->from)} where {$this->wrap('rowid')} in ({$selectSql})";
  242. }
  243. /**
  244. * Compile a truncate table statement into SQL.
  245. *
  246. * @param \Illuminate\Database\Query\Builder $query
  247. * @return array
  248. */
  249. public function compileTruncate(Builder $query)
  250. {
  251. return [
  252. 'delete from sqlite_sequence where name = ?' => [$query->from],
  253. 'delete from '.$this->wrapTable($query->from) => [],
  254. ];
  255. }
  256. /**
  257. * Wrap the given JSON selector.
  258. *
  259. * @param string $value
  260. * @return string
  261. */
  262. protected function wrapJsonSelector($value)
  263. {
  264. [$field, $path] = $this->wrapJsonFieldAndPath($value);
  265. return 'json_extract('.$field.$path.')';
  266. }
  267. }