PageRenderTime 47ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/tools/parser_sql/processors/TableProcessor.php

https://gitlab.com/staging06/myproject
PHP | 356 lines | 257 code | 42 blank | 57 comment | 26 complexity | fa6bfaefe00a779eea116d9997275017 MD5 | raw file
  1. <?php
  2. /**
  3. * TableProcessor.php
  4. *
  5. * This file implements the processor for the TABLE statements.
  6. *
  7. * Copyright (c) 2010-2012, Justin Swanhart
  8. * with contributions by André Rothe <arothe@phosco.info, phosco@gmx.de>
  9. *
  10. * All rights reserved.
  11. *
  12. * Redistribution and use in source and binary forms, with or without modification,
  13. * are permitted provided that the following conditions are met:
  14. *
  15. * * Redistributions of source code must retain the above copyright notice,
  16. * this list of conditions and the following disclaimer.
  17. * * Redistributions in binary form must reproduce the above copyright notice,
  18. * this list of conditions and the following disclaimer in the documentation
  19. * and/or other materials provided with the distribution.
  20. *
  21. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
  22. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  23. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
  24. * SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  25. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
  26. * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
  27. * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  28. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  29. * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
  30. * DAMAGE.
  31. */
  32. require_once(dirname(__FILE__) . '/AbstractProcessor.php');
  33. require_once(dirname(__FILE__) . '/CreateDefinitionProcessor.php');
  34. require_once(dirname(__FILE__) . '/../utils/ExpressionType.php');
  35. /**
  36. *
  37. * This class processes the TABLE statements.
  38. *
  39. * @author arothe
  40. *
  41. */
  42. class TableProcessor extends AbstractProcessor {
  43. protected function getReservedType($token) {
  44. return array('expr_type' => ExpressionType::RESERVED, 'base_expr' => $token);
  45. }
  46. protected function getConstantType($token) {
  47. return array('expr_type' => ExpressionType::CONSTANT, 'base_expr' => $token);
  48. }
  49. protected function getOperatorType($token) {
  50. return array('expr_type' => ExpressionType::OPERATOR, 'base_expr' => $token);
  51. }
  52. protected function clear(&$expr, &$base_expr, &$category) {
  53. $expr = array();
  54. $base_expr = '';
  55. $category = 'CREATE_DEF';
  56. }
  57. public function process($tokens) {
  58. $currCategory = "TABLE_NAME";
  59. $result = array('base_expr' => false, 'name' => false, 'no_quotes' => false, 'create-def' => false,
  60. 'options' => false, 'like' => false, 'select-option' => false);
  61. $expr = array();
  62. $base_expr = '';
  63. $skip = 0;
  64. foreach ($tokens as $token) {
  65. $trim = trim($token);
  66. $base_expr .= $token;
  67. if ($skip > 0) {
  68. $skip--;
  69. continue;
  70. }
  71. if ($skip < 0) {
  72. break;
  73. }
  74. if ($trim === "") {
  75. continue;
  76. }
  77. $upper = strtoupper($trim);
  78. switch ($upper) {
  79. case ',':
  80. # it is possible to separate the table options with comma!
  81. if ($prevCategory === 'CREATE_DEF') {
  82. $last = array_pop($result['options']);
  83. $last['delim'] = ',';
  84. $result['options'][] = $last;
  85. $base_expr = "";
  86. }
  87. continue 2;
  88. case 'UNION':
  89. if ($prevCategory === 'CREATE_DEF') {
  90. $expr[] = $this->getReservedType($trim);
  91. $currCategory = 'UNION';
  92. continue 2;
  93. }
  94. break;
  95. case 'LIKE':
  96. # like without parenthesis
  97. if ($prevCategory === 'TABLE_NAME') {
  98. $currCategory = $upper;
  99. continue 2;
  100. }
  101. break;
  102. case '=':
  103. # the optional operator
  104. if ($prevCategory === 'TABLE_OPTION') {
  105. $expr[] = $this->getOperatorType($trim);
  106. continue 2; # don't change the category
  107. }
  108. break;
  109. case 'CHARACTER':
  110. if ($prevCategory === 'CREATE_DEF') {
  111. $expr[] = $this->getReservedType($trim);
  112. $currCategory = 'TABLE_OPTION';
  113. }
  114. if ($prevCategory === 'TABLE_OPTION') {
  115. # add it to the previous DEFAULT
  116. $expr[] = $this->getReservedType($trim);
  117. continue 2;
  118. }
  119. break;
  120. case 'SET':
  121. if ($prevCategory === 'TABLE_OPTION') {
  122. # add it to a previous CHARACTER
  123. $expr[] = $this->getReservedType($trim);
  124. $currCategory = 'CHARSET';
  125. continue 2;
  126. }
  127. break;
  128. case 'COLLATE':
  129. if ($prevCategory === 'TABLE_OPTION') {
  130. # add it to the previous DEFAULT
  131. $expr[] = $this->getReservedType($trim);
  132. $currCategory = 'COLLATE';
  133. continue 2;
  134. }
  135. break;
  136. case 'DIRECTORY':
  137. if ($currCategory === 'INDEX_DIRECTORY' || $currCategory === 'DATA_DIRECTORY') {
  138. # after INDEX or DATA
  139. $expr[] = $this->getReservedType($trim);
  140. continue 2;
  141. }
  142. break;
  143. case 'INDEX':
  144. if ($prevCategory === 'CREATE_DEF') {
  145. $expr[] = $this->getReservedType($trim);
  146. $currCategory = 'INDEX_DIRECTORY';
  147. continue 2;
  148. }
  149. break;
  150. case 'DATA':
  151. if ($prevCategory === 'CREATE_DEF') {
  152. $expr[] = $this->getReservedType($trim);
  153. $currCategory = 'DATA_DIRECTORY';
  154. continue 2;
  155. }
  156. break;
  157. case 'INSERT_METHOD':
  158. case 'DELAY_KEY_WRITE':
  159. case 'ROW_FORMAT':
  160. case 'PASSWORD':
  161. case 'MAX_ROWS':
  162. case 'MIN_ROWS':
  163. case 'PACK_KEYS':
  164. case 'CHECKSUM':
  165. case 'COMMENT':
  166. case 'CONNECTION':
  167. case 'AUTO_INCREMENT':
  168. case 'AVG_ROW_LENGTH':
  169. case 'ENGINE':
  170. case 'TYPE':
  171. case 'STATS_AUTO_RECALC':
  172. case 'STATS_PERSISTENT':
  173. case 'KEY_BLOCK_SIZE':
  174. if ($prevCategory === 'CREATE_DEF') {
  175. $expr[] = $this->getReservedType($trim);
  176. $currCategory = $prevCategory = 'TABLE_OPTION';
  177. continue 2;
  178. }
  179. break;
  180. case 'DYNAMIC':
  181. case 'FIXED':
  182. case 'COMPRESSED':
  183. case 'REDUNDANT':
  184. case 'COMPACT':
  185. case 'NO':
  186. case 'FIRST':
  187. case 'LAST':
  188. case 'DEFAULT':
  189. if ($prevCategory === 'CREATE_DEF') {
  190. # DEFAULT before CHARACTER SET and COLLATE
  191. $expr[] = $this->getReservedType($trim);
  192. $currCategory = 'TABLE_OPTION';
  193. }
  194. if ($prevCategory === 'TABLE_OPTION') {
  195. # all assignments with the keywords
  196. $expr[] = $this->getReservedType($trim);
  197. $result['options'][] = array('expr_type' => ExpressionType::EXPRESSION,
  198. 'base_expr' => trim($base_expr), 'delim' => ' ',
  199. 'sub_tree' => $expr);
  200. $this->clear($expr, $base_expr, $currCategory);
  201. }
  202. break;
  203. case 'IGNORE':
  204. case 'REPLACE':
  205. $expr[] = $this->getReservedType($trim);
  206. $result['select-option'] = array('base_expr' => trim($base_expr), 'duplicates' => $trim, 'as' => false,
  207. 'sub_tree' => $expr);
  208. continue 2;
  209. case 'AS':
  210. $expr[] = $this->getReservedType($trim);
  211. if (!isset($result['select-option']['duplicates'])) {
  212. $result['select-option']['duplicates'] = false;
  213. }
  214. $result['select-option']['as'] = true;
  215. $result['select-option']['base_expr'] = trim($base_expr);
  216. $result['select-option']['sub_tree'] = $expr;
  217. continue 2;
  218. case 'PARTITION':
  219. # TODO: parse partition options
  220. $skip = -1;
  221. break;
  222. default:
  223. switch ($currCategory) {
  224. case 'CHARSET':
  225. # the charset name
  226. $expr[] = $this->getConstantType($trim);
  227. $result['options'][] = array('expr_type' => ExpressionType::CHARSET,
  228. 'base_expr' => trim($base_expr), 'delim' => ' ',
  229. 'sub_tree' => $expr);
  230. $this->clear($expr, $base_expr, $currCategory);
  231. break;
  232. case 'COLLATE':
  233. # the collate name
  234. $expr[] = $this->getConstantType($trim);
  235. $result['options'][] = array('expr_type' => ExpressionType::COLLATE,
  236. 'base_expr' => trim($base_expr), 'delim' => ' ',
  237. 'sub_tree' => $expr);
  238. $this->clear($expr, $base_expr, $currCategory);
  239. break;
  240. case 'DATA_DIRECTORY':
  241. # we have the directory name
  242. $expr[] = $this->getConstantType($trim);
  243. $result['options'][] = array('expr_type' => ExpressionType::DIRECTORY, 'kind' => 'DATA',
  244. 'base_expr' => trim($base_expr), 'delim' => ' ',
  245. 'sub_tree' => $expr);
  246. $this->clear($expr, $base_expr, $prevCategory);
  247. continue 3;
  248. case 'INDEX_DIRECTORY':
  249. # we have the directory name
  250. $expr[] = $this->getConstantType($trim);
  251. $result['options'][] = array('expr_type' => ExpressionType::DIRECTORY, 'kind' => 'INDEX',
  252. 'base_expr' => trim($base_expr), 'delim' => ' ',
  253. 'sub_tree' => $expr);
  254. $this->clear($expr, $base_expr, $prevCategory);
  255. continue 3;
  256. case 'TABLE_NAME':
  257. $result['base_expr'] = $result['name'] = $trim;
  258. $result['no_quotes'] = $this->revokeQuotation($trim);
  259. $this->clear($expr, $base_expr, $prevCategory);
  260. break;
  261. case 'LIKE':
  262. $result['like'] = array('expr_type' => ExpressionType::TABLE, 'table' => $trim, 'base_expr' => $trim,
  263. 'no_quotes' => $this->revokeQuotation($trim));
  264. $this->clear($expr, $base_expr, $currCategory);
  265. break;
  266. case '':
  267. # after table name
  268. if ($prevCategory === 'TABLE_NAME' && $upper[0] === '(' && substr($upper, -1) === ')') {
  269. $unparsed = $this->splitSQLIntoTokens($this->removeParenthesisFromStart($trim));
  270. $processor = new CreateDefinitionProcessor();
  271. $coldef = $processor->process($unparsed);
  272. $result['create-def'] = array('expr_type' => ExpressionType::BRACKET_EXPRESSION,
  273. 'base_expr' => $base_expr, 'sub_tree' => $coldef['create-def']);
  274. $expr = array();
  275. $base_expr = '';
  276. $currCategory = 'CREATE_DEF';
  277. }
  278. break;
  279. case 'UNION':
  280. # TODO: this token starts and ends with parenthesis
  281. # and contains a list of table names (comma-separated)
  282. # split the token and add the list as subtree
  283. # we must change the DefaultProcessor
  284. $unparsed = $this->splitSQLIntoTokens($this->removeParenthesisFromStart($trim));
  285. $expr[] = array('expr_type' => ExpressionType::BRACKET_EXPRESSION, 'base_expr' => $trim,
  286. 'sub_tree' => '***TODO***');
  287. $result['options'][] = array('expr_type' => ExpressionType::UNION, 'base_expr' => trim($base_expr),
  288. 'delim' => ' ', 'sub_tree' => $expr);
  289. $this->clear($expr, $base_expr, $currCategory);
  290. break;
  291. default:
  292. # strings and numeric constants
  293. $expr[] = $this->getConstantType($trim);
  294. $result['options'][] = array('expr_type' => ExpressionType::EXPRESSION,
  295. 'base_expr' => trim($base_expr), 'delim' => ' ',
  296. 'sub_tree' => $expr);
  297. $this->clear($expr, $base_expr, $currCategory);
  298. break;
  299. }
  300. break;
  301. }
  302. $prevCategory = $currCategory;
  303. $currCategory = "";
  304. }
  305. if ($result['like'] === false) {
  306. unset($result['like']);
  307. }
  308. if ($result['select-option'] === false) {
  309. unset($result['select-option']);
  310. }
  311. return $result;
  312. }
  313. }
  314. ?>