ILIAS  release_5-2 Revision v5.2.25-18-g3f80b828510
class.ilDBPdoManagerPostgres.php
Go to the documentation of this file.
1<?php
2require_once('class.ilDBPdoManager.php');
3require_once('./Services/Database/classes/QueryUtils/class.ilPostgresQueryUtils.php');
4
11
15 public function getQueryUtils() {
16 if (!$this->query_utils) {
17 $this->query_utils = new ilPostgresQueryUtils($this->db_instance);
18 }
19
20 return $this->query_utils;
21 }
22
23
31 public function getTableCreationQuery($name, $fields, $options = array()) {
32 return $this->getQueryUtils()->createTable($name, $fields, $options);
33 }
34
35
42 public function createTable($name, $fields, $options = array()) {
43 return $this->pdo->exec($this->getQueryUtils()->createTable($name, $fields, $options));
44 }
45
46
51 public function listTables($database = null) {
53
54 // gratuitously stolen from PEAR DB _getSpecialQuery in pgsql.php
55 $query = 'SELECT c.relname AS "Name"' . ' FROM pg_class c, pg_user u' . ' WHERE c.relowner = u.usesysid' . " AND c.relkind = 'r'"
56 . ' AND NOT EXISTS' . ' (SELECT 1 FROM pg_views' . ' WHERE viewname = c.relname)' . " AND c.relname !~ '^(pg_|sql_)'" . ' UNION'
57 . ' SELECT c.relname AS "Name"' . ' FROM pg_class c' . " WHERE c.relkind = 'r'" . ' AND NOT EXISTS' . ' (SELECT 1 FROM pg_views'
58 . ' WHERE viewname = c.relname)' . ' AND NOT EXISTS' . ' (SELECT 1 FROM pg_user' . ' WHERE usesysid = c.relowner)'
59 . " AND c.relname !~ '^pg_'";
61
62 if ($db->options['portability']) {
63 $result = array_map(($db->options['field_case'] == CASE_LOWER ? 'strtolower' : 'strtoupper'), $result);
64 }
65 sort($result); // FSX Patch
66 return $result;
67 }
68
69
74 public function createDatabase($name) {
76 $name = $db->quoteIdentifier($name, true);
77
78 return $db->manipulate("CREATE DATABASE $name");
79 }
80
81
86 public function dropDatabase($name) {
88
89 $name = $db->quoteIdentifier($name, true);
90
91 return $db->manipulate("DROP DATABASE $name");
92 }
93
94
101 public function alterTable($name, $changes, $check) {
102 $db = $this->db_instance;
103 $reverse = $db->loadModule(ilDBConstants::MODULE_REVERSE);
108 foreach ($changes as $change_name => $change) {
109 switch ($change_name) {
110 case 'add':
111 case 'remove':
112 case 'change':
113 case 'name':
114 case 'rename':
115 break;
116 default:
117 throw new ilDatabaseException('change type "' . $change_name . '\" not yet supported');
118 }
119 }
120
121 if ($check) {
122 return true;
123 }
124
125 if (!empty($changes['add']) && is_array($changes['add'])) {
126 foreach ($changes['add'] as $field_name => $field) {
127
128 $query = 'ADD ' . $db->getFieldDefinition()->getDeclaration($field['type'], $field_name, $field);
129 $result = $db->manipulate("ALTER TABLE $name $query");
130 }
131 }
132
133 if (!empty($changes['remove']) && is_array($changes['remove'])) {
134 foreach ($changes['remove'] as $field_name => $field) {
135 $field_name = $db->quoteIdentifier($field_name, true);
136 $query = 'DROP ' . $field_name;
137 $result = $db->manipulate("ALTER TABLE $name $query");
138 }
139 }
140
141 if (!empty($changes['change']) && is_array($changes['change'])) {
142 foreach ($changes['change'] as $field_name => $field) {
143 $field_name = $db->quoteIdentifier($field_name, true);
144 if (!empty($field['type'])) {
145 $server_info = $db->getServerVersion();
146
147 if (is_array($server_info) && $server_info['major'] < 8) {
148 throw new ilDatabaseException('changing column type for "' . $change_name . '\" requires PostgreSQL 8.0 or above');
149 }
150
151 $query = "ALTER $field_name TYPE " . $db->getFieldDefinition()->getTypeDeclaration($field);
152 $result = $db->manipulate("ALTER TABLE $name $query");
153 }
154 if (array_key_exists('default', $field)) {
155 $query = "ALTER $field_name SET DEFAULT " . $db->quote($field['definition']['default'], $field['definition']['type']);
156 $result = $db->manipulate("ALTER TABLE $name $query");
157 }
158 if (!empty($field['notnull'])) {
159 $query = "ALTER $field_name " . ($field['definition']['notnull'] ? "SET" : "DROP") . ' NOT NULL';
160 $result = $db->manipulate("ALTER TABLE $name $query");
161 }
162 }
163 }
164
165 if (!empty($changes['rename']) && is_array($changes['rename'])) {
166 foreach ($changes['rename'] as $field_name => $field) {
167 $field_name = $db->quoteIdentifier($field_name, true);
168 $result = $db->manipulate("ALTER TABLE $name RENAME COLUMN $field_name TO " . $db->quoteIdentifier($field['name'], true));
169 }
170 }
171
172 if (!empty($changes['name'])) {
173 $result = $db->manipulate("ALTER TABLE " . $db->quoteIdentifier($name, true) . " RENAME TO " . $db->quoteIdentifier($changes['name']));
174
175 $idx = array_merge($this->listTableIndexes($changes['name']), $this->listTableConstraints($changes['name']));
176 foreach ($idx as $index_name) {
177 $index_newname = preg_replace("/^$name/", $changes['name'], $index_name);
178 $result = $db->manipulate("ALTER INDEX " . $this->getIndexName($index_name) . " RENAME TO " . $this->getIndexName($index_newname));
179 }
180 }
181
182 return true;
183 }
184
185
190 public function listTableFields($table) {
191 $db = $this->db_instance;
192
193 $table = $db->quoteIdentifier($table, true);
194 $res = $this->pdo->query("select * from $table");
195 for ($i = 0; $i < $res->columnCount(); $i++) {
196 $data[] = $res->getColumnMeta($i)["name"];
197 }
198 return $data;
199 }
200
201
206 public function listTableIndexes($table) {
207 $db = $this->db_instance;
208
209 $table = $db->quote($table, 'text');
210 $subquery = "SELECT indexrelid FROM pg_index, pg_class";
211 $subquery .= " WHERE pg_class.relname=$table AND pg_class.oid=pg_index.indrelid AND indisunique != 't' AND indisprimary != 't'";
212 $query = "SELECT relname FROM pg_class WHERE oid IN ($subquery)";
213 $indexes = $db->queryCol($query, 'text');
214
215 $result = array();
216 foreach ($indexes as $index) {
217 $index = $this->fixIndexName($index);
218 if (!empty($index)) {
219 $result[$index] = true;
220 }
221 }
222
223 if ($db->options['portability']) {
224 $result = array_change_key_case($result, $db->options['field_case']);
225 }
226
227 return array_keys($result);
228 }
229
230
235 public function listTableConstraints($table) {
236 $db = $this->db_instance;
237
238 $table = $db->quote($table, 'text');
239 $subquery = "SELECT indexrelid FROM pg_index, pg_class";
240 $subquery .= " WHERE pg_class.relname=$table AND pg_class.oid=pg_index.indrelid AND (indisunique = 't' OR indisprimary = 't')";
241 $query = "SELECT relname FROM pg_class WHERE oid IN ($subquery)";
242 $constraints = $db->queryCol($query);
243
244 $result = array();
245 foreach ($constraints as $constraint) {
246 $constraint = $this->fixIndexName($constraint);
247 if (!empty($constraint)) {
248 $result[$constraint] = true;
249 }
250 }
251
252 if ($db->options['portability']
253 && $db->options['field_case'] == CASE_LOWER
254 ) {
255 $result = array_change_key_case($result, $db->options['field_case']);
256 }
257
258 return array_keys($result);
259 }
260
261
268 public function createSequence($seq_name, $start = 1, $options = array()) {
269 $db = $this->db_instance;
270
271 $sequence_name = $db->quoteIdentifier($db->getSequenceName($seq_name), true);
272
273 return $db->manipulate("CREATE SEQUENCE $sequence_name INCREMENT 1" . ($start < 1 ? " MINVALUE $start" : '') . " START $start");
274 }
275
276
281 public function dropSequence($seq_name) {
282 $db = $this->db_instance;
283
284 $sequence_name = $db->quoteIdentifier($db->getSequenceName($seq_name), true);
285
286 return $db->manipulate("DROP SEQUENCE $sequence_name");
287 }
288
289
295 public function dropIndex($table, $name) {
296 $db = $this->db_instance;
297
298 $name = $this->getIndexName($name);
299 $name = $db->quoteIdentifier($this->getDBInstance()->constraintName($table, $name), true);
300
301 return $db->manipulate("DROP INDEX $name");
302 }
303
304
309 protected function fixIndexName($idx) {
310 $idx_pattern = '/^' . preg_replace('/%s/', '([a-z0-9_]+)', ilDBPdoFieldDefinition::INDEX_FORMAT) . '$/i';
311 $idx_name = preg_replace($idx_pattern, '\\1', $idx);
312 if ($idx_name && !strcasecmp($idx, $this->db_instance->getIndexName($idx_name))) {
313 return $idx_name;
314 }
315
316 return $idx;
317 }
318
319
324 public function listSequences($database = null) {
325 $db = $this->db_instance;
326
327 $query = "SELECT relname FROM pg_class WHERE relkind = 'S' AND relnamespace IN";
328 $query .= "(SELECT oid FROM pg_namespace WHERE nspname NOT LIKE 'pg_%' AND nspname != 'information_schema')";
329 $table_names = $db->queryCol($query);
330
331 $result = array();
332 foreach ($table_names as $table_name) {
333 $result[] = $this->fixSequenceName($table_name);
334 }
335 if ($db->options['portability']) {
336 $result = array_map(($db->options['field_case'] == CASE_LOWER ? 'strtolower' : 'strtoupper'), $result);
337 }
338 sort($result); // FSX patch
339
340 return $result;
341 }
342
343
350 public function dropConstraint($table, $name, $primary = false) {
351 $table_quoted = $this->getDBInstance()->quoteIdentifier($table, true);
352 $name = $this->getDBInstance()->quoteIdentifier($table . '_' . $this->getDBInstance()->getIndexName($name), true);
353
354 return $this->pdo->exec("ALTER TABLE $table_quoted DROP CONSTRAINT $name");
355 }
356}
$result
An exception for terminatinating execution or to throw for unit testing.
getTableCreationQuery($name, $fields, $options=array())
dropConstraint($table, $name, $primary=false)
createTable($name, $fields, $options=array())
createSequence($seq_name, $start=1, $options=array())
Class ilDBPdoManager.
fixSequenceName($sqn, $check=false)
alterTable($name, $changes, $check)
Class ilDatabaseException.
Class ilPostgresQueryUtils.
if(!is_array($argv)) $options