SqlTokenizer.php 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. <?php
  2. /**
  3. * @link http://www.yiiframework.com/
  4. * @copyright Copyright (c) 2008 Yii Software LLC
  5. * @license http://www.yiiframework.com/license/
  6. */
  7. namespace yii\db\sqlite;
  8. /**
  9. * SqlTokenizer splits SQLite query into individual SQL tokens.
  10. * It's used to obtain a `CHECK` constraint information from a `CREATE TABLE` SQL code.
  11. *
  12. * @see http://www.sqlite.org/draft/tokenreq.html
  13. * @see https://sqlite.org/lang.html
  14. * @author Sergey Makinen <sergey@makinen.ru>
  15. * @since 2.0.13
  16. */
  17. class SqlTokenizer extends \yii\db\SqlTokenizer
  18. {
  19. /**
  20. * {@inheritdoc}
  21. */
  22. protected function isWhitespace(&$length)
  23. {
  24. static $whitespaces = [
  25. "\f" => true,
  26. "\n" => true,
  27. "\r" => true,
  28. "\t" => true,
  29. ' ' => true,
  30. ];
  31. $length = 1;
  32. return isset($whitespaces[$this->substring($length)]);
  33. }
  34. /**
  35. * {@inheritdoc}
  36. */
  37. protected function isComment(&$length)
  38. {
  39. static $comments = [
  40. '--' => true,
  41. '/*' => true,
  42. ];
  43. $length = 2;
  44. if (!isset($comments[$this->substring($length)])) {
  45. return false;
  46. }
  47. if ($this->substring($length) === '--') {
  48. $length = $this->indexAfter("\n") - $this->offset;
  49. } else {
  50. $length = $this->indexAfter('*/') - $this->offset;
  51. }
  52. return true;
  53. }
  54. /**
  55. * {@inheritdoc}
  56. */
  57. protected function isOperator(&$length, &$content)
  58. {
  59. static $operators = [
  60. '!=',
  61. '%',
  62. '&',
  63. '(',
  64. ')',
  65. '*',
  66. '+',
  67. ',',
  68. '-',
  69. '.',
  70. '/',
  71. ';',
  72. '<',
  73. '<<',
  74. '<=',
  75. '<>',
  76. '=',
  77. '==',
  78. '>',
  79. '>=',
  80. '>>',
  81. '|',
  82. '||',
  83. '~',
  84. ];
  85. return $this->startsWithAnyLongest($operators, true, $length);
  86. }
  87. /**
  88. * {@inheritdoc}
  89. */
  90. protected function isIdentifier(&$length, &$content)
  91. {
  92. static $identifierDelimiters = [
  93. '"' => '"',
  94. '[' => ']',
  95. '`' => '`',
  96. ];
  97. if (!isset($identifierDelimiters[$this->substring(1)])) {
  98. return false;
  99. }
  100. $delimiter = $identifierDelimiters[$this->substring(1)];
  101. $offset = $this->offset;
  102. while (true) {
  103. $offset = $this->indexAfter($delimiter, $offset + 1);
  104. if ($delimiter === ']' || $this->substring(1, true, $offset) !== $delimiter) {
  105. break;
  106. }
  107. }
  108. $length = $offset - $this->offset;
  109. $content = $this->substring($length - 2, true, $this->offset + 1);
  110. if ($delimiter !== ']') {
  111. $content = strtr($content, ["$delimiter$delimiter" => $delimiter]);
  112. }
  113. return true;
  114. }
  115. /**
  116. * {@inheritdoc}
  117. */
  118. protected function isStringLiteral(&$length, &$content)
  119. {
  120. if ($this->substring(1) !== "'") {
  121. return false;
  122. }
  123. $offset = $this->offset;
  124. while (true) {
  125. $offset = $this->indexAfter("'", $offset + 1);
  126. if ($this->substring(1, true, $offset) !== "'") {
  127. break;
  128. }
  129. }
  130. $length = $offset - $this->offset;
  131. $content = strtr($this->substring($length - 2, true, $this->offset + 1), ["''" => "'"]);
  132. return true;
  133. }
  134. /**
  135. * {@inheritdoc}
  136. */
  137. protected function isKeyword($string, &$content)
  138. {
  139. static $keywords = [
  140. 'ABORT' => true,
  141. 'ACTION' => true,
  142. 'ADD' => true,
  143. 'AFTER' => true,
  144. 'ALL' => true,
  145. 'ALTER' => true,
  146. 'ANALYZE' => true,
  147. 'AND' => true,
  148. 'AS' => true,
  149. 'ASC' => true,
  150. 'ATTACH' => true,
  151. 'AUTOINCREMENT' => true,
  152. 'BEFORE' => true,
  153. 'BEGIN' => true,
  154. 'BETWEEN' => true,
  155. 'BY' => true,
  156. 'CASCADE' => true,
  157. 'CASE' => true,
  158. 'CAST' => true,
  159. 'CHECK' => true,
  160. 'COLLATE' => true,
  161. 'COLUMN' => true,
  162. 'COMMIT' => true,
  163. 'CONFLICT' => true,
  164. 'CONSTRAINT' => true,
  165. 'CREATE' => true,
  166. 'CROSS' => true,
  167. 'CURRENT_DATE' => true,
  168. 'CURRENT_TIME' => true,
  169. 'CURRENT_TIMESTAMP' => true,
  170. 'DATABASE' => true,
  171. 'DEFAULT' => true,
  172. 'DEFERRABLE' => true,
  173. 'DEFERRED' => true,
  174. 'DELETE' => true,
  175. 'DESC' => true,
  176. 'DETACH' => true,
  177. 'DISTINCT' => true,
  178. 'DROP' => true,
  179. 'EACH' => true,
  180. 'ELSE' => true,
  181. 'END' => true,
  182. 'ESCAPE' => true,
  183. 'EXCEPT' => true,
  184. 'EXCLUSIVE' => true,
  185. 'EXISTS' => true,
  186. 'EXPLAIN' => true,
  187. 'FAIL' => true,
  188. 'FOR' => true,
  189. 'FOREIGN' => true,
  190. 'FROM' => true,
  191. 'FULL' => true,
  192. 'GLOB' => true,
  193. 'GROUP' => true,
  194. 'HAVING' => true,
  195. 'IF' => true,
  196. 'IGNORE' => true,
  197. 'IMMEDIATE' => true,
  198. 'IN' => true,
  199. 'INDEX' => true,
  200. 'INDEXED' => true,
  201. 'INITIALLY' => true,
  202. 'INNER' => true,
  203. 'INSERT' => true,
  204. 'INSTEAD' => true,
  205. 'INTERSECT' => true,
  206. 'INTO' => true,
  207. 'IS' => true,
  208. 'ISNULL' => true,
  209. 'JOIN' => true,
  210. 'KEY' => true,
  211. 'LEFT' => true,
  212. 'LIKE' => true,
  213. 'LIMIT' => true,
  214. 'MATCH' => true,
  215. 'NATURAL' => true,
  216. 'NO' => true,
  217. 'NOT' => true,
  218. 'NOTNULL' => true,
  219. 'NULL' => true,
  220. 'OF' => true,
  221. 'OFFSET' => true,
  222. 'ON' => true,
  223. 'OR' => true,
  224. 'ORDER' => true,
  225. 'OUTER' => true,
  226. 'PLAN' => true,
  227. 'PRAGMA' => true,
  228. 'PRIMARY' => true,
  229. 'QUERY' => true,
  230. 'RAISE' => true,
  231. 'RECURSIVE' => true,
  232. 'REFERENCES' => true,
  233. 'REGEXP' => true,
  234. 'REINDEX' => true,
  235. 'RELEASE' => true,
  236. 'RENAME' => true,
  237. 'REPLACE' => true,
  238. 'RESTRICT' => true,
  239. 'RIGHT' => true,
  240. 'ROLLBACK' => true,
  241. 'ROW' => true,
  242. 'SAVEPOINT' => true,
  243. 'SELECT' => true,
  244. 'SET' => true,
  245. 'TABLE' => true,
  246. 'TEMP' => true,
  247. 'TEMPORARY' => true,
  248. 'THEN' => true,
  249. 'TO' => true,
  250. 'TRANSACTION' => true,
  251. 'TRIGGER' => true,
  252. 'UNION' => true,
  253. 'UNIQUE' => true,
  254. 'UPDATE' => true,
  255. 'USING' => true,
  256. 'VACUUM' => true,
  257. 'VALUES' => true,
  258. 'VIEW' => true,
  259. 'VIRTUAL' => true,
  260. 'WHEN' => true,
  261. 'WHERE' => true,
  262. 'WITH' => true,
  263. 'WITHOUT' => true,
  264. ];
  265. $string = mb_strtoupper($string, 'UTF-8');
  266. if (!isset($keywords[$string])) {
  267. return false;
  268. }
  269. $content = $string;
  270. return true;
  271. }
  272. }