Schema.php 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  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\oci;
  8. use yii\db\TableSchema;
  9. use yii\db\ColumnSchema;
  10. /**
  11. * Schema is the class for retrieving metadata from an Oracle database
  12. *
  13. * @todo mapping from physical types to abstract types
  14. *
  15. * @author Qiang Xue <[email protected]>
  16. * @since 2.0
  17. */
  18. class Schema extends \yii\db\Schema
  19. {
  20. /**
  21. * @inheritdoc
  22. */
  23. public function init()
  24. {
  25. parent::init();
  26. if ($this->defaultSchema === null) {
  27. $this->defaultSchema = $this->db->username;
  28. }
  29. }
  30. /**
  31. * @inheritdoc
  32. */
  33. public function quoteSimpleTableName($name)
  34. {
  35. return '"' . $name . '"';
  36. }
  37. /**
  38. * @inheritdoc
  39. */
  40. public function quoteSimpleColumnName($name)
  41. {
  42. return '"' . $name . '"';
  43. }
  44. /**
  45. * @inheritdoc
  46. */
  47. public function createQueryBuilder()
  48. {
  49. return new QueryBuilder($this->db);
  50. }
  51. /**
  52. * @inheritdoc
  53. */
  54. public function loadTableSchema($name)
  55. {
  56. $table = new TableSchema();
  57. $this->resolveTableNames($table, $name);
  58. if ($this->findColumns($table)) {
  59. $this->findConstraints($table);
  60. return $table;
  61. } else {
  62. return null;
  63. }
  64. }
  65. /**
  66. * Resolves the table name and schema name (if any).
  67. *
  68. * @param TableSchema $table the table metadata object
  69. * @param string $name the table name
  70. */
  71. protected function resolveTableNames($table, $name)
  72. {
  73. $parts = explode('.', str_replace('"', '', $name));
  74. if (isset($parts[1])) {
  75. $table->schemaName = $parts[0];
  76. $table->name = $parts[1];
  77. } else {
  78. $table->schemaName = $this->defaultSchema;
  79. $table->name = $name;
  80. }
  81. $table->fullName = $table->schemaName !== $this->defaultSchema ? $table->schemaName . '.' . $table->name : $table->name;
  82. }
  83. /**
  84. * Collects the table column metadata.
  85. * @param TableSchema $table the table schema
  86. * @return boolean whether the table exists
  87. */
  88. protected function findColumns($table)
  89. {
  90. $schemaName = $table->schemaName;
  91. $tableName = $table->name;
  92. $sql = <<<EOD
  93. SELECT a.column_name, a.data_type ||
  94. case
  95. when data_precision is not null
  96. then '(' || a.data_precision ||
  97. case when a.data_scale > 0 then ',' || a.data_scale else '' end
  98. || ')'
  99. when data_type = 'DATE' then ''
  100. when data_type = 'NUMBER' then ''
  101. else '(' || to_char(a.data_length) || ')'
  102. end as data_type,
  103. a.nullable, a.data_default,
  104. ( SELECT D.constraint_type
  105. FROM ALL_CONS_COLUMNS C
  106. inner join ALL_constraints D on D.OWNER = C.OWNER and D.constraint_name = C.constraint_name
  107. WHERE C.OWNER = B.OWNER
  108. and C.table_name = B.object_name
  109. and C.column_name = A.column_name
  110. and D.constraint_type = 'P') as Key,
  111. com.comments as column_comment
  112. FROM ALL_TAB_COLUMNS A
  113. inner join ALL_OBJECTS B ON b.owner = a.owner and ltrim(B.OBJECT_NAME) = ltrim(A.TABLE_NAME)
  114. LEFT JOIN user_col_comments com ON (A.table_name = com.table_name AND A.column_name = com.column_name)
  115. WHERE
  116. a.owner = '{$schemaName}'
  117. and (b.object_type = 'TABLE' or b.object_type = 'VIEW')
  118. and b.object_name = '{$tableName}'
  119. ORDER by a.column_id
  120. EOD;
  121. try {
  122. $columns = $this->db->createCommand($sql)->queryAll();
  123. } catch (\Exception $e) {
  124. return false;
  125. }
  126. foreach ($columns as $column) {
  127. $c = $this->createColumn($column);
  128. $table->columns[$c->name] = $c;
  129. if ($c->isPrimaryKey) {
  130. $table->primaryKey[] = $c->name;
  131. $table->sequenceName = '';
  132. $c->autoIncrement = true;
  133. }
  134. }
  135. return true;
  136. }
  137. protected function createColumn($column)
  138. {
  139. $c = new ColumnSchema();
  140. $c->name = $column['COLUMN_NAME'];
  141. $c->allowNull = $column['NULLABLE'] === 'Y';
  142. $c->isPrimaryKey = strpos($column['KEY'], 'P') !== false;
  143. $c->comment = $column['COLUMN_COMMENT'] === null ? '' : $column['COLUMN_COMMENT'];
  144. $this->extractColumnType($c, $column['DATA_TYPE']);
  145. $this->extractColumnSize($c, $column['DATA_TYPE']);
  146. if (stripos($column['DATA_DEFAULT'], 'timestamp') !== false) {
  147. $c->defaultValue = null;
  148. } else {
  149. $c->defaultValue = $c->typecast($column['DATA_DEFAULT']);
  150. }
  151. return $c;
  152. }
  153. protected function findConstraints($table)
  154. {
  155. $sql = <<<EOD
  156. SELECT D.constraint_type as CONSTRAINT_TYPE, C.COLUMN_NAME, C.position, D.r_constraint_name,
  157. E.table_name as table_ref, f.column_name as column_ref,
  158. C.table_name
  159. FROM ALL_CONS_COLUMNS C
  160. inner join ALL_constraints D on D.OWNER = C.OWNER and D.constraint_name = C.constraint_name
  161. left join ALL_constraints E on E.OWNER = D.r_OWNER and E.constraint_name = D.r_constraint_name
  162. left join ALL_cons_columns F on F.OWNER = E.OWNER and F.constraint_name = E.constraint_name and F.position = c.position
  163. WHERE C.OWNER = '{$table->schemaName}'
  164. and C.table_name = '{$table->name}'
  165. and D.constraint_type <> 'P'
  166. order by d.constraint_name, c.position
  167. EOD;
  168. $command = $this->db->createCommand($sql);
  169. foreach ($command->queryAll() as $row) {
  170. if ($row['CONSTRAINT_TYPE'] === 'R') {
  171. $name = $row["COLUMN_NAME"];
  172. $table->foreignKeys[$name] = [$row["TABLE_REF"], $row["COLUMN_REF"]];
  173. }
  174. }
  175. }
  176. /**
  177. * @inheritdoc
  178. */
  179. protected function findTableNames($schema = '')
  180. {
  181. if ($schema === '') {
  182. $sql = <<<EOD
  183. SELECT table_name, '{$schema}' as table_schema FROM user_tables
  184. EOD;
  185. $command = $this->db->createCommand($sql);
  186. } else {
  187. $sql = <<<EOD
  188. SELECT object_name as table_name, owner as table_schema FROM all_objects
  189. WHERE object_type = 'TABLE' AND owner=:schema
  190. EOD;
  191. $command = $this->db->createCommand($sql);
  192. $command->bindParam(':schema', $schema);
  193. }
  194. $rows = $command->queryAll();
  195. $names = [];
  196. foreach ($rows as $row) {
  197. $names[] = $row['TABLE_NAME'];
  198. }
  199. return $names;
  200. }
  201. /**
  202. * Extracts the data types for the given column
  203. * @param ColumnSchema $column
  204. * @param string $dbType DB type
  205. */
  206. protected function extractColumnType($column, $dbType)
  207. {
  208. $column->dbType = $dbType;
  209. if (strpos($dbType, 'FLOAT') !== false) {
  210. $column->type = 'double';
  211. } elseif (strpos($dbType, 'NUMBER') !== false || strpos($dbType, 'INTEGER') !== false) {
  212. if (strpos($dbType, '(') && preg_match('/\((.*)\)/', $dbType, $matches)) {
  213. $values = explode(',', $matches[1]);
  214. if (isset($values[1]) and (((int)$values[1]) > 0)) {
  215. $column->type = 'double';
  216. } else {
  217. $column->type = 'integer';
  218. }
  219. } else {
  220. $column->type = 'double';
  221. }
  222. } else {
  223. $column->type = 'string';
  224. }
  225. }
  226. /**
  227. * Extracts size, precision and scale information from column's DB type.
  228. * @param ColumnSchema $column
  229. * @param string $dbType the column's DB type
  230. */
  231. protected function extractColumnSize($column, $dbType)
  232. {
  233. if (strpos($dbType, '(') && preg_match('/\((.*)\)/', $dbType, $matches)) {
  234. $values = explode(',', $matches[1]);
  235. $column->size = $column->precision = (int)$values[0];
  236. if (isset($values[1])) {
  237. $column->scale = (int)$values[1];
  238. }
  239. }
  240. }
  241. }