ILIAS  release_5-3 Revision v5.3.23-19-g915713cf615
class.ilMySQLAbstraction.php
Go to the documentation of this file.
1<?php
2/* Copyright (c) 1998-2009 ILIAS open source, Extended GPL, see docs/LICENSE */
3
13{
14
18 public $analyzer;
22 protected $ilDBInterface;
26 protected $manager;
30 protected $reverse;
34 protected $testmode;
35
36
40 public function __construct()
41 {
42 global $ilDB;
43
44 $this->ilDBInterface = $ilDB;
45 $this->manager = $ilDB->loadModule(ilDBConstants::MODULE_MANAGER);
46 $this->reverse = $ilDB->loadModule(ilDBConstants::MODULE_REVERSE);
47 if (@is_file('../Services/Database/classes/class.ilDBAnalyzer.php')) {
48 include_once '../Services/Database/classes/class.ilDBAnalyzer.php';
49 } else {
50 include_once './Services/Database/classes/class.ilDBAnalyzer.php';
51 }
52 $this->analyzer = new ilDBAnalyzer();
53 $this->setTestMode(false);
54 }
55
56
60 public function setTestMode($a_testmode)
61 {
62 $this->testmode = $a_testmode;
63 }
64
65
69 public function getTestMode()
70 {
71 return $this->testmode;
72 }
73
74
82 public function performAbstraction($a_table_name, $a_set_text_ts_fields_notnull_false = true)
83 {
84 // to do: log this procedure
85
86 // count number of records at the beginning
87 $nr_rec = $this->countRecords($a_table_name);
88
89 // convert table name to lowercase
90 if (!$this->getTestMode()) {
91 $this->lowerCaseTableName($a_table_name);
92 $a_table_name = strtolower($a_table_name);
93 $this->storeStep($a_table_name, 10);
94 }
95
96 // get auto increment information
97 $auto_inc_field = $this->analyzer->getAutoIncrementField($a_table_name);
98
99 // get primary key information
100 $pk = $this->analyzer->getPrimaryKeyInformation($a_table_name);
101
102 // get indices information
103 $indices = $this->analyzer->getIndicesInformation($a_table_name);
104
105 // get constraints information
106 $constraints = $this->analyzer->getConstraintsInformation($a_table_name);
107
108 // get field information
109 $fields = $this->analyzer->getFieldInformation($a_table_name);
110
111 if (!$this->getTestMode()) {
112 // remove auto increment
113 $this->removeAutoIncrement($a_table_name, $auto_inc_field, $fields);
114 $this->storeStep($a_table_name, 20);
115
116 // remove primary key
117 $this->removePrimaryKey($a_table_name, $pk);
118 $this->storeStep($a_table_name, 30);
119
120 // remove indices
121 $this->removeIndices($a_table_name, $indices);
122 $this->storeStep($a_table_name, 40);
123
124 // remove constraints
125 $this->removeConstraints($a_table_name, $constraints);
126 $this->storeStep($a_table_name, 45);
127 }
128
129 // alter table using mdb2 field types
130 $this->alterTable($a_table_name, $fields, $a_set_text_ts_fields_notnull_false, $pk);
131 if ($this->getTestMode()) {
132 $a_table_name = strtolower($a_table_name) . "_copy";
133 } else {
134 $this->storeStep($a_table_name, 50);
135 }
136
137 // lower case field names
138 $this->lowerCaseColumnNames($a_table_name);
139 if (!$this->getTestMode()) {
140 $this->storeStep($a_table_name, 60);
141 }
142
143 // add primary key
144 $this->addPrimaryKey($a_table_name, $pk);
145 if (!$this->getTestMode()) {
146 $this->storeStep($a_table_name, 70);
147 }
148
149 // add indices
150 $this->addIndices($a_table_name, $indices);
151 if (!$this->getTestMode()) {
152 $this->storeStep($a_table_name, 80);
153 }
154
155 // add constraints
156 $this->addConstraints($a_table_name, $constraints);
157 if (!$this->getTestMode()) {
158 $this->storeStep($a_table_name, 85);
159 }
160
161 // add "auto increment" sequence
162 if ($auto_inc_field != "") {
163 $this->addAutoIncrementSequence($a_table_name, $auto_inc_field);
164 }
165 if (!$this->getTestMode()) {
166 $this->storeStep($a_table_name, 90);
167 }
168
169 // replace empty strings with null values in text fields
170 $this->replaceEmptyStringsWithNull($a_table_name);
171 if (!$this->getTestMode()) {
172 $this->storeStep($a_table_name, 100);
173 }
174
175 // replace empty "0000-00-00..." dates with null
176 $this->replaceEmptyDatesWithNull($a_table_name);
177 if (!$this->getTestMode()) {
178 $this->storeStep($a_table_name, 110);
179 }
180
181 $nr_rec2 = $this->countRecords($a_table_name);
182
183 if (!$this->getTestMode()) {
184 if ($nr_rec != $nr_rec2) {
185 throw new ilDatabaseException("ilMySQLAbstraction: Unexpected difference in table record number, table '" . $a_table_name . "'."
186 . " Before: " . ((int) $nr_rec) . ", After: " . ((int) $nr_rec2) . ".");
187 }
188 }
189 }
190
191
198 public function countRecords($a_table_name)
199 {
200 global $ilDB;
201
202 $st = $ilDB->prepare("SELECT count(*) AS cnt FROM `" . $a_table_name . "`");
203 $res = $ilDB->execute($st);
204 $rec = $ilDB->fetchAssoc($res);
205
206 return $rec["cnt"];
207 }
208
209
216 public function storeStep($a_table, $a_step)
217 {
218 $st = $this->ilDBInterface->prepareManip("REPLACE INTO abstraction_progress (table_name, step)" . " VALUES (?,?)", array(
219 "text",
220 "integer",
221 ));
222 $this->ilDBInterface->execute($st, array( $a_table, $a_step ));
223 }
224
225
232 public function replaceEmptyStringsWithNull($a_table)
233 {
234 global $ilDB;
235
236 $fields = $this->analyzer->getFieldInformation($a_table);
237 $upfields = array();
238 foreach ($fields as $field => $def) {
239 if ($def["type"] == "text"
240 && ($def["length"] >= 1 && $def["length"] <= 4000)
241 ) {
242 $upfields[] = $field;
243 }
244 }
245 foreach ($upfields as $uf) {
246 $ilDB->query("UPDATE `" . $a_table . "` SET `" . $uf . "` = null WHERE `" . $uf . "` = ''");
247 }
248 }
249
250
257 public function replaceEmptyDatesWithNull($a_table)
258 {
259 global $ilDB;
260
261 if (!$this->ilDBInterface->tableExists($a_table)) {
262 return;
263 }
264
265 $fields = $this->analyzer->getFieldInformation($a_table);
266 $upfields = array();
267 foreach ($fields as $field => $def) {
268 if ($def["type"] == "timestamp") {
269 $upfields[] = $field;
270 }
271 }
272 foreach ($upfields as $uf) {
273 $ilDB->query("UPDATE `" . $a_table . "` SET `" . $uf . "` = null WHERE `" . $uf . "` = '0000-00-00 00:00:00'");
274 }
275
276 $upfields = array();
277 reset($fields);
278 foreach ($fields as $field => $def) {
279 if ($def["type"] == "date") {
280 $upfields[] = $field;
281 }
282 }
283 foreach ($upfields as $uf) {
284 $ilDB->query("UPDATE `" . $a_table . "` SET `" . $uf . "` = null WHERE `" . $uf . "` = '0000-00-00'");
285 }
286 }
287
288
294 public function lowerCaseTableName($a_table_name)
295 {
296 global $ilDB;
297
298 if ($a_table_name != strtolower($a_table_name)) {
299 // this may look strange, but it does not work directly
300 // (seems that mysql does not see no difference whether upper or lowercase characters are used
301 mysql_query("ALTER TABLE `" . $a_table_name . "` RENAME `" . strtolower($a_table_name) . "xxx" . "`");
302 mysql_query("ALTER TABLE `" . strtolower($a_table_name) . "xxx" . "` RENAME `" . strtolower($a_table_name) . "`");
303 }
304 }
305
306
312 public function lowerCaseColumnNames($a_table_name)
313 {
314 global $ilDB;
315
316 $result = mysql_query("SHOW COLUMNS FROM `" . $a_table_name . "`");
317 while ($row = mysql_fetch_assoc($result)) {
318 if ($row["Field"] != strtolower($row["Field"])) {
319 $ilDB->renameTableColumn($a_table_name, $row["Field"], strtolower($row["Field"]));
320 }
321 }
322 }
323
324
331 public function removeAutoIncrement($a_table_name, $a_auto_inc_field)
332 {
333 if ($a_auto_inc_field != "") {
334 $this->ilDBInterface->modifyTableColumn($a_table_name, $a_auto_inc_field, array());
335 }
336 }
337
338
345 public function removePrimaryKey($a_table, $a_pk)
346 {
347 if ($a_pk["name"] != "") {
348 $this->ilDBInterface->dropPrimaryKey($a_table, $a_pk["name"]);
349 }
350 }
351
352
359 public function removeIndices($a_table, $a_indices)
360 {
361 if (is_array($a_indices)) {
362 foreach ($a_indices as $index) {
363 $this->ilDBInterface->query("ALTER TABLE `" . $a_table . "` DROP INDEX `" . $index["name"] . "`");
364 }
365 }
366 }
367
368
375 public function removeConstraints($a_table, $a_constraints)
376 {
377 if (is_array($a_constraints)) {
378 foreach ($a_constraints as $c) {
379 if ($c["type"] == "unique") {
380 $this->ilDBInterface->query("ALTER TABLE `" . $a_table . "` DROP INDEX `" . $c["name"] . "`");
381 }
382 }
383 }
384 }
385
386
395 public function alterTable($a_table, $a_fields, $a_set_text_ts_fields_notnull_false = true, $pk = "")
396 {
397 $n_fields = array();
398 foreach ($a_fields as $field => $d) {
399 $def = $this->reverse->getTableFieldDefinition($a_table, $field);
400 $this->ilDBInterface->handleError($def);
401 $best_alt = $this->analyzer->getBestDefinitionAlternative($def);
402 $def = $def[$best_alt];
403
404 // remove "current_timestamp" default for timestamps (not supported)
405 if (strtolower($def["nativetype"]) == "timestamp"
406 && strtolower($def["default"]) == "current_timestamp"
407 ) {
408 unset($def["default"]);
409 }
410
411 if (strtolower($def["type"]) == "float") {
412 unset($def["length"]);
413 }
414
415 // remove all invalid attributes
416 foreach ($def as $k => $v) {
417 if (!in_array($k, array( "type", "default", "notnull", "length", "unsigned", "fixed" ))) {
418 unset($def[$k]);
419 }
420 }
421
422 // determine length for decimal type
423 if ($def["type"] == "decimal") {
424 $l_arr = explode(",", $def["length"]);
425 $def["length"] = $l_arr[0];
426 }
427
428 // remove length values for float
429 if ($def["type"] == "float") {
430 unset($def["length"]);
431 }
432
433 // set notnull to false for text/timestamp/date fields
434 if ($a_set_text_ts_fields_notnull_false
435 && ($def["type"] == "text"
436 || $def["type"] == "timestamp"
437 || $def["type"] == "date")
438 && (!is_array($pk) || !isset($field, $pk["fields"][$field]))
439 ) {
440 $def["notnull"] = false;
441 }
442
443 // set unsigned to false for integers
444 if ($def["type"] == "integer") {
445 $def["unsigned"] = false;
446 }
447
448 // set notnull to false for blob and clob
449 if ($def["type"] == "blob" || $def["type"] == "clob") {
450 $def["notnull"] = false;
451 }
452
453 // remove "0000-00-00..." default values
454 if (($def["type"] == "timestamp" && $def["default"] == "0000-00-00 00:00:00")
455 || ($def["type"] == "date" && $def["default"] == "0000-00-00")
456 ) {
457 unset($def["default"]);
458 }
459
460 $a = array();
461 foreach ($def as $k => $v) {
462 $a[$k] = $v;
463 }
464 $def["definition"] = $a;
465
466 $n_fields[$field] = $def;
467 }
468
469 $changes = array(
470 "change" => $n_fields,
471 );
472
473 if (!$this->getTestMode()) {
474 $r = $this->manager->alterTable($a_table, $changes, false);
475 } else {
476 $r = $this->manager->createTable(strtolower($a_table) . "_copy", $n_fields);
477 }
478
479 return true;
480 }
481
482
487 public function addPrimaryKey($a_table, $a_pk)
488 {
489 if (is_array($a_pk["fields"])) {
490 $fields = array();
491 foreach ($a_pk["fields"] as $f => $pos) {
492 $fields[] = strtolower($f);
493 }
494 $this->ilDBInterface->addPrimaryKey($a_table, $fields);
495 }
496 }
497
498
505 public function addIndices($a_table, $a_indices)
506 {
507 if (is_array($a_indices)) {
508 $all_valid = true;
509
510 foreach ($a_indices as $index) {
511 if (strlen($index["name"]) > 3) {
512 $all_valid = false;
513 }
514 }
515
516 $cnt = 1;
517 foreach ($a_indices as $index) {
518 if (is_array($index["fields"])) {
519 if (!$all_valid) {
520 $index["name"] = "i" . $cnt;
521 }
522 $fields = array();
523 foreach ($index["fields"] as $f => $pos) {
524 $fields[] = strtolower($f);
525 }
526 $this->ilDBInterface->addIndex($a_table, $fields, strtolower($index["name"]), $index["fulltext"]);
527 $cnt++;
528 }
529 }
530 }
531 }
532
533
540 public function addConstraints($a_table, $a_constraints)
541 {
542 if (is_array($a_constraints)) {
543 $all_valid = true;
544
545 foreach ($a_constraints as $c) {
546 if (strlen($c["name"]) > 3) {
547 $all_valid = false;
548 }
549 }
550
551 $cnt = 1;
552 foreach ($a_constraints as $c) {
553 if (is_array($c["fields"])) {
554 if (!$all_valid) {
555 $c["name"] = "c" . $cnt;
556 }
557 $fields = array();
558 foreach ($c["fields"] as $f => $pos) {
559 $fields[] = strtolower($f);
560 }
561 $this->ilDBInterface->addUniqueConstraint($a_table, $fields, strtolower($c["name"]));
562 $cnt++;
563 }
564 }
565 }
566 }
567
568
573 public function fixIndexNames($a_table)
574 {
575 if (!$this->ilDBInterface->tableExists($a_table)) {
576 return;
577 }
578 $all_valid = true;
579 $indices = $this->analyzer->getIndicesInformation($a_table);
580 foreach ($indices as $index) {
581 if (strlen($index["name"]) > 3) {
582 $all_valid = false;
583 }
584 }
585
586 if (!$all_valid) {
587 foreach ($indices as $index) {
588 $this->ilDBInterface->dropIndex($a_table, $index["name"]);
589 }
590 $this->addIndices($a_table, $indices);
591 }
592 }
593
594
601 public function addAutoIncrementSequence($a_table, $a_auto_inc_field)
602 {
603 if ($a_auto_inc_field != "") {
604 $set = $this->ilDBInterface->query("SELECT MAX(`" . strtolower($a_auto_inc_field) . "`) ma FROM `" . $a_table . "`");
605 $rec = $this->ilDBInterface->fetchAssoc($set);
606 $next = $rec["ma"] + 1;
607 $this->ilDBInterface->createSequence($a_table, $next);
608 }
609 }
610
611
616 public function fixClobNotNull($a_table)
617 {
618 if (!$this->ilDBInterface->tableExists($a_table)) {
619 return;
620 }
621 $all_valid = true;
622 $fields = $this->analyzer->getFieldInformation($a_table);
623 foreach ($fields as $name => $def) {
624 if ($def["type"] == "clob" && $def["notnull"] == true) {
625 $this->ilDBInterface->modifyTableColumn($a_table, $name, array( "type" => "clob", "notnull" => false ));
626 }
627 }
628 }
629
630
635 public function fixDatetimeValues($a_table)
636 {
637 if (!$this->ilDBInterface->tableExists($a_table)) {
638 return;
639 }
640 $all_valid = true;
641 $fields = $this->analyzer->getFieldInformation($a_table);
642 foreach ($fields as $name => $def) {
643 if ($def["type"] == "timestamp"
644 && ($def["notnull"] == true || $def["default"] == "0000-00-00 00:00:00")
645 ) {
646 $nd = array( "type" => "timestamp", "notnull" => false );
647 if ($def["default"] == "0000-00-00 00:00:00") {
648 $nd["default"] = null;
649 }
650 $this->ilDBInterface->modifyTableColumn($a_table, $name, $nd);
651 }
652 if ($def["type"] == "date"
653 && ($def["notnull"] == true || $def["default"] == "0000-00-00")
654 ) {
655 $nd = array( "type" => "date", "notnull" => false );
656 if ($def["default"] == "0000-00-00") {
657 $nd["default"] = null;
658 }
659 $this->ilDBInterface->modifyTableColumn($a_table, $name, $nd);
660 }
661 }
662 }
663}
$result
An exception for terminatinating execution or to throw for unit testing.
This class gives all kind of DB information using the MDB2 manager and reverse module.
Class ilDatabaseException.
This class includes methods that help to abstract ILIAS 3.10.x MySQL tables for the use with MDB2 abs...
lowerCaseColumnNames($a_table_name)
lower case column names
fixClobNotNull($a_table)
This is only used on tables that have already been abstracted but missed the "full treatment".
performAbstraction($a_table_name, $a_set_text_ts_fields_notnull_false=true)
Converts an existing (MySQL) ILIAS table in an abstract table.
fixIndexNames($a_table)
This is only used on tables that have already been abstracted but missed the "full treatment".
countRecords($a_table_name)
Check number of records before and after.
replaceEmptyDatesWithNull($a_table)
Replace empty dates with null.
removeConstraints($a_table, $a_constraints)
Remove Constraints.
removeIndices($a_table, $a_indices)
Remove Indices.
alterTable($a_table, $a_fields, $a_set_text_ts_fields_notnull_false=true, $pk="")
replaceEmptyStringsWithNull($a_table)
Replace empty strings with null values.
fixDatetimeValues($a_table)
This is only used on tables that have already been abstracted but missed the "full treatment".
lowerCaseTableName($a_table_name)
Lower case table and field names.
removePrimaryKey($a_table, $a_pk)
Remove primary key from table.
addConstraints($a_table, $a_constraints)
Add constraints.
addIndices($a_table, $a_indices)
Add indices.
storeStep($a_table, $a_step)
Store performed step.
removeAutoIncrement($a_table_name, $a_auto_inc_field)
Remove auto_increment attribute of a field.
addAutoIncrementSequence($a_table, $a_auto_inc_field)
Add autoincrement sequence.
$def
Definition: croninfo.php:21
for( $i=6;$i< 13;$i++) for($i=1; $i< 13; $i++) $d
Definition: date.php:296
$nd
Definition: error.php:10
$r
Definition: example_031.php:79
Interface ilDBInterface.
execute($stmt, $data=array())
fetchAssoc($query_result)
addPrimaryKey($table_name, $primary_keys)
query($query)
Run a (read-only) Query on the database.
modifyTableColumn($table, $column, $attributes)
tableExists($table_name)
createSequence($table_name, $start=1)
prepareManip($a_query, $a_types=null)
dropIndex($a_table, $a_name="i1")
addIndex($table_name, $fields, $index_name='', $fulltext=false)
if($format !==null) $name
Definition: metadata.php:146
$index
Definition: metadata.php:60
foreach($_POST as $key=> $value) $res
global $ilDB