Mysql.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  1. <?php
  2. Lib::loadClass('Core_StorageBase');
  3. Lib::loadClass('Core_StorageFactory');
  4. class Core_Storage_Mysql extends Core_StorageBase {
  5. protected $_databaseName = '';
  6. protected $_zasob_id = 0;
  7. protected $_pdo = null;
  8. public function __construct($pdo) {
  9. $this->_pdo = $pdo;
  10. $this->_databaseName = $pdo->getDatabaseName();
  11. $this->_zasob_id = $pdo->getZasobId();
  12. }
  13. public function fetchAllAssoc($sql) {
  14. if (empty($sql)) {
  15. throw new Exception("Empty query");
  16. }
  17. $stmt = $this->_pdo->query($sql);
  18. return $stmt->fetchAll(PDO::FETCH_ASSOC);
  19. }
  20. public function query($query) {
  21. throw new Exception("Storage " . __FUNCTION__ . " not defined");
  22. $res = mysql_query($query, $this->_conn);
  23. if (!$res) {
  24. $this->_set_error('SQL QUERY FAILED: '.mysql_error($this->_conn));
  25. return $null;
  26. }
  27. }
  28. public function getTableStruct($tblName) {
  29. $sql = "
  30. -- show fields from {$tblName}
  31. select cols.COLUMN_NAME as name
  32. , cols.DATA_TYPE as type
  33. , if('YES' = cols.IS_NULLABLE, 1, 0) as is_nullable
  34. , cols.COLUMN_DEFAULT as default_value
  35. , if(cols.COLUMN_DEFAULT is null, 1, 0) as default_is_null
  36. , cols.CHARACTER_MAXIMUM_LENGTH as max_length
  37. , cols.NUMERIC_PRECISION as num_precision
  38. , cols.NUMERIC_SCALE as num_scale
  39. , cols.CHARACTER_SET_NAME as char_encoding -- latin2
  40. , cols.COLLATION_NAME as char_collation -- latin2_general_ci
  41. , cols.EXTRA as extra
  42. , cols.COLUMN_TYPE as raw_storage_type
  43. -- , cols.*
  44. from INFORMATION_SCHEMA.COLUMNS cols
  45. where cols.TABLE_SCHEMA like :db_name
  46. and cols.TABLE_NAME like :tbl_name
  47. ";
  48. $sth = $this->_pdo->prepare($sql);
  49. $sth->bindValue(':db_name', $this->_pdo->getDatabaseName(), PDO::PARAM_STR);
  50. $sth->bindValue(':tbl_name', $tblName, PDO::PARAM_STR);
  51. $sth->execute();
  52. $structRaw = $sth->fetchAll();
  53. if (empty($structRaw)) throw new Exception("Empty struct for table '{$tblName}'", 404);
  54. foreach ($structRaw as $field) {
  55. $struct[$field['name']] = $field;
  56. }
  57. return $struct;
  58. }
  59. protected function _getTableStruct($tblName) {
  60. throw new Exception("Turned OFF C." . __CLASS__ . " F." . __FUNCTION__);
  61. $tblStructRaw = $this->getTableStructRaw($tblName);
  62. $tblStruct = array();
  63. foreach ($tblStructRaw as $fieldStruct) {
  64. $fldName = $fieldStruct['COLUMN_NAME'];
  65. $storageType = '';
  66. /*
  67. BOOLEAN xsd: {true, false, 1, 0}
  68. SERIAL is an alias for BIGINT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE
  69. SET
  70. */
  71. if ('varchar' == $fieldStruct['DATA_TYPE']
  72. || 'char' == $fieldStruct['DATA_TYPE']
  73. ) {
  74. $storageType = Core_StorageFactory::getType('String');
  75. if ($fieldStruct['CHARACTER_MAXIMUM_LENGTH'] > 0) {
  76. $storageType->setMaxLength($fieldStruct['CHARACTER_MAXIMUM_LENGTH']);
  77. }
  78. }
  79. else if ('text' == $fieldStruct['DATA_TYPE']
  80. || 'longtext' == $fieldStruct['DATA_TYPE']
  81. || 'mediumtext' == $fieldStruct['DATA_TYPE']
  82. || 'tinytext' == $fieldStruct['DATA_TYPE']
  83. ) {
  84. $storageType = Core_StorageFactory::getType('Text');
  85. }
  86. else if ('int' == $fieldStruct['DATA_TYPE']
  87. || 'tinyint' == $fieldStruct['DATA_TYPE']
  88. || 'smallint' == $fieldStruct['DATA_TYPE']
  89. || 'mediumint' == $fieldStruct['DATA_TYPE']
  90. || 'bigint' == $fieldStruct['DATA_TYPE']
  91. || 'bit' == $fieldStruct['DATA_TYPE']
  92. ) {
  93. $storageType = Core_StorageFactory::getType('Integer');
  94. $storageType->setTotalDigits($fieldStruct['NUMERIC_PRECISION']);
  95. }
  96. else if ('decimal' == $fieldStruct['DATA_TYPE']) {
  97. $storageType = Core_StorageFactory::getType('Decimal');
  98. if ($fieldStruct['NUMERIC_SCALE'] > 0) {
  99. $storageType->setFractionDigits($fieldStruct['NUMERIC_SCALE']);
  100. }
  101. if ($fieldStruct['NUMERIC_PRECISION'] > 0) {
  102. $storageType->setTotalDigits($fieldStruct['NUMERIC_PRECISION']);
  103. }
  104. }
  105. else if ('double' == $fieldStruct['DATA_TYPE']
  106. || 'real' == $fieldStruct['DATA_TYPE']
  107. || 'float' == $fieldStruct['DATA_TYPE']
  108. ) {
  109. $storageType = Core_StorageFactory::getType('Double');
  110. }
  111. else if ('binary' == $fieldStruct['DATA_TYPE']
  112. || 'varbinary' == $fieldStruct['DATA_TYPE']
  113. || 'blob' == $fieldStruct['DATA_TYPE']
  114. || 'tinyblob' == $fieldStruct['DATA_TYPE']
  115. || 'longblob' == $fieldStruct['DATA_TYPE']
  116. || 'mediumblob' == $fieldStruct['DATA_TYPE']
  117. ) {
  118. $storageType = Core_StorageFactory::getType('Binary');
  119. $storageType->setRestriction('maxExclusive', $fieldStruct['CHARACTER_MAXIMUM_LENGTH']);
  120. }
  121. else if ('enum' == $fieldStruct['DATA_TYPE']) {
  122. $storageType = Core_StorageFactory::getType('Enumeration');
  123. $enumValues = explode(',', str_replace(array('(',')',"'",'"'), '', substr($fieldStruct['COLUMN_TYPE'], 5)));
  124. $enumList = array();
  125. foreach ($enumValues as $value) {
  126. $enumList[] = $value;
  127. }
  128. $storageType->setEnumeration($enumList);
  129. }
  130. else if ('timestamp' == $fieldStruct['DATA_TYPE']) {
  131. $storageType = Core_StorageFactory::getType('DateTime');
  132. $storageType->setFormat('yyyy-MM-dd hh:mm:ss');
  133. }
  134. else if ('datetime' == $fieldStruct['DATA_TYPE']) {
  135. $storageType = Core_StorageFactory::getType('DateTime');
  136. $storageType->setFormat('yyyy-MM-dd hh:mm');
  137. }
  138. else if ('date' == $fieldStruct['DATA_TYPE']) {
  139. $storageType = Core_StorageFactory::getType('Date');
  140. $storageType->setFormat('yyyy-MM-dd');
  141. }
  142. else if ('time' == $fieldStruct['DATA_TYPE']) {
  143. $storageType = Core_StorageFactory::getType('Time');
  144. $storageType->setFormat('hh:mm:ss');
  145. }
  146. else if ('year' == $fieldStruct['DATA_TYPE']) {
  147. $storageType = Core_StorageFactory::getType('Year');
  148. $storageType->setFormat('yyyy');
  149. }
  150. else if ('point' == $fieldStruct['DATA_TYPE']) {
  151. $storageType = Core_StorageFactory::getType('Point');
  152. }
  153. else if ('linestring' == $fieldStruct['DATA_TYPE']) {
  154. $storageType = Core_StorageFactory::getType('Linestring');
  155. }
  156. else if ('polygon' == $fieldStruct['DATA_TYPE']) {
  157. $storageType = Core_StorageFactory::getType('Polygon');
  158. }
  159. else if ('geometry' == $fieldStruct['DATA_TYPE']
  160. || 'multipoint' == $fieldStruct['DATA_TYPE']
  161. || 'multilinestring' == $fieldStruct['DATA_TYPE']
  162. || 'multipolygon' == $fieldStruct['DATA_TYPE']
  163. || 'geometrycollection' == $fieldStruct['DATA_TYPE']
  164. ) {
  165. $storageType = Core_StorageFactory::getType('Geometry');
  166. $storageType->setSpatialType($fieldStruct['COLUMN_TYPE']);
  167. }
  168. else {
  169. $storageType = Core_StorageFactory::getType('Unknown');
  170. $storageType->setRawType($fieldStruct['COLUMN_TYPE']);
  171. }
  172. if (!$storageType) {
  173. echo "<div class=\"alert alert-warning\">Storage type '{$fieldStruct['COLUMN_TYPE']}' not recognized</div>";
  174. //TODO: throw new Exception("Storage type '{$fieldStruct['COLUMN_TYPE']}' not recognized");
  175. }
  176. if ('PRI' == $fieldStruct['COLUMN_KEY']) {
  177. $storageType->setPrimaryKey(true);
  178. }
  179. $vFldNillable = false;
  180. if ('YES' == $fieldStruct['IS_NULLABLE']) {
  181. $vFldNillable = true;
  182. } else if ('NO' == $fieldStruct['IS_NULLABLE']
  183. && 'PRI' == $fieldStruct['COLUMN_KEY']
  184. && 'auto_increment' == $fieldStruct['EXTRA']
  185. ) {
  186. $vFldNillable = true;
  187. }
  188. $storageType->setNillable($vFldNillable);
  189. if (!empty($fieldStruct['COLUMN_DEFAULT'])) {
  190. $storageType->setDefault($fieldStruct['COLUMN_DEFAULT']);
  191. } else if ('0' === $fieldStruct['COLUMN_DEFAULT']) {
  192. $storageType->setDefault(0);
  193. } else if ('' === $fieldStruct['COLUMN_DEFAULT']) {
  194. $storageType->setDefault('');
  195. } else if (null === $fieldStruct['COLUMN_DEFAULT']
  196. && 'YES' == $fieldStruct['IS_NULLABLE']
  197. && 1 == $fieldStruct['COLUMN_DEFAULT_IS_NULL']
  198. ) {
  199. $storageType->setDefault(null);
  200. }
  201. $tblStruct[$fldName] = $storageType;
  202. }
  203. return $tblStruct;
  204. }
  205. public function getTableStructRaw($tblName) {
  206. $tblNamePattern = '/^[a-zA-Z0-9_]+$/';
  207. if (!preg_match($tblNamePattern, $tblName)) {
  208. throw new Exception("Table name not allowed");
  209. }
  210. $sqlTblName = $tblName;
  211. $sql = "show fields from `{$sqlTblName}` ";
  212. $sql = "select cols.*
  213. -- , `IS_NULLABLE` as `Nullable`
  214. -- , `COLUMN_DEFAULT` as `DEFAULT`
  215. , IF(cols.`IS_NULLABLE`='YES' and cols.`COLUMN_DEFAULT` is null, 1, 0) as `COLUMN_DEFAULT_IS_NULL`
  216. from `INFORMATION_SCHEMA`.`COLUMNS` cols
  217. where cols.`TABLE_NAME`='{$sqlTblName}'
  218. and cols.`TABLE_SCHEMA`='{$this->_databaseName}'
  219. ";
  220. return $this->fetchAllAssoc($sql);
  221. }
  222. public function getViewStructTODO($viewName) {// TODO: getViewStruct
  223. $viewNamePattern = '/^[a-zA-Z0-9_]+$/';
  224. if (!preg_match($viewNamePattern, $viewName)) {
  225. throw new Exception("View name not allowed");
  226. }
  227. }
  228. public function getViewStructRaw($viewName) {
  229. $viewNamePattern = '/^[a-zA-Z0-9_]+$/';
  230. if (!preg_match($viewNamePattern, $viewName)) {
  231. throw new Exception("View name not allowed");
  232. }
  233. $sqlViewName = $viewName;
  234. $sql = "show create view `{$sqlViewName}` ";
  235. return $this->fetchAllAssoc($sql);
  236. }
  237. public function getTableListWithInfo() {
  238. return $this->getTableFullList();
  239. }
  240. public function getTableList() {
  241. return array_filter($this->getTableFullList(), function($row) {
  242. return ('BASE TABLE' == $row['table_type']);
  243. });
  244. }
  245. public function getViewList() {
  246. return array_filter($this->getTableFullList(), function($row) {
  247. return ('VIEW' == $row['table_type']);
  248. });
  249. }
  250. public function getTableFullList() {
  251. return array_map(function($row) {
  252. $values = array_values($row);
  253. return array('table_name' => strtolower($values[0]), 'table_type' => $values[1]);
  254. }, $this->_pdo->fetchAll('show full tables'));
  255. }
  256. function createTableStructure($conf) { // @param $conf: [ 'tableName', 'fields', 'primaryKey', 'keys' ]
  257. $encoding = V::get('encoding', "latin2", $conf);
  258. $sqlLinesCreateCmd = array_map([ self, '_makeCreateFieldCommand' ], $conf['fields']);
  259. if (!empty($conf['primaryKey'])) $sqlLinesCreateCmd[] = "PRIMARY KEY (`{$conf['primaryKey']}`)";
  260. if (!empty($conf['keys'])) throw new Exception("");
  261. $sql = "CREATE TABLE IF NOT EXISTS `{$conf['tableName']}` (" .
  262. "\n\t" . implode(",\n\t", $sqlLinesCreateCmd) .
  263. "\n" . ") ENGINE=MyISAM DEFAULT CHARSET={$encoding};";
  264. DBG::nicePrint($sql, "DBG:create table sql");
  265. $this->_pdo->execSql($sql);
  266. // CREATE TABLE IF NOT EXISTS `CRM__@SELECTED_CONTEXT` (
  267. // `ID` int(11) unsigned NOT NULL AUTO_INCREMENT,
  268. // `name` varchar(32) NOT NULL,
  269. // `A_CREATE_TIME` datetime,
  270. // `A_LAST_ACCESS_TIME` datetime,
  271. // `A_LAST_UPDATE_TIME` datetime,
  272. // PRIMARY KEY (`ID`),
  273. // UNIQUE KEY `name` (`name`)
  274. // ) ENGINE=MyISAM DEFAULT CHARSET=utf8;
  275. }
  276. static function _makeCreateFieldCommand($fieldStruct) {
  277. $isNullable = V::get('is_nullable', '', $fieldStruct);
  278. return implode(" ", [
  279. $fieldStruct['name'],
  280. $fieldStruct['raw_storage_type'],
  281. ($isNullable) ? "" : "NOT NULL",
  282. V::get('extra', '', $fieldStruct),
  283. ]);
  284. }
  285. }