ILIAS  trunk Revision v11.0_alpha-3011-gc6b235a2e85
class.ilDBPdoManager.php
Go to the documentation of this file.
1<?php
2
19declare(strict_types=1);
20
22
28{
29 protected ?\ilQueryUtils $query_utils = null;
30
34 public function __construct(protected \PDO $pdo, protected \ilDBPdo $db_instance)
35 {
36 }
37
38 public function getQueryUtils(): \ilQueryUtils
39 {
40 if ($this->query_utils === null) {
41 $this->query_utils = new ilMySQLQueryUtils($this->db_instance);
42 }
43
44 return $this->query_utils;
45 }
46
47 public function getDBInstance(): \ilDBPdo
48 {
49 return $this->db_instance;
50 }
51
55 public function listTables(?string $database = null): array
56 {
57 $str = 'SHOW TABLES ' . ($database ? ' IN ' . $database : '');
58 $r = $this->pdo->query($str);
59 $tables = [];
60
61 $sequence_identifier = "_seq";
62 while ($data = $r->fetchColumn()) {
63 if (!preg_match("/$sequence_identifier$/um", $data)) {
64 $tables[] = $data;
65 }
66 }
67
68 return $tables;
69 }
70
71 protected function fixSequenceName(string $sqn, bool $check = false): string
72 {
73 $seq_pattern = '/^' . preg_replace('/%s/', '([a-z0-9_]+)', ilDBConstants::SEQUENCE_FORMAT) . '$/i';
74 $seq_name = preg_replace($seq_pattern, '\\1', $sqn);
75 if ($seq_name && !strcasecmp($sqn, $this->db_instance->getSequenceName($seq_name))) {
76 return $seq_name;
77 }
78
79 return $sqn;
80 }
81
85 public function listSequences(?string $database = null): array
86 {
87 $query = "SHOW TABLES LIKE '%_seq'";
88 if (!is_null($database)) {
89 $query .= " FROM $database";
90 }
91
92 $res = $this->db_instance->query($query);
93
94 $result = [];
95 while ($table_name = $this->db_instance->fetchAssoc($res)) {
96 $sqn = $this->fixSequenceName(reset($table_name), true);
97 if ($sqn !== '' && $sqn !== '0') {
98 $result[] = $sqn;
99 }
100 }
101 if ($this->db_instance->options['portability'] ?? null) {
102 return array_map(
103 ($this->db_instance->options['field_case'] === CASE_LOWER ? 'strtolower' : 'strtoupper'),
104 $result
105 );
106 }
107
108 return $result;
109 }
110
114 public function createConstraint(string $table, string $name, array $definition): bool
115 {
116 $db = $this->db_instance;
117
118 $table = $db->quoteIdentifier($table, true);
119 $name = $db->quoteIdentifier($db->getIndexName($name), true);
120 $query = "ALTER TABLE $table ADD CONSTRAINT $name";
121 if (!empty($definition['primary'])) {
122 $query .= ' PRIMARY KEY';
123 } elseif (!empty($definition['unique'])) {
124 $query .= ' UNIQUE';
125 }
126 $fields = [];
127 foreach (array_keys($definition['fields']) as $field) {
128 $fields[] = $db->quoteIdentifier($field, true);
129 }
130 $query .= ' (' . implode(', ', $fields) . ')';
131
132 return (bool) $this->pdo->exec($query);
133 }
134
135 public function createSequence(string $seq_name, int $start = 1, array $options = []): bool
136 {
137 $sequence_name = $this->db_instance->quoteIdentifier($this->db_instance->getSequenceName($seq_name));
138 $seqcol_name = $this->db_instance->quoteIdentifier(ilDBConstants::SEQUENCE_COLUMNS_NAME);
139
140 $options_strings = [];
141
142 if (!empty($options['comment'])) {
143 $options_strings['comment'] = 'COMMENT = ' . $this->db_instance->quote($options['comment'], 'text');
144 }
145
146 if (!empty($options['charset'])) {
147 $options_strings['charset'] = 'DEFAULT CHARACTER SET ' . $options['charset'];
148 if (!empty($options['collate'])) {
149 $options_strings['charset'] .= ' COLLATE ' . $options['collate'];
150 }
151 }
152
153 $type = false;
154 if (!empty($options['type'])) {
155 $type = $options['type'];
156 }
157 if ($type) {
158 $options_strings[] = "ENGINE = $type";
159 }
160
161 $query = "CREATE TABLE $sequence_name ($seqcol_name INT NOT NULL AUTO_INCREMENT, PRIMARY KEY ($seqcol_name))";
162
163 if (!empty($options_strings)) {
164 $query .= ' ' . implode(' ', $options_strings);
165 }
166 $this->pdo->exec($query);
167
168 if ($start == 1) {
169 return true;
170 }
171
172 $query = "INSERT INTO $sequence_name ($seqcol_name) VALUES (" . ($start - 1) . ')';
173 $this->pdo->exec($query);
174
175 return true;
176 }
177
181 public function alterTable(string $name, array $changes, bool $check): bool
182 {
183 $db = $this->db_instance;
184
185 foreach (array_keys($changes) as $change_name) {
186 switch ($change_name) {
187 case 'add':
188 case 'remove':
189 case 'change':
190 case 'rename':
191 case 'name':
192 break;
193 default:
194 throw new ilDatabaseException('change type "' . $change_name . '" not yet supported');
195 }
196 }
197
198 if ($check) {
199 return true;
200 }
201
202 $query = '';
203 if (!empty($changes['name'])) {
204 $change_name = $db->quoteIdentifier($changes['name']);
205 $query .= 'RENAME TO ' . $change_name;
206 }
207
208 if (!empty($changes['add']) && is_array($changes['add'])) {
209 foreach ($changes['add'] as $field_name => $field) {
210 if ($query !== '') {
211 $query .= ', ';
212 }
213 $fd = $db->getFieldDefinition();
214 if ($fd !== null) {
215 $query .= 'ADD ' . $fd->getDeclaration($field['type'], $field_name, $field);
216 }
217 }
218 }
219
220 if (!empty($changes['remove']) && is_array($changes['remove'])) {
221 foreach (array_keys($changes['remove']) as $field_name) {
222 if ($query !== '') {
223 $query .= ', ';
224 }
225 $field_name = $db->quoteIdentifier($field_name);
226 $query .= 'DROP ' . $field_name;
227 }
228 }
229
230 $rename = [];
231 if (!empty($changes['rename']) && is_array($changes['rename'])) {
232 foreach ($changes['rename'] as $field_name => $field) {
233 $rename[$field['name']] = $field_name;
234 }
235 }
236
237 if (!empty($changes['change']) && is_array($changes['change'])) {
238 foreach ($changes['change'] as $field_name => $field) {
239 if ($query !== '') {
240 $query .= ', ';
241 }
242 if (isset($rename[$field_name])) {
243 $old_field_name = $rename[$field_name];
244 unset($rename[$field_name]);
245 } else {
246 $old_field_name = $field_name;
247 }
248 $old_field_name = $db->quoteIdentifier($old_field_name);
249 $fd = $this->db_instance->getFieldDefinition();
250 if ($fd !== null) {
251 $query .= "CHANGE $old_field_name " . $fd
252 ->getDeclaration(
253 $field['definition']['type'],
254 $field_name,
255 $field['definition']
256 );
257 }
258 }
259 }
260
261 if (!empty($rename) && is_array($rename)) {
262 foreach ($rename as $renamed_field) {
263 if ($query !== '') {
264 $query .= ', ';
265 }
266 $field = $changes['rename'][$renamed_field];
267 $renamed_field = $db->quoteIdentifier($renamed_field);
268 $fd = $this->db_instance->getFieldDefinition();
269 if ($fd !== null) {
270 $query .= 'CHANGE ' . $renamed_field . ' ' . $fd
271 ->getDeclaration(
272 $field['definition']['type'],
273 $field['name'],
274 $field['definition']
275 );
276 }
277 }
278 }
279
280 if ($query === '') {
281 return true;
282 }
283
284 $name = $db->quoteIdentifier($name, true);
285
286 $statement = "ALTER TABLE $name $query";
287
288 return (bool) $this->pdo->exec($statement);
289 }
290
291 public function createTable(string $name, array $fields, array $options = []): bool
292 {
293 $options['type'] = $this->db_instance->getStorageEngine();
294
295 return (bool) $this->pdo->exec($this->getQueryUtils()->createTable($name, $fields, $options));
296 }
297
298 public function getIndexName(string $idx): string
299 {
300 return $this->db_instance->getIndexName($idx);
301 }
302
303 public function getSequenceName(string $sqn): string
304 {
305 return $this->db_instance->getSequenceName($sqn);
306 }
307
308 public function listTableFields(string $table): array
309 {
310 $table = $this->db_instance->quoteIdentifier($table);
311 $query = "SHOW COLUMNS FROM $table";
312 $result = $this->db_instance->query($query);
313 $return = [];
314 while ($data = $this->db_instance->fetchObject($result)) {
315 $return[] = $data->Field;
316 }
317
318 return $return;
319 }
320
324 public function listTableConstraints(string $table): array
325 {
326 $key_name = 'Key_name';
327 $non_unique = 'Non_unique';
328
329 $db = $this->getDBInstance();
330 if ($db->options['portability'] ?? null) {
331 if ($db->options['field_case'] == CASE_LOWER) {
332 $key_name = strtolower($key_name);
333 $non_unique = strtolower($non_unique);
334 } else {
335 $key_name = strtoupper($key_name);
336 $non_unique = strtoupper($non_unique);
337 }
338 }
339
340 $table = $this->db_instance->quoteIdentifier($table);
341 $query = "SHOW INDEX FROM $table";
342 $result_set = $this->db_instance->query($query);
343
344 $result = [];
345 while ($index_data = $this->db_instance->fetchAssoc($result_set)) {
346 if (!$index_data[$non_unique]) {
347 $index = $index_data[$key_name] !== 'PRIMARY' ? $this->fixIndexName($index_data[$key_name]) : 'PRIMARY';
348 if (!empty($index)) {
349 $index = strtolower($index);
350 $result[$index] = true;
351 }
352 }
353 }
354
355 if ($this->db_instance->options['portability'] ?? null) {
356 $result = array_change_key_case($result, $this->db_instance->options['field_case']);
357 }
358
359 return array_keys($result);
360 }
361
365 public function listTableIndexes(string $table): array
366 {
367 $key_name = 'Key_name';
368 $non_unique = 'Non_unique';
369 if ($this->db_instance->options['portability'] ?? null) {
370 if ($this->db_instance->options['field_case'] == CASE_LOWER) {
371 $key_name = strtolower($key_name);
372 $non_unique = strtolower($non_unique);
373 } else {
374 $key_name = strtoupper($key_name);
375 $non_unique = strtoupper($non_unique);
376 }
377 }
378
379 $table = $this->db_instance->quoteIdentifier($table);
380 $query = "SHOW INDEX FROM $table";
381 $result_set = $this->db_instance->query($query);
382 $indexes = [];
383 while ($index_data = $this->db_instance->fetchAssoc($result_set)) {
384 $indexes[] = $index_data;
385 }
386 $result = [];
387 foreach ($indexes as $index_data) {
388 if ($index_data[$non_unique] && ($index = $this->fixIndexName($index_data[$key_name]))) {
389 $result[$index] = true;
390 }
391 }
392
393 if ($this->db_instance->options['portability'] ?? null) {
394 $result = array_change_key_case($result, $this->db_instance->options['field_case']);
395 }
396
397 return array_keys($result);
398 }
399
400 protected function fixIndexName(string $idx): string
401 {
402 $idx_pattern = '/^' . preg_replace('/%s/', '([a-z0-9_]+)', ilDBPdoFieldDefinition::INDEX_FORMAT) . '$/i';
403 $idx_name = preg_replace($idx_pattern, '\\1', $idx);
404 if ($idx_name && !strcasecmp($idx, $this->db_instance->getIndexName($idx_name))) {
405 return $idx_name;
406 }
407
408 return $idx;
409 }
410
411 public function createIndex(string $table, string $name, array $definition): bool
412 {
413 $table = $this->db_instance->quoteIdentifier($table, true);
414 $name = $this->db_instance->quoteIdentifier($this->db_instance->getIndexName($name), true);
415 $query = "CREATE INDEX $name ON $table";
416 $fields = [];
417 foreach ($definition['fields'] as $field => $fieldinfo) {
418 if (!empty($fieldinfo['length'])) {
419 $fields[] = $this->db_instance->quoteIdentifier($field, true) . '(' . $fieldinfo['length'] . ')';
420 } else {
421 $fields[] = $this->db_instance->quoteIdentifier($field, true);
422 }
423 }
424 $query .= ' (' . implode(', ', $fields) . ')';
425
426 return (bool) $this->pdo->exec($query);
427 }
428
429 public function dropIndex(string $table, string $name): bool
430 {
431 $table = $this->db_instance->quoteIdentifier($table, true);
432 $name = $this->db_instance->quoteIdentifier($this->db_instance->getIndexName($name), true);
433
434 return (bool) $this->pdo->exec("DROP INDEX $name ON $table");
435 }
436
437 public function dropSequence(string $seq_name): bool
438 {
439 $sequence_name = $this->db_instance->quoteIdentifier($this->db_instance->getSequenceName($seq_name));
440
441 return (bool) $this->pdo->exec("DROP TABLE $sequence_name");
442 }
443
447 public function getTableCreationQuery(string $name, array $fields, array $options = []): string
448 {
449 return $this->getQueryUtils()->createTable($name, $fields, $options);
450 }
451
452 public function dropConstraint(string $table, string $name, bool $primary = false): bool
453 {
454 $db = $this->getDBInstance();
455 $table = $db->quoteIdentifier($table, true);
456 if ($primary || strtolower($name) === 'primary') {
457 $query = "ALTER TABLE $table DROP PRIMARY KEY";
458 } else {
459 $name = $db->quoteIdentifier($db->getIndexName($name), true);
460 $query = "ALTER TABLE $table DROP INDEX $name";
461 }
462
463 return (bool) $this->pdo->exec($query);
464 }
465
466 public function dropTable(string $name): bool
467 {
468 $db = $this->getDBInstance();
469 $name = $db->quoteIdentifier($name, true);
470
471 return (bool) $this->pdo->exec("DROP TABLE $name");
472 }
473
478 public function addForeignKey(
479 string $foreign_key_name,
480 array $field_names,
481 string $table_name,
482 array $reference_field_names,
483 string $reference_table,
484 ?ForeignKeyConstraints $on_update = null,
485 ?ForeignKeyConstraints $on_delete = null
486 ): bool {
487 $table = $this->db_instance->quoteIdentifier($table_name, true);
488 $reference_table = $this->db_instance->quoteIdentifier($reference_table, true);
489 $field_names = implode(",", $field_names);
490 $field_names = $this->db_instance->quoteIdentifier($field_names, true);
491 $reference_field_names = implode(",", $reference_field_names);
492 $reference_field_names = $this->db_instance->quoteIdentifier($reference_field_names, true);
493 $foreign_key_name = $this->db_instance->quoteIdentifier($foreign_key_name, true);
494 $update = '';
495 if ($on_update !== null) {
496 $on_update = $on_update->value;
497 $update = "ON UPDATE $on_update";
498 }
499 $delete = '';
500 if ($on_delete !== null) {
501 $on_delete = $on_delete->value;
502 $delete = "ON DELETE $on_delete";
503 }
504 $query = "ALTER TABLE
505 $table ADD CONSTRAINT
506 $foreign_key_name FOREIGN KEY ($field_names)
507 REFERENCES $reference_table ($reference_field_names)
508 $update
509 $delete
510 ";
511
512 return (bool) $this->pdo->exec($query);
513 }
514
515 public function dropForeignKey(string $foreign_key_name, string $table_name): bool
516 {
517 $table = $this->db_instance->quoteIdentifier($table_name, true);
518 $name = $this->db_instance->quoteIdentifier($foreign_key_name, true);
519 $query = "ALTER TABLE $table DROP FOREIGN KEY $name;";
520
521 return (bool) $this->pdo->exec($query);
522 }
523
524 public function foreignKeyExists(string $foreign_key_name, string $table_name): bool
525 {
526 $query = "SELECT * FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE CONSTRAINT_TYPE='FOREIGN KEY';";
527 $result_set = $this->db_instance->query($query);
528 while ($foreign_data = $this->db_instance->fetchAssoc($result_set)) {
529 if (array_key_exists(
530 'CONSTRAINT_NAME',
531 $foreign_data
532 ) && $foreign_data['CONSTRAINT_NAME'] === $foreign_key_name) {
533 return true;
534 }
535 }
536 return false;
537 }
538}
$check
Definition: buildRTE.php:81
return true
Class ilDBPdoManager.
alterTable(string $name, array $changes, bool $check)
__construct(protected \PDO $pdo, protected \ilDBPdo $db_instance)
ilDBPdoManager constructor.
addForeignKey(string $foreign_key_name, array $field_names, string $table_name, array $reference_field_names, string $reference_table, ?ForeignKeyConstraints $on_update=null, ?ForeignKeyConstraints $on_delete=null)
dropSequence(string $seq_name)
dropConstraint(string $table, string $name, bool $primary=false)
listTableConstraints(string $table)
ilQueryUtils $query_utils
dropForeignKey(string $foreign_key_name, string $table_name)
getTableCreationQuery(string $name, array $fields, array $options=[])
fixSequenceName(string $sqn, bool $check=false)
createConstraint(string $table, string $name, array $definition)
createSequence(string $seq_name, int $start=1, array $options=[])
fixIndexName(string $idx)
listTables(?string $database=null)
dropTable(string $name)
createIndex(string $table, string $name, array $definition)
foreignKeyExists(string $foreign_key_name, string $table_name)
getIndexName(string $idx)
getSequenceName(string $sqn)
createTable(string $name, array $fields, array $options=[])
listTableIndexes(string $table)
dropIndex(string $table, string $name)
listSequences(?string $database=null)
listTableFields(string $table)
Class pdoDB.
Class ilDatabaseException.
Class ilMySQLQueryUtils.
Class ilQueryUtils.
Interface ilDBManager.
Interface ilDBPdoManagerInterface All these methods are not in MDB 2 will be moved to a seperate inte...
$res
Definition: ltiservices.php:69