PageRenderTime 40ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 0ms

/bitrix/modules/perfmon/lib/sql/column.php

https://bitbucket.org/alex_poluektov/itech_test
PHP | 325 lines | 234 code | 21 blank | 70 comment | 45 complexity | 6bedd792c88e32d08c05a05faa0f58be MD5 | raw file
Possible License(s): Apache-2.0
  1. <?php
  2. namespace Bitrix\Perfmon\Sql;
  3. use Bitrix\Main\NotSupportedException;
  4. class Column extends BaseObject
  5. {
  6. public $type = '';
  7. public $length = '';
  8. public $nullable = true;
  9. public $default = null;
  10. protected static $types = array(
  11. 'INT' => true,
  12. 'INTEGER' => true,
  13. 'TINYINT' => true,
  14. 'NUMERIC' => true,
  15. 'NUMBER' => true,
  16. 'FLOAT' => true,
  17. 'DOUBLE' => true,
  18. 'DECIMAL' => true,
  19. 'BIGINT' => true,
  20. 'SMALLINT' => true,
  21. 'MEDIUMINT' => true,
  22. 'VARCHAR' => true,
  23. 'VARCHAR2' => true,
  24. 'CHAR' => true,
  25. 'TIMESTAMP' => true,
  26. 'DATETIME' => true,
  27. 'DATE' => true,
  28. 'TIME' => true,
  29. 'TEXT' => true,
  30. 'LONGTEXT' => true,
  31. 'MEDIUMTEXT' => true,
  32. 'CLOB' => true,
  33. 'BLOB' => true,
  34. 'MEDIUMBLOB' => true,
  35. 'LONGBLOB' => true,
  36. 'VARBINARY' => true,
  37. 'IMAGE' => true,
  38. 'ENUM' => true,
  39. );
  40. /**
  41. * Checks the $type against type list:
  42. * - INT
  43. * - INTEGER
  44. * - TINYINT
  45. * - NUMERIC
  46. * - NUMBER
  47. * - FLOAT
  48. * - DOUBLE
  49. * - DECIMAL
  50. * - BIGINT
  51. * - SMALLINT
  52. * - MEDIUMINT
  53. * - VARCHAR
  54. * - VARCHAR2
  55. * - CHAR
  56. * - TIMESTAMP
  57. * - DATETIME
  58. * - DATE
  59. * - TIME
  60. * - TEXT
  61. * - LONGTEXT
  62. * - MEDIUMTEXT
  63. * - CLOB
  64. * - BLOB
  65. * - MEDIUMBLOB
  66. * - LONGBLOB
  67. * - VARBINARY
  68. * - IMAGE
  69. * - ENUM
  70. *
  71. * @param string $type Type of a column.
  72. *
  73. * @return boolean
  74. */
  75. public static function checkType($type)
  76. {
  77. return isset(self::$types[$type]);
  78. }
  79. /**
  80. * Creates column object from tokens.
  81. * <p>
  82. * Current position should point to the name of the column.
  83. *
  84. * @param Tokenizer $tokenizer Tokens collection.
  85. *
  86. * @return Column
  87. * @throws NotSupportedException
  88. */
  89. public static function create(Tokenizer $tokenizer)
  90. {
  91. $columnName = $tokenizer->getCurrentToken()->text;
  92. $tokenizer->nextToken();
  93. $tokenizer->skipWhiteSpace();
  94. $token = $tokenizer->getCurrentToken();
  95. $columnType = $token->upper;
  96. if (!self::checkType($columnType))
  97. {
  98. throw new NotSupportedException("column type expected but [".$tokenizer->getCurrentToken()->text."] found. line: ".$tokenizer->getCurrentToken()->line);
  99. }
  100. $column = new self($columnName);
  101. $column->type = $columnType;
  102. $level = $token->level;
  103. $lengthLevel = -1;
  104. $columnDefinition = '';
  105. do
  106. {
  107. if ($token->level == $level && $token->text == ',')
  108. break;
  109. if ($token->level < $level && $token->text == ')')
  110. break;
  111. $columnDefinition .= $token->text;
  112. if ($token->upper === 'NOT')
  113. $column->nullable = false;
  114. elseif ($token->upper === 'DEFAULT')
  115. $column->default = false;
  116. elseif ($column->default === false)
  117. {
  118. if ($token->type !== Token::T_WHITESPACE && $token->type !== Token::T_COMMENT)
  119. {
  120. $column->default = $token->text;
  121. }
  122. }
  123. $token = $tokenizer->nextToken();
  124. //parentheses after type
  125. if ($lengthLevel == -1)
  126. {
  127. if ($token->text == '(')
  128. {
  129. $lengthLevel = $token->level;
  130. $column->length = '';
  131. while (!$tokenizer->endOfInput())
  132. {
  133. $columnDefinition .= $token->text;
  134. $token = $tokenizer->nextToken();
  135. if ($token->level == $lengthLevel && $token->text == ')')
  136. break;
  137. $column->length .= $token->text;
  138. }
  139. }
  140. elseif ($token->type !== Token::T_WHITESPACE && $token->type !== Token::T_COMMENT)
  141. {
  142. $lengthLevel = 0;
  143. }
  144. }
  145. }
  146. while (!$tokenizer->endOfInput());
  147. $column->setBody($columnDefinition);
  148. return $column;
  149. }
  150. /**
  151. * Return DDL for table column creation.
  152. *
  153. * @param string $dbType Database type (MYSQL, ORACLE or MSSQL).
  154. *
  155. * @return array|string
  156. */
  157. public function getCreateDdl($dbType = '')
  158. {
  159. switch ($dbType)
  160. {
  161. case "MYSQL":
  162. return "ALTER TABLE ".$this->parent->name." ADD ".$this->name." ".$this->body;
  163. case "MSSQL":
  164. return "ALTER TABLE ".$this->parent->name." ADD ".$this->name." ".$this->body;
  165. case "ORACLE":
  166. return "ALTER TABLE ".$this->parent->name." ADD (".$this->name." ".$this->body.")";
  167. default:
  168. return "// ".get_class($this).":getCreateDdl for database type [".$dbType."] not implemented";
  169. }
  170. }
  171. /**
  172. * Return DDL for column destruction.
  173. *
  174. * @param string $dbType Database type (MYSQL, ORACLE or MSSQL).
  175. *
  176. * @return array|string
  177. */
  178. public function getDropDdl($dbType = '')
  179. {
  180. switch ($dbType)
  181. {
  182. case "MYSQL":
  183. return "ALTER TABLE ".$this->parent->name." DROP ".$this->name;
  184. case "MSSQL":
  185. return "ALTER TABLE ".$this->parent->name." DROP COLUMN ".$this->name;
  186. case "ORACLE":
  187. return "ALTER TABLE ".$this->parent->name." DROP (".$this->name.")";
  188. default:
  189. return "// ".get_class($this).":getDropDdl for database type [".$dbType."] not implemented";
  190. }
  191. }
  192. /**
  193. * Return DDL for object modification.
  194. * <p>
  195. * Implemented only for MySQL database. For Oracle or MS SQL returns commentary.
  196. *
  197. * @param Column $target Target object.
  198. * @param string $dbType Database type (MYSQL, ORACLE or MSSQL).
  199. *
  200. * @return array|string
  201. */
  202. public function getModifyDdl(Column $target, $dbType = '')
  203. {
  204. switch ($dbType)
  205. {
  206. case "MYSQL":
  207. return "ALTER TABLE ".$this->parent->name." CHANGE ".$this->name." ".$target->name." ".$target->body;
  208. case "MSSQL":
  209. if ($this->nullable !== $target->nullable)
  210. {
  211. $nullDdl = ($target->nullable? " NULL": " NOT NULL");
  212. }
  213. else
  214. {
  215. $nullDdl = "";
  216. }
  217. if (
  218. $this->type === $target->type
  219. && $this->default === $target->default
  220. && (
  221. intval($this->length) < intval($target->length)
  222. || (
  223. intval($target->length) < intval($this->length)
  224. && strtoupper($this->type) === "CHAR"
  225. )
  226. )
  227. )
  228. {
  229. $sql = array();
  230. foreach ($this->parent->indexes->getList() as $index)
  231. {
  232. if (in_array($this->name, $index->columns))
  233. {
  234. $sql[] = $index->getDropDdl($dbType);
  235. }
  236. }
  237. $sql[] = "ALTER TABLE ".$this->parent->name." ALTER COLUMN ".$this->name." ".$target->body.$nullDdl;
  238. foreach ($this->parent->indexes->getList() as $index)
  239. {
  240. if (in_array($this->name, $index->columns))
  241. {
  242. $sql[] = $index->getCreateDdl($dbType);
  243. }
  244. }
  245. return $sql;
  246. }
  247. elseif (
  248. $this->type === $target->type
  249. && $this->default === $target->default
  250. && intval($this->length) === intval($target->length)
  251. && $this->nullable !== $target->nullable
  252. )
  253. {
  254. return "ALTER TABLE ".$this->parent->name." ALTER COLUMN ".$this->name." ".$target->body;
  255. }
  256. else
  257. {
  258. return "// ".get_class($this).":getModifyDdl for database type [".$dbType."] not implemented. Change requested from [$this->body] to [$target->body].";
  259. }
  260. case "ORACLE":
  261. if (
  262. $this->type === $target->type
  263. && $this->default === $target->default
  264. && (
  265. intval($this->length) < intval($target->length)
  266. || (
  267. intval($target->length) < intval($this->length)
  268. && strtoupper($this->type) === "CHAR"
  269. )
  270. )
  271. )
  272. {
  273. return "ALTER TABLE ".$this->parent->name." MODIFY (".$this->name." ".$target->type."(".$target->length.")".")";
  274. }
  275. elseif (
  276. $this->type === $target->type
  277. && $this->default === $target->default
  278. && intval($this->length) === intval($target->length)
  279. && $this->nullable !== $target->nullable
  280. )
  281. {
  282. return "
  283. declare
  284. l_nullable varchar2(1);
  285. begin
  286. select nullable into l_nullable
  287. from user_tab_columns
  288. where table_name = '".$this->parent->name."'
  289. and column_name = '".$this->name."';
  290. if l_nullable = '".($target->nullable? "N": "Y")."' then
  291. execute immediate 'alter table ".$this->parent->name." modify (".$this->name." ".($target->nullable? "NULL": "NOT NULL").")';
  292. end if;
  293. end;
  294. ";
  295. }
  296. else
  297. {
  298. return "// ".get_class($this).":getModifyDdl for database type [".$dbType."] not implemented. Change requested from [$this->body] to [$target->body].";
  299. }
  300. default:
  301. return "// ".get_class($this).":getModifyDdl for database type [".$dbType."] not implemented. Change requested from [$this->body] to [$target->body].";
  302. }
  303. }
  304. }