ILIAS  release_5-2 Revision v5.2.25-18-g3f80b828510
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
17 public $analyzer;
21 protected $ilDBInterface;
25 protected $manager;
29 protected $reverse;
33 protected $testmode;
34
35
39 public function __construct() {
40 global $ilDB;
41
42 $this->ilDBInterface = $ilDB;
43 $this->manager = $ilDB->loadModule(ilDBConstants::MODULE_MANAGER);
44 $this->reverse = $ilDB->loadModule(ilDBConstants::MODULE_REVERSE);
45 if (@is_file('../Services/Database/classes/class.ilDBAnalyzer.php')) {
46 include_once '../Services/Database/classes/class.ilDBAnalyzer.php';
47 } else {
48 include_once './Services/Database/classes/class.ilDBAnalyzer.php';
49 }
50 $this->analyzer = new ilDBAnalyzer();
51 $this->setTestMode(false);
52 }
53
54
58 public function setTestMode($a_testmode) {
59 $this->testmode = $a_testmode;
60 }
61
62
66 public function getTestMode() {
67 return $this->testmode;
68 }
69
70
78 public function performAbstraction($a_table_name, $a_set_text_ts_fields_notnull_false = true) {
79 // to do: log this procedure
80
81 // count number of records at the beginning
82 $nr_rec = $this->countRecords($a_table_name);
83
84 // convert table name to lowercase
85 if (!$this->getTestMode()) {
86 $this->lowerCaseTableName($a_table_name);
87 $a_table_name = strtolower($a_table_name);
88 $this->storeStep($a_table_name, 10);
89 }
90
91 // get auto increment information
92 $auto_inc_field = $this->analyzer->getAutoIncrementField($a_table_name);
93
94 // get primary key information
95 $pk = $this->analyzer->getPrimaryKeyInformation($a_table_name);
96
97 // get indices information
98 $indices = $this->analyzer->getIndicesInformation($a_table_name);
99
100 // get constraints information
101 $constraints = $this->analyzer->getConstraintsInformation($a_table_name);
102
103 // get field information
104 $fields = $this->analyzer->getFieldInformation($a_table_name);
105
106 if (!$this->getTestMode()) {
107 // remove auto increment
108 $this->removeAutoIncrement($a_table_name, $auto_inc_field, $fields);
109 $this->storeStep($a_table_name, 20);
110
111 // remove primary key
112 $this->removePrimaryKey($a_table_name, $pk);
113 $this->storeStep($a_table_name, 30);
114
115 // remove indices
116 $this->removeIndices($a_table_name, $indices);
117 $this->storeStep($a_table_name, 40);
118
119 // remove constraints
120 $this->removeConstraints($a_table_name, $constraints);
121 $this->storeStep($a_table_name, 45);
122 }
123
124 // alter table using mdb2 field types
125 $this->alterTable($a_table_name, $fields, $a_set_text_ts_fields_notnull_false, $pk);
126 if ($this->getTestMode()) {
127 $a_table_name = strtolower($a_table_name) . "_copy";
128 } else {
129 $this->storeStep($a_table_name, 50);
130 }
131
132 // lower case field names
133 $this->lowerCaseColumnNames($a_table_name);
134 if (!$this->getTestMode()) {
135 $this->storeStep($a_table_name, 60);
136 }
137
138 // add primary key
139 $this->addPrimaryKey($a_table_name, $pk);
140 if (!$this->getTestMode()) {
141 $this->storeStep($a_table_name, 70);
142 }
143
144 // add indices
145 $this->addIndices($a_table_name, $indices);
146 if (!$this->getTestMode()) {
147 $this->storeStep($a_table_name, 80);
148 }
149
150 // add constraints
151 $this->addConstraints($a_table_name, $constraints);
152 if (!$this->getTestMode()) {
153 $this->storeStep($a_table_name, 85);
154 }
155
156 // add "auto increment" sequence
157 if ($auto_inc_field != "") {
158 $this->addAutoIncrementSequence($a_table_name, $auto_inc_field);
159 }
160 if (!$this->getTestMode()) {
161 $this->storeStep($a_table_name, 90);
162 }
163
164 // replace empty strings with null values in text fields
165 $this->replaceEmptyStringsWithNull($a_table_name);
166 if (!$this->getTestMode()) {
167 $this->storeStep($a_table_name, 100);
168 }
169
170 // replace empty "0000-00-00..." dates with null
171 $this->replaceEmptyDatesWithNull($a_table_name);
172 if (!$this->getTestMode()) {
173 $this->storeStep($a_table_name, 110);
174 }
175
176 $nr_rec2 = $this->countRecords($a_table_name);
177
178 if (!$this->getTestMode()) {
179 if ($nr_rec != $nr_rec2) {
180 throw new ilDatabaseException("ilMySQLAbstraction: Unexpected difference in table record number, table '" . $a_table_name . "'."
181 . " Before: " . ((int)$nr_rec) . ", After: " . ((int)$nr_rec2) . ".");
182 }
183 }
184 }
185
186
193 public function countRecords($a_table_name) {
194 global $ilDB;
195
196 $st = $ilDB->prepare("SELECT count(*) AS cnt FROM `" . $a_table_name . "`");
197 $res = $ilDB->execute($st);
198 $rec = $ilDB->fetchAssoc($res);
199
200 return $rec["cnt"];
201 }
202
203
210 public function storeStep($a_table, $a_step) {
211 $st = $this->ilDBInterface->prepareManip("REPLACE INTO abstraction_progress (table_name, step)" . " VALUES (?,?)", array(
212 "text",
213 "integer",
214 ));
215 $this->ilDBInterface->execute($st, array( $a_table, $a_step ));
216 }
217
218
225 public function replaceEmptyStringsWithNull($a_table) {
226 global $ilDB;
227
228 $fields = $this->analyzer->getFieldInformation($a_table);
229 $upfields = array();
230 foreach ($fields as $field => $def) {
231 if ($def["type"] == "text"
232 && ($def["length"] >= 1 && $def["length"] <= 4000)
233 ) {
234 $upfields[] = $field;
235 }
236 }
237 foreach ($upfields as $uf) {
238 $ilDB->query("UPDATE `" . $a_table . "` SET `" . $uf . "` = null WHERE `" . $uf . "` = ''");
239 }
240 }
241
242
249 public function replaceEmptyDatesWithNull($a_table) {
250 global $ilDB;
251
252 if (!$this->ilDBInterface->tableExists($a_table)) {
253 return;
254 }
255
256 $fields = $this->analyzer->getFieldInformation($a_table);
257 $upfields = array();
258 foreach ($fields as $field => $def) {
259 if ($def["type"] == "timestamp") {
260 $upfields[] = $field;
261 }
262 }
263 foreach ($upfields as $uf) {
264 $ilDB->query("UPDATE `" . $a_table . "` SET `" . $uf . "` = null WHERE `" . $uf . "` = '0000-00-00 00:00:00'");
265 }
266
267 $upfields = array();
268 reset($fields);
269 foreach ($fields as $field => $def) {
270 if ($def["type"] == "date") {
271 $upfields[] = $field;
272 }
273 }
274 foreach ($upfields as $uf) {
275 $ilDB->query("UPDATE `" . $a_table . "` SET `" . $uf . "` = null WHERE `" . $uf . "` = '0000-00-00'");
276 }
277 }
278
279
285 public function lowerCaseTableName($a_table_name) {
286 global $ilDB;
287
288 if ($a_table_name != strtolower($a_table_name)) {
289 // this may look strange, but it does not work directly
290 // (seems that mysql does not see no difference whether upper or lowercase characters are used
291 mysql_query("ALTER TABLE `" . $a_table_name . "` RENAME `" . strtolower($a_table_name) . "xxx" . "`");
292 mysql_query("ALTER TABLE `" . strtolower($a_table_name) . "xxx" . "` RENAME `" . strtolower($a_table_name) . "`");
293 }
294 }
295
296
302 public function lowerCaseColumnNames($a_table_name) {
303 global $ilDB;
304
305 $result = mysql_query("SHOW COLUMNS FROM `" . $a_table_name . "`");
306 while ($row = mysql_fetch_assoc($result)) {
307 if ($row["Field"] != strtolower($row["Field"])) {
308 $ilDB->renameTableColumn($a_table_name, $row["Field"], strtolower($row["Field"]));
309 }
310 }
311 }
312
313
320 public function removeAutoIncrement($a_table_name, $a_auto_inc_field) {
321 if ($a_auto_inc_field != "") {
322 $this->ilDBInterface->modifyTableColumn($a_table_name, $a_auto_inc_field, array());
323 }
324 }
325
326
333 public function removePrimaryKey($a_table, $a_pk) {
334 if ($a_pk["name"] != "") {
335 $this->ilDBInterface->dropPrimaryKey($a_table, $a_pk["name"]);
336 }
337 }
338
339
346 public function removeIndices($a_table, $a_indices) {
347 if (is_array($a_indices)) {
348 foreach ($a_indices as $index) {
349 $this->ilDBInterface->query("ALTER TABLE `" . $a_table . "` DROP INDEX `" . $index["name"] . "`");
350 }
351 }
352 }
353
354
361 public function removeConstraints($a_table, $a_constraints) {
362 if (is_array($a_constraints)) {
363 foreach ($a_constraints as $c) {
364 if ($c["type"] == "unique") {
365 $this->ilDBInterface->query("ALTER TABLE `" . $a_table . "` DROP INDEX `" . $c["name"] . "`");
366 }
367 }
368 }
369 }
370
371
380 public function alterTable($a_table, $a_fields, $a_set_text_ts_fields_notnull_false = true, $pk = "") {
381 $n_fields = array();
382 foreach ($a_fields as $field => $d) {
383 $def = $this->reverse->getTableFieldDefinition($a_table, $field);
384 $this->ilDBInterface->handleError($def);
385 $best_alt = $this->analyzer->getBestDefinitionAlternative($def);
386 $def = $def[$best_alt];
387
388 // remove "current_timestamp" default for timestamps (not supported)
389 if (strtolower($def["nativetype"]) == "timestamp"
390 && strtolower($def["default"]) == "current_timestamp"
391 ) {
392 unset($def["default"]);
393 }
394
395 if (strtolower($def["type"]) == "float") {
396 unset($def["length"]);
397 }
398
399 // remove all invalid attributes
400 foreach ($def as $k => $v) {
401 if (!in_array($k, array( "type", "default", "notnull", "length", "unsigned", "fixed" ))) {
402 unset($def[$k]);
403 }
404 }
405
406 // determine length for decimal type
407 if ($def["type"] == "decimal") {
408 $l_arr = explode(",", $def["length"]);
409 $def["length"] = $l_arr[0];
410 }
411
412 // remove length values for float
413 if ($def["type"] == "float") {
414 unset($def["length"]);
415 }
416
417 // set notnull to false for text/timestamp/date fields
418 if ($a_set_text_ts_fields_notnull_false
419 && ($def["type"] == "text"
420 || $def["type"] == "timestamp"
421 || $def["type"] == "date")
422 && (!is_array($pk) || !isset($field, $pk["fields"][$field]))
423 ) {
424 $def["notnull"] = false;
425 }
426
427 // set unsigned to false for integers
428 if ($def["type"] == "integer") {
429 $def["unsigned"] = false;
430 }
431
432 // set notnull to false for blob and clob
433 if ($def["type"] == "blob" || $def["type"] == "clob") {
434 $def["notnull"] = false;
435 }
436
437 // remove "0000-00-00..." default values
438 if (($def["type"] == "timestamp" && $def["default"] == "0000-00-00 00:00:00")
439 || ($def["type"] == "date" && $def["default"] == "0000-00-00")
440 ) {
441 unset($def["default"]);
442 }
443
444 $a = array();
445 foreach ($def as $k => $v) {
446 $a[$k] = $v;
447 }
448 $def["definition"] = $a;
449
450 $n_fields[$field] = $def;
451 }
452
453 $changes = array(
454 "change" => $n_fields,
455 );
456
457 if (!$this->getTestMode()) {
458 $r = $this->manager->alterTable($a_table, $changes, false);
459 } else {
460 $r = $this->manager->createTable(strtolower($a_table) . "_copy", $n_fields);
461 }
462
463 return true;
464 }
465
466
471 public function addPrimaryKey($a_table, $a_pk) {
472 if (is_array($a_pk["fields"])) {
473 $fields = array();
474 foreach ($a_pk["fields"] as $f => $pos) {
475 $fields[] = strtolower($f);
476 }
477 $this->ilDBInterface->addPrimaryKey($a_table, $fields);
478 }
479 }
480
481
488 public function addIndices($a_table, $a_indices) {
489 if (is_array($a_indices)) {
490 $all_valid = true;
491
492 foreach ($a_indices as $index) {
493 if (strlen($index["name"]) > 3) {
494 $all_valid = false;
495 }
496 }
497
498 $cnt = 1;
499 foreach ($a_indices as $index) {
500 if (is_array($index["fields"])) {
501 if (!$all_valid) {
502 $index["name"] = "i" . $cnt;
503 }
504 $fields = array();
505 foreach ($index["fields"] as $f => $pos) {
506 $fields[] = strtolower($f);
507 }
508 $this->ilDBInterface->addIndex($a_table, $fields, strtolower($index["name"]), $index["fulltext"]);
509 $cnt ++;
510 }
511 }
512 }
513 }
514
515
522 public function addConstraints($a_table, $a_constraints) {
523 if (is_array($a_constraints)) {
524 $all_valid = true;
525
526 foreach ($a_constraints as $c) {
527 if (strlen($c["name"]) > 3) {
528 $all_valid = false;
529 }
530 }
531
532 $cnt = 1;
533 foreach ($a_constraints as $c) {
534 if (is_array($c["fields"])) {
535 if (!$all_valid) {
536 $c["name"] = "c" . $cnt;
537 }
538 $fields = array();
539 foreach ($c["fields"] as $f => $pos) {
540 $fields[] = strtolower($f);
541 }
542 $this->ilDBInterface->addUniqueConstraint($a_table, $fields, strtolower($c["name"]));
543 $cnt ++;
544 }
545 }
546 }
547 }
548
549
554 public function fixIndexNames($a_table) {
555 if (!$this->ilDBInterface->tableExists($a_table)) {
556 return;
557 }
558 $all_valid = true;
559 $indices = $this->analyzer->getIndicesInformation($a_table);
560 foreach ($indices as $index) {
561 if (strlen($index["name"]) > 3) {
562 $all_valid = false;
563 }
564 }
565
566 if (!$all_valid) {
567 foreach ($indices as $index) {
568 $this->ilDBInterface->dropIndex($a_table, $index["name"]);
569 }
570 $this->addIndices($a_table, $indices);
571 }
572 }
573
574
581 public function addAutoIncrementSequence($a_table, $a_auto_inc_field) {
582 if ($a_auto_inc_field != "") {
583 $set = $this->ilDBInterface->query("SELECT MAX(`" . strtolower($a_auto_inc_field) . "`) ma FROM `" . $a_table . "`");
584 $rec = $this->ilDBInterface->fetchAssoc($set);
585 $next = $rec["ma"] + 1;
586 $this->ilDBInterface->createSequence($a_table, $next);
587 }
588 }
589
590
595 public function fixClobNotNull($a_table) {
596 if (!$this->ilDBInterface->tableExists($a_table)) {
597 return;
598 }
599 $all_valid = true;
600 $fields = $this->analyzer->getFieldInformation($a_table);
601 foreach ($fields as $name => $def) {
602 if ($def["type"] == "clob" && $def["notnull"] == true) {
603 $this->ilDBInterface->modifyTableColumn($a_table, $name, array( "type" => "clob", "notnull" => false ));
604 }
605 }
606 }
607
608
613 public function fixDatetimeValues($a_table) {
614 if (!$this->ilDBInterface->tableExists($a_table)) {
615 return;
616 }
617 $all_valid = true;
618 $fields = $this->analyzer->getFieldInformation($a_table);
619 foreach ($fields as $name => $def) {
620 if ($def["type"] == "timestamp"
621 && ($def["notnull"] == true || $def["default"] == "0000-00-00 00:00:00")
622 ) {
623 $nd = array( "type" => "timestamp", "notnull" => false );
624 if ($def["default"] == "0000-00-00 00:00:00") {
625 $nd["default"] = null;
626 }
627 $this->ilDBInterface->modifyTableColumn($a_table, $name, $nd);
628 }
629 if ($def["type"] == "date"
630 && ($def["notnull"] == true || $def["default"] == "0000-00-00")
631 ) {
632 $nd = array( "type" => "date", "notnull" => false );
633 if ($def["default"] == "0000-00-00") {
634 $nd["default"] = null;
635 }
636 $this->ilDBInterface->modifyTableColumn($a_table, $name, $nd);
637 }
638 }
639 }
640}
for($col=0; $col< 50; $col++) $d
$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.
$nd
Definition: error.php:11
$r
Definition: example_031.php:79
Interface ilDBInterface.
execute($stmt, $data=array())
fetchAssoc($query_result)
addPrimaryKey($table_name, $primary_keys)
query($query)
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)
global $ilDB