SqliteDialectTrait.php 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. <?php
  2. /**
  3. * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
  4. * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
  5. *
  6. * Licensed under The MIT License
  7. * For full copyright and license information, please see the LICENSE.txt
  8. * Redistributions of files must retain the above copyright notice.
  9. *
  10. * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
  11. * @link https://cakephp.org CakePHP(tm) Project
  12. * @since 3.0.0
  13. * @license https://opensource.org/licenses/mit-license.php MIT License
  14. */
  15. namespace Cake\Database\Dialect;
  16. use Cake\Database\Expression\FunctionExpression;
  17. use Cake\Database\Schema\SqliteSchema;
  18. use Cake\Database\SqlDialectTrait;
  19. use Cake\Database\SqliteCompiler;
  20. /**
  21. * SQLite dialect trait
  22. *
  23. * @internal
  24. */
  25. trait SqliteDialectTrait
  26. {
  27. use SqlDialectTrait;
  28. use TupleComparisonTranslatorTrait;
  29. /**
  30. * String used to start a database identifier quoting to make it safe
  31. *
  32. * @var string
  33. */
  34. protected $_startQuote = '"';
  35. /**
  36. * String used to end a database identifier quoting to make it safe
  37. *
  38. * @var string
  39. */
  40. protected $_endQuote = '"';
  41. /**
  42. * The schema dialect class for this driver
  43. *
  44. * @var \Cake\Database\Schema\SqliteSchema
  45. */
  46. protected $_schemaDialect;
  47. /**
  48. * Mapping of date parts.
  49. *
  50. * @var array
  51. */
  52. protected $_dateParts = [
  53. 'day' => 'd',
  54. 'hour' => 'H',
  55. 'month' => 'm',
  56. 'minute' => 'M',
  57. 'second' => 'S',
  58. 'week' => 'W',
  59. 'year' => 'Y'
  60. ];
  61. /**
  62. * Returns a dictionary of expressions to be transformed when compiling a Query
  63. * to SQL. Array keys are method names to be called in this class
  64. *
  65. * @return array
  66. */
  67. protected function _expressionTranslators()
  68. {
  69. $namespace = 'Cake\Database\Expression';
  70. return [
  71. $namespace . '\FunctionExpression' => '_transformFunctionExpression',
  72. $namespace . '\TupleComparison' => '_transformTupleComparison'
  73. ];
  74. }
  75. /**
  76. * Receives a FunctionExpression and changes it so that it conforms to this
  77. * SQL dialect.
  78. *
  79. * @param \Cake\Database\Expression\FunctionExpression $expression The function expression
  80. * to translate for SQLite.
  81. * @return void
  82. */
  83. protected function _transformFunctionExpression(FunctionExpression $expression)
  84. {
  85. switch ($expression->getName()) {
  86. case 'CONCAT':
  87. // CONCAT function is expressed as exp1 || exp2
  88. $expression->setName('')->setConjunction(' ||');
  89. break;
  90. case 'DATEDIFF':
  91. $expression
  92. ->setName('ROUND')
  93. ->setConjunction('-')
  94. ->iterateParts(function ($p) {
  95. return new FunctionExpression('JULIANDAY', [$p['value']], [$p['type']]);
  96. });
  97. break;
  98. case 'NOW':
  99. $expression->setName('DATETIME')->add(["'now'" => 'literal']);
  100. break;
  101. case 'CURRENT_DATE':
  102. $expression->setName('DATE')->add(["'now'" => 'literal']);
  103. break;
  104. case 'CURRENT_TIME':
  105. $expression->setName('TIME')->add(["'now'" => 'literal']);
  106. break;
  107. case 'EXTRACT':
  108. $expression
  109. ->setName('STRFTIME')
  110. ->setConjunction(' ,')
  111. ->iterateParts(function ($p, $key) {
  112. if ($key === 0) {
  113. $value = strtolower(rtrim($p, 's'));
  114. if (isset($this->_dateParts[$value])) {
  115. $p = ['value' => '%' . $this->_dateParts[$value], 'type' => null];
  116. }
  117. }
  118. return $p;
  119. });
  120. break;
  121. case 'DATE_ADD':
  122. $expression
  123. ->setName('DATE')
  124. ->setConjunction(',')
  125. ->iterateParts(function ($p, $key) {
  126. if ($key === 1) {
  127. $p = ['value' => $p, 'type' => null];
  128. }
  129. return $p;
  130. });
  131. break;
  132. case 'DAYOFWEEK':
  133. $expression
  134. ->setName('STRFTIME')
  135. ->setConjunction(' ')
  136. ->add(["'%w', " => 'literal'], [], true)
  137. ->add([') + (1' => 'literal']); // Sqlite starts on index 0 but Sunday should be 1
  138. break;
  139. }
  140. }
  141. /**
  142. * Get the schema dialect.
  143. *
  144. * Used by Cake\Database\Schema package to reflect schema and
  145. * generate schema.
  146. *
  147. * @return \Cake\Database\Schema\SqliteSchema
  148. */
  149. public function schemaDialect()
  150. {
  151. if (!$this->_schemaDialect) {
  152. $this->_schemaDialect = new SqliteSchema($this);
  153. }
  154. return $this->_schemaDialect;
  155. }
  156. /**
  157. * {@inheritDoc}
  158. */
  159. public function disableForeignKeySQL()
  160. {
  161. return 'PRAGMA foreign_keys = OFF';
  162. }
  163. /**
  164. * {@inheritDoc}
  165. */
  166. public function enableForeignKeySQL()
  167. {
  168. return 'PRAGMA foreign_keys = ON';
  169. }
  170. /**
  171. * {@inheritDoc}
  172. *
  173. * @return \Cake\Database\SqliteCompiler
  174. */
  175. public function newCompiler()
  176. {
  177. return new SqliteCompiler();
  178. }
  179. }