Pgsql.php 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. <?php
  2. Lib::loadClass('Core_StorageBase');
  3. Lib::loadClass('Core_StorageFactory');
  4. class Core_Storage_Pgsql 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 getTableStruct($tblName) {
  14. throw new Exception("TODO: F." . __FUNCTION__);
  15. $sql = "
  16. -- show fields from {$tblName}
  17. select cols.COLUMN_NAME as name
  18. , cols.DATA_TYPE as type
  19. , if('YES' = cols.IS_NULLABLE, 1, 0) as is_nullable
  20. , cols.COLUMN_DEFAULT as default_value
  21. , if(cols.COLUMN_DEFAULT is null, 1, 0) as default_is_null
  22. , cols.CHARACTER_MAXIMUM_LENGTH as max_length
  23. , cols.NUMERIC_PRECISION as num_precision
  24. , cols.NUMERIC_SCALE as num_scale
  25. , cols.CHARACTER_SET_NAME as char_encoding -- latin2
  26. , cols.COLLATION_NAME as char_collation -- latin2_general_ci
  27. , cols.EXTRA as extra
  28. , cols.COLUMN_TYPE as raw_storage_type
  29. -- , cols.*
  30. from INFORMATION_SCHEMA.COLUMNS cols
  31. where cols.TABLE_SCHEMA like :db_name
  32. and cols.TABLE_NAME like :tbl_name
  33. ";
  34. $sth = $this->_pdo->prepare($sql);
  35. $sth->bindValue(':db_name', $this->_pdo->getDatabaseName(), PDO::PARAM_STR);
  36. $sth->bindValue(':tbl_name', $tblName, PDO::PARAM_STR);
  37. $sth->execute();
  38. $structRaw = $sth->fetchAll();
  39. if (empty($structRaw)) throw new Exception("Empty struct for table '{$tblName}'");
  40. foreach ($structRaw as $field) {
  41. $struct[$field['name']] = $field;
  42. }
  43. return $struct;
  44. }
  45. protected function _getTableStruct($tblName) {// ?
  46. $tblStructRaw = $this->getTableStructRaw($tblName);
  47. $tblStruct = array();
  48. foreach ($tblStructRaw as $fieldStruct) {
  49. $fldName = $fieldStruct['column_name'];
  50. $storageType = '';
  51. if ('integer' == $fieldStruct['data_type']
  52. || 'bigint' == $fieldStruct['data_type']
  53. || 'smallint' == $fieldStruct['data_type']
  54. ) {
  55. $storageType = Core_StorageFactory::getType('Integer');
  56. }
  57. else if ('character varying' == $fieldStruct['data_type']
  58. || 'character' == $fieldStruct['data_type']
  59. ) {
  60. $storageType = Core_StorageFactory::getType('String');
  61. $storageType->setMaxLength($fieldStruct['character_maximum_length']);
  62. }
  63. else if ('numeric' == $fieldStruct['data_type']
  64. || 'decimal' == $fieldStruct['data_type']
  65. ) {
  66. $storageType = Core_StorageFactory::getType('Decimal');
  67. }
  68. else if ('real' == $fieldStruct['data_type']
  69. || 'double precision' == $fieldStruct['data_type']
  70. ) {
  71. $storageType = Core_StorageFactory::getType('Double');
  72. }
  73. else if ('text' == $fieldStruct['data_type']) {
  74. $storageType = Core_StorageFactory::getType('Text');
  75. }
  76. else if ('"char"' == $fieldStruct['data_type']) {
  77. $storageType = Core_StorageFactory::getType('String');
  78. $storageType->setMaxLength(1);
  79. }
  80. else if ('date' == $fieldStruct['data_type']) {
  81. $storageType = Core_StorageFactory::getType('Date');
  82. }
  83. else if ('timestamp without time zone' == $fieldStruct['data_type']) {
  84. $storageType = Core_StorageFactory::getType('DateTime');
  85. }
  86. else if ('timestamp with time zone' == $fieldStruct['data_type']) {
  87. $storageType = Core_StorageFactory::getType('DateTime');
  88. }
  89. else if ('USER-DEFINED' == $fieldStruct['data_type']) {
  90. if ('geometry' == $fieldStruct['udt_name']) {
  91. $storageType = Core_StorageFactory::getType('Geometry');
  92. $rawStructure = $this->_getStructureRaw('public', $tblName, $fldName);
  93. if (!empty($rawStructure[0]['type'])) {
  94. $spatialType = $rawStructure[0]['type'];
  95. $storageType->setSpatialType($spatialType);
  96. }
  97. } else {
  98. $storageType = Core_StorageFactory::getType('Unknown');
  99. $storageType->setRawType(array('data_type'=>$fieldStruct['data_type'], 'udt_name'=>$fieldStruct['udt_name']));
  100. }
  101. }
  102. else {
  103. $storageType = Core_StorageFactory::getType('Unknown');
  104. $storageType->setRawType(array('data_type'=>$fieldStruct['data_type'], 'udt_name'=>$fieldStruct['udt_name']));
  105. }
  106. if (!$storageType) {
  107. echo "<div class=\"alert alert-warning\">Storage type '{$fieldStruct['Type']}' not recognized</div>";
  108. // TODO: throw new Exception("Storage type '{$fieldStruct['Type']}' not recognized");
  109. }
  110. if ($fieldStruct['is_primary_key'] > 0) {
  111. $storageType->setPrimaryKey(true);
  112. }
  113. $vFldNillable = false;
  114. if ('YES' == $fieldStruct['is_nullable']) {
  115. $vFldNillable = true;
  116. } else if ('NO' == $fieldStruct['is_nullable']
  117. && $fieldStruct['is_primary_key'] > 0
  118. && 'nextval(' == substr($fieldStruct['column_default'], 0, 8)
  119. ) {
  120. $vFldNillable = true;
  121. }
  122. $storageType->setNillable($vFldNillable);
  123. $vFldDefault = $fieldStruct['column_default'];
  124. if (!empty($vFldDefault)) {
  125. if ('::"char"' == substr($vFldDefault, -8)) {
  126. $vFldDefault = substr($vFldDefault, 1, -9);
  127. $storageType->setDefault($vFldDefault);
  128. } else if ('::"text"' == substr($vFldDefault, -8)) {
  129. $vFldDefault = substr($vFldDefault, 1, -9);
  130. $storageType->setDefault($vFldDefault);
  131. } else if ('::bpchar' == substr($vFldDefault, -8)) {
  132. $vFldDefault = substr($vFldDefault, 1, -9);
  133. $storageType->setDefault($vFldDefault);
  134. } else if ('::character varying' == substr($vFldDefault, -19)) {
  135. $vFldDefault = substr($vFldDefault, 1, -20);
  136. $storageType->setDefault($vFldDefault);
  137. } else if (is_numeric($vFldDefault)) {
  138. $storageType->setDefault($vFldDefault);
  139. } else if ('now()' == $vFldDefault) {
  140. // TODO: default = now()
  141. }
  142. } else if ('0' === $vFldDefault) {
  143. $storageType->setDefault('0');
  144. }
  145. $tblStruct[$fldName] = $storageType;
  146. }
  147. return $tblStruct;
  148. }
  149. public function getTableStructRaw($tblName) {// ?
  150. $tblNamePattern = '/^[a-zA-Z0-9_]+$/';
  151. if (!preg_match($tblNamePattern, $tblName)) {
  152. throw new Exception("Table name not allowed");
  153. }
  154. $sqlTblName = $tblName;
  155. $sql = "select * from information_schema.columns where table_name='{$sqlTblName}'";
  156. $sqlAllPrimaryKeys = "
  157. select tc.table_schema, tc.table_name, kc.column_name
  158. from
  159. information_schema.table_constraints tc,
  160. information_schema.key_column_usage kc
  161. where
  162. tc.constraint_type = 'PRIMARY KEY'
  163. and kc.table_name = tc.table_name
  164. and kc.table_schema = tc.table_schema
  165. and kc.constraint_name = tc.constraint_name
  166. order by 1, 2;
  167. ";
  168. $sql = "select cols.*
  169. , (select count(kc.column_name)
  170. from information_schema.table_constraints tc
  171. join information_schema.key_column_usage kc on(kc.table_name = tc.table_name
  172. and kc.table_schema = tc.table_schema
  173. and kc.constraint_name = tc.constraint_name)
  174. where tc.constraint_type = 'PRIMARY KEY'
  175. and tc.table_name = cols.table_name
  176. and kc.column_name = cols.column_name
  177. ) as is_primary_key
  178. from information_schema.columns cols
  179. where cols.table_name='{$sqlTblName}'
  180. ";
  181. return $this->fetchAllAssoc($sql);
  182. }
  183. public function getTableListWithInfo() {
  184. return $this->_getPgsqlStructureRaw();
  185. }
  186. public function _getPgsqlStructureRaw($schemaName = 'public', $tableName = '', $fieldName = '') {
  187. $rawStructureList = array();
  188. $sqlWhereAndSchemaName = ($schemaName) ? " and n.nspname='{$schemaName}' " : '';
  189. $sqlWhereAndTableName = ($tableName) ? " and c.relname='{$tableName}' " : '';
  190. $sqlWhereAndFieldName = ($fieldName) ? " and f.attname='{$fieldName}' " : '';
  191. $sql = "
  192. select
  193. c.relname as table_name,
  194. f.attnum as number,
  195. f.attname as name,
  196. f.attnum,
  197. f.attnotnull as notnull,
  198. f.atttypid,
  199. f.atttypmod,
  200. pg_catalog.format_type(f.atttypid,f.atttypmod) as type,
  201. case when p.contype = 'p' then 1 else 0 end as primarykey,
  202. case when p.contype = 'u' then 1 else 0 end as uniquekey,
  203. case when p.contype = 'f' then g.relname end as foreignkey,
  204. case when p.contype = 'f' then p.confkey end as foreignkey_fieldnum,
  205. case when p.contype = 'f' then g.relname end as foreignkey,
  206. case when p.contype = 'f' then p.conkey end as foreignkey_connnum,
  207. case when f.atthasdef = 't' then d.adsrc end as default
  208. from pg_attribute f
  209. join pg_class c on c.oid = f.attrelid
  210. join pg_type t on t.oid = f.atttypid
  211. left join pg_attrdef d on d.adrelid = c.oid and d.adnum = f.attnum
  212. left join pg_namespace n on n.oid = c.relnamespace
  213. left join pg_constraint p on p.conrelid = c.oid and f.attnum = any (p.conkey)
  214. left join pg_class as g on p.confrelid = g.oid
  215. where c.relkind = 'r'::char
  216. {$sqlWhereAndSchemaName}
  217. {$sqlWhereAndTableName}
  218. {$sqlWhereAndFieldName}
  219. and f.attnum > 0
  220. order by c.relname, number
  221. ";
  222. return $this->_pdo->fetchAll($sql);
  223. }
  224. public function getTableList() {
  225. return array_filter($this->getTableFullList(), function($row) {
  226. return ('BASE TABLE' == $row['table_type']);
  227. });
  228. }
  229. public function getViewList() {
  230. return array_filter($this->getTableFullList(), function($row) {
  231. return ('VIEW' == $row['table_type']);
  232. });
  233. }
  234. public function getTableFullList() {
  235. return array_map(function($row) {
  236. $row['table_name'] = strtolower($row['table_name']);
  237. return $row;
  238. }, $this->_pdo->fetchAll("
  239. select table_name, table_type
  240. from information_schema.tables
  241. where table_schema not in ('pg_catalog', 'information_schema')
  242. "));
  243. }
  244. public function fetchAllAssoc($sql) {// ?
  245. if (empty($sql)) {
  246. throw new Exception("Empty query");
  247. }
  248. $stmt = $this->_pdo->query($sql);
  249. return $stmt->fetchAll(PDO::FETCH_ASSOC);
  250. }
  251. }