Pgsql.php 9.6 KB

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