SqliteDialectTrait.php 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  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 'RAND':
  102. $expression
  103. ->setName('ABS')
  104. ->add(["RANDOM() % 1" => 'literal'], [], true);
  105. break;
  106. case 'CURRENT_DATE':
  107. $expression->setName('DATE')->add(["'now'" => 'literal']);
  108. break;
  109. case 'CURRENT_TIME':
  110. $expression->setName('TIME')->add(["'now'" => 'literal']);
  111. break;
  112. case 'EXTRACT':
  113. $expression
  114. ->setName('STRFTIME')
  115. ->setConjunction(' ,')
  116. ->iterateParts(function ($p, $key) {
  117. if ($key === 0) {
  118. $value = rtrim(strtolower($p), 's');
  119. if (isset($this->_dateParts[$value])) {
  120. $p = ['value' => '%' . $this->_dateParts[$value], 'type' => null];
  121. }
  122. }
  123. return $p;
  124. });
  125. break;
  126. case 'DATE_ADD':
  127. $expression
  128. ->setName('DATE')
  129. ->setConjunction(',')
  130. ->iterateParts(function ($p, $key) {
  131. if ($key === 1) {
  132. $p = ['value' => $p, 'type' => null];
  133. }
  134. return $p;
  135. });
  136. break;
  137. case 'DAYOFWEEK':
  138. $expression
  139. ->setName('STRFTIME')
  140. ->setConjunction(' ')
  141. ->add(["'%w', " => 'literal'], [], true)
  142. ->add([') + (1' => 'literal']); // Sqlite starts on index 0 but Sunday should be 1
  143. break;
  144. }
  145. }
  146. /**
  147. * Get the schema dialect.
  148. *
  149. * Used by Cake\Database\Schema package to reflect schema and
  150. * generate schema.
  151. *
  152. * @return \Cake\Database\Schema\SqliteSchema
  153. */
  154. public function schemaDialect()
  155. {
  156. if (!$this->_schemaDialect) {
  157. $this->_schemaDialect = new SqliteSchema($this);
  158. }
  159. return $this->_schemaDialect;
  160. }
  161. /**
  162. * {@inheritDoc}
  163. */
  164. public function disableForeignKeySQL()
  165. {
  166. return 'PRAGMA foreign_keys = OFF';
  167. }
  168. /**
  169. * {@inheritDoc}
  170. */
  171. public function enableForeignKeySQL()
  172. {
  173. return 'PRAGMA foreign_keys = ON';
  174. }
  175. /**
  176. * {@inheritDoc}
  177. *
  178. * @return \Cake\Database\SqliteCompiler
  179. */
  180. public function newCompiler()
  181. {
  182. return new SqliteCompiler();
  183. }
  184. }